1556 lines
66 KiB
C
1556 lines
66 KiB
C
#include "tpm.h"
|
|
#include "facilities.h"
|
|
#include "edm.h"
|
|
|
|
#include <it2s-tender/constants.h>
|
|
#include <it2s-asn/etsi-its-sdu/itss-security/EIS_SecurityRequest.h>
|
|
#include <it2s-asn/etsi-its-sdu/itss-security/EIS_SecurityReply.h>
|
|
#include <it2s-asn/etsi-its-sdu/itss-facilities/EIS_FacilitiesIndication.h>
|
|
#include <it2s-tender/time.h>
|
|
#include <it2s-asn/etsi-its-sdu/itss-networking/EIS_NetworkingRequest.h>
|
|
#include <it2s-tender/space.h>
|
|
#include <it2s-tender/recorder.h>
|
|
#include <it2s-tender/packet.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
static char* tts(int type) {
|
|
static char* stype[] = {"null", "entry", "exit", "single"};
|
|
if (type < 1 || type > 3) return stype[0];
|
|
else return stype[type];
|
|
}
|
|
|
|
int tpm_is_inside_zone(tolling_info_t* ti) {
|
|
int rv = 0;
|
|
|
|
double point[2];
|
|
int16_t heading;
|
|
itss_space_lock();
|
|
itss_space_get();
|
|
point[0] = epv.space.data.latitude.value/1.0e7;
|
|
point[1] = epv.space.data.longitude.value/1.0e7;
|
|
heading = epv.space.data.heading.value;
|
|
itss_space_unlock();
|
|
|
|
if (it2s_geodesy_inside_polygon(point[0], point[1], ti->zone.polygon, ti->zone.polygon_len)) {
|
|
uint16_t da = abs((int16_t)heading - (int16_t)ti->asn->angle);
|
|
if (da <= 900 || da >= 2700) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tpm_should_retransmit() {
|
|
|
|
tolling_t* tolling = &facilities.tolling;
|
|
|
|
uint64_t now = itss_ts_get(TIME_MICROSECONDS);
|
|
|
|
if (tolling->station.obu.rt_on) {
|
|
if (now > tolling->station.obu.rt_init + TOLLING_RT_TIMEOUT_MS*1000ULL) {
|
|
tolling->station.obu.rt_on = false;
|
|
return 0;
|
|
}
|
|
if (now > tolling->station.obu.rt_t_trigger + TOLLING_RT_PERIOD_MS*1000ULL) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tpm_pay(tolling_info_t* info, void** security_socket, uint8_t* neighbour, uint8_t* dst_addr) {
|
|
int rv = 0;
|
|
|
|
tolling_t* tolling = (tolling_t*) &facilities.tolling;
|
|
|
|
const size_t buf_len = INDICATION_BUFFER_SIZE;
|
|
uint8_t tpm_uper[buf_len];
|
|
uint8_t buf1[buf_len], buf2[buf_len];
|
|
|
|
if (!tolling->enabled) {
|
|
log_debug("[tolling] tolling is disabled");
|
|
return rv;
|
|
}
|
|
|
|
EI1_TPM_t* tpm = NULL;
|
|
EIS_NetworkingRequest_t* nr = NULL;
|
|
EIS_SecurityRequest_t* sreq = NULL;
|
|
EIS_SecurityReply_t* srep = NULL;
|
|
EIS_FacilitiesIndication_t* fi = NULL;
|
|
|
|
pthread_mutex_lock(&tolling->lock);
|
|
|
|
tolling->station.obu.t_init = itss_ts_get(TIME_MICROSECONDS);
|
|
tolling->station.obu.active = true;
|
|
tolling->station.obu.nonce = rand() + 1;
|
|
|
|
log_info("[tolling] issuing toll %s.request | client: %lld nonce: %lld", tts(info->asn->tollType), tolling->station.obu.client_id, tolling->station.obu.nonce);
|
|
|
|
// TPM
|
|
tpm = calloc(1, sizeof(EI1_TPM_t));
|
|
|
|
tpm->header.messageID = 117;
|
|
tpm->header.protocolVersion = 0;
|
|
pthread_mutex_lock(&facilities.id.lock);
|
|
tpm->header.stationID = facilities.id.station_id;
|
|
pthread_mutex_unlock(&facilities.id.lock);
|
|
|
|
tpm->tpm = calloc(1, sizeof(EI1_TollingPaymentMessage_t));
|
|
|
|
// timestamp
|
|
asn_ulong2INTEGER(&tpm->tpm->timestamp, itss_time_get());
|
|
|
|
// stationType
|
|
tpm->tpm->stationType = facilities.station_type;
|
|
|
|
// referencePosition
|
|
itss_space_lock();
|
|
itss_space_get();
|
|
tpm->tpm->referencePosition.altitude.altitudeValue = epv.space.data.altitude.value;
|
|
tpm->tpm->referencePosition.altitude.altitudeConfidence = epv.space.data.altitude.confidence;
|
|
tpm->tpm->referencePosition.latitude = epv.space.data.latitude.value;
|
|
tpm->tpm->referencePosition.longitude = epv.space.data.longitude.value;
|
|
uint16_t lat_conf = epv.space.data.latitude.confidence;
|
|
uint16_t lon_conf = epv.space.data.longitude.confidence;
|
|
itss_space_unlock();
|
|
if (lat_conf > lon_conf) {
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 0;
|
|
} else {
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 900;
|
|
}
|
|
|
|
tpm->tpm->tollingType = calloc(1, sizeof(EI1_TollingType_t));
|
|
EI1_TollingType_t* type = tpm->tpm->tollingType;
|
|
|
|
switch (info->asn->tollType) {
|
|
case EI1_TollType_entry:
|
|
if (tolling->station.obu.toll_type != -1 &&
|
|
!tolling->station.obu.rt_on) {
|
|
log_error("[tolling] trying to issue entry.request but current tolling state is %s - resetting",
|
|
tts(tolling->station.obu.toll_type));
|
|
tolling->station.obu.toll_type = -1;
|
|
tolling->station.obu.active = false;
|
|
ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tolling->station.obu.entry_proof);
|
|
tolling->station.obu.entry_proof = NULL;
|
|
}
|
|
type->present = EI1_TollingType_PR_entry;
|
|
type->choice.entry.present = EI1_TollingEntry_PR_request;
|
|
type->choice.entry.choice.request.clientId = tolling->station.obu.client_id;
|
|
type->choice.entry.choice.request.infoId = info->asn->id;
|
|
type->choice.entry.choice.request.transactionNonce = tolling->station.obu.nonce;
|
|
break;
|
|
|
|
case EI1_TollType_exit:
|
|
type->present = EI1_TollingType_PR_exit;
|
|
type->choice.exit = calloc(1, sizeof(EI1_TollingExit_t));
|
|
type->choice.exit->present = EI1_TollingExit_PR_request;
|
|
type->choice.exit->choice.request = calloc(1, sizeof(EI1_TollingExitRequest_t));
|
|
type->choice.exit->choice.request->clientId = tolling->station.obu.client_id;
|
|
type->choice.exit->choice.request->infoId = info->asn->id;
|
|
type->choice.exit->choice.request->transactionNonce = tolling->station.obu.nonce;
|
|
|
|
if (tolling->station.obu.toll_type != EI1_TollingType_PR_entry &&
|
|
!tolling->station.obu.rt_on) {
|
|
log_error("[tolling] trying to issue exit.request but current tolling state is %s - will not provide entry proof",
|
|
tts(tolling->station.obu.toll_type));
|
|
} else {
|
|
uint8_t b_tep[1024];
|
|
asn_enc_rval_t e_tep = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tolling->station.obu.entry_proof, b_tep, 1024);
|
|
if (e_tep.encoded == -1) {
|
|
log_error("[tolling] error encoding TPM entry proof (%s)", e_tep.failed_type->name);
|
|
ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tolling->station.obu.entry_proof);
|
|
tolling->station.obu.entry_proof = NULL;
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
uper_decode_complete(NULL, &asn_DEF_EI1_TPM, (void**) &type->choice.exit->choice.request->entryProof, b_tep, (e_tep.encoded+7)/8);
|
|
}
|
|
break;
|
|
|
|
case EI1_TollType_single:
|
|
if (tolling->station.obu.toll_type != -1 &&
|
|
!tolling->station.obu.rt_on) {
|
|
log_error("[tolling] trying to issue single.request but current tolling state is %s",
|
|
tts(tolling->station.obu.toll_type));
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
type->present = EI1_TollingType_PR_single;
|
|
type->choice.single.present = EI1_TollingSingle_PR_request;
|
|
type->choice.single.choice.request.clientId = tolling->station.obu.client_id;
|
|
type->choice.single.choice.request.infoId = info->asn->id;
|
|
type->choice.single.choice.request.transactionNonce = tolling->station.obu.nonce;
|
|
break;
|
|
}
|
|
|
|
tolling->station.obu.toll_type = info->asn->tollType;
|
|
|
|
|
|
// Encode TollingPaymentMessage
|
|
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm->tpm, buf1, buf_len);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) {
|
|
// Sign
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_sign;
|
|
sreq->choice.sign.data.size = enc.encoded;
|
|
sreq->choice.sign.data.buf = malloc(enc.encoded);
|
|
memcpy(sreq->choice.sign.data.buf, buf1, enc.encoded);
|
|
|
|
buf2[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf2+1, INDICATION_BUFFER_SIZE-1);
|
|
log_debug("->[security] SecurityRequest.sign (%ldB)", enc.encoded+1);
|
|
itss_0send(*security_socket, buf2, enc.encoded+1);
|
|
int32_t rl = itss_0recv_rt(security_socket, buf1, buf_len, buf2, enc.encoded+1, 1000);
|
|
log_debug("<-[security] SecurityReply.sign (%dB)", rl);
|
|
|
|
if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf1, rl).code) {
|
|
log_error("SecurityReply.sign decode failure");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) {
|
|
log_error("SecurityReply.sign rejected");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
tpm->tpmSignature = calloc(1, sizeof(EI1_TpmSignature_t));
|
|
tpm->tpmSignature->r.size = srep->data->choice.sign.r.size;
|
|
tpm->tpmSignature->r.buf = malloc(srep->data->choice.sign.r.size);
|
|
memcpy(tpm->tpmSignature->r.buf, srep->data->choice.sign.r.buf, srep->data->choice.sign.r.size);
|
|
tpm->tpmSignature->s.size = srep->data->choice.sign.s.size;
|
|
tpm->tpmSignature->s.buf = malloc(srep->data->choice.sign.s.size);
|
|
memcpy(tpm->tpmSignature->s.buf, srep->data->choice.sign.s.buf, srep->data->choice.sign.s.size);
|
|
tpm->tpmSignature->signer.size = srep->data->choice.sign.signer.size;
|
|
tpm->tpmSignature->signer.buf = malloc(srep->data->choice.sign.signer.size);
|
|
memcpy(tpm->tpmSignature->signer.buf, srep->data->choice.sign.signer.buf, srep->data->choice.sign.signer.size);
|
|
tpm->tpmSignature->type = srep->data->choice.sign.type;
|
|
}
|
|
|
|
// Encode TPM
|
|
enc = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tpm, tpm_uper, buf_len);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TPM.request (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
size_t tpm_uper_len = (enc.encoded + 7) / 8;
|
|
|
|
if (facilities.edm.enabled) {
|
|
edm_encap(tpm_uper, (uint16_t*)&tpm_uper_len, buf_len, 7011);
|
|
}
|
|
|
|
// [transport] request (TR)
|
|
nr = calloc(1, sizeof(EIS_NetworkingRequest_t));
|
|
nr->present = EIS_NetworkingRequest_PR_packet;
|
|
EIS_NetworkingPacketRequest_t* npr = &nr->choice.packet;
|
|
|
|
uint64_t id = 0;
|
|
|
|
switch (facilities.tolling.protocol.p) {
|
|
case TOLLING_PROTOCOL_GN_SPKI:
|
|
case TOLLING_PROTOCOL_GN_DPKI:
|
|
npr->transport.present = EIS_NetworkingPacketRequestTP_PR_btp;
|
|
npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn;
|
|
|
|
npr->network.choice.gn.securityProfile.encrypt = true;
|
|
npr->network.choice.gn.securityProfile.sign = true;
|
|
|
|
if(neighbour){
|
|
npr->network.choice.gn.securityNeighbour = calloc(1, sizeof(OCTET_STRING_t));
|
|
npr->network.choice.gn.securityNeighbour->size = 8;
|
|
npr->network.choice.gn.securityNeighbour->buf = malloc(8);
|
|
memcpy(npr->network.choice.gn.securityNeighbour->buf, neighbour, 8);
|
|
}
|
|
|
|
npr->data.size = tpm_uper_len;
|
|
npr->data.buf = malloc(tpm_uper_len);
|
|
memcpy(npr->data.buf, tpm_uper, tpm_uper_len);
|
|
|
|
npr->id = itss_id(npr->data.buf, npr->data.size);
|
|
id = npr->id;
|
|
|
|
npr->transport.choice.btp.destinationPort = 7011;
|
|
npr->transport.choice.btp.btpType = EIS_BTPType_btpB;
|
|
npr->network.choice.gn.destinationAddress.buf = malloc(6);
|
|
for (int i = 0; i < 6; ++i) {
|
|
npr->network.choice.gn.destinationAddress.buf[i] = 0xff;
|
|
}
|
|
npr->network.choice.gn.destinationAddress.size = 6;
|
|
npr->network.choice.gn.trafficClass = 2;
|
|
npr->network.choice.gn.packetTransportType = EIS_PacketTransportType_shb;
|
|
break;
|
|
|
|
case TOLLING_PROTOCOL_TLS:
|
|
case TOLLING_PROTOCOL_TLS_GN:
|
|
case TOLLING_PROTOCOL_TLS_SHS:
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_tlsSend;
|
|
sreq->choice.tlsSend.data.buf = malloc(tpm_uper_len);
|
|
sreq->choice.tlsSend.data.size = tpm_uper_len;
|
|
memcpy(sreq->choice.tlsSend.data.buf, tpm_uper, tpm_uper_len);
|
|
|
|
tlsc_t* tlsc = tolling_tlsc_get(dst_addr, 7011);
|
|
if (tlsc) {
|
|
id = tlsc->id;
|
|
} else {
|
|
tlsc = tolling_tlsc_new(dst_addr, 7011);
|
|
id = tlsc->id;
|
|
}
|
|
++tlsc->nmsg;
|
|
sreq->choice.tlsSend.connId = id;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1);
|
|
|
|
log_debug("[tolling]-> SecurityRequest.tlsSend ->[security] | size:%ldB", enc.encoded);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int rc = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
if (rc == -1) {
|
|
log_error("[tolling]-> SecurityRequest.tlsSend ->[security] <TIMEOUT>");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
log_debug("[tolling]<- SecurityReply.tlsSend <-[security] | size:%dB", rc);
|
|
|
|
EIS_SecurityReply_t* srep = NULL;
|
|
asn_dec_rval_t dec = oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, buf_len);
|
|
|
|
if (dec.code ||
|
|
srep->returnCode != EIS_SecurityReplyReturnCode_accepted ||
|
|
!srep->data ||
|
|
srep->data->present != EIS_SecurityReplyData_PR_tlsSend) {
|
|
log_error("[tolling]<- SecurityReply.tlsSend rejected");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
// TR TCP
|
|
npr->transport.present = EIS_NetworkingPacketRequestTP_PR_tcp;
|
|
|
|
npr->id = id;
|
|
|
|
npr->transport.choice.tcp.destinationAddress = calloc(1, sizeof(OCTET_STRING_t));
|
|
npr->transport.choice.tcp.destinationAddress->buf = malloc(16);
|
|
npr->transport.choice.tcp.destinationAddress->size = 16;
|
|
memcpy(npr->transport.choice.tcp.destinationAddress->buf, dst_addr, 16);
|
|
npr->transport.choice.tcp.destinationPort = 7011;
|
|
npr->transport.choice.tcp.sourcePort = 7011;
|
|
|
|
npr->data.buf = malloc(srep->data->choice.tlsSend.data.size);
|
|
npr->data.size = srep->data->choice.tlsSend.data.size;
|
|
memcpy(npr->data.buf, srep->data->choice.tlsSend.data.buf, srep->data->choice.tlsSend.data.size);
|
|
|
|
if (tolling->protocol.p == TOLLING_PROTOCOL_TLS_GN ||
|
|
tolling->protocol.p == TOLLING_PROTOCOL_TLS_SHS) {
|
|
npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn6a;
|
|
npr->network.choice.gn6a.gn.packetTransportType = EIS_PacketTransportType_shb;
|
|
npr->network.choice.gn6a.gn.destinationAddress.buf = calloc(1, 6);
|
|
npr->network.choice.gn6a.gn.destinationAddress.size = 6;
|
|
npr->network.choice.gn6a.gn.securityProfile.encrypt = false;
|
|
npr->network.choice.gn6a.gn.securityProfile.sign = true;
|
|
|
|
npr->network.choice.gn6a.ip.destinationAddress.buf = malloc(16);
|
|
npr->network.choice.gn6a.ip.destinationAddress.size = 16;
|
|
memcpy(npr->network.choice.gn6a.ip.destinationAddress.buf, dst_addr, 16);
|
|
} else {
|
|
npr->network.present = EIS_NetworkingPacketRequestNW_PR_ip;
|
|
npr->network.choice.ip.destinationAddress.buf = malloc(16);
|
|
npr->network.choice.ip.destinationAddress.size = 16;
|
|
memcpy(npr->network.choice.ip.destinationAddress.buf, dst_addr, 16);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// encode TR
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, nr, buf1+1, buf_len-1);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TR TPM.request (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id,
|
|
(tolling->protocol.p == TOLLING_PROTOCOL_GN_SPKI || tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI)
|
|
? "NR.packet.btp" : "NR.packet.tcp"));
|
|
|
|
// Retransmission
|
|
uint64_t now = itss_ts_get(TIME_MICROSECONDS);
|
|
if (!tolling->station.obu.rt_on) {
|
|
tolling->station.obu.rt_init = now;
|
|
tolling->station.obu.rt_on = true;
|
|
}
|
|
tolling->station.obu.rt_t_trigger = now;
|
|
|
|
// Logging
|
|
if (facilities.logging.dbms) {
|
|
pthread_mutex_lock(&facilities.id.lock);
|
|
uint32_t station_id = facilities.id.station_id;
|
|
pthread_mutex_unlock(&facilities.id.lock);
|
|
itss_db_add(facilities.logging.dbms, station_id, id, true, 117, NULL, tpm_uper, tpm_uper_len);
|
|
}
|
|
|
|
// send to [applications]
|
|
fi = calloc(1, sizeof(EIS_FacilitiesIndication_t));
|
|
fi->present = EIS_FacilitiesIndication_PR_message;
|
|
fi->choice.message.id = id;
|
|
fi->choice.message.itsMessageType = 7011;
|
|
fi->choice.message.data.size = tpm_uper_len;
|
|
fi->choice.message.data.buf = malloc(tpm_uper_len);
|
|
memcpy(fi->choice.message.data.buf, tpm_uper, tpm_uper_len);
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_FacilitiesIndication, NULL, fi, buf1+1, buf_len-1);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding FI TPM.request (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_APPLICATIONS, id, "FI.message (TPM.request)"));
|
|
|
|
if (facilities.logging.recorder) {
|
|
uint16_t buffer_len = INDICATION_BUFFER_SIZE;
|
|
uint8_t buffer[buffer_len];
|
|
int e = itss_management_record_packet_sdu(
|
|
buffer,
|
|
buffer_len,
|
|
tpm_uper,
|
|
tpm_uper_len,
|
|
id,
|
|
itss_time_get(),
|
|
ITSS_FACILITIES,
|
|
true);
|
|
if (e != -1) {
|
|
itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buffer, e, ITSS_MANAGEMENT, id, "MReq.packet.set"));
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
pthread_mutex_unlock(&tolling->lock);
|
|
ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tpm);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_NetworkingRequest, nr);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_FacilitiesIndication, fi);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static int rsu_handle_recv(EI1_TPM_t* tpm_rx, void** security_socket, uint8_t* neighbour, uint8_t* src_addr) {
|
|
|
|
int rv = 0;
|
|
|
|
if (!tpm_rx->tpm->tollingType) {
|
|
log_error("[tolling] received TPM does not have a type");
|
|
return 1;
|
|
}
|
|
|
|
EI1_TollingType_t* type_rx = tpm_rx->tpm->tollingType;
|
|
|
|
uint64_t client_id, nonce, info_id;
|
|
const uint32_t buf_len = 1800;
|
|
uint8_t buf1[buf_len], buf2[buf_len];
|
|
uint8_t tpm_uper[buf_len];
|
|
|
|
EIS_SecurityRequest_t* sreq = NULL;
|
|
EIS_SecurityReply_t* srep = NULL;
|
|
|
|
tolling_t* tolling = &facilities.tolling;
|
|
|
|
switch (type_rx->present) {
|
|
case EI1_TollingType_PR_entry:
|
|
if (type_rx->choice.entry.present != EI1_TollingEntry_PR_request) {
|
|
log_error("[tolling] received TPM.entry is not request");
|
|
return 1;
|
|
}
|
|
client_id = type_rx->choice.entry.choice.request.clientId;
|
|
nonce = type_rx->choice.entry.choice.request.transactionNonce;
|
|
info_id = type_rx->choice.entry.choice.request.infoId;
|
|
break;
|
|
|
|
case EI1_TollingType_PR_exit:
|
|
if (!type_rx->choice.exit ||
|
|
type_rx->choice.exit->present != EI1_TollingExit_PR_request ||
|
|
!type_rx->choice.exit->choice.request
|
|
) {
|
|
log_error("[tolling] received TPM.exit is not request");
|
|
return 1;
|
|
}
|
|
|
|
if (tolling->protocol.p != TOLLING_PROTOCOL_GN_DPKI) {
|
|
log_warn("[tolling] cannot cryptographically verify entryProof in mode different than GN-DPKI");
|
|
client_id = type_rx->choice.exit->choice.request->clientId;
|
|
nonce = type_rx->choice.exit->choice.request->transactionNonce;
|
|
info_id = type_rx->choice.exit->choice.request->infoId;
|
|
} else {
|
|
client_id = type_rx->choice.exit->choice.request->clientId;
|
|
nonce = type_rx->choice.exit->choice.request->transactionNonce;
|
|
info_id = type_rx->choice.exit->choice.request->infoId;
|
|
|
|
if (!type_rx->choice.exit->choice.request->entryProof) {
|
|
log_error("[tolling] received TPM.exit.request does not contain entry proof");
|
|
return 1;
|
|
}
|
|
|
|
EI1_TPM_t* ep = (EI1_TPM_t*) type_rx->choice.exit->choice.request->entryProof;
|
|
|
|
if (!ep->tpmSignature) {
|
|
log_error("[tolling] received TPM.exit.request.entryProof does not contain signature");;
|
|
return 1;
|
|
}
|
|
|
|
// Encode TollingPaymentMessage
|
|
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, ep->tpm, buf1, buf_len);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Verify
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_verify;
|
|
// message
|
|
sreq->choice.verify.message.size = enc.encoded;
|
|
sreq->choice.verify.message.buf = malloc(enc.encoded);
|
|
memcpy(sreq->choice.verify.message.buf, buf1, enc.encoded);
|
|
|
|
// r
|
|
sreq->choice.verify.r.size = ep->tpmSignature->r.size;
|
|
sreq->choice.verify.r.buf = malloc(ep->tpmSignature->r.size);
|
|
memcpy(sreq->choice.verify.r.buf, ep->tpmSignature->r.buf, ep->tpmSignature->r.size);
|
|
// s
|
|
sreq->choice.verify.s.size = ep->tpmSignature->s.size;
|
|
sreq->choice.verify.s.buf = malloc(ep->tpmSignature->s.size);
|
|
memcpy(sreq->choice.verify.s.buf, ep->tpmSignature->s.buf, ep->tpmSignature->s.size);
|
|
// signer
|
|
sreq->choice.verify.signer.size = ep->tpmSignature->signer.size;
|
|
sreq->choice.verify.signer.buf = malloc(ep->tpmSignature->signer.size);
|
|
memcpy(sreq->choice.verify.signer.buf, ep->tpmSignature->signer.buf, ep->tpmSignature->signer.size);
|
|
// signature type
|
|
sreq->choice.verify.type = ep->tpmSignature->type;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1);
|
|
log_debug("->[security] SecurityRequest.verify (%ldB)", enc.encoded+1);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
log_debug("<-[security] SecurityReply.verify (%dB)", rl);
|
|
|
|
if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rl).code) {
|
|
log_error("SecurityReply.verify decode failure");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) {
|
|
log_error("SecurityReply.verify rejected");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->data->choice.verify.report != EIS_SecurityVerifyConfirmCode_success) {
|
|
log_debug("entry proof signature verify failed");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep);
|
|
sreq = NULL;
|
|
srep = NULL;
|
|
}
|
|
break;
|
|
|
|
case EI1_TollingType_PR_single:
|
|
if (type_rx->choice.single.present != EI1_TollingSingle_PR_request) {
|
|
log_error("[tolling] received TPM.single is not request");
|
|
return 1;
|
|
}
|
|
client_id = type_rx->choice.single.choice.request.clientId;
|
|
nonce = type_rx->choice.single.choice.request.transactionNonce;
|
|
info_id = type_rx->choice.single.choice.request.infoId;
|
|
break;
|
|
|
|
default:
|
|
log_error("[tolling] received TPM has unrecognized type");
|
|
return 1;
|
|
}
|
|
|
|
|
|
switch (tolling->protocol.p) {
|
|
case TOLLING_PROTOCOL_GN_SPKI:
|
|
case TOLLING_PROTOCOL_GN_DPKI:
|
|
log_info("[tolling] received toll %s.request | client: %lld (certificate id: 0x%02x%02x%02x) nonce: %lld",
|
|
tts(type_rx->present),
|
|
client_id,
|
|
neighbour ? neighbour[5] : 0,
|
|
neighbour ? neighbour[6] : 0,
|
|
neighbour ? neighbour[7] : 0,
|
|
nonce
|
|
);
|
|
break;
|
|
case TOLLING_PROTOCOL_TLS:
|
|
case TOLLING_PROTOCOL_TLS_GN:
|
|
case TOLLING_PROTOCOL_TLS_SHS:
|
|
log_info("[tolling] received toll %s.request | client: %lld nonce: %lld",
|
|
tts(type_rx->present),
|
|
client_id,
|
|
nonce
|
|
);
|
|
break;
|
|
}
|
|
|
|
int known_id = 0;
|
|
for (int i = 0; i < facilities.tolling.infos.length; i++) {
|
|
if (info_id != facilities.tolling.infos.z[i]->asn->id) {
|
|
known_id = 1;
|
|
}
|
|
}
|
|
if (!known_id) {
|
|
log_warn("[tolling] received TPM has unkown info_id");
|
|
return 1;
|
|
}
|
|
|
|
asn_enc_rval_t enc;
|
|
EIS_NetworkingRequest_t* nr = NULL;
|
|
EIS_FacilitiesIndication_t* fi = NULL;
|
|
EI1_TPM_t* tpm = NULL;
|
|
|
|
if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) {
|
|
|
|
if (!tpm_rx->tpmSignature) {
|
|
log_error("[tolling] in simple mode but TPM without signature received");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Encode TollingPaymentMessage
|
|
enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm_rx->tpm, buf1, buf_len);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
// Verify
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_verify;
|
|
// message
|
|
sreq->choice.verify.message.size = enc.encoded;
|
|
sreq->choice.verify.message.buf = malloc(enc.encoded);
|
|
memcpy(sreq->choice.verify.message.buf, buf1, enc.encoded);
|
|
|
|
// r
|
|
sreq->choice.verify.r.size = tpm_rx->tpmSignature->r.size;
|
|
sreq->choice.verify.r.buf = malloc(tpm_rx->tpmSignature->r.size);
|
|
memcpy(sreq->choice.verify.r.buf, tpm_rx->tpmSignature->r.buf, tpm_rx->tpmSignature->r.size);
|
|
// s
|
|
sreq->choice.verify.s.size = tpm_rx->tpmSignature->s.size;
|
|
sreq->choice.verify.s.buf = malloc(tpm_rx->tpmSignature->s.size);
|
|
memcpy(sreq->choice.verify.s.buf, tpm_rx->tpmSignature->s.buf, tpm_rx->tpmSignature->s.size);
|
|
// signer
|
|
sreq->choice.verify.signer.size = tpm_rx->tpmSignature->signer.size;
|
|
sreq->choice.verify.signer.buf = malloc(tpm_rx->tpmSignature->signer.size);
|
|
memcpy(sreq->choice.verify.signer.buf, tpm_rx->tpmSignature->signer.buf, tpm_rx->tpmSignature->signer.size);
|
|
// signature type
|
|
sreq->choice.verify.type = tpm_rx->tpmSignature->type;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1);
|
|
log_debug("->[security] SecurityRequest.verify (%ldB)", enc.encoded+1);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
log_debug("<-[security] SecurityReply.verify (%dB)", rl);
|
|
|
|
if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rl).code) {
|
|
log_error("SecurityReply.verify decode failure");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) {
|
|
log_error("SecurityReply.verify rejected");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->data->choice.verify.report != EIS_SecurityVerifyConfirmCode_success) {
|
|
log_debug("signature verify failed");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep);
|
|
sreq = NULL;
|
|
srep = NULL;
|
|
}
|
|
|
|
|
|
// TPM
|
|
tpm = calloc(1, sizeof(EI1_TPM_t));
|
|
|
|
tpm->header.messageID = 117;
|
|
tpm->header.protocolVersion = 0;
|
|
pthread_mutex_lock(&facilities.id.lock);
|
|
tpm->header.stationID = facilities.id.station_id;
|
|
pthread_mutex_unlock(&facilities.id.lock);
|
|
|
|
tpm->tpm = calloc(1, sizeof(EI1_TollingPaymentMessage_t));
|
|
|
|
// timestamp
|
|
asn_ulong2INTEGER(&tpm->tpm->timestamp, itss_time_get());
|
|
|
|
// stationType
|
|
tpm->tpm->stationType = facilities.station_type;
|
|
|
|
// referencePosition
|
|
itss_space_lock();
|
|
itss_space_get();
|
|
tpm->tpm->referencePosition.altitude.altitudeValue = epv.space.data.altitude.value;
|
|
tpm->tpm->referencePosition.altitude.altitudeConfidence = epv.space.data.altitude.confidence;
|
|
tpm->tpm->referencePosition.latitude = epv.space.data.latitude.value;
|
|
tpm->tpm->referencePosition.longitude = epv.space.data.longitude.value;
|
|
uint16_t lat_conf = epv.space.data.latitude.confidence;
|
|
uint16_t lon_conf = epv.space.data.longitude.confidence;
|
|
itss_space_unlock();
|
|
if (lat_conf > lon_conf) {
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 0;
|
|
} else {
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf;
|
|
tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 900;
|
|
}
|
|
|
|
// Client management
|
|
for (int i = 0 ; i < tolling->station.rsu.clients_len; ++i) {
|
|
if (itss_time_get() > tolling->station.rsu.clients[i]->ts + TOLLING_CLIENT_LIFETIME_MS) {
|
|
free(tolling->station.rsu.clients[i]);
|
|
tolling->station.rsu.clients[i] = NULL;
|
|
for (int j = i; j < tolling->station.rsu.clients_len-1; ++j) {
|
|
tolling->station.rsu.clients[j] = tolling->station.rsu.clients[j+1];
|
|
}
|
|
--tolling->station.rsu.clients_len;
|
|
}
|
|
}
|
|
|
|
// Find client
|
|
toll_client_t* client = NULL;
|
|
for (int i = 0; i < tolling->station.rsu.clients_len; ++i) {
|
|
if (tolling->station.rsu.clients[i]->id == client_id) {
|
|
client = tolling->station.rsu.clients[i];
|
|
}
|
|
}
|
|
|
|
// Create client
|
|
if (!client) {
|
|
if (tolling->station.rsu.clients_len-1 >= TOLLING_MAX_CLIENTS) {
|
|
log_error("[tolling] max clients reached");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
tolling->station.rsu.clients[tolling->station.rsu.clients_len] = malloc(sizeof(toll_client_t));
|
|
client = tolling->station.rsu.clients[tolling->station.rsu.clients_len];
|
|
client->id = client_id;
|
|
client->station_id = tpm_rx->header.stationID;
|
|
client->ts = itss_time_get();
|
|
client->accepted = -1;
|
|
}
|
|
|
|
uint8_t confirmation_code = EI1_TollingConfirmationCode_rejected;
|
|
if (itss_time_get() > client->ts + TOLLING_PAYMENT_MIN_PERIOD_MS ||
|
|
client->accepted == -1) {
|
|
confirmation_code = EI1_TollingConfirmationCode_accepted;
|
|
client->accepted = true;
|
|
} else if (client->accepted &&
|
|
itss_time_get() < client->ts + TOLLING_PAYMENT_MIN_PERIOD_MS) {
|
|
confirmation_code = EI1_TollingConfirmationCode_alreadyAccepted;
|
|
}
|
|
|
|
tpm->tpm->tollingType = calloc(1, sizeof(EI1_TollingType_t));
|
|
switch (tpm_rx->tpm->tollingType->present) {
|
|
case EI1_TollingType_PR_entry:
|
|
tpm->tpm->tollingType->present = EI1_TollingType_PR_entry;
|
|
tpm->tpm->tollingType->choice.entry.present = EI1_TollingEntry_PR_reply;
|
|
tpm->tpm->tollingType->choice.entry.choice.reply.clientId = client_id;
|
|
tpm->tpm->tollingType->choice.entry.choice.reply.infoId = info_id;
|
|
tpm->tpm->tollingType->choice.entry.choice.reply.transactionNonce = nonce;
|
|
tpm->tpm->tollingType->choice.entry.choice.reply.confirmationCode = confirmation_code;
|
|
break;
|
|
case EI1_TollingType_PR_exit:
|
|
tpm->tpm->tollingType->present = EI1_TollingType_PR_exit;
|
|
tpm->tpm->tollingType->choice.exit = calloc(1, sizeof(EI1_TollingExit_t));
|
|
tpm->tpm->tollingType->choice.exit->present = EI1_TollingExit_PR_reply;
|
|
tpm->tpm->tollingType->choice.exit->choice.reply.clientId = client_id;
|
|
tpm->tpm->tollingType->choice.exit->choice.reply.infoId = info_id;
|
|
tpm->tpm->tollingType->choice.exit->choice.reply.transactionNonce = nonce;
|
|
tpm->tpm->tollingType->choice.exit->choice.reply.confirmationCode = confirmation_code;
|
|
break;
|
|
case EI1_TollingType_PR_single:
|
|
tpm->tpm->tollingType->present = EI1_TollingType_PR_single;
|
|
tpm->tpm->tollingType->choice.single.present = EI1_TollingSingle_PR_reply;
|
|
tpm->tpm->tollingType->choice.single.choice.reply.clientId = client_id;
|
|
tpm->tpm->tollingType->choice.single.choice.reply.infoId = info_id;
|
|
tpm->tpm->tollingType->choice.single.choice.reply.transactionNonce = nonce;
|
|
tpm->tpm->tollingType->choice.single.choice.reply.confirmationCode = confirmation_code;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// TODO check clientId
|
|
|
|
// Encode TollingPaymentMessage
|
|
enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm->tpm, buf1, buf_len);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) {
|
|
// Sign
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_sign;
|
|
sreq->choice.sign.data.size = enc.encoded;
|
|
sreq->choice.sign.data.buf = malloc(enc.encoded);
|
|
memcpy(sreq->choice.sign.data.buf, buf1, enc.encoded);
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding SecurityRequest (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
log_debug("->[security] SecurityRequest.sign (%ldB)", enc.encoded+1);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int rc = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
log_debug("<-[security] SecurityReply.sign (%dB)", rc);
|
|
|
|
if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rc).code) {
|
|
log_error("SecurityReply.sign decode failure");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) {
|
|
log_error("SecurityReply.sign rejected");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
tpm->tpmSignature = calloc(1, sizeof(EI1_TpmSignature_t));
|
|
tpm->tpmSignature->r.size = srep->data->choice.sign.r.size;
|
|
tpm->tpmSignature->r.buf = malloc(srep->data->choice.sign.r.size);
|
|
memcpy(tpm->tpmSignature->r.buf, srep->data->choice.sign.r.buf, srep->data->choice.sign.r.size);
|
|
tpm->tpmSignature->s.size = srep->data->choice.sign.s.size;
|
|
tpm->tpmSignature->s.buf = malloc(srep->data->choice.sign.s.size);
|
|
memcpy(tpm->tpmSignature->s.buf, srep->data->choice.sign.s.buf, srep->data->choice.sign.s.size);
|
|
tpm->tpmSignature->signer.size = srep->data->choice.sign.signer.size;
|
|
tpm->tpmSignature->signer.buf = malloc(srep->data->choice.sign.signer.size);
|
|
memcpy(tpm->tpmSignature->signer.buf, srep->data->choice.sign.signer.buf, srep->data->choice.sign.signer.size);
|
|
tpm->tpmSignature->type = srep->data->choice.sign.type;
|
|
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep);
|
|
sreq = NULL;
|
|
srep = NULL;
|
|
}
|
|
|
|
// encode TPM
|
|
enc = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tpm, tpm_uper, buf_len);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TPM.reply (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
size_t tpm_uper_len = (enc.encoded + 7) / 8;
|
|
|
|
if (facilities.edm.enabled) {
|
|
edm_encap(tpm_uper, (uint16_t*)&tpm_uper_len, buf_len, 7011);
|
|
}
|
|
|
|
uint64_t id = 0;
|
|
|
|
nr = calloc(1, sizeof(EIS_NetworkingRequest_t));
|
|
nr->present = EIS_NetworkingRequest_PR_packet;
|
|
EIS_NetworkingPacketRequest_t* npr = &nr->choice.packet;
|
|
|
|
// [transport] request (TR)
|
|
switch (tolling->protocol.p) {
|
|
case TOLLING_PROTOCOL_GN_SPKI:
|
|
case TOLLING_PROTOCOL_GN_DPKI:
|
|
npr->transport.present = EIS_NetworkingPacketRequestTP_PR_btp;
|
|
npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn;
|
|
|
|
npr->network.choice.gn.securityProfile.encrypt = true;
|
|
npr->network.choice.gn.securityProfile.sign = true;
|
|
|
|
if(neighbour){
|
|
npr->network.choice.gn.securityNeighbour = calloc(1, sizeof(OCTET_STRING_t));
|
|
npr->network.choice.gn.securityNeighbour->size = 8;
|
|
npr->network.choice.gn.securityNeighbour->buf = malloc(8);
|
|
memcpy(npr->network.choice.gn.securityNeighbour->buf, neighbour, 8);
|
|
}
|
|
|
|
npr->data.size = tpm_uper_len;
|
|
npr->data.buf = malloc(tpm_uper_len);
|
|
memcpy(npr->data.buf, tpm_uper, tpm_uper_len);
|
|
|
|
npr->id = itss_id(npr->data.buf, npr->data.size);
|
|
id = npr->id;
|
|
|
|
npr->transport.choice.btp.destinationPort = 7011;
|
|
npr->transport.choice.btp.btpType = EIS_BTPType_btpB;
|
|
npr->network.choice.gn.destinationAddress.buf = malloc(6);
|
|
for (int i = 0; i < 6; ++i) {
|
|
npr->network.choice.gn.destinationAddress.buf[i] = 0xff;
|
|
}
|
|
npr->network.choice.gn.destinationAddress.size = 6;
|
|
npr->network.choice.gn.trafficClass = 2;
|
|
npr->network.choice.gn.packetTransportType = EIS_PacketTransportType_shb;
|
|
|
|
|
|
if (neighbour) { /* neighbour ID for [security] encryption */
|
|
npr->network.choice.gn.securityNeighbour = calloc(1, sizeof(OCTET_STRING_t));
|
|
npr->network.choice.gn.securityNeighbour->size = 8;
|
|
npr->network.choice.gn.securityNeighbour->buf = malloc(8);
|
|
memcpy(npr->network.choice.gn.securityNeighbour->buf, neighbour, 8);
|
|
}
|
|
break;
|
|
|
|
case TOLLING_PROTOCOL_TLS:
|
|
case TOLLING_PROTOCOL_TLS_GN:
|
|
case TOLLING_PROTOCOL_TLS_SHS:
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_tlsSend;
|
|
sreq->choice.tlsSend.data.buf = malloc(tpm_uper_len);
|
|
sreq->choice.tlsSend.data.size = tpm_uper_len;
|
|
memcpy(sreq->choice.tlsSend.data.buf, tpm_uper, tpm_uper_len);
|
|
|
|
tlsc_t* tlsc = tolling_tlsc_get(src_addr, 7011);
|
|
if (tlsc) {
|
|
id = tlsc->id;
|
|
} else {
|
|
tlsc = tolling_tlsc_new(src_addr, 7011);
|
|
id = tlsc->id;
|
|
}
|
|
++tlsc->nmsg;
|
|
sreq->choice.tlsSend.connId = id;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1);
|
|
|
|
log_debug("[tolling]-> SecurityRequest.tlsSend ->[security] | size:%ldB", enc.encoded);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int rc = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
if (rc == -1) {
|
|
log_error("[tolling]-> SecurityRequest.tlsSend ->[security] <TIMEOUT>");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
log_debug("[tolling]<- SecurityReply.tlsSend <-[security] | size:%dB", rc);
|
|
|
|
asn_dec_rval_t dec = oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rc);
|
|
|
|
if (dec.code ||
|
|
srep->returnCode != EIS_SecurityReplyReturnCode_accepted ||
|
|
!srep->data ||
|
|
srep->data->present != EIS_SecurityReplyData_PR_tlsSend) {
|
|
log_error("[tolling]<- SecurityReply.tlsSend rejected");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
// TR TCP
|
|
npr->transport.present = EIS_NetworkingPacketRequestTP_PR_tcp;
|
|
|
|
npr->id = id;
|
|
|
|
npr->transport.choice.tcp.destinationAddress = calloc(1, sizeof(OCTET_STRING_t));
|
|
npr->transport.choice.tcp.destinationAddress->buf = malloc(16);
|
|
npr->transport.choice.tcp.destinationAddress->size = 16;
|
|
memcpy(npr->transport.choice.tcp.destinationAddress->buf,src_addr, 16);
|
|
npr->transport.choice.tcp.destinationPort = 7011;
|
|
npr->transport.choice.tcp.sourcePort = 7011;
|
|
|
|
npr->data.buf = malloc(srep->data->choice.tlsSend.data.size);
|
|
npr->data.size = srep->data->choice.tlsSend.data.size;
|
|
memcpy(npr->data.buf, srep->data->choice.tlsSend.data.buf, srep->data->choice.tlsSend.data.size);
|
|
|
|
if (tolling->protocol.p == TOLLING_PROTOCOL_TLS_GN) {
|
|
npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn6a;
|
|
npr->network.choice.gn6a.gn.packetTransportType = EIS_PacketTransportType_shb;
|
|
npr->network.choice.gn6a.gn.destinationAddress.buf = calloc(1, 6);
|
|
npr->network.choice.gn6a.gn.destinationAddress.size = 6;
|
|
npr->network.choice.gn6a.gn.securityProfile.encrypt = false;
|
|
npr->network.choice.gn6a.gn.securityProfile.sign = true;
|
|
|
|
npr->network.choice.gn6a.ip.destinationAddress.buf = malloc(16);
|
|
npr->network.choice.gn6a.ip.destinationAddress.size = 16;
|
|
memcpy(npr->network.choice.gn6a.ip.destinationAddress.buf, src_addr, 16);
|
|
} else {
|
|
npr->network.present = EIS_NetworkingPacketRequestNW_PR_ip;
|
|
npr->network.choice.ip.destinationAddress.buf = malloc(16);
|
|
npr->network.choice.ip.destinationAddress.size = 16;
|
|
memcpy(npr->network.choice.ip.destinationAddress.buf, src_addr, 16);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// encode TR
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, nr, buf1+1, buf_len-1);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TR TPM.reply (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id,
|
|
(tolling->protocol.p == TOLLING_PROTOCOL_GN_SPKI || tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) ? "NR.packet.btp" : "NR.packet.tcp"));
|
|
|
|
// Logging
|
|
if (facilities.logging.dbms) {
|
|
pthread_mutex_lock(&facilities.id.lock);
|
|
uint32_t station_id = facilities.id.station_id;
|
|
pthread_mutex_unlock(&facilities.id.lock);
|
|
itss_db_add(facilities.logging.dbms, station_id, id, true, 117, NULL, tpm_uper, tpm_uper_len);
|
|
}
|
|
|
|
// send to [applications]
|
|
fi = calloc(1, sizeof(EIS_FacilitiesIndication_t));
|
|
fi->present = EIS_FacilitiesIndication_PR_message;
|
|
fi->choice.message.id = id;
|
|
fi->choice.message.itsMessageType = 7011;
|
|
fi->choice.message.data.size = tpm_uper_len;
|
|
fi->choice.message.data.buf = malloc(tpm_uper_len);
|
|
memcpy(fi->choice.message.data.buf, tpm_uper, tpm_uper_len);
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_FacilitiesIndication, NULL, fi, buf1+1, buf_len-1);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding FI TPM.reply (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_APPLICATIONS, id, "FI.message (TPM.reply)"));
|
|
if (facilities.logging.recorder) {
|
|
uint16_t buffer_len = INDICATION_BUFFER_SIZE;
|
|
uint8_t buffer[buffer_len];
|
|
int e = itss_management_record_packet_sdu(
|
|
buffer,
|
|
buffer_len,
|
|
tpm_uper,
|
|
tpm_uper_len,
|
|
id,
|
|
itss_time_get(),
|
|
ITSS_FACILITIES,
|
|
true);
|
|
if (e != -1) {
|
|
itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buffer, e, ITSS_MANAGEMENT, id, "MReq.packet.set"));
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tpm);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_NetworkingRequest, nr);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_FacilitiesIndication, fi);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static int veh_handle_recv(tolling_t* tolling, EI1_TPM_t* tpm_rx, void** security_socket, itss_queue_t* tx_queue, uint8_t* neighbour, uint8_t* src_addr) {
|
|
int rv = 0;
|
|
|
|
if (!tpm_rx->tpm->tollingType) {
|
|
log_error("[tolling] received TPM does not have a type");
|
|
return 1;
|
|
}
|
|
|
|
EI1_TollingType_t* type_rx = tpm_rx->tpm->tollingType;
|
|
|
|
uint64_t client_id, nonce, info_id;
|
|
int confirmation_code;
|
|
|
|
EIS_SecurityRequest_t* sreq = NULL;
|
|
EIS_SecurityReply_t* srep = NULL;
|
|
EIS_NetworkingRequest_t* tr = NULL;
|
|
|
|
const uint16_t buf_len = INDICATION_BUFFER_SIZE;
|
|
uint8_t buf1[buf_len], buf2[buf_len];
|
|
|
|
switch (type_rx->present) {
|
|
case EI1_TollingType_PR_entry:
|
|
if (type_rx->choice.entry.present != EI1_TollingEntry_PR_reply) {
|
|
log_error("[tolling] received TPM.entry is not reply");
|
|
return 1;
|
|
}
|
|
if (tolling->station.obu.toll_type != EI1_TollingType_PR_entry) {
|
|
log_error("[tolling] received TPM toll (%d) is not expected toll type (%d)",
|
|
EI1_TollingType_PR_entry, tolling->station.obu.toll_type);
|
|
}
|
|
client_id = type_rx->choice.entry.choice.reply.clientId;
|
|
nonce = type_rx->choice.entry.choice.reply.transactionNonce;
|
|
info_id = type_rx->choice.entry.choice.reply.infoId;
|
|
confirmation_code = type_rx->choice.entry.choice.reply.confirmationCode;
|
|
|
|
uint8_t b_tep[INDICATION_BUFFER_SIZE];
|
|
asn_enc_rval_t e_tep = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tpm_rx, b_tep, INDICATION_BUFFER_SIZE);
|
|
if (e_tep.encoded == -1) {
|
|
log_error("[tolling] error encoding received TPM as entry proof");
|
|
return 1;
|
|
}
|
|
uper_decode_complete(NULL, &asn_DEF_EI1_TPM, (void**) &tolling->station.obu.entry_proof, b_tep, (e_tep.encoded+7)/8);
|
|
break;
|
|
|
|
case EI1_TollingType_PR_exit:
|
|
if (!type_rx->choice.exit ||
|
|
type_rx->choice.exit->present != EI1_TollingExit_PR_reply
|
|
) {
|
|
log_error("[tolling] received TPM.exit is not reply");
|
|
return 1;
|
|
}
|
|
if (tolling->station.obu.toll_type != EI1_TollingType_PR_exit) {
|
|
log_error("[tolling] received TPM toll (%d) is not expected toll type (%d)",
|
|
EI1_TollingType_PR_exit, tolling->station.obu.toll_type);
|
|
return 1;
|
|
}
|
|
client_id = type_rx->choice.exit->choice.reply.clientId;
|
|
nonce = type_rx->choice.exit->choice.reply.transactionNonce;
|
|
info_id = type_rx->choice.exit->choice.reply.infoId;
|
|
confirmation_code = type_rx->choice.exit->choice.reply.confirmationCode;
|
|
break;
|
|
|
|
case EI1_TollingType_PR_single:
|
|
if (type_rx->choice.single.present != EI1_TollingSingle_PR_reply) {
|
|
log_error("[tolling] received TPM.single is not reply");
|
|
return 1;
|
|
}
|
|
if (tolling->station.obu.toll_type != EI1_TollingType_PR_single) {
|
|
log_error("[tolling] received TPM type (%d) is not expected toll type (%d)",
|
|
EI1_TollingType_PR_single, tolling->station.obu.toll_type);
|
|
}
|
|
client_id = type_rx->choice.single.choice.reply.clientId;
|
|
nonce = type_rx->choice.single.choice.reply.transactionNonce;
|
|
info_id = type_rx->choice.single.choice.reply.infoId;
|
|
confirmation_code = type_rx->choice.single.choice.reply.confirmationCode;
|
|
break;
|
|
|
|
default:
|
|
log_error("[tolling] received TPM has unrecognized type");
|
|
return 1;
|
|
}
|
|
|
|
if (client_id != tolling->station.obu.client_id) {
|
|
log_debug("[tolling]<- received TPM.reply clientId different from ego");
|
|
return 1;
|
|
}
|
|
|
|
if (nonce != tolling->station.obu.nonce) {
|
|
log_error("[tolling]<- received TPM.reply nonce different from sent request");
|
|
return 1;
|
|
}
|
|
|
|
|
|
// Encode TollingPaymentMessage
|
|
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm_rx->tpm, buf1, buf_len);
|
|
if (enc.encoded == -1) {
|
|
log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name);
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
bool accepted = true;
|
|
if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) {
|
|
// Verify
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_verify;
|
|
// message
|
|
sreq->choice.verify.message.size = enc.encoded;
|
|
sreq->choice.verify.message.buf = malloc(enc.encoded);
|
|
memcpy(sreq->choice.verify.message.buf, buf1, enc.encoded);
|
|
// r
|
|
sreq->choice.verify.r.size = tpm_rx->tpmSignature->r.size;
|
|
sreq->choice.verify.r.buf = malloc(tpm_rx->tpmSignature->r.size);
|
|
memcpy(sreq->choice.verify.r.buf, tpm_rx->tpmSignature->r.buf, tpm_rx->tpmSignature->r.size);
|
|
// s
|
|
sreq->choice.verify.s.size = tpm_rx->tpmSignature->s.size;
|
|
sreq->choice.verify.s.buf = malloc(tpm_rx->tpmSignature->s.size);
|
|
memcpy(sreq->choice.verify.s.buf, tpm_rx->tpmSignature->s.buf, tpm_rx->tpmSignature->s.size);
|
|
// signer
|
|
sreq->choice.verify.signer.size = tpm_rx->tpmSignature->signer.size;
|
|
sreq->choice.verify.signer.buf = malloc(tpm_rx->tpmSignature->signer.size);
|
|
memcpy(sreq->choice.verify.signer.buf, tpm_rx->tpmSignature->signer.buf, tpm_rx->tpmSignature->signer.size);
|
|
// signature type
|
|
sreq->choice.verify.type = tpm_rx->tpmSignature->type;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, INDICATION_BUFFER_SIZE-1);
|
|
log_debug("->[security] SecurityRequest.verify (%ldB)", enc.encoded+1);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
log_debug("<-[security] SecurityReply.verify (%dB)", rl);
|
|
|
|
if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rl).code) {
|
|
log_error("SecurityReply.verify decode failure");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) {
|
|
log_error("SecurityReply.verify rejected");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (srep->data->choice.verify.report != EIS_SecurityVerifyConfirmCode_success) {
|
|
log_debug("signature verify failed");
|
|
rv = 1;
|
|
goto cleanup;
|
|
}
|
|
|
|
accepted = confirmation_code == EI1_TollingConfirmationCode_accepted || confirmation_code == EI1_TollingConfirmationCode_alreadyAccepted;
|
|
}
|
|
|
|
switch (type_rx->present) {
|
|
case EI1_TollingType_PR_entry:
|
|
log_info("[tolling] received entry.reply | client: %lld nonce: %lld accepted: %s", tolling->station.obu.client_id, tolling->station.obu.nonce, accepted ? "yes" : "no");
|
|
break;
|
|
|
|
case EI1_TollingType_PR_exit:
|
|
log_info("[tolling] received exit.reply | client: %lld nonce: %lld accepted: %s", tolling->station.obu.client_id, tolling->station.obu.nonce, accepted ? "yes" : "no");
|
|
tolling->station.obu.toll_type = -1;
|
|
tolling->station.obu.active = false;
|
|
ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tolling->station.obu.entry_proof);
|
|
tolling->station.obu.entry_proof = NULL;
|
|
break;
|
|
|
|
case EI1_TollingType_PR_single:
|
|
log_info("[tolling] received single.reply | client: %lld nonce: %lld accepted: %s", tolling->station.obu.client_id, tolling->station.obu.nonce, accepted ? "yes" : "no");
|
|
tolling->station.obu.toll_type = -1;
|
|
tolling->station.obu.active = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Close TCP & TLS conn
|
|
if (tolling->protocol.p == TOLLING_PROTOCOL_TLS ||
|
|
tolling->protocol.p == TOLLING_PROTOCOL_TLS_GN ||
|
|
tolling->protocol.p == TOLLING_PROTOCOL_TLS_SHS) {
|
|
tlsc_t* tlsc = tolling_tlsc_get(src_addr, 7011);
|
|
if (tlsc) {
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_tlsClose;
|
|
sreq->choice.tlsClose.connId = tlsc->id;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1);
|
|
log_debug("->[security] SecurityRequest.tlsClose (%ldB)", enc.encoded+1);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
log_debug("<-[security] SecurityReply.tlsClose (%dB)", rl);
|
|
|
|
uint32_t id = rand();
|
|
tr = calloc(1, sizeof(EIS_NetworkingRequest_t));
|
|
tr->present = EIS_NetworkingRequest_PR_data;
|
|
tr->choice.data.present = EIS_NetworkingDataRequest_PR_tcp;
|
|
tr->choice.data.choice.tcp.present = EIS_TCPDataRequest_PR_connCloseReq;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.closeByPeer = false;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.destinationPort = 7011;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.size = 16;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf = malloc(16);
|
|
memcpy(tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf, src_addr, 16);
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.id = id;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, tr, buf1+1, buf_len-1);
|
|
itss_queue_send(tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id, "NR.data.tcp.connClose"));
|
|
|
|
free(tlsc);
|
|
for (int i = 0; i < tolling->protocol.c.tls.n_tlsc; ++i) {
|
|
if (tlsc == tolling->protocol.c.tls.tls_conns[i]) {
|
|
for (int j = i; j < tolling->protocol.c.tls.n_tlsc-1; ++j) {
|
|
tolling->protocol.c.tls.tls_conns[j] = tolling->protocol.c.tls.tls_conns[j+1];
|
|
}
|
|
--tolling->protocol.c.tls.n_tlsc;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
log_debug("[tolling] unable to close TLS connection, not found");
|
|
}
|
|
}
|
|
|
|
|
|
cleanup:
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq);
|
|
ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep);
|
|
|
|
return rv;
|
|
}
|
|
|
|
int tpm_recv(EI1_TPM_t* tpm_rx, void** security_socket, uint8_t* neighbour, uint8_t* src_addr) {
|
|
|
|
tolling_t* tolling = &facilities.tolling;
|
|
|
|
if (!tolling->enabled) {
|
|
log_debug("[tolling] tolling is disabled");
|
|
return 0;
|
|
}
|
|
|
|
if (!tpm_rx->tpm) {
|
|
log_error("[tolling] received TPM does not have substructure TollingPaymentMessage");
|
|
return 1;
|
|
}
|
|
|
|
if (!tpm_rx->tpm->tollingType) {
|
|
log_error("[tolling] received TPM does not have a type");
|
|
return 1;
|
|
}
|
|
|
|
pthread_mutex_lock(&tolling->lock);
|
|
|
|
switch (tpm_rx->tpm->tollingType->present) {
|
|
// Entry
|
|
case EI1_TollingType_PR_entry:
|
|
switch (tpm_rx->tpm->tollingType->choice.entry.present) {
|
|
case EI1_TollingSingle_PR_request:
|
|
if (facilities.station_type != 15) {
|
|
log_debug("[tolling] received TPM.entry.request, ignoring");
|
|
goto cleanup;
|
|
}
|
|
rsu_handle_recv(tpm_rx, security_socket, neighbour, src_addr);
|
|
break;
|
|
case EI1_TollingSingle_PR_reply:
|
|
if (facilities.station_type == 15) {
|
|
log_debug("[tolling] received TPM.entry.reply, ignoring");
|
|
goto cleanup;
|
|
}
|
|
if (!veh_handle_recv(tolling, tpm_rx, security_socket, facilities.tx_queue, neighbour, src_addr)) {
|
|
itss_time_lock();
|
|
log_info("[tolling] entry.reply took %lld us", itss_ts_get(TIME_MICROSECONDS) - tolling->station.obu.t_init);
|
|
itss_time_unlock();
|
|
tolling->station.obu.rt_on = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
// Exit
|
|
case EI1_TollingType_PR_exit:
|
|
if (!tpm_rx->tpm->tollingType->choice.exit) {
|
|
return 1;
|
|
}
|
|
switch (tpm_rx->tpm->tollingType->choice.exit->present) {
|
|
case EI1_TollingSingle_PR_request:
|
|
if (facilities.station_type != 15) {
|
|
log_debug("[tolling] received TPM.exit.request, ignoring");
|
|
goto cleanup;
|
|
}
|
|
rsu_handle_recv(tpm_rx, security_socket, neighbour, src_addr);
|
|
break;
|
|
case EI1_TollingSingle_PR_reply:
|
|
if (facilities.station_type == 15) {
|
|
log_debug("[tolling] received TPM.exit.reply, ignoring");
|
|
goto cleanup;
|
|
}
|
|
if (!veh_handle_recv(tolling, tpm_rx, security_socket, facilities.tx_queue, neighbour, src_addr)) {
|
|
itss_time_lock();
|
|
log_info("[tolling] exit.reply took %lld us", itss_ts_get(TIME_MICROSECONDS) - tolling->station.obu.t_init);
|
|
itss_time_unlock();
|
|
tolling->station.obu.rt_on = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
// Single
|
|
case EI1_TollingType_PR_single:
|
|
switch (tpm_rx->tpm->tollingType->choice.single.present) {
|
|
case EI1_TollingSingle_PR_request:
|
|
if (facilities.station_type != 15) {
|
|
log_debug("[tolling] received TPM.single.request, ignoring");
|
|
goto cleanup;
|
|
}
|
|
rsu_handle_recv(tpm_rx, security_socket, neighbour, src_addr);
|
|
break;
|
|
case EI1_TollingSingle_PR_reply:
|
|
if (facilities.station_type == 15) {
|
|
log_debug("[tolling] received TPM.single.reply, ignoring");
|
|
goto cleanup;
|
|
}
|
|
if (!veh_handle_recv(tolling, tpm_rx, security_socket, facilities.tx_queue, neighbour, src_addr)) {
|
|
itss_time_lock();
|
|
log_info("[tolling] single.reply took %lld us", itss_ts_get(TIME_MICROSECONDS) - tolling->station.obu.t_init);
|
|
itss_time_unlock();
|
|
tolling->station.obu.rt_on = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
cleanup:
|
|
pthread_mutex_unlock(&tolling->lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tolling_init(uint8_t station_type) {
|
|
tolling_t* tolling = &facilities.tolling;
|
|
pthread_mutex_init(&tolling->lock, NULL);
|
|
|
|
switch (station_type) {
|
|
case 15:
|
|
for (int i = 0; i < TOLLING_MAX_CLIENTS; ++i) {
|
|
tolling->station.rsu.clients[i] = NULL;
|
|
}
|
|
break;
|
|
default:
|
|
tolling->station.obu.toll_type = -1;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
tolling_info_t* tolling_info_new(EI1_TollingPaymentInfo_t* tpi) {
|
|
tolling_info_t* ti = calloc(1, sizeof(tolling_info_t));
|
|
|
|
ti->timestamp = itss_time_get();
|
|
ti->asn = tpi;
|
|
|
|
ti->zone.polygon_len = tpi->zone.list.count;
|
|
ti->zone.polygon = malloc(tpi->zone.list.count * sizeof(double[2]));
|
|
|
|
for (int i = 0; i < tpi->zone.list.count; ++i) {
|
|
ti->zone.polygon[i][0] = tpi->zone.list.array[i]->latitude / 1.0e7;
|
|
ti->zone.polygon[i][1] = tpi->zone.list.array[i]->longitude / 1.0e7;
|
|
}
|
|
|
|
return ti;
|
|
}
|
|
|
|
void tolling_info_free(tolling_info_t* ti) {
|
|
ASN_STRUCT_FREE(asn_DEF_EI1_TollingPaymentInfo, ti->asn);
|
|
free(ti->zone.polygon);
|
|
free(ti);
|
|
}
|
|
|
|
tlsc_t* tolling_tlsc_new(uint8_t ipv6[16], uint16_t port) {
|
|
|
|
tolling_t* tolling = &facilities.tolling;
|
|
|
|
log_debug("[tolling] new tlsc, nconns=%d", tolling->protocol.c.tls.n_tlsc);
|
|
if (tolling->protocol.c.tls.n_tlsc >= TOLLING_MAX_CONNS - 1) {
|
|
return NULL;
|
|
}
|
|
tolling->protocol.c.tls.tls_conns[tolling->protocol.c.tls.n_tlsc] = calloc(1, sizeof(tlsc_t));
|
|
tlsc_t* tlsc = tolling->protocol.c.tls.tls_conns[tolling->protocol.c.tls.n_tlsc];
|
|
memcpy(tlsc->ipv6, ipv6, 16);
|
|
tlsc->port = port;
|
|
tlsc->id = rand();
|
|
tlsc->ts = itss_time_get();
|
|
tlsc->nmsg = 0;
|
|
tlsc->state = 0;
|
|
++tolling->protocol.c.tls.n_tlsc;
|
|
return tlsc;
|
|
}
|
|
|
|
tlsc_t* tolling_tlsc_get(uint8_t ipv6[16], uint16_t port) {
|
|
tolling_t* tolling = &facilities.tolling;
|
|
log_debug("[tolling] new get , nconns=%d", tolling->protocol.c.tls.n_tlsc);
|
|
tlsc_t* tlsc = NULL;
|
|
for (int i = 0; i < tolling->protocol.c.tls.n_tlsc; ++i) {
|
|
if (!memcmp(tolling->protocol.c.tls.tls_conns[i]->ipv6, ipv6, 16) &&
|
|
tolling->protocol.c.tls.tls_conns[i]->port == port) {
|
|
tlsc = tolling->protocol.c.tls.tls_conns[i];
|
|
tlsc->ts = itss_time_get();
|
|
break;
|
|
}
|
|
}
|
|
return tlsc;
|
|
}
|
|
|
|
|
|
void tolling_tlsc_mgmt(itss_queue_t* tx_queue, void** security_socket) {
|
|
tolling_t* tolling = &facilities.tolling;
|
|
pthread_mutex_lock(&tolling->lock);
|
|
uint64_t now = itss_time_get();
|
|
for (int i = 0; i < tolling->protocol.c.tls.n_tlsc; ++i) {
|
|
tlsc_t* tlsc = tolling->protocol.c.tls.tls_conns[i];
|
|
if (tlsc->ts + TOLLING_CONN_TIMEOUT_MS < now) {
|
|
EIS_SecurityRequest_t* sreq = NULL;
|
|
EIS_NetworkingRequest_t* tr = NULL;
|
|
const uint32_t buf_len = 1024;
|
|
uint8_t buf1[buf_len], buf2[buf_len];
|
|
log_debug("[tolling] closing TCP/TLS connection");
|
|
|
|
sreq = calloc(1, sizeof(EIS_SecurityRequest_t));
|
|
sreq->present = EIS_SecurityRequest_PR_tlsClose;
|
|
sreq->choice.tlsClose.connId = tlsc->id;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1);
|
|
log_debug("->[security] SecurityRequest.tlsClose (%ldB)", enc.encoded+1);
|
|
itss_0send(*security_socket, buf1, enc.encoded+1);
|
|
int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000);
|
|
log_debug("<-[security] SecurityReply.tlsClose (%dB)", rl);
|
|
|
|
uint64_t id = rand() + 1;
|
|
tr = calloc(1, sizeof(EIS_NetworkingRequest_t));
|
|
tr->present = EIS_NetworkingRequest_PR_data;
|
|
tr->choice.data.present = EIS_NetworkingDataRequest_PR_tcp;
|
|
tr->choice.data.choice.tcp.present = EIS_TCPDataRequest_PR_connCloseReq;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.closeByPeer = false;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.destinationPort = 7011;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.size = 16;
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf = malloc(16);
|
|
memcpy(tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf, tlsc->ipv6, 16);
|
|
tr->choice.data.choice.tcp.choice.connCloseReq.id = id;
|
|
|
|
buf1[0] = ITSS_FACILITIES;
|
|
enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, tr, buf1+1, buf_len-1);
|
|
itss_queue_send(tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id, "NR.data.tcp.connClose"));
|
|
|
|
free(tlsc);
|
|
for (int j = i; j < tolling->protocol.c.tls.n_tlsc-1; ++j) {
|
|
tolling->protocol.c.tls.tls_conns[j] = tolling->protocol.c.tls.tls_conns[j+1];
|
|
}
|
|
--tolling->protocol.c.tls.n_tlsc;
|
|
--i;
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&tolling->lock);
|
|
}
|