#include "saem.h" #include "facilities.h" #include "infrastructure.h" #include "tpm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include SAEM_CODE_R saem_check(void* fc, bulletin_t* bulletin, SAEM_t* saem, uint8_t* neighbour) { facilities_t* facilities = (facilities_t*) fc; int rv = 0; if (saem->header.messageID != messageID_saem) { return SAEM_INVALID_HEADER_MESSAGE_ID; } if (saem->header.protocolVersion != 1) { return SAEM_INVALID_HEADER_VERSION; } pthread_mutex_lock(&bulletin->lock); if (saem->sam.body.serviceInfos) { for (int i = 0; i < saem->sam.body.serviceInfos->list.count; ++i) { ServiceInfo_t* si = saem->sam.body.serviceInfos->list.array[i]; uint16_t its_aid = si->serviceID; int index = -1; for (int a = 0; a < bulletin->to_consume_len; ++a) { // TODO allow different services for same itsAid and stationID /* Check existence through stationID and itsAid */ if (saem->header.stationID == bulletin->to_consume[a]->station_id && its_aid == bulletin->to_consume[a]->its_aid) { index = a; break; } } if (index == -1) { rv = SAEM_NEW; if (bulletin->to_consume_len + 1 < MAX_ANNOUNCEMENTS_LEN) { bulletin->to_consume[bulletin->to_consume_len]->its_aid = its_aid; bulletin->to_consume[bulletin->to_consume_len]->station_id = saem->header.stationID; bulletin->to_consume[bulletin->to_consume_len]->timestamp = it2s_tender_get_clock(&facilities->epv); if (si->chOptions.extensions) { for (int e = 0; e < si->chOptions.extensions->list.count; ++e) { switch (si->chOptions.extensions->list.array[e]->present) { case ServiceInfoExt_PR_providerServiceContext: bulletin->to_consume[bulletin->to_provide_len]->info.context_len = si->chOptions.extensions->list.array[e]->choice.providerServiceContext.size; bulletin->to_consume[bulletin->to_provide_len]->info.context = malloc(si->chOptions.extensions->list.array[e]->choice.providerServiceContext.size); memcpy(bulletin->to_consume[bulletin->to_provide_len]->info.context, si->chOptions.extensions->list.array[e]->choice.providerServiceContext.buf, si->chOptions.extensions->list.array[e]->choice.providerServiceContext.size ); break; case ServiceInfoExt_PR_applicationDataSAM: bulletin->to_consume[bulletin->to_provide_len]->info.data_len = si->chOptions.extensions->list.array[e]->choice.applicationDataSAM.size; bulletin->to_consume[bulletin->to_provide_len]->info.data = malloc(si->chOptions.extensions->list.array[e]->choice.applicationDataSAM.size); memcpy(bulletin->to_consume[bulletin->to_provide_len]->info.data, si->chOptions.extensions->list.array[e]->choice.applicationDataSAM.buf, si->chOptions.extensions->list.array[e]->choice.applicationDataSAM.size ); if (facilities->station_type != 15 && facilities->tolling.infos.length < TOLLING_INFOS_MAX_LENGTH) { TollingPaymentInfo_t* tpi = NULL; asn_dec_rval_t dec = uper_decode_complete( NULL, &asn_DEF_TollingPaymentInfo, (void**) &tpi, si->chOptions.extensions->list.array[e]->choice.applicationDataSAM.buf, si->chOptions.extensions->list.array[e]->choice.applicationDataSAM.size ); if (!dec.code) { facilities->tolling.infos.z[facilities->tolling.infos.length] = tolling_info_new(&facilities->epv, tpi); bulletin->to_consume[bulletin->to_provide_len]->info.internal_p = facilities->tolling.infos.z[facilities->tolling.infos.length]; ++facilities->tolling.infos.length; } else { ASN_STRUCT_FREE(asn_DEF_TollingPaymentInfo, tpi); } } break; case ServiceInfoExt_PR_addressIPv6: memcpy(bulletin->to_consume[bulletin->to_consume_len]->endpoint.ipv6_addr, si->chOptions.extensions->list.array[e]->choice.addressIPv6.buf, 16); break; case ServiceInfoExt_PR_servicePort: bulletin->to_consume[bulletin->to_consume_len]->endpoint.port = si->chOptions.extensions->list.array[e]->choice.servicePort; break; default: break; } } } if (neighbour) { bulletin->to_consume[bulletin->to_consume_len]->certificate_id = malloc(8); memcpy(bulletin->to_consume[bulletin->to_consume_len]->certificate_id, neighbour, 8); } index = bulletin->to_consume_len; ++bulletin->to_consume_len; } } uint16_t ci_index = si->channelIndex; // TODO channelInfos if (saem->sam.body.channelInfos) { if (saem->sam.body.channelInfos->list.count >= ci_index + 1) { } } } } pthread_mutex_unlock(&bulletin->lock); return rv == SAEM_NEW ? SAEM_NEW : SAEM_OK; } void bulletin_init(bulletin_t* bulletin) { pthread_mutex_init(&bulletin->lock, NULL); bulletin->to_consume_len = 0; for (int i = 0; i < MAX_ANNOUNCEMENTS_LEN; ++i) { bulletin->to_consume[i] = calloc(1, sizeof(announcement_t)); } } int mk_saem(facilities_t* facilities, uint8_t* b_saem, uint32_t* b_saem_len) { int rv = 0; // Check tolling advertisements if (!facilities->tolling.infos.length) { return 1; } asn_enc_rval_t enc; SAEM_t* saem = calloc(1, sizeof(SAEM_t)); /* header */ saem->header.protocolVersion = 1; saem->header.messageID = messageID_saem; pthread_mutex_lock(&facilities->id.lock); saem->header.stationID = facilities->id.station_id; /* sam */ saem->sam.version = 0; saem->sam.body.serviceInfos = calloc(1, sizeof(ServiceInfos_t)); saem->sam.body.serviceInfos->list.count = facilities->bulletin.to_provide_len; saem->sam.body.serviceInfos->list.size = facilities->bulletin.to_provide_len * sizeof(void*); saem->sam.body.serviceInfos->list.array = malloc(facilities->bulletin.to_provide_len * sizeof(void*)); uint8_t buf[1024]; for (int i = 0; i < facilities->bulletin.to_provide_len; ++i) { saem->sam.body.serviceInfos->list.array[i] = calloc(1, sizeof(ServiceInfo_t)); saem->sam.body.serviceInfos->list.array[i]->serviceID = facilities->bulletin.to_provide[i]->its_aid; saem->sam.body.serviceInfos->list.array[i]->chOptions.extensions = calloc(1, sizeof(ServiceInfoExts_t)); ServiceInfoExts_t* exts = saem->sam.body.serviceInfos->list.array[i]->chOptions.extensions; switch (facilities->tolling.protocol) { case TOLLING_PROTOCOL_SIMPLE: exts->list.count = 3; exts->list.size = 3 * sizeof(void*); exts->list.array = malloc(3 * sizeof(void*)); exts->list.array[0] = calloc(1, sizeof(ServiceInfoExt_t)); exts->list.array[0]->present = ServiceInfoExt_PR_providerServiceContext; char ctx_s[] = "tolling:simple"; exts->list.array[0]->choice.providerServiceContext.size = strlen(ctx_s); exts->list.array[0]->choice.providerServiceContext.buf = malloc(strlen(ctx_s)); memcpy(exts->list.array[0]->choice.providerServiceContext.buf, ctx_s, strlen(ctx_s)); exts->list.array[1] = calloc(1, sizeof(ServiceInfoExt_t)); exts->list.array[1]->present = ServiceInfoExt_PR_servicePort; exts->list.array[1]->choice.servicePort = 7011; exts->list.array[2] = calloc(1, sizeof(ServiceInfoExt_t)); exts->list.array[2]->present = ServiceInfoExt_PR_applicationDataSAM; exts->list.array[2]->choice.applicationDataSAM.buf = malloc(1024); enc = uper_encode_to_buffer(&asn_DEF_TollingPaymentInfo, NULL, facilities->tolling.infos.z[0]->asn, exts->list.array[2]->choice.applicationDataSAM.buf, 1024); if (enc.encoded == -1) { syslog_err("[facilities] [sa] failure to encode TollingPaymentInfo (%s)", enc.failed_type->name); rv = 1; goto cleanup; } exts->list.array[2]->choice.applicationDataSAM.size = (enc.encoded + 7) / 8; break; case TOLLING_PROTOCOL_TLS: exts->list.count = 4; exts->list.size = 4 * sizeof(void*); exts->list.array = malloc(4 * sizeof(void*)); exts->list.array[0] = calloc(1, sizeof(ServiceInfoExt_t)); exts->list.array[0]->present = ServiceInfoExt_PR_providerServiceContext; char ctx_t[] = "tolling:tls"; exts->list.array[0]->choice.providerServiceContext.size = strlen(ctx_t); exts->list.array[0]->choice.providerServiceContext.buf = malloc(strlen(ctx_t)); memcpy(exts->list.array[0]->choice.providerServiceContext.buf, ctx_t, strlen(ctx_t)); exts->list.array[1] = calloc(1, sizeof(ServiceInfoExt_t)); exts->list.array[1]->present = ServiceInfoExt_PR_addressIPv6; exts->list.array[1]->choice.addressIPv6.size = 16; exts->list.array[1]->choice.addressIPv6.buf = malloc(16); memcpy(exts->list.array[1]->choice.addressIPv6.buf, facilities->id.ipv6_addr, 16); exts->list.array[2] = calloc(1, sizeof(ServiceInfoExt_t)); exts->list.array[2]->present = ServiceInfoExt_PR_servicePort; exts->list.array[2]->choice.servicePort = 7011; exts->list.array[3] = calloc(1, sizeof(ServiceInfoExt_t)); exts->list.array[3]->present = ServiceInfoExt_PR_applicationDataSAM; exts->list.array[3]->choice.applicationDataSAM.buf = malloc(1024); enc = uper_encode_to_buffer(&asn_DEF_TollingPaymentInfo, NULL, facilities->tolling.infos.z[0]->asn, exts->list.array[3]->choice.applicationDataSAM.buf, 1024); if (enc.encoded == -1) { syslog_err("[facilities] [sa] failure to encode TollingPaymentInfo (%s)", enc.failed_type->name); rv = 1; goto cleanup; } exts->list.array[3]->choice.applicationDataSAM.size = (enc.encoded + 7) / 8; break; } } pthread_mutex_unlock(&facilities->id.lock); enc = asn_encode_to_buffer(NULL, ATS_UNALIGNED_CANONICAL_PER, &asn_DEF_SAEM, saem, b_saem, *b_saem_len); if (enc.encoded == -1) { syslog_err("[facilities] [sa] failure to encode SAEM (%s)", enc.failed_type->name); rv = 1; goto cleanup; } *b_saem_len = enc.encoded; cleanup: ASN_STRUCT_FREE(asn_DEF_SAEM, saem); return rv; } void *sa_service(void *fc) { facilities_t *facilities = (facilities_t*) fc; pthread_mutex_init(&facilities->bulletin.lock, NULL); TransportRequest_t *tr = calloc(1, sizeof(TransportRequest_t)); tr->present = TransportRequest_PR_packet; TransportPacketRequest_t* tpr = &tr->choice.packet; tpr->present = TransportPacketRequest_PR_btp; BTPPacketRequest_t *bpr = &tpr->choice.btp; bulletin_t* bulletin = &facilities->bulletin; bpr->btpType = BTPType_btpB; bpr->gn.destinationAddress.buf = malloc(6); for (int i = 0; i < 6; ++i) { bpr->gn.destinationAddress.buf[i] = 0xff; } bpr->gn.destinationAddress.size = 6; bpr->gn.packetTransportType = PacketTransportType_shb; bpr->destinationPort = Port_saem; bpr->gn.trafficClass = 2; bpr->data.buf = malloc(512); bpr->data.size = 512; bpr->gn.securityProfile.sign = true; void* security_socket = zmq_socket(facilities->zmq.ctx, ZMQ_REQ); zmq_connect(security_socket, facilities->zmq.security_address); uint8_t tr_oer[1024]; tr_oer[0] = 4; // Facilities int rv = 0; int sleep_ms = 100; int mk_saem_n_sleep = 0; while (!facilities->exit) { if (bulletin->to_provide_len && sleep_ms*mk_saem_n_sleep >= 1000) { rv = mk_saem(facilities, bpr->data.buf, (uint32_t *) &bpr->data.size); if (!rv) { bpr->id = rand() + 1; asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_TransportRequest, NULL, tr, tr_oer+1, 1023); if (enc.encoded == -1) { syslog_err("[facilities] encoding TR for SAEM failed"); continue; } else { it2s_tender_queue_send(facilities->tx_queue, tr_oer, enc.encoded+1, ITSS_TRANSPORT, bpr->id, "TR.packet.btp"); // Logging if (facilities->logging.dbms) { pthread_mutex_lock(&facilities->id.lock); uint64_t station_id = facilities->id.station_id; pthread_mutex_unlock(&facilities->id.lock); it2s_tender_db_add(facilities->logging.dbms, station_id, bpr->id, &facilities->epv, true, messageID_saem, NULL, bpr->data.buf, bpr->data.size); } if (facilities->logging.recorder) { uint16_t buffer_len = 2048; uint8_t buffer[buffer_len]; int e = it2s_tender_management_record_packet_sdu( buffer, buffer_len, bpr->data.buf, bpr->data.size, bpr->id, it2s_tender_get_clock(&facilities->epv), ITSS_FACILITIES, true); if (e != -1) { it2s_tender_queue_send(facilities->tx_queue, buffer, e, ITSS_MANAGEMENT, bpr->id, "MReq.packet.set"); } } } } mk_saem_n_sleep = 0; } ++mk_saem_n_sleep; int32_t lat, lon; it2s_tender_lock_space(&facilities->epv); it2s_tender_get_space(&facilities->epv); lat = facilities->epv.space.latitude; lon = facilities->epv.space.longitude; it2s_tender_unlock_space(&facilities->epv); uint64_t now = it2s_tender_get_clock(&facilities->epv); pthread_mutex_lock(&bulletin->lock); for (int a = 0; a < bulletin->to_consume_len; ++a) { /* do some checks, e.g. * is advertised service close by? * do we want to enjoy the advertised service? */ // Tolling if (facilities->tolling.enabled && bulletin->to_consume[a]->its_aid == 0 && now > bulletin->to_consume[a]->t_trigger + TOLLING_PAYMENT_MIN_PERIOD_MS && facilities->station_type != 15) { tolling_info_s* info = (tolling_info_s*) bulletin->to_consume[a]->info.internal_p; if (!tpm_is_inside_zone(facilities, info)) { continue; } switch (facilities->tolling.protocol) { case TOLLING_PROTOCOL_SIMPLE: tpm_pay(facilities, info, security_socket, bulletin->to_consume[a]->certificate_id, NULL); ++bulletin->to_consume[a]->n_trigger; bulletin->to_consume[a]->t_trigger = now; break; case TOLLING_PROTOCOL_TLS: tpm_pay(facilities, info, security_socket, NULL, bulletin->to_consume[a]->endpoint.ipv6_addr); ++bulletin->to_consume[a]->n_trigger; bulletin->to_consume[a]->t_trigger = now; break; } } } pthread_mutex_unlock(&bulletin->lock); usleep(sleep_ms*1000); } ASN_STRUCT_FREE(asn_DEF_TransportRequest, tr); return NULL; }