diff --git a/src/cam.c b/src/cam.c index 36deb9b..4909570 100644 --- a/src/cam.c +++ b/src/cam.c @@ -90,9 +90,9 @@ static int mk_cam(facilities_t* facilities, uint8_t *cam_oer, uint32_t *cam_len) cam->header.protocolVersion = 2; cam->header.messageID = ItsPduHeader__messageID_cam; - pthread_mutex_lock(&facilities->lock); - cam->header.stationID = facilities->station_id; - pthread_mutex_unlock(&facilities->lock); + pthread_mutex_lock(&facilities->id.lock); + cam->header.stationID = facilities->id.value; + pthread_mutex_unlock(&facilities->id.lock); cam->cam.camParameters.basicContainer.stationType = facilities->station_type; diff --git a/src/config.c b/src/config.c index f9fd8e2..c761f8c 100644 --- a/src/config.c +++ b/src/config.c @@ -176,12 +176,15 @@ int facilities_config(void* facilities_s) { facilities->use_security = config->security.use_security; - facilities->id_random = config->security.identity.random; - if (facilities->id_random) { + pthread_mutex_init(&facilities->id.lock, NULL); + pthread_mutex_init(&facilities->id.change.lock, NULL); + + facilities->id.change.random = config->security.identity.random; + if (facilities->id.change.random) { srand(time(NULL)); - facilities->station_id = rand(); + facilities->id.value = rand(); } else { - facilities->station_id = config->security.identity.station_id; + facilities->id.value = config->security.identity.station_id; } // DENM diff --git a/src/facilities.c b/src/facilities.c index 586793f..7015cb5 100644 --- a/src/facilities.c +++ b/src/facilities.c @@ -209,23 +209,44 @@ static int security_indication(facilities_t *facilities, void* responder_secured asn_dec_rval_t dec = oer_decode(NULL, &asn_DEF_SecurityIndication, (void**) &si, msg, msg_len); if (dec.code) { - syslog_err("[networking]<- invalid SIndication received"); + syslog_err("[facilities]<- invalid SIndication received"); + rv = 1; + goto cleanup; + } + + pthread_mutex_lock(&facilities->id.change.lock); + if (facilities->id.change.stage == ID_CHANGE_BLOCKED) { + pthread_mutex_unlock(&facilities->id.change.lock); + syslog_debug("[facilities] identity change is currently blocked"); + rv = 1; + goto cleanup; + } + + if (facilities->id.change.stage == ID_CHANGE_PREPARE && + si->choice.idChangeEvent.command != SecurityIdChangeEventType_commit && + si->choice.idChangeEvent.command != SecurityIdChangeEventType_abort) { + pthread_mutex_unlock(&facilities->id.change.lock); + syslog_debug("[facilities] current identity change state is prepare, but received identity change command is not commit nor abort"); rv = 1; goto cleanup; } switch (si->choice.idChangeEvent.command) { case SecurityIdChangeEventType_prepare: - pthread_mutex_lock(&facilities->lock); + + facilities->id.change.stage = ID_CHANGE_PREPARE; + + pthread_mutex_lock(&facilities->id.lock); pthread_mutex_lock(&facilities->lightship->lock); - facilities->in_idchange = true; break; case SecurityIdChangeEventType_commit: ; + facilities->id.change.stage = ID_CHANGE_COMMIT; + // Change Station ID - facilities->station_id = rand(); - pthread_mutex_unlock(&facilities->lock); + facilities->id.value = rand(); + pthread_mutex_unlock(&facilities->id.lock); // Reset lightship for (int i = 0; i < facilities->lightship->pos_history_len; ++i) { @@ -238,22 +259,26 @@ static int security_indication(facilities_t *facilities, void* responder_secured facilities->lightship->next_cam_max = 0; facilities->lightship->next_cam_min = 0; - facilities->in_idchange = false; pthread_mutex_unlock(&facilities->lightship->lock); + + facilities->id.change.stage = ID_CHANGE_INACTIVE; break; case SecurityIdChangeEventType_abort: - facilities->in_idchange = false; - pthread_mutex_unlock(&facilities->lock); + pthread_mutex_unlock(&facilities->id.lock); pthread_mutex_unlock(&facilities->lightship->lock); + facilities->id.change.stage = ID_CHANGE_INACTIVE; break; + default: + pthread_mutex_unlock(&facilities->id.change.lock); syslog_err("[networking]<- unhandled idChangeEvent command type"); rv = 1; goto cleanup; } + pthread_mutex_unlock(&facilities->id.change.lock); sr->present = SecurityResponse_PR_idChangeEvent; sr->choice.idChangeEvent.returnCode = 0; @@ -267,9 +292,9 @@ cleanup: sr->choice.idChangeEvent.returnCode = 1; enc = oer_encode_to_buffer(&asn_DEF_SecurityResponse, NULL, sr, buffer, 64); zmq_send(responder_secured, buffer, enc.encoded, 0); - zmq_recv(responder_secured, buffer, 64, 0); } + pthread_mutex_unlock(&facilities->id.change.lock); ASN_STRUCT_FREE(asn_DEF_SecurityResponse, sr); ASN_STRUCT_FREE(asn_DEF_SecurityIndication, si); @@ -382,7 +407,7 @@ int main() { syslog_info("[facilities] starting"); facilities_t facilities; - facilities.exit = false; + memset(&facilities, 0x00, sizeof(facilities_t)); facilities.zmq.ctx = zmq_ctx_new(); facilities.lightship = lightship_init(); @@ -391,15 +416,12 @@ int main() { facilities.den = calloc(1, sizeof(den_t)); facilities.infrastructure = calloc(1, sizeof(infrastructure_t)); - pthread_mutex_init(&facilities.lock, NULL); - time_t t; srand((unsigned) time(&t)); if (facilities_config(&facilities)) return 1; facilities.lightship->type = facilities.station_type; - facilities.in_idchange = false; // Tx pthread_create(&facilities.transmitting, NULL, tx, (void*) &facilities); @@ -420,6 +442,7 @@ int main() { uint8_t buffer[PACKET_MAX_LEN]; syslog_info("[facilities] listening"); uint8_t code; + bool in_idchange; while (!facilities.exit) { zmq_poll(facilities.zmq.responders, facilities.zmq.n_responders, -1); @@ -430,8 +453,20 @@ int main() { switch (buffer[0]) { case 3: - if (!facilities.in_idchange) { + in_idchange = true; + pthread_mutex_lock(&facilities.id.change.lock); + if (facilities.id.change.stage == ID_CHANGE_INACTIVE) { + in_idchange = false; + facilities.id.change.stage = ID_CHANGE_BLOCKED; + } + pthread_mutex_unlock(&facilities.id.change.lock); + + if (!in_idchange) { transport_indication(&facilities, facilities.zmq.responders[i].socket, buffer+1, PACKET_MAX_LEN-1); + + pthread_mutex_lock(&facilities.id.change.lock); + facilities.id.change.stage = ID_CHANGE_INACTIVE; + pthread_mutex_unlock(&facilities.id.change.lock); } else { code = 1; zmq_send(facilities.zmq.responders[i].socket, &code, 1, 0); @@ -439,12 +474,25 @@ int main() { break; case 5: - if (!facilities.in_idchange) { + in_idchange = true; + pthread_mutex_lock(&facilities.id.change.lock); + if (facilities.id.change.stage == ID_CHANGE_INACTIVE) { + in_idchange = false; + facilities.id.change.stage = ID_CHANGE_BLOCKED; + } + pthread_mutex_unlock(&facilities.id.change.lock); + + if (!in_idchange) { facilities_request(&facilities, facilities.zmq.responders[i].socket, buffer+1, PACKET_MAX_LEN-1); + + pthread_mutex_lock(&facilities.id.change.lock); + facilities.id.change.stage = ID_CHANGE_INACTIVE; + pthread_mutex_unlock(&facilities.id.change.lock); } else { code = 1; zmq_send(facilities.zmq.responders[i].socket, &code, 1, 0); } + break; case 6: diff --git a/src/facilities.h b/src/facilities.h index 5d6e20d..6d99122 100644 --- a/src/facilities.h +++ b/src/facilities.h @@ -11,6 +11,13 @@ #include "queue.h" #include "cpm.h" +enum ID_CHANGE_STAGE { + ID_CHANGE_INACTIVE, + ID_CHANGE_BLOCKED, + ID_CHANGE_PREPARE, + ID_CHANGE_COMMIT +}; + typedef struct epv { pthread_mutex_t lock; @@ -61,10 +68,15 @@ typedef struct facilities { bool use_security; bool replay; - pthread_mutex_t lock; - uint64_t station_id; - bool id_random; - bool in_idchange; + struct { + pthread_mutex_t lock; + uint64_t value; + struct { + pthread_mutex_t lock; + bool random; + int stage; + } change; + } id; epv_t epv; diff --git a/src/requests.c b/src/requests.c index 03ed2b1..fd5d73e 100644 --- a/src/requests.c +++ b/src/requests.c @@ -138,9 +138,9 @@ int facilities_request_single_message(facilities_t* facilities, void* responder, if (fwd) { // set stationID - pthread_mutex_lock(&facilities->lock); - ((DENM_t*)its_msg)->header.stationID = facilities->station_id; - pthread_mutex_unlock(&facilities->lock); + pthread_mutex_lock(&facilities->id.lock); + ((DENM_t*)its_msg)->header.stationID = facilities->id.value; + pthread_mutex_unlock(&facilities->id.lock); // Set only one trace if (facilities->station_type != 15) { @@ -409,9 +409,9 @@ int facilities_request_attribute_types(facilities_t* facilities, void* responder fdres->result->choice.attributes.list.array[j] = calloc(1, sizeof(FacilitiesAttribute_t) ); fdres->result->choice.attributes.list.array[j]->data.size = 8; fdres->result->choice.attributes.list.array[j]->data.buf = malloc(8); - pthread_mutex_lock(&facilities->lock); - *((uint64_t*) fdres->result->choice.attributes.list.array[j]->data.buf) = facilities->station_id; - pthread_mutex_unlock(&facilities->lock); + pthread_mutex_lock(&facilities->id.lock); + *((uint64_t*) fdres->result->choice.attributes.list.array[j]->data.buf) = facilities->id.value; + pthread_mutex_unlock(&facilities->id.lock); break; default: