From 2e7b926827ad199c264b9d6e771de757cb4f2937 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 May 2024 13:04:45 +0200 Subject: [PATCH 01/39] nrUE NAS: remove mm_counter and sm_counter, replace with nas_count Specs (24.501, 33.501) don't seem to mention mm_counter and sm_counter, simply nas_count, let's use this. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 8 ++++---- openair3/NAS/NR_UE/nr_nas_msg_sim.h | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 97f9ca1aef..544abf4676 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -603,7 +603,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); stream_cipher.context = nas->security_container->integrity_context; - stream_cipher.count = nas->security.mm_counter++; + stream_cipher.count = nas->security.nas_count++; stream_cipher.bearer = 1; stream_cipher.direction = 0; stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); @@ -703,7 +703,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia initialNasMsg->length = length; stream_cipher.context = nas->security_container->integrity_context; - stream_cipher.count = nas->security.mm_counter++; + stream_cipher.count = nas->security.nas_count++; stream_cipher.bearer = 1; stream_cipher.direction = 0; stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); @@ -765,7 +765,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi nas_stream_cipher_t stream_cipher = { .context = nas->security_container->integrity_context, - .count = nas->security.mm_counter++, + .count = nas->security.nas_count++, .bearer = 1, .direction = 0, .message = (unsigned char *)(initialNasMsg->data + 6), @@ -855,7 +855,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); stream_cipher.context = nas->security_container->integrity_context; - stream_cipher.count = nas->security.mm_counter++; + stream_cipher.count = nas->security.nas_count++; stream_cipher.bearer = 1; stream_cipher.direction = 0; stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg_sim.h index 0d2d8f5cc9..dbb18e1425 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.h @@ -92,8 +92,7 @@ typedef struct { uint8_t res[16]; uint8_t rand[16]; uint8_t kgnb[32]; - uint32_t mm_counter; - uint32_t sm_counter; + uint32_t nas_count; } ue_sa_security_key_t; typedef struct { From b615162630d1625ae83f06c3c296f941bd93b41a Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 May 2024 16:35:00 +0200 Subject: [PATCH 02/39] nrUE NAS: there are actually two NAS COUNT, one for DL and one for UL --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 8 ++++---- openair3/NAS/NR_UE/nr_nas_msg_sim.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 544abf4676..a63d448f1f 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -603,7 +603,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); stream_cipher.context = nas->security_container->integrity_context; - stream_cipher.count = nas->security.nas_count++; + stream_cipher.count = nas->security.nas_count_ul++; stream_cipher.bearer = 1; stream_cipher.direction = 0; stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); @@ -703,7 +703,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia initialNasMsg->length = length; stream_cipher.context = nas->security_container->integrity_context; - stream_cipher.count = nas->security.nas_count++; + stream_cipher.count = nas->security.nas_count_ul++; stream_cipher.bearer = 1; stream_cipher.direction = 0; stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); @@ -765,7 +765,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi nas_stream_cipher_t stream_cipher = { .context = nas->security_container->integrity_context, - .count = nas->security.nas_count++, + .count = nas->security.nas_count_ul++, .bearer = 1, .direction = 0, .message = (unsigned char *)(initialNasMsg->data + 6), @@ -855,7 +855,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); stream_cipher.context = nas->security_container->integrity_context; - stream_cipher.count = nas->security.nas_count++; + stream_cipher.count = nas->security.nas_count_ul++; stream_cipher.bearer = 1; stream_cipher.direction = 0; stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg_sim.h index dbb18e1425..8bc8a724c5 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.h @@ -92,7 +92,8 @@ typedef struct { uint8_t res[16]; uint8_t rand[16]; uint8_t kgnb[32]; - uint32_t nas_count; + uint32_t nas_count_ul; + uint32_t nas_count_dl; } ue_sa_security_key_t; typedef struct { From 41037d57b5d78b962bd2a2a6053fdc3b5df3d066 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 May 2024 18:15:19 +0200 Subject: [PATCH 03/39] nrUE NAS: handle SecurityModeCommand Get the security algorithms from SecurityModeCommand. Restructure the code a bit: add the function handle_security_mode_command() and adapt the code to use it. Derive also knas_enc (not used yet). Do the derivation for knas_enc and knas_int only after reception of SecurityModeCommand. We need the algorithms configured by core network to derive those keys. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 62 +++++++++++++++++++---------- openair3/NAS/NR_UE/nr_nas_msg_sim.h | 1 + 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index a63d448f1f..99b7f9c51d 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -303,7 +303,8 @@ void derive_kamf(uint8_t *kseaf, uint8_t *kamf, uint16_t abba, uicc_t* uicc) { } //------------------------------------------------------------------------------ -void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t kamf[32], uint8_t *knas_int) { +void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t kamf[32], uint8_t *knas) +{ uint8_t S[20] = {0}; uint8_t out[32] = { 0 }; S[0] = 0x69; //FC @@ -317,7 +318,7 @@ void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t byte_array_t data = {.buf = S, .len = 7}; kdf(kamf, data, 32, out); - memcpy(knas_int, out+16, 16); + memcpy(knas, out+16, 16); } void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){ @@ -362,7 +363,6 @@ void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) { uint8_t *kausf = nas->security.kausf; uint8_t *kseaf = nas->security.kseaf; uint8_t *kamf = nas->security.kamf; - uint8_t *knas_int = nas->security.knas_int; uint8_t *output = nas->security.res; uint8_t *rand = nas->security.rand; uint8_t *kgnb = nas->security.kgnb; @@ -385,7 +385,6 @@ void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) { derive_kausf(ck, ik, sqn, kausf, nas->uicc); derive_kseaf(kausf, kseaf, nas->uicc); derive_kamf(kseaf, kamf, 0x0000, nas->uicc); - derive_knas(0x02, 2, kamf, knas_int); derive_kgnb(kamf,0,kgnb); printf("kausf:"); @@ -406,12 +405,6 @@ void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) { printf("%x ", kamf[i]); } printf("\n"); - - printf("knas_int:\n"); - for(int i = 0; i < 16; i++){ - printf("%x ", knas_int[i]); - } - printf("\n"); } nr_ue_nas_t *get_ue_nas_info(module_id_t module_id) @@ -515,10 +508,6 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *buf) { derive_ue_keys(buf, nas); - /* todo: as of now, nia2 is hardcoded in derive_ue_keys(), remove this hardcoding, use NAS signalling for getting proper algorithm */ - /* todo: deal with ciphering for this stream_security_container_init() (handle ciphering in general) */ - /* todo: stream_security_container_delete() is not called anywhere, deal with that */ - nas->security_container = stream_security_container_init(0, 2 /* hardcoded: nia2 */, NULL, nas->security.knas_int); OctetString res; res.length = 16; res.value = calloc(1,16); @@ -610,8 +599,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia /* length in bits */ stream_cipher.blength = (initialNasMsg->length - 6) << 3; - // only for Type of integrity protection algorithm: 128-5G-IA2 (2) - stream_compute_integrity(EIA2_128_ALG_ID, &stream_cipher, mac); + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); for(int i = 0; i < 4; i++){ @@ -619,6 +607,40 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia } } +static void handle_security_mode_command(instance_t instance, nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length) +{ + /* retrieve integrity and ciphering algorithms */ + AssertFatal(pdu_length > 10, "nas: bad pdu\n"); + int ciphering_algorithm = (pdu[10] >> 4) & 0x0f; + int integrity_algorithm = pdu[10] & 0x0f; + + uint8_t *kamf = nas->security.kamf; + uint8_t *knas_enc = nas->security.knas_enc; + uint8_t *knas_int = nas->security.knas_int; + + /* derive keys */ + derive_knas(0x01, ciphering_algorithm, kamf, knas_enc); + derive_knas(0x02, integrity_algorithm, kamf, knas_int); + + printf("knas_int: "); + for(int i = 0; i < 16; i++){ + printf("%x ", knas_int[i]); + } + printf("\n"); + + printf("knas_enc: "); + for(int i = 0; i < 16; i++){ + printf("%x ", knas_enc[i]); + } + printf("\n"); + + /* todo: stream_security_container_delete() is not called anywhere, deal with that */ + nas->security_container = stream_security_container_init(ciphering_algorithm, integrity_algorithm, knas_enc, knas_int); + + nas_itti_kgnb_refresh_req(instance, nas->security.kgnb); + generateSecurityModeComplete(nas, initialNasMsg); +} + static void decodeRegistrationAccept(const uint8_t *buf, int len, nr_ue_nas_t *nas) { registration_accept_msg reg_acc = {0}; @@ -1203,7 +1225,8 @@ void *nas_nrue(void *args_p) as_nas_info_t initialNasMsg = {0}; uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data; - int msg_type = get_msg_type(pdu_buffer, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length); + int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length; + int msg_type = get_msg_type(pdu_buffer, pdu_length); nr_ue_nas_t *nas = get_ue_nas_info(0); switch (msg_type) { @@ -1214,14 +1237,13 @@ void *nas_nrue(void *args_p) generateAuthenticationResp(nas, &initialNasMsg, pdu_buffer); break; case FGS_SECURITY_MODE_COMMAND: - nas_itti_kgnb_refresh_req(instance, nas->security.kgnb); - generateSecurityModeComplete(nas, &initialNasMsg); + handle_security_mode_command(instance, nas, &initialNasMsg, pdu_buffer, pdu_length); break; case FGS_DOWNLINK_NAS_TRANSPORT: decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer); break; case REGISTRATION_ACCEPT: - handle_registration_accept(instance, nas, pdu_buffer, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length); + handle_registration_accept(instance, nas, pdu_buffer, pdu_length); break; case FGS_DEREGISTRATION_ACCEPT: LOG_I(NAS, "received deregistration accept\n"); diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg_sim.h index 8bc8a724c5..d6f7430bdd 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.h @@ -89,6 +89,7 @@ typedef struct { uint8_t kseaf[32]; uint8_t kamf[32]; uint8_t knas_int[16]; + uint8_t knas_enc[16]; uint8_t res[16]; uint8_t rand[16]; uint8_t kgnb[32]; From ce771a17dcea65caa465e1b8d6e323f7271b6855 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 May 2024 18:26:31 +0200 Subject: [PATCH 04/39] nrUE NAS: adapt code to use configured integrity algorithm --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 99b7f9c51d..952b886a3d 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -733,7 +733,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia stream_cipher.blength = (initialNasMsg->length - 6) << 3; // only for Type of integrity protection algorithm: 128-5G-IA2 (2) - stream_compute_integrity(EIA2_128_ALG_ID, &stream_cipher, mac); + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); for(int i = 0; i < 4; i++){ @@ -885,7 +885,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * stream_cipher.blength = (initialNasMsg->length - 6) << 3; // only for Type of integrity protection algorithm: 128-5G-IA2 (2) - stream_compute_integrity(EIA2_128_ALG_ID, &stream_cipher, mac); + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); for(int i = 0; i < 4; i++){ From 6c42ea62935ae641a98e7c74527afe048cf8e0dd Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 May 2024 18:34:32 +0200 Subject: [PATCH 05/39] nrUE NAS: don't hardcode sequence number, get value from NAS COUNT UL as per standard (see 33.501 6.4.3.1, see 24.501 4.4.3) --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 952b886a3d..42caa30075 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -680,7 +680,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia sp_msg->header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE; sp_msg->header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED; sp_msg->header.message_authentication_code = 0; - sp_msg->header.sequence_number = 1; + sp_msg->header.sequence_number = nas->security.nas_count_ul & 0xff; length = 7; sp_msg->plain.mm_msg.registration_complete.protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE; length += 1; @@ -762,7 +762,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi sp_msg->header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE; sp_msg->header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED; sp_msg->header.message_authentication_code = 0; - sp_msg->header.sequence_number = 3; + sp_msg->header.sequence_number = nas->security.nas_count_ul & 0xff; int size = sizeof(fgs_nas_message_security_header_t); fgs_deregistration_request_ue_originating_msg *dereg_req = &sp_msg->plain.mm_msg.fgs_deregistration_request_ue_originating; @@ -824,7 +824,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * uint8_t mac[4]; nas_msg.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE; nas_msg.header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED; - nas_msg.header.sequence_number = 2; + nas_msg.header.sequence_number = nas->security.nas_count_ul & 0xff; size += 7; From 4cc1bb5433a8f51557b1601c584055c78cc1e780 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 23 May 2024 16:51:58 +0200 Subject: [PATCH 06/39] nrUE NAS: hotfix for get_msg_type() The version before this commit is wrong, taking wrong byte for msg_type in some cases. I don't have much time to implement a proper NAS PDU parser, so let's go with hardcoded values. Some later work will be done to have a cleaner solution. As of now, it's too much work. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 49 ++++++++++++++++++----------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 42caa30075..99ea2aef85 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -894,30 +894,41 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * } -uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) { - uint8_t msg_type = 0; - uint8_t offset = 0; +static uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) +{ + if (pdu_buffer == NULL) + goto error; - if ((pdu_buffer != NULL) && (length > 0)) { - if (((nas_msg_header_t *)(pdu_buffer))->choice.security_protected_nas_msg_header_t.security_header_type > 0) { - offset += SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; - if (offset < length) { - msg_type = ((mm_msg_header_t *)(pdu_buffer + offset))->message_type; + /* get security header type */ + if (length < 2) + goto error; - if (msg_type == FGS_DOWNLINK_NAS_TRANSPORT) { - dl_nas_transport_t tmp; - memcpy(&tmp, pdu_buffer + offset, sizeof(tmp)); - msg_type = tmp.sm_nas_msg_header.message_type; - } - } - } else { // plain 5GS NAS message - msg_type = ((nas_msg_header_t *)(pdu_buffer))->choice.plain_nas_msg_header.message_type; - } - } else { - LOG_I(NAS, "[UE] Received invalid downlink message\n"); + int security_header_type = pdu_buffer[1]; + + if (security_header_type == 0) { + /* plain NAS message */ + if (length < 3) + goto error; + return pdu_buffer[2]; + } + + if (length < 10) + goto error; + + int msg_type = pdu_buffer[9]; + + if (msg_type == FGS_DOWNLINK_NAS_TRANSPORT) { + if (length < 17) + goto error; + + msg_type = pdu_buffer[16]; } return msg_type; + +error: + LOG_E(NAS, "[UE] Received invalid downlink message\n"); + return 0; } static void send_nas_uplink_data_req(instance_t instance, const as_nas_info_t *initial_nas_msg) From 075f8330f6efc132bf90652a576b156d6e336993 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 10:58:03 +0200 Subject: [PATCH 07/39] nrUE NAS: implement downlink security processing Maybe not totally ok (code has some comments). To be refined if needed. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 80 ++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 99ea2aef85..4a87729188 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -60,6 +60,76 @@ extern uint16_t NB_UE_INST; static nr_ue_nas_t nr_ue_nas = {0}; static nr_nas_msg_snssai_t nas_allowed_nssai[8]; +typedef enum { + NAS_SECURITY_NO_SECURITY_CONTEXT, + NAS_SECURITY_INTEGRITY_FAILED, + NAS_SECURITY_INTEGRITY_PASSED, + NAS_SECURITY_BAD_INPUT +} security_state_t; + +security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_buffer, int pdu_length) +{ + if (nas->security_container == NULL) + return NAS_SECURITY_NO_SECURITY_CONTEXT; + /* header is 7 bytes, require at least one byte of payload */ + if (pdu_length < 8) + return NAS_SECURITY_BAD_INPUT; + /* only accept "integrity protected and ciphered" messages */ + if (pdu_buffer[1] != 2) { + LOG_E(NAS, "todo: unhandled security type %d\n", pdu_buffer[2]); + return NAS_SECURITY_BAD_INPUT; + } + + /* synchronize NAS SQN, based on 24.501 4.4.3.1 */ + int nas_sqn = pdu_buffer[6]; + int target_sqn = nas->security.nas_count_dl & 0xff; + if (nas_sqn != target_sqn) { + if (nas_sqn < target_sqn) + nas->security.nas_count_dl += 256; + nas->security.nas_count_dl &= ~255; + nas->security.nas_count_dl |= nas_sqn; + } + if (nas->security.nas_count_dl > 0x00ffffff) { + /* it's doubtful that this will happen, so let's simply exit for the time being */ + /* to be refined if needed */ + LOG_E(NAS, "max NAS COUNT DL reached\n"); + exit(1); + } + + /* check integrity */ + uint8_t computed_mac[4]; + nas_stream_cipher_t stream_cipher; + stream_cipher.context = nas->security_container->integrity_context; + stream_cipher.count = nas->security.nas_count_dl; + stream_cipher.bearer = 1; /* todo: don't hardcode */ + stream_cipher.direction = 1; + stream_cipher.message = pdu_buffer + 6; + /* length in bits */ + stream_cipher.blength = (pdu_length - 6) << 3; + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, computed_mac); + + uint8_t *received_mac = pdu_buffer + 2; + + if (memcmp(received_mac, computed_mac, 4) != 0) + return NAS_SECURITY_INTEGRITY_FAILED; + + /* decipher */ + uint8_t buf[pdu_length - 7]; + stream_cipher.context = nas->security_container->ciphering_context; + stream_cipher.count = nas->security.nas_count_dl; + stream_cipher.bearer = 1; /* todo: don't hardcode */ + stream_cipher.direction = 1; + stream_cipher.message = pdu_buffer + 7; + /* length in bits */ + stream_cipher.blength = (pdu_length - 7) << 3; + stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); + memcpy(pdu_buffer + 7, buf, pdu_length - 7); + + nas->security.nas_count_dl++; + + return NAS_SECURITY_INTEGRITY_PASSED; +} + static int nas_protected_security_header_encode( char *buffer, const fgs_nas_message_security_header_t *header, @@ -1234,11 +1304,19 @@ void *nas_nrue(void *args_p) NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data); as_nas_info_t initialNasMsg = {0}; + nr_ue_nas_t *nas = get_ue_nas_info(0); uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data; int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length; + + security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length); + if (security_state != NAS_SECURITY_INTEGRITY_PASSED + && security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) { + LOG_E(NAS, "NAS integrity failed, discard incoming message\n"); + break; + } + int msg_type = get_msg_type(pdu_buffer, pdu_length); - nr_ue_nas_t *nas = get_ue_nas_info(0); switch (msg_type) { case FGS_IDENTITY_REQUEST: From 245f430ad92af96042af79c129860e4989f4c6f8 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 16:28:48 +0200 Subject: [PATCH 08/39] nrUE NAS: apply ciphering to uplink messages Before this commit, only integrity protection was applied. This was working only if the NAS connection is using NEA0. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 87 +++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 4a87729188..eb832cb609 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -661,6 +661,19 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); + /* ciphering */ + uint8_t buf[initialNasMsg->length - 7]; + stream_cipher.context = nas->security_container->ciphering_context; + stream_cipher.count = nas->security.nas_count_ul; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7); + /* length in bits */ + stream_cipher.blength = (initialNasMsg->length - 7) << 3; + stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); + memcpy(stream_cipher.message, buf, initialNasMsg->length - 7); + + /* integrity protection */ stream_cipher.context = nas->security_container->integrity_context; stream_cipher.count = nas->security.nas_count_ul++; stream_cipher.bearer = 1; @@ -766,6 +779,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia // encode the message initialNasMsg->data = (Byte_t *)malloc(length * sizeof(Byte_t)); + initialNasMsg->length = length; /* Encode the first octet of the header (extended protocol discriminator) */ ENCODE_U8(initialNasMsg->data + size, sp_msg->header.protocol_discriminator, size); @@ -792,8 +806,20 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia if(sortransparentcontainer) { encode_registration_complete(&sp_msg->plain.mm_msg.registration_complete, initialNasMsg->data + size, length - size); } - - initialNasMsg->length = length; + + /* ciphering */ + uint8_t buf[initialNasMsg->length - 7]; + stream_cipher.context = nas->security_container->ciphering_context; + stream_cipher.count = nas->security.nas_count_ul; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7); + /* length in bits */ + stream_cipher.blength = (initialNasMsg->length - 7) << 3; + stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); + memcpy(stream_cipher.message, buf, initialNasMsg->length - 7); + + /* integrity protection */ stream_cipher.context = nas->security_container->integrity_context; stream_cipher.count = nas->security.nas_count_ul++; stream_cipher.bearer = 1; @@ -801,8 +827,6 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); /* length in bits */ stream_cipher.blength = (initialNasMsg->length - 6) << 3; - - // only for Type of integrity protection algorithm: 128-5G-IA2 (2) stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); @@ -855,19 +879,35 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi initialNasMsg->length = security_header_len + mm_msg_encode(&sp_msg->plain.mm_msg, (uint8_t *)(initialNasMsg->data + security_header_len), size - security_header_len); - nas_stream_cipher_t stream_cipher = { - .context = nas->security_container->integrity_context, - .count = nas->security.nas_count_ul++, - .bearer = 1, - .direction = 0, - .message = (unsigned char *)(initialNasMsg->data + 6), - .blength = (initialNasMsg->length - 6) << 3, /* length in bits */ - }; - uint8_t mac[4]; - nas_stream_encrypt_eia2(&stream_cipher, mac); + nas_stream_cipher_t stream_cipher; - for(int i = 0; i < 4; i++) - initialNasMsg->data[2 + i] = mac[i]; + /* ciphering */ + uint8_t buf[initialNasMsg->length - 7]; + stream_cipher.context = nas->security_container->ciphering_context; + stream_cipher.count = nas->security.nas_count_ul; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7); + /* length in bits */ + stream_cipher.blength = (initialNasMsg->length - 7) << 3; + stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); + memcpy(stream_cipher.message, buf, initialNasMsg->length - 7); + + /* integrity protection */ + stream_cipher.context = nas->security_container->integrity_context; + stream_cipher.count = nas->security.nas_count_ul++; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); + /* length in bits */ + stream_cipher.blength = (initialNasMsg->length - 6) << 3; + uint8_t mac[4]; + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); + + printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); + for(int i = 0; i < 4; i++){ + initialNasMsg->data[2+i] = mac[i]; + } } static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, nas_pdu_session_req_t *pdu_req) @@ -946,6 +986,19 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); + /* ciphering */ + uint8_t buf[initialNasMsg->length - 7]; + stream_cipher.context = nas->security_container->ciphering_context; + stream_cipher.count = nas->security.nas_count_ul; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7); + /* length in bits */ + stream_cipher.blength = (initialNasMsg->length - 7) << 3; + stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); + memcpy(stream_cipher.message, buf, initialNasMsg->length - 7); + + /* integrity protection */ stream_cipher.context = nas->security_container->integrity_context; stream_cipher.count = nas->security.nas_count_ul++; stream_cipher.bearer = 1; @@ -953,8 +1006,6 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); /* length in bits */ stream_cipher.blength = (initialNasMsg->length - 6) << 3; - - // only for Type of integrity protection algorithm: 128-5G-IA2 (2) stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); From 56abe6c1187bb3d72bd4d902b1332ac0ccbdd83d Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 16:32:47 +0200 Subject: [PATCH 09/39] nrUE NAS: deal with security for NAS_CONN_ESTABLI_CNF This message is ciphered + integrity protected, let's decipher it and integrity check it. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index eb832cb609..c2de7fd8d3 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -1291,13 +1291,23 @@ void *nas_nrue(void *args_p) NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); uint8_t *pdu_buffer = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.data; - int msg_type = get_msg_type(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); + int pdu_length = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length; + + nr_ue_nas_t *nas = get_ue_nas_info(0); + + security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length); + if (security_state != NAS_SECURITY_INTEGRITY_PASSED + && security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) { + LOG_E(NAS, "NAS integrity failed, discard incoming message\n"); + break; + } + + int msg_type = get_msg_type(pdu_buffer, pdu_length); if (msg_type == REGISTRATION_ACCEPT) { - nr_ue_nas_t *nas = get_ue_nas_info(0); - handle_registration_accept(instance, nas, pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); + handle_registration_accept(instance, nas, pdu_buffer, pdu_length); } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { - capture_pdu_session_establishment_accept_msg(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); + capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length); } break; From a10092906734936c643ec9383d80859e58383003 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 16:34:20 +0200 Subject: [PATCH 10/39] nrUE NAS: accept some messages without integrity+ciphering OAI core network is sending Deregistation Accept in clear, even after security context activation. The standards is not clear to me, so let's accept it. To be removed if incorrect with respect to the standards. (The core network will need to be fixed then.) --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index c2de7fd8d3..3155d82234 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -62,6 +62,7 @@ static nr_nas_msg_snssai_t nas_allowed_nssai[8]; typedef enum { NAS_SECURITY_NO_SECURITY_CONTEXT, + NAS_SECURITY_UNPROTECTED, NAS_SECURITY_INTEGRITY_FAILED, NAS_SECURITY_INTEGRITY_PASSED, NAS_SECURITY_BAD_INPUT @@ -71,6 +72,8 @@ security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_buffer, { if (nas->security_container == NULL) return NAS_SECURITY_NO_SECURITY_CONTEXT; + if (pdu_buffer[1] == 0) + return NAS_SECURITY_UNPROTECTED; /* header is 7 bytes, require at least one byte of payload */ if (pdu_length < 8) return NAS_SECURITY_BAD_INPUT; @@ -1371,6 +1374,14 @@ void *nas_nrue(void *args_p) int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length; security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length); + /* special cases accepted without protection */ + if (security_state == NAS_SECURITY_UNPROTECTED) { + int msg_type = get_msg_type(pdu_buffer, pdu_length); + /* for the moment, only FGS_DEREGISTRATION_ACCEPT is accepted */ + if (msg_type == FGS_DEREGISTRATION_ACCEPT) + security_state = NAS_SECURITY_INTEGRITY_PASSED; + } + if (security_state != NAS_SECURITY_INTEGRITY_PASSED && security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) { LOG_E(NAS, "NAS integrity failed, discard incoming message\n"); From 04027b9265210665684164db8d28611b5eedf19e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 16:50:39 +0200 Subject: [PATCH 11/39] nrUE NAS: minor changes in get_allowed_nssai() This function was very wrong, now it's just wrong. (It does not sanitize the input properly. Some bad input may have unexpected effects on the nrUE.) It needs a serious rewrite. I just wanted to "fix" it so that it processes correctly some correct input data. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 3155d82234..db747610ee 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -1157,11 +1157,13 @@ static void get_allowed_nssai(nr_nas_msg_snssai_t nssai[8], const uint8_t *pdu_b case 0x15: // allowed NSSAI length = *pdu_buffer++; parse_allowed_nssai(nssai, pdu_buffer, length); + pdu_buffer += length; break; default: - LOG_W(NAS, "This NAS IEI is not handled when extracting list of allowed NSSAI\n"); - pdu_buffer = end; + LOG_W(NAS, "This NAS IEI (0x%2.2x) is not handled when extracting list of allowed NSSAI\n", type); + length = *pdu_buffer++; + pdu_buffer += length; break; } } From 0147bb2e08b77911dbe009f6cb9d79d6bc6fe5c8 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 16:58:08 +0200 Subject: [PATCH 12/39] nrUE NAS: add NEA1 and NIA1 in nrUE security capabilities --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index db747610ee..aa2c4ddde4 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -532,8 +532,8 @@ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas) mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT; mm_msg->registration_request.nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI; mm_msg->registration_request.nruesecuritycapability.length = 8; - mm_msg->registration_request.nruesecuritycapability.fg_EA = 0xa0; - mm_msg->registration_request.nruesecuritycapability.fg_IA = 0x20; + mm_msg->registration_request.nruesecuritycapability.fg_EA = 0xe0; + mm_msg->registration_request.nruesecuritycapability.fg_IA = 0x60; mm_msg->registration_request.nruesecuritycapability.EEA = 0; mm_msg->registration_request.nruesecuritycapability.EIA = 0; size += 10; From 4c248a433ecc15dec66573a324716fc285e27195 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 23:10:14 +0200 Subject: [PATCH 13/39] nrUE NAS: bugfix: add sequence number to generateSecurityModeComplete It was working because on initial connection, it is 0. But it's probably a bad assumption. --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index aa2c4ddde4..2594bbad92 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -634,6 +634,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia // set security protected header nas_msg.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE; nas_msg.header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX; + nas_msg.header.sequence_number = nas->security.nas_count_ul & 0xff; size += 7; mm_msg = &nas_msg.security_protected.plain.mm_msg; From a1c4c356bd7f3febc3454ea80d121d41fbbb41fd Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Fri, 24 May 2024 23:12:08 +0200 Subject: [PATCH 14/39] nrUE NAS: check NAS COUNT UL It should not be > 0xffffff. Normally the core network would prevent this case from happening. Plus to reach this value means to send a lot of NAS messages, which is very doubtful in practice. Anyway, it's better to deal with the case. We exit if that happens. To be refined if needed (very doubtful). --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 2594bbad92..05feaafac2 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -668,6 +668,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia /* ciphering */ uint8_t buf[initialNasMsg->length - 7]; stream_cipher.context = nas->security_container->ciphering_context; + AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n"); stream_cipher.count = nas->security.nas_count_ul; stream_cipher.bearer = 1; stream_cipher.direction = 0; @@ -814,6 +815,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia /* ciphering */ uint8_t buf[initialNasMsg->length - 7]; stream_cipher.context = nas->security_container->ciphering_context; + AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n"); stream_cipher.count = nas->security.nas_count_ul; stream_cipher.bearer = 1; stream_cipher.direction = 0; @@ -888,6 +890,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi /* ciphering */ uint8_t buf[initialNasMsg->length - 7]; stream_cipher.context = nas->security_container->ciphering_context; + AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n"); stream_cipher.count = nas->security.nas_count_ul; stream_cipher.bearer = 1; stream_cipher.direction = 0; @@ -993,6 +996,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * /* ciphering */ uint8_t buf[initialNasMsg->length - 7]; stream_cipher.context = nas->security_container->ciphering_context; + AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n"); stream_cipher.count = nas->security.nas_count_ul; stream_cipher.bearer = 1; stream_cipher.direction = 0; From fc42a2a5f15030467eee776dfcc92bc4df7a6925 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Mon, 27 May 2024 17:25:59 +0200 Subject: [PATCH 15/39] security EIA1: bugfix: memory alignment + read out of array Compiling the nrUE with -fsanitize=undefined leads to a crash because the function nas_stream_encrypt_eia1() accesses the data as uint32_t but the data is not aligned. Actually this function wants 64 bits (big-endian) of data, so let's introduce a simple function to read a big-endian 64 bits value. It may seem bad (unoptimized), but looking at the output of gcc without -fsanitize=undefined this will be translated as just one movbeq instruction (on the machine where I did the test), which is actually less instructions than the previous version which was doing too movbel plus orq. Moreover, after the main loop we need to process the last remaining bytes (so less than 8). The code was wrong, reading past the input data (and also not caring about alignment). It may work, it may fail, it depends on many things. But it's plain wrong. So this was replaced for something better, simpler. No need for mask32bit() anymore, only one call to U64() is needed. And now -fsanitize=undefined is happy, so all is good. We also restrict the input length to be multiple of 8 bits. I don't think it's a problem. To be refined if I'm wrong. (I think RRC and NAS messages are 8-bits aligned, so it shouldn't be a problem.) --- openair3/SECU/nas_stream_eia1.c | 60 ++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/openair3/SECU/nas_stream_eia1.c b/openair3/SECU/nas_stream_eia1.c index c648ee585f..dd514c777b 100644 --- a/openair3/SECU/nas_stream_eia1.c +++ b/openair3/SECU/nas_stream_eia1.c @@ -88,25 +88,36 @@ static uint64_t MUL64(uint64_t V, uint64_t P, uint64_t c) return result; } -/* mask32bit. -* Input n: an integer in 1-32. -* Output : a 32 bit mask. -* Prepares a 32 bit mask with required number of 1 bits on the MSB side. -*/ -static uint32_t mask32bit(int n) +/* read a big endian uint64_t at given address (potentially not 64-bits aligned) + * don't read more than 'available_bytes' + * (use 0 if no byte to read) + * (note: the compiler will optimize this, no need to do better) + */ +static inline uint64_t U64(uint8_t *p, int available_bytes) { - uint32_t mask=0x0; + uint64_t a = 0; + uint64_t b = 0; + uint64_t c = 0; + uint64_t d = 0; + uint64_t e = 0; + uint64_t f = 0; + uint64_t g = 0; + uint64_t h = 0; + switch (available_bytes) { + case 8: h = p[7]; /* falltrough */ + case 7: g = p[6]; /* falltrough */ + case 6: f = p[5]; /* falltrough */ + case 5: e = p[4]; /* falltrough */ + case 4: d = p[3]; /* falltrough */ + case 3: c = p[2]; /* falltrough */ + case 2: b = p[1]; /* falltrough */ + case 1: a = p[0]; + } - if ( n%32 == 0 ) - return 0xffffffff; - - while (n--) - mask = (mask>>1) ^ 0x80000000; - - return mask; + return (a << (32+24)) | (b << (32+16)) | (c << (32+8)) | (d << 32) + | (e << 24) | (f << 16) | (g << 8) | h; } - /*! * @brief Create integrity cmac t for a given message. * @param[in] stream_cipher Structure containing various variables to setup encoding @@ -125,11 +136,8 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o uint64_t c; uint64_t M_D_2; int rem_bits; - uint32_t mask = 0; - uint32_t *message; uint8_t *key = (uint8_t *)stream_cipher->context; - message = (uint32_t*)stream_cipher->message; /* To operate 32 bit message internally. */ /* Load the Integrity Key for SNOW3G initialization as in section 4.4. */ memcpy(K+3,key+0,4); /*K[3] = key[0]; we assume K[3]=key[0]||key[1]||...||key[31] , with key[0] the @@ -181,11 +189,14 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o EVAL = 0; c = 0x1b; + AssertFatal(stream_cipher->blength % 8 == 0, "unsupported buffer length\n"); + + uint8_t *message = stream_cipher->message; + /* for 0 <= i <= D-3 */ for (i=0; i 32) { - M_D_2 = ( (uint64_t) hton_int32(message[2*(D-2)]) << 32 ) | - (uint64_t) (hton_int32(message[2*(D-2)+1]) & mask); - } else { - M_D_2 = ( (uint64_t) hton_int32(message[2*(D-2)]) & mask) << 32 ; - } + M_D_2 = U64(&message[4 * (2*(D-2))], rem_bits/8); V = EVAL ^ M_D_2; EVAL = MUL64(V,P,c); From a4bb7da1ce0182ff505f603c66faaf6e9834090b Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 22 May 2024 11:29:06 +0200 Subject: [PATCH 16/39] hotfix for cumulative DAI computation at UE --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index f4812e639c..1cc4177f11 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1365,7 +1365,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, // if temp_dai is less or equal than cumulative highest dai for given slot // it's an indication dai was reset due to modulo 4 operation if (temp_dai <= highest_dai) { - int mod4_count = (highest_dai / 4) + 1; // to take into account how many times dai wrapped up (modulo 4) + int mod4_count = (highest_dai + 1) / 4; // to take into account how many times dai wrapped up (modulo 4) current_harq->dai_cumul += (mod4_count * 4); } LOG_D(NR_MAC, From 7fc8fe25136e09a1af0f1ad8f503cf1280b6c94e Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 22 May 2024 19:32:29 +0200 Subject: [PATCH 17/39] fixing mapped_ssb_idx (it was not containing SSB index anymore) --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 30 +++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 54065ad757..6a502263ee 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1695,13 +1695,25 @@ static void build_ssb_list(NR_UE_MAC_INST_t *mac) uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask; // check if if current SSB is transmitted if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) { - ssb_list->nb_ssb_per_index[ssb_index]=ssb_list->nb_tx_ssb; + ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb; ssb_list->nb_tx_ssb++; } + else + ssb_list->nb_ssb_per_index[ssb_index] = -1; } ssb_list->tx_ssb = calloc(ssb_list->nb_tx_ssb, sizeof(*ssb_list->tx_ssb)); } +static int get_ssb_idx_from_list(ssb_list_info_t *ssb_list, int idx) +{ + for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) { + if (ssb_list->nb_ssb_per_index[ssb_index] == idx) + return ssb_index; + } + AssertFatal(false, "Couldn't find SSB index in SSB list\n"); + return 0; +} + // Map the transmitted SSBs to the ROs and create the association pattern according to the config static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) { @@ -1790,7 +1802,7 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) // WIP: only one possible association period so the starting PRACH configuration period is automatically 0 // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO // this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule - int ssb_idx = 0; + int idx = 0; bool done = false; for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) { prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx]; @@ -1807,9 +1819,10 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) // Go through the list of transmitted SSBs and map the required amount of SSBs to this RO // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO // this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule - for (; ssb_idx < ssb_list->nb_tx_ssb; ssb_idx++) { - ssb_info_t *tx_ssb = ssb_list->tx_ssb + ssb_idx; + for (; idx < ssb_list->nb_tx_ssb; idx++) { + ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx; // Map only the transmitted ssb_idx + int ssb_idx = get_ssb_idx_from_list(ssb_list, idx); ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx; ro_p->nb_mapped_ssb++; AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1, @@ -1830,11 +1843,11 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) tx_ssb->nb_mapped_ro); // If all the required SSBs are mapped to this RO, exit the loop of SSBs if (ro_p->nb_mapped_ssb == ssb_rach_ratio) { - ssb_idx++; + idx++; break; } } - done = MAX_NB_SSB == ssb_idx; + done = MAX_NB_SSB == idx; } } } @@ -1846,8 +1859,8 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end; prach_period++) { // Go through the list of transmitted SSBs - for (int ssb_idx = 0; ssb_idx < ssb_list->nb_tx_ssb; ssb_idx++) { - ssb_info_t *tx_ssb = ssb_list->tx_ssb + ssb_idx; + for (int idx = 0; idx < ssb_list->nb_tx_ssb; idx++) { + ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx; uint8_t nb_mapped_ro_in_association_period=0; // Reset the nb of mapped ROs for the new SSB index bool done = false; // Map all the required ROs to this SSB @@ -1863,6 +1876,7 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) for (int ro_in_freq = 0; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq && !done; ro_in_freq++) { prach_occasion_info_t *ro_p = slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq; + int ssb_idx = get_ssb_idx_from_list(ssb_list, idx); ro_p->mapped_ssb_idx[0] = ssb_idx; ro_p->nb_mapped_ssb = 1; AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1, From cd5822e9277253095d1ed4e2ce854a34e43e152f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Apr 2024 15:57:30 +0200 Subject: [PATCH 18/39] Update FHI 7.2 ORAN patch: unaligned access, detect/handle PRACH packets --- cmake_targets/tools/MODULES/Findxran.cmake | 2 + .../E/oaioran_E.patch | 86 ++++++++++++++++--- radio/fhi_72/CMakeLists.txt | 2 +- 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/cmake_targets/tools/MODULES/Findxran.cmake b/cmake_targets/tools/MODULES/Findxran.cmake index 810206c32c..961efc4e38 100644 --- a/cmake_targets/tools/MODULES/Findxran.cmake +++ b/cmake_targets/tools/MODULES/Findxran.cmake @@ -109,6 +109,8 @@ elseif (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.1") set(xran_VERSION 5.1.1) elseif (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.2") set(xran_VERSION 5.1.2) +elseif (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.3") + set(xran_VERSION 5.1.3) endif() unset(xran_VERSION_LINE) unset(xran_VERSION_STRING) diff --git a/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch b/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch index 6252623542..a40aefac2b 100644 --- a/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch +++ b/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch @@ -7,7 +7,7 @@ index 7508117..0dbe0bd 100644 #include -#define VERSIONX "oran_e_maintenance_release_v1.0" -+#define VERSIONX "oran_e_maintenance_release_v1.2" ++#define VERSIONX "oran_e_maintenance_release_v1.3" #define APP_O_DU 0 #define APP_O_RU 1 @@ -114,7 +114,7 @@ index 7419ae1..a85f973 100644 * @ingroup xran * diff --git a/fhi_lib/lib/api/xran_up_api.h b/fhi_lib/lib/api/xran_up_api.h -index 7d3afc5..3e00c5a 100644 +index 7d3afc5..e2f1f21 100644 --- a/fhi_lib/lib/api/xran_up_api.h +++ b/fhi_lib/lib/api/xran_up_api.h @@ -80,6 +80,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, @@ -125,6 +125,16 @@ index 7d3afc5..3e00c5a 100644 union ecpri_seq_id *seq_id, uint16_t *num_prbu, uint16_t *start_prbu, +@@ -89,7 +90,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, + int8_t expect_comp, + enum xran_comp_hdr_type staticComp, + uint8_t *compMeth, +- uint8_t *iqWidth); ++ uint8_t *iqWidth, ++ uint8_t *is_prach); + + inline int xran_prepare_iq_symbol_portion( + struct rte_mbuf *mbuf, diff --git a/fhi_lib/lib/ethernet/ethdi.c b/fhi_lib/lib/ethernet/ethdi.c index b6ba257..b53325f 100644 --- a/fhi_lib/lib/ethernet/ethdi.c @@ -173,9 +183,18 @@ index e6d3067..8e0abee 100644 static int16_t saturateAbs(int16_t inVal) { diff --git a/fhi_lib/lib/src/xran_bfp_uplane.cpp b/fhi_lib/lib/src/xran_bfp_uplane.cpp -index a345df4..7831fa0 100644 +index a345df4..109b05a 100644 --- a/fhi_lib/lib/src/xran_bfp_uplane.cpp +++ b/fhi_lib/lib/src/xran_bfp_uplane.cpp +@@ -90,7 +90,7 @@ namespace BFP_UPlane + { + const __m512i* rawData = reinterpret_cast(dataIn.dataExpanded); + /// Abs +- const auto rawDataAbs = _mm512_abs_epi16(rawData[0]); ++ const auto rawDataAbs = _mm512_abs_epi16(_mm512_loadu_epi16(rawData)); + /// No need to do a full horizontal max operation here, just do a max IQ step, + /// compute the exponents and then use a reduce max over all exponent values. This + /// is the fastest way to handle a single RB. @@ -116,7 +116,7 @@ namespace BFP_UPlane /// Get AVX512 pointer aligned to desired RB const __m512i* rawDataIn = reinterpret_cast(dataIn.dataExpanded + numREOffset); @@ -195,10 +214,18 @@ index a345df4..7831fa0 100644 dataOut->dataCompressed[thisRBExpAddr] = thisExp; /// Now have 1 RB worth of bytes separated into 3 chunks (1 per lane) diff --git a/fhi_lib/lib/src/xran_common.c b/fhi_lib/lib/src/xran_common.c -index baa673f..edd4ecb 100644 +index baa673f..00bfdf2 100644 --- a/fhi_lib/lib/src/xran_common.c +++ b/fhi_lib/lib/src/xran_common.c -@@ -656,6 +656,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) +@@ -650,12 +650,15 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) + uint8_t compMeth = 0; + uint8_t iqWidth = 0; + ++ uint8_t is_prach = 0; ++ + void *pHandle = NULL; + int ret = MBUF_FREE; + uint32_t mb_free = 0; int32_t valid_res = 0; int expect_comp = (p_dev_ctx->fh_cfg.ru_conf.compMeth != XRAN_COMPMETHOD_NONE); enum xran_comp_hdr_type staticComp = p_dev_ctx->fh_cfg.ru_conf.xranCompHdrType; @@ -206,7 +233,7 @@ index baa673f..edd4ecb 100644 if (staticComp == XRAN_COMP_HDR_TYPE_STATIC) { -@@ -674,6 +675,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) +@@ -674,6 +677,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) &subframe_id, &slot_id, &symb_id, @@ -214,7 +241,14 @@ index baa673f..edd4ecb 100644 &seq, &num_prbu, &start_prbu, -@@ -688,23 +690,9 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) +@@ -683,28 +687,15 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) + expect_comp, + staticComp, + &compMeth, +- &iqWidth); ++ &iqWidth, ++ &is_prach); + if (num_bytes <= 0){ print_err("num_bytes is wrong [%d]\n", num_bytes); return MBUF_FREE; } @@ -241,7 +275,16 @@ index baa673f..edd4ecb 100644 #ifndef FCN_ADAPT if(valid_res != 0) { print_dbg("valid_res is wrong [%d] ant %u (%u : %u : %u : %u) seq %u num_bytes %d\n", valid_res, Ant_ID, frame_id, subframe_id, slot_id, symb_id, seq.seq_id, num_bytes); -@@ -1189,7 +1177,7 @@ int generate_cpmsg_prach(void *pHandle, struct xran_cp_gen_params *params, struc +@@ -756,7 +747,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid) + print_dbg("Transport layer fragmentation (eCPRI) is not supported\n"); + } + +- } else if (Ant_ID >= p_dev_ctx->PrachCPConfig.eAxC_offset && p_dev_ctx->fh_cfg.prachEnable) { ++ } else if (/*Ant_ID >= p_dev_ctx->PrachCPConfig.eAxC_offset && */p_dev_ctx->fh_cfg.prachEnable && is_prach) { + /* PRACH packet has ruportid = num_eAxc + ant_id */ + Ant_ID -= p_dev_ctx->PrachCPConfig.eAxC_offset; + symbol_total_bytes[p_dev_ctx->xran_port_id][CC_ID][Ant_ID] += num_bytes; +@@ -1189,7 +1180,7 @@ int generate_cpmsg_prach(void *pHandle, struct xran_cp_gen_params *params, struc timeOffset += startSymId * (2048 + 144); } timeOffset = timeOffset >> nNumerology; //original number is Tc, convert to Ts based on mu @@ -250,7 +293,7 @@ index baa673f..edd4ecb 100644 timeOffset += 16; params->dir = XRAN_DIR_UL; -@@ -1295,8 +1283,7 @@ int32_t ring_processing_func(void* args) +@@ -1295,8 +1286,7 @@ int32_t ring_processing_func(void* args) for (i = 0; i < ctx->io_cfg.num_vfs && i < XRAN_VF_MAX; i++){ for(qi = 0; qi < ctx->rxq_per_port[i]; qi++) { @@ -430,7 +473,7 @@ index 36bd72c..f7f5678 100644 int idx = 0; uint16_t *psrc = (uint16_t *)iq_data_start; diff --git a/fhi_lib/lib/src/xran_up_api.c b/fhi_lib/lib/src/xran_up_api.c -index 397853a..4a714b5 100644 +index 397853a..8977e3d 100644 --- a/fhi_lib/lib/src/xran_up_api.c +++ b/fhi_lib/lib/src/xran_up_api.c @@ -329,6 +329,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, @@ -441,7 +484,26 @@ index 397853a..4a714b5 100644 union ecpri_seq_id *seq_id, uint16_t *num_prbu, uint16_t *start_prbu, -@@ -387,6 +388,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, +@@ -338,7 +339,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, + int8_t expect_comp, + enum xran_comp_hdr_type staticComp, + uint8_t *compMeth, +- uint8_t *iqWidth) ++ uint8_t *iqWidth, ++ uint8_t *is_prach) + { + #if XRAN_MLOG_VAR + uint32_t mlogVar[10]; +@@ -374,6 +376,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, + return 0; /* packet too short */ + + radio_hdr->sf_slot_sym.value = rte_be_to_cpu_16(radio_hdr->sf_slot_sym.value); ++ if (radio_hdr->data_feature.filter_id > 0) *is_prach = 1; ++ else *is_prach = 0; + + if (frame_id) + *frame_id = radio_hdr->frame_id; +@@ -387,6 +391,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, if (symb_id) *symb_id = radio_hdr->sf_slot_sym.symb_id; @@ -450,7 +512,7 @@ index 397853a..4a714b5 100644 /* Process data section hdr */ struct data_section_hdr *data_hdr = (void *)rte_pktmbuf_adj(mbuf, sizeof(*radio_hdr)); -@@ -401,6 +404,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, +@@ -401,6 +407,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf, *sym_inc = data_hdr->fields.sym_inc; *rb = data_hdr->fields.rb; *sect_id = data_hdr->fields.sect_id; diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index 88552eb46b..f0da1c891e 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -2,7 +2,7 @@ pkg_check_modules(dpdk REQUIRED libdpdk) pkg_check_modules(numa REQUIRED numa) -find_package(xran 5.1.2 EXACT REQUIRED) # E release -> 5 +find_package(xran 5.1.3 EXACT REQUIRED) # E release -> 5 # Ignore xran-specific warning: we don't care/can't change the following warning, so suppress # alignment 1 of 'struct XYZ' is less than 2 From f7917abb288445ddd4f52d18b1a5cb8a6b489cfb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Apr 2024 16:14:41 +0200 Subject: [PATCH 19/39] Print xran headers version used during compilation --- radio/fhi_72/oran_isolate.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index bdc786f482..32bdb7c771 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -34,6 +34,11 @@ #include "common/utils/threadPool/thread-pool.h" #include "oaioran.h" +// include the following file for VERSIONX, version of xran lib, to print it during +// startup. Only relevant for printing, if it ever makes problem, remove this +// line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api +#include "../../app/src/common.h" + typedef struct { eth_state_t e; rru_config_msg_type_t last_msg; @@ -309,7 +314,7 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d eth->last_msg = (rru_config_msg_type_t)-1; - printf("ORAN: %s\n", __FUNCTION__); + LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX); initNotifiedFIFO(&oran_sync_fifo); eth->oran_priv = oai_oran_initialize(openair0_cfg); From 98e9129d69c9af896aa1361144bc5f3d19e64bb6 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 30 Apr 2024 17:25:05 +0200 Subject: [PATCH 20/39] Allocate sufficient buffers for 1x1 config xran's xran_bm_init() uses rte_pktmbuf_pool_create() to allocate DPDK buffers. For a 1x1 configuration, the number of buffers might be too small, and rte_pktmbuf_pool_create() might fail. This commit ensures that we increase the number of buffers to have enough even in a 1x1 configuration. This works by chosing the next power of two, which is recommended as per DPDK documentation. Closes-Bug: #750 --- radio/fhi_72/oran-init.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index 2fbca36d56..8673b5d2b4 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -123,6 +123,14 @@ static struct xran_prb_map get_xran_prb_map_ul(const struct xran_fh_config *f) return prbmap; } +static uint32_t next_power_2(uint32_t num) +{ + uint32_t power = 2; + while (power < num) + power <<= 1; + return power; +} + static uint32_t oran_allocate_uplane_buffers( void *instHandle, struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN], @@ -132,7 +140,10 @@ static uint32_t oran_allocate_uplane_buffers( { xran_status_t status; uint32_t pool; - uint32_t numBufs = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT; + // we need at least XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT + // buffers, but xran_bm_init() uses rte_pktmbuf_pool_create() which + // recommends to use a power of two for the buffers + uint32_t numBufs = next_power_2(XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT); status = xran_bm_init(instHandle, &pool, numBufs, bufSize); AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status); printf("xran_bm_init() hInstance %p poolIdx %u elements %u size %u\n", instHandle, pool, numBufs, bufSize); @@ -211,14 +222,14 @@ static void oran_allocate_cplane_buffers(void *instHandle, { xran_status_t status; uint32_t poolSec; - uint32_t numBufsSec = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT * sect * XRAN_MAX_FRAGMENT; + uint32_t numBufsSec = next_power_2(XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT * sect * XRAN_MAX_FRAGMENT); uint32_t bufSizeSec = sizeof(struct xran_section_desc); status = xran_bm_init(instHandle, &poolSec, numBufsSec, bufSizeSec); AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status); printf("xran_bm_init() hInstance %p poolIdx %u elements %u size %u\n", instHandle, poolSec, numBufsSec, bufSizeSec); uint32_t poolPrb; - uint32_t numBufsPrb = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT; + uint32_t numBufsPrb = next_power_2(XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT); uint32_t bufSizePrb = size_of_prb_map; status = xran_bm_init(instHandle, &poolPrb, numBufsPrb, bufSizePrb); AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status); From 489824fdcf6a659ed6c4a1f859033465ab2d3f9f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 23 May 2024 14:45:14 +0200 Subject: [PATCH 21/39] Enforce gcc/g++-11 when building 7.2 FHI through xran --- doc/ORAN_FHI7.2_Tutorial.md | 2 ++ radio/fhi_72/CMakeLists.txt | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index cb6657dde7..58f7047369 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -391,6 +391,8 @@ Compile the fronthaul interface library by calling `make` and the option environment variables `RTE_SDK` for the path to the source tree of DPDK, and `XRAN_DIR` to set the path to the fronthaul library. +**Note**: you need at least gcc-11 and g++-11. + ```bash cd ~/phy/fhi_lib/lib make clean diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index f0da1c891e..ba28d4c448 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -1,3 +1,10 @@ +# we need at least gcc-11 to build xran, so let's enforce it here +# (because xran might not check it, and we have control here) +if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.0 + OR CMAKE_C_COMPILER_VERSION VERSION_LESS 11.0) + message(FATAL_ERROR "you need to have at least gcc/g++-11 to use 7.2 FHI through xran") +endif() + # use env var PKG_CONFIG_PATH to override paths to libdpdk.pc pkg_check_modules(dpdk REQUIRED libdpdk) pkg_check_modules(numa REQUIRED numa) From a9718835d48a9f672c333903ffbc4e42af1138a1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 16:45:17 +0200 Subject: [PATCH 22/39] 7.2 FH: auto-compute FFT size --- doc/ORAN_FHI7.2_Tutorial.md | 1 - executables/nr-ru.c | 6 ++++-- radio/COMMON/common_lib.h | 2 ++ radio/fhi_72/oran-config.c | 8 +++++--- radio/fhi_72/oran-params.h | 2 -- .../CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf | 1 - .../CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf | 1 - .../CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel650.conf | 1 - .../CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf | 1 - 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 58f7047369..7d5671eb5b 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -791,7 +791,6 @@ Edit the sample OAI gNB configuration file and check following parameters: compression * `iq_width_prach`: Width of PRACH IQ samples: if 16, no compression, if <16, applies compression - * `fft_size`: size of FFT performed by RU, set to 12 by default * `prach_config`: PRACH-specific configuration * `eAxC_offset`: PRACH antenna offset * `kbar`: the PRACH guard interval, provided in RU diff --git a/executables/nr-ru.c b/executables/nr-ru.c index a5a670916e..8d87dd6018 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -912,7 +912,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) } } -static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, int slots_per_frame) +static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, int slots_per_frame, uint16_t ofdm_symbol_size) { const nfapi_nr_prach_config_t *prach_config = &config->prach_config; const nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table; @@ -934,6 +934,8 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_ } } } + + split7->fftSize = log2(ofdm_symbol_size); } /* this function maps the RU tx and rx buffers to the available rf chains. @@ -1157,7 +1159,7 @@ void *ru_thread( void *param ) { nr_dump_frame_parms(fp); nr_phy_init_RU(ru); fill_rf_config(ru, ru->rf_config_file); - fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame); + fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame, fp->ofdm_symbol_size); if(!emulate_rf) { // Start IF device if any diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h index 0ff54a79ce..aa2d9e3189 100644 --- a/radio/COMMON/common_lib.h +++ b/radio/COMMON/common_lib.h @@ -195,6 +195,8 @@ typedef struct split7_config { struct { symbol_direction_t sym_dir[14]; } slot_dirs[160]; + /*! this is the exponent in 2^X for the FFT size */ + uint16_t fftSize; } split7_config_t; /*! \brief RF frontend parameters set by application */ diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 853d2cefc4..ddee538dfd 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -729,7 +729,7 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame return true; } -static bool set_fh_ru_config(const paramdef_t *rup, int nru, struct xran_ru_config *ru_config) +static bool set_fh_ru_config(const paramdef_t *rup, uint16_t fftSize, int nru, struct xran_ru_config *ru_config) { ru_config->xranTech = XRAN_RAN_5GNR; ru_config->xranCat = XRAN_CATEGORY_A; @@ -740,7 +740,8 @@ static bool set_fh_ru_config(const paramdef_t *rup, int nru, struct xran_ru_conf ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr; AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n"); ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE; - ru_config->fftSize = *gpd(rup, nru, ORAN_RU_CONFIG_FFT_SIZE)->uptr; + AssertFatal(fftSize > 0, "FFT size cannot be 0\n"); + ru_config->fftSize = fftSize; ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER; ru_config->iqOrder = XRAN_I_Q_ORDER; ru_config->xran_max_frame = 0; @@ -779,6 +780,7 @@ bool set_fh_config(int ru_idx, int num_rus, const openair0_config_t *oai0, struc DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]); DevAssert(oai0->nr_band > 0); DevAssert(oai0->nr_scs_for_raster > 0); + AssertFatal(oai0->threequarter_fs == 0, "cannot use three-quarter sampling with O-RAN 7.2 split\n"); // we simply assume that the loading process provides function to_nrarfcn() // to calculate the ARFCN numbers from frequency. That is not clean, but the @@ -869,7 +871,7 @@ bool set_fh_config(int ru_idx, int num_rus, const openair0_config_t *oai0, struc return false; if (!set_fh_frame_config(oai0, &fh_config->frame_conf)) return false; - if (!set_fh_ru_config(rup, nru, &fh_config->ru_conf)) + if (!set_fh_ru_config(rup, oai0->split7.fftSize, nru, &fh_config->ru_conf)) return false; fh_config->bbdev_enc = NULL; diff --git a/radio/fhi_72/oran-params.h b/radio/fhi_72/oran-params.h index a3fb22267b..c7e17ea42a 100644 --- a/radio/fhi_72/oran-params.h +++ b/radio/fhi_72/oran-params.h @@ -91,13 +91,11 @@ #define ORAN_RU_CONFIG_IQWIDTH "iq_width" #define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach" -#define ORAN_RU_CONFIG_FFT_SIZE "fft_size" // clang-format off #define ORAN_RU_DESC {\ {ORAN_RU_CONFIG_IQWIDTH, "sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \ {ORAN_RU_CONFIG_IQWIDTH_PRACH, "PRACH sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \ - {ORAN_RU_CONFIG_FFT_SIZE, "Size of FFT at RU\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=12, TYPE_UINT8, 0}, \ } // clang-format on diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf index 5984d32b17..46bcb97982 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf @@ -295,7 +295,6 @@ fhi_72 = { ru_config = { iq_width = 9; iq_width_prach = 9; - fft_size = 12; }; prach_config = { eAxC_offset = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf index d5c22b7e5e..8cabc3e87e 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf @@ -288,7 +288,6 @@ fhi_72 = { ru_config = { iq_width = 9; iq_width_prach = 9; - fft_size = 12; }; prach_config = { eAxC_offset = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel650.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel650.conf index ddcb28a331..65d7a0e8c8 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel650.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel650.conf @@ -288,7 +288,6 @@ fhi_72 = { ru_config = { iq_width = 9; iq_width_prach = 9; - fft_size = 12; }; prach_config = { eAxC_offset = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf index 1ddba82cdf..88fa646936 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf @@ -286,7 +286,6 @@ fhi_72 = { ru_config = { iq_width = 9; iq_width_prach = 9; - fft_size = 12; }; prach_config = { eAxC_offset = 4; From 321c4751768522edc9c868c609c0ab351f07d2ff Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 2 Jun 2024 11:28:39 +0200 Subject: [PATCH 23/39] Fix integer overflow avoid UBsan error: openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c:459:77: runtime error: signed integer overflo w: 2009540296 + 668087372 cannot be represented in type 'int' --- openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 723d13f65e..96266e279a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -454,10 +454,9 @@ static void nr_ulsch_channel_level(int **ul_ch_estimates_ext, avg128U = simde_mm_add_epi32(avg128U, simde_mm_srai_epi32(simde_mm_madd_epi16(ul_ch128[i], ul_ch128[i]), x)); } - avg[aatx*frame_parms->nb_antennas_rx+aarx] = (((int32_t*)&avg128U)[0] + - ((int32_t*)&avg128U)[1] + - ((int32_t*)&avg128U)[2] + - ((int32_t*)&avg128U)[3]) / y; + int32_t *avg32i = (int32_t *)&avg128U; + int64_t avg64 = (int64_t)avg32i[0] + avg32i[1] + avg32i[2] + avg32i[3]; + avg[aatx * frame_parms->nb_antennas_rx + aarx] = avg64 / y; } } From 0199d861b75bf33acb5b80c6dacd3b2cf2e8f981 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 2 Jun 2024 11:35:15 +0200 Subject: [PATCH 24/39] Fix integer overflow avoid UBsan error: openair1/PHY/NR_TRANSPORT/pucch_rx.c:266:21: runtime error: signed integer overflow: 2113190528 + 117251752 cannot be represented in type 'int' --- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 64ce300ae4..6e2f7f7e03 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -237,7 +237,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, uint8_t index=0; int nb_re_pucch = 12*pucch_pdu->prb_size; // prb size is 1 - int signal_energy = 0, signal_energy_ant0 = 0; + int64_t signal_energy = 0, signal_energy_ant0 = 0; for (int l=0; lnr_of_symbols; l++) { uint8_t l2 = l + pucch_pdu->start_symbol_index; From f4659b2b0c00ae4e8395984dedec576a68042cd9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Sun, 2 Jun 2024 11:35:47 +0200 Subject: [PATCH 25/39] Fix integer overflow Avoid UBSan error: openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c:183:22: runtime error: signed integer overflow: 2122747784 + 27403601 cannot be represented in type 'int' --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index ded4ece652..061cb93d04 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -162,7 +162,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB,int slot, int first_symb,int num_symb } //rb } // symb int nb_rb=0; - int32_t n0_subband_tot=0; + int64_t n0_subband_tot=0; int32_t n0_subband_tot_perANT[frame_parms->nb_antennas_rx]; memset(n0_subband_tot_perANT, 0, sizeof(n0_subband_tot_perANT)); From 3c5edab8f5b4eb91cddfadca699feb101f4ea240 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 6 Jun 2024 07:27:30 +0200 Subject: [PATCH 26/39] Fix memory leak: free NotifiedFIFO_elt --- executables/nr-ru.c | 1 + 1 file changed, 1 insertion(+) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 8d87dd6018..991c59e110 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1344,6 +1344,7 @@ void *ru_thread( void *param ) { rx_tti_busy[info->slot_rx % RU_RX_SLOT_DEPTH] = false; if ((info->slot_rx % RU_RX_SLOT_DEPTH) == (proc->tti_rx % RU_RX_SLOT_DEPTH)) not_done = false; + delNotifiedFIFO_elt(res); } if (!res) break; From e60f82ccc25e4bd94810afa55165d15efe9bbe40 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Thu, 6 Jun 2024 14:22:06 +0200 Subject: [PATCH 27/39] Increase iperf test timeout In some testcases, especially when iperf test duration is short (10s), client does not report on time and report collection is interrupted. This commit increase timeout for iperf/iperf3 commands. --- ci-scripts/cls_oaicitest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index db3cec5e35..a9d3652f9d 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -810,7 +810,7 @@ class OaiCiTest(): with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(EPC.IPAddress) as cmd_svr: port = 5002 + idx cmd_ue.run(f'{ue.getCmdPrefix()} iperf -B {ueIP} -s -u -i1 >> {server_filename} &', timeout=iperf_time*1.5) - cmd_svr.run(f'{svr.getCmdPrefix()} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 2>&1 | tee {client_filename}', timeout=iperf_time*1.5) + cmd_svr.run(f'{svr.getCmdPrefix()} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 2>&1 | tee {client_filename}', timeout=iperf_time*2.5) cmd_ue.run(f'cp {client_filename} {logPath}/{client_filename}') cmd_ue.run(f'cp {server_filename} {logPath}/{server_filename}') status, msg = Iperf_analyzeV2UDP(server_filename, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate) @@ -818,7 +818,7 @@ class OaiCiTest(): with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(EPC.IPAddress) as cmd_svr: port = 5002 + idx # note: some core setups start an iperf3 server automatically, indicated in ci_infra by runIperf3Server: False` - t = iperf_time * 1.5 + t = iperf_time * 2.5 if runIperf3Server: cmd_svr.run(f'{svr.getCmdPrefix()} nohup timeout -vk3 {t} iperf3 -s -B {svrIP} -p {port} -1 {jsonReport} &', timeout=t) cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False) From ce0f48d2b2cc54d4e68afa6cd7049645632e2fa9 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 7 Jun 2024 15:12:59 +0100 Subject: [PATCH 28/39] Add support for MIMO 2x2 with USRP B210 at 20 MHz BW and 3/4 sampling rate Tested with B210 and Quectel RM500Q-GL --- openair1/PHY/NR_TRANSPORT/nr_prach.c | 6 ++++++ openair1/PHY/NR_UE_TRANSPORT/nr_prach.c | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 4bf70acaa8..c9f645333b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -316,6 +316,12 @@ void rx_nr_prach_ru(RU_t *ru, dftlen >>= 1; break; + case 23040: + // 20 MHz @ 23.04 Ms/s + Ncp = (Ncp * 3) / 4; + dftlen = (dftlen * 3) / 4; + break; + case 30720: // 20, 25, 30 MHz @ 30.72 Ms/s break; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c index ea24f0a45c..471b2aee38 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_prach.c @@ -65,7 +65,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t c16_t prach[(4688 + 4 * 24576) * 2] __attribute__((aligned(32))) = {0}; int16_t prachF_tmp[(4688+4*24576)*4*2] __attribute__((aligned(32))) = {0}; - int16_t Ncp = 0; + int Ncp = 0; int prach_start, prach_sequence_length, i, prach_len, dftlen, mu, kbar, K, n_ra_prb, k, prachStartSymbol, sample_offset_slot; fd_occasion = 0; @@ -332,6 +332,12 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t dftlen >>= 1; break; + case 23040: + // 20 MHz @ 23.04 Ms/s + Ncp = (Ncp * 3) / 4; + dftlen = (dftlen * 3) / 4; + break; + case 30720: // 20, 25, 30 MHz @ 30.72 Ms/s break; From 45d4cec2a617f10e8f19b8231b9b379d950577ff Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 6 Jun 2024 21:02:05 +0200 Subject: [PATCH 29/39] fix regressions for large physical cell id values --- common/utils/nr/nr_common.c | 22 ++++---- executables/nr-ue.c | 6 +-- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 6 ++- .../nr_dl_channel_estimation.c | 6 +-- openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h | 6 +-- .../PHY/NR_UE_TRANSPORT/nr_initial_sync.c | 54 ++++++++----------- openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c | 8 +-- 7 files changed, 53 insertions(+), 55 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index fb9d9103e6..977b5051f8 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -1126,21 +1126,23 @@ int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, con const double startFreq = get_start_freq(fc, nbRB, mu); const double stopFreq = get_stop_freq(fc, nbRB, mu); - int scanGscnStart = -1; - int scanGscnStop = -1; - sync_raster_t tmpRaster = {0}; - for (const sync_raster_t *r = sync_raster; r < r + (sizeof(sync_raster) / sizeof(sync_raster_t)); r++) { - if (r->band == nrBand && r->scs_index == mu) { - tmpRaster = *r; - break; - } + int scanGscnStart = 0; + int scanGscnStop = 0; + const sync_raster_t *tmpRaster = sync_raster; + const sync_raster_t * end=sync_raster + sizeofArray(sync_raster); + while (tmpRaster < end && (tmpRaster->band != nrBand || tmpRaster->scs_index != mu)) + tmpRaster++; + if (tmpRaster >= end) { + LOG_E(PHY, "raster not found nrband=%d, mu=%d\n", nrBand, mu); + return 0; } - find_gscn_to_scan(startFreq, stopFreq, tmpRaster, &scanGscnStart, &scanGscnStop); + + find_gscn_to_scan(startFreq, stopFreq, *tmpRaster, &scanGscnStart, &scanGscnStop); const double scs = MU_SCS(mu) * 1e3; const double pointA = fc - (nbRB / 2 * scs * NR_NB_SC_PER_RB); int numGscn = 0; - for (int g = scanGscnStart; (g <= scanGscnStop) && (numGscn < MAX_GSCN_BAND); g += tmpRaster.step_gscn) { + for (int g = scanGscnStart; (g <= scanGscnStop) && (numGscn < MAX_GSCN_BAND); g += tmpRaster->step_gscn) { ssbInfo[numGscn].ssRef = get_ssref_from_gscn(g); ssbInfo[numGscn].ssbFirstSC = get_ssb_first_sc(pointA, ssbInfo[numGscn].ssRef, mu); ssbInfo[numGscn].gscn = g; diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 0a47de2a59..7627a6f5b9 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -735,6 +735,7 @@ void *UE_thread(void *arg) readFrame(UE, &sync_timestamp, false); notifiedFIFO_elt_t *Msg = newNotifiedFIFO_elt(sizeof(syncData_t), 0, &nf, UE_synch); syncData_t *syncMsg = (syncData_t *)NotifiedFifoData(Msg); + *syncMsg = (syncData_t){0}; NR_DL_FRAME_PARMS *fp = &UE->frame_parms; if (UE->UE_scan_carrier) { // Get list of GSCN in this band for UE's bandwidth and center frequency. @@ -743,10 +744,7 @@ void *UE_thread(void *arg) get_scan_ssb_first_sc(fp->dl_CarrierFreq, fp->N_RB_DL, fp->nr_band, fp->numerology_index, syncMsg->gscnInfo); } else { LOG_W(PHY, "SSB position provided\n"); - nr_gscn_info_t *g = syncMsg->gscnInfo; - g->ssbFirstSC = fp->ssb_start_subcarrier; - g->gscn = 0; - g->ssRef = 0; + syncMsg->gscnInfo[0] = (nr_gscn_info_t){.ssbFirstSC = fp->ssb_start_subcarrier}; syncMsg->numGscn = 1; } syncMsg->UE = UE; diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 64ce300ae4..d0c6146e45 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -1147,7 +1147,11 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, uint32_t x1 = 0, x2 = 0, sGold = 0; uint8_t *sGold8 = (uint8_t *)&sGold; - x2 = (((1<<17)*((14*slot) + (pucch_pdu->start_symbol_index+symb) + 1)*((2*pucch_pdu->dmrs_scrambling_id) + 1)) + (2*pucch_pdu->dmrs_scrambling_id))%(1U<<31); // c_init calculation according to TS38.211 subclause + const int scramble = pucch_pdu->dmrs_scrambling_id * 2; + // fixme: when MR2754 will be merged, use the gold sequence cache instead of regenerate each time + x2 = ((1ULL << 17) * ((NR_NUMBER_OF_SYMBOLS_PER_SLOT * slot + pucch_pdu->start_symbol_index + symb + 1) * (scramble + 1)) + + scramble) + % (1U << 31); // c_init calculation according to TS38.211 subclause #ifdef DEBUG_NR_PUCCH_RX printf("slot %d, start_symbol_index %d, symbol %d, dmrs_scrambling_id %d\n", slot,pucch_pdu->start_symbol_index,symb,pucch_pdu->dmrs_scrambling_id); diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 047f022d02..4245d3a7bf 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -651,12 +651,12 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp, const UE_nr_rxtx_proc_t *proc, unsigned char symbol, int dmrss, - uint8_t ssb_index, - uint8_t n_hf, + uint ssb_index, + uint n_hf, int ssb_start_subcarrier, const c16_t rxdataF[][fp->samples_per_slot_wCP], bool sidelink, - uint16_t Nid) + uint Nid) { int Ns = proc->nr_slot_rx; c16_t pilot[200] __attribute__((aligned(16))); diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 65bcd5c7d7..fc2e2bba62 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -75,12 +75,12 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp, const UE_nr_rxtx_proc_t *proc, unsigned char symbol, int dmrss, - uint8_t ssb_index, - uint8_t n_hf, + uint ssb_index, + uint n_hf, int ssb_start_subcarrier, const c16_t rxdataF[][fp->samples_per_slot_wCP], bool sidelink, - uint16_t Nid); + uint Nid); int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index 097739d142..4788c9ed9d 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -47,9 +47,7 @@ #include "PHY/TOOLS/tools_defs.h" #include "nr-uesoftmodem.h" -//static nfapi_nr_config_request_t config_t; -//static nfapi_nr_config_request_t* config =&config_t; -// #define DEBUG_INITIAL_SYNCH +//#define DEBUG_INITIAL_SYNCH #define DUMP_PBCH_CH_ESTIMATES 0 // structure used for multiple SSB detection @@ -223,8 +221,7 @@ void nr_scan_ssb(void *arg) ssbInfo->ssbOffset = sync_pos - fp->nb_prefix_samples; #ifdef DEBUG_INITIAL_SYNCH - LOG_I(PHY, "[UE%d] Initial sync : Estimated PSS position %d, Nid2 %d\n", ue->Mod_id, sync_pos, ue->common_vars.nid2); - LOG_I(PHY, "sync_pos %d ssb_offset %d \n", sync_pos, ue->ssb_offset); + LOG_I(PHY, "Initial sync : Estimated PSS position %d, Nid2 %d, ssb offset %d\n", sync_pos, nid2, ssbInfo->ssbOffset); #endif /* check that SSS/PBCH block is continuous inside the received buffer */ if (ssbInfo->ssbOffset + NR_N_SYMBOLS_SSB * (fp->ofdm_symbol_size + fp->nb_prefix_samples) >= fp->samples_per_frame) { @@ -256,10 +253,6 @@ void nr_scan_ssb(void *arg) rxdataF, link_type_dl); -#ifdef DEBUG_INITIAL_SYNCH - LOG_I(PHY, "Calling sss detection (normal CP)\n"); -#endif - int freq_offset_sss = 0; int32_t metric_tdd_ncp = 0; uint8_t phase_tdd_ncp; @@ -273,7 +266,15 @@ void nr_scan_ssb(void *arg) &phase_tdd_ncp, &freq_offset_sss, rxdataF); - +#ifdef DEBUG_INITIAL_SYNCH + LOG_I(PHY, + "TDD Normal prefix: sss detection result; %d, CellId %d metric %d, phase %d, measured offset %d\n", + ssbInfo->syncRes.cell_detected, + ssbInfo->nidCell, + metric_tdd_ncp, + phase_tdd_ncp, + ssbInfo->syncRes.rx_offset); +#endif ssbInfo->freqOffset = freq_offset_pss + freq_offset_sss; uint32_t nr_gold_pbch_ref[2][64][NR_PBCH_DMRS_LENGTH_DWORD]; @@ -315,23 +316,24 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, for (int s = 0; s < numGscn; s++) { notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(nr_ue_ssb_scan_t), gscnInfo[s].gscn, &nf, &nr_scan_ssb); nr_ue_ssb_scan_t *ssbInfo = (nr_ue_ssb_scan_t *)NotifiedFifoData(req); - ssbInfo->gscnInfo = gscnInfo[s]; + *ssbInfo = (nr_ue_ssb_scan_t){.gscnInfo = gscnInfo[s], + .fp = &ue->frame_parms, + .proc = proc, + .syncRes.cell_detected = false, + .nFrames = n_frames, + .foFlag = ue->UE_fo_compensation, + .targetNidCell = ue->target_Nid_cell}; ssbInfo->rxdata = malloc16_clear(fp->nb_antennas_rx * sizeof(c16_t *)); for (int ant = 0; ant < fp->nb_antennas_rx; ant++) { - ssbInfo->rxdata[ant] = malloc16_clear((fp->samples_per_frame * 2 + fp->ofdm_symbol_size) * sizeof(c16_t)); + ssbInfo->rxdata[ant] = malloc16(sizeof(c16_t) * (fp->samples_per_frame * 2 + fp->ofdm_symbol_size)); memcpy(ssbInfo->rxdata[ant], ue->common_vars.rxdata[ant], sizeof(c16_t) * fp->samples_per_frame * 2); + memset(ssbInfo->rxdata[ant] + fp->samples_per_frame * 2, 0, fp->ofdm_symbol_size * sizeof(c16_t)); } LOG_I(NR_PHY, "Scanning GSCN: %d, with SSB offset: %d, SSB Freq: %lf\n", ssbInfo->gscnInfo.gscn, ssbInfo->gscnInfo.ssbFirstSC, ssbInfo->gscnInfo.ssRef); - ssbInfo->fp = &ue->frame_parms; - ssbInfo->proc = proc; - ssbInfo->syncRes.cell_detected = false; - ssbInfo->nFrames = n_frames; - ssbInfo->foFlag = ue->UE_fo_compensation; - ssbInfo->targetNidCell = ue->target_Nid_cell; pushTpool(&get_nrUE_params()->Tpool, req); } @@ -437,16 +439,6 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, res.syncRes.rx_offset = res.ssbOffset - sync_pos_frame; } -#ifdef DEBUG_INITIAL_SYNCH - LOG_I(PHY, - "TDD Normal prefix: CellId %d metric %d, phase %d, pbch detected %d, measured offset %d\n", - fp->Nid_cell, - metric_tdd_ncp, - phase_tdd_ncp, - ret.cell_detected, - ret.rx_offset); -#endif - if (res.syncRes.cell_detected) { LOG_I(PHY, "[UE%d] In synch, rx_offset %d samples\n", ue->Mod_id, res.syncRes.rx_offset); LOG_I(PHY, "[UE %d] Measured Carrier Frequency offset %d Hz\n", ue->Mod_id, res.freqOffset); @@ -455,7 +447,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, LOG_I(PHY,"[UE%d] Initial sync : PBCH not ok\n",ue->Mod_id); LOG_I(PHY, "[UE%d] Initial sync : Estimated PSS position %d, Nid2 %d\n", ue->Mod_id, sync_pos, ue->common_vars.nid2); LOG_I(PHY,"[UE%d] Initial sync : Estimated Nid_cell %d, Frame_type %d\n",ue->Mod_id, - frame_parms->Nid_cell,frame_parms->frame_type); + fp->Nid_cell,fp->frame_type); #endif } @@ -481,10 +473,10 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, ue->measurements.rx_power_avg_dB[0] = dB_fixed(ue->measurements.rx_power_avg[0]); #ifdef DEBUG_INITIAL_SYNCH - LOG_I(PHY, "[UE%d] Initial sync : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]); + LOG_I(PHY, "[UE%d] Initial sync failed : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]); #endif } else { - LOG_A(PHY, "Initial sync successful\n"); + LOG_A(PHY, "Initial sync successful, PCI: %d\n",fp->Nid_cell); } // exit_fun("debug exit"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INITIAL_UE_SYNC, VCD_FUNCTION_OUT); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c index e2f9e03cb3..a9b155a9bd 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c @@ -55,11 +55,12 @@ static uint16_t nr_pbch_extract(uint32_t rxdataF_sz, uint32_t symbol, uint32_t s_offset, int ssb_start_subcarrier, - const NR_DL_FRAME_PARMS *frame_parms) + const NR_DL_FRAME_PARMS *frame_parms, + int nid) { uint16_t rb; uint8_t i, j, aarx; - int nushiftmod4 = frame_parms->Nid_cell % 4; + int nushiftmod4 = nid % 4; AssertFatal(symbol>=1 && symbol<5, "symbol %d illegal for PBCH extraction\n", symbol); @@ -418,7 +419,8 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue, symbol, symbol_offset, ssb_start_subcarrier, - frame_parms); + frame_parms, + Nid_cell); #ifdef DEBUG_PBCH LOG_I(PHY,"[PHY] PBCH Symbol %d ofdm size %d\n",symbol, frame_parms->ofdm_symbol_size); LOG_I(PHY,"[PHY] PBCH starting channel_level\n"); From 37e6e7e944fb4f7e343baca65c99303475f3e8e7 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Fri, 7 Jun 2024 16:21:14 +0200 Subject: [PATCH 30/39] add test physical cell id in 5G range --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 6faa7e9d80..3d531315ea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -65,6 +65,7 @@ static void schedule_ssb(frame_t frame, dl_config_pdu->PDUSize =2 + sizeof(nfapi_nr_dl_tti_ssb_pdu_rel15_t); AssertFatal(scc->physCellId!=NULL,"ServingCellConfigCommon->physCellId is null\n"); + AssertFatal(*scc->physCellId < 1008 && *scc->physCellId >=0, "5G physicall cell id out of range: %ld\n", *scc->physCellId); dl_config_pdu->ssb_pdu.ssb_pdu_rel15.PhysCellId = *scc->physCellId; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.BetaPss = 0; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i_ssb; From 516b91fc908d37911f4a50650a5f7666de67024d Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 12 Jun 2024 10:25:50 +0200 Subject: [PATCH 31/39] Fix integer overflow Avoid UBSan error: openair1/SCHED_NR/phy_procedures_nr_gNB.c:869:43: runtime error: signed integer overflow: 1546663455 + 1635930955 cannot be represented in type 'int' --- openair1/PHY/defs_gNB.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 20413098bd..d5de27aaee 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -349,7 +349,7 @@ typedef struct { /// measured RX noise power int ulsch_noise_power[8]; /// total noise over antennas - int ulsch_noise_power_tot; + uint32_t ulsch_noise_power_tot; /// \brief llr values. /// - first index: ? [0..1179743] (hard coded) int16_t *llr; From b17354b74f9683256f8aaf22449e6fdd668d9306 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 12 Jun 2024 10:29:50 +0200 Subject: [PATCH 32/39] Fix integer overflow Avoid UBSan error: openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c:246:18: runtime error: signed integer overflow: 1457321472 + 922889664 cannot be represented in type 'int' --- openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index 061cb93d04..c8cc7f98d9 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -203,7 +203,7 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB, unsigned char symbol, uint8_t nrOfLayers) { - int rx_power_tot = 0; + uint32_t rx_power_tot = 0; unsigned short rx_power_avg_dB; unsigned short rx_power_tot_dB; RU_t *ru = gNB->RU_list[0]; From 4980be04f3503b9a7c9ef891f77442a3f5dfcbb0 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 12 Jun 2024 10:34:45 +0200 Subject: [PATCH 33/39] Fix integer overflow Avoid UBSan error: openair1/SCHED_NR/phy_procedures_nr_gNB.c:867:37: runtime error: signed integer overflow: 1744750952 + 412859840 cannot be represented in type 'int' --- openair1/PHY/defs_gNB.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index d5de27aaee..4dc930c22c 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -345,7 +345,7 @@ typedef struct { /// measured RX power based on DRS int ulsch_power[8]; /// total signal over antennas - int ulsch_power_tot; + uint32_t ulsch_power_tot; /// measured RX noise power int ulsch_noise_power[8]; /// total noise over antennas From 63125876219d168709e39cb68af0215c240e681b Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Wed, 12 Jun 2024 10:36:58 +0200 Subject: [PATCH 34/39] Fix integer overflow Avoid UBSan error: openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c:1524:41: runtime error: signed integer overflow: 737285888 + 1459370880 cannot be represented in type 'int' --- openair1/PHY/defs_gNB.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 4dc930c22c..7af241ebaa 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -343,7 +343,7 @@ typedef struct { /// \f$\log_2(\max|H_i|^2)\f$ int16_t log2_maxh; /// measured RX power based on DRS - int ulsch_power[8]; + uint32_t ulsch_power[8]; /// total signal over antennas uint32_t ulsch_power_tot; /// measured RX noise power From 9c913fa040b8f6f059affb1ddd71c9bf6133028d Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 20 May 2024 13:30:49 +0200 Subject: [PATCH 35/39] Introduce googletest library The library will be either found in the system or downloaded via FetchContent. --- CMakeLists.txt | 15 +++++++++++++++ doc/UnitTests.md | 5 +++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 03cbc144c7..5226e05c66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2507,6 +2507,21 @@ if(ENABLE_TESTS) # meta-target: each test is supposed to add_dependencies(tests ${NEWTEST}) # then, it is possible to build and execute all tests using "ninja tests && ctest" add_custom_target(tests) + find_package(GTest) + if (NOT GTest_FOUND) + message(STATUS "GTest package not found, will download googletest automatically. To prevent that install google test on your system (libgtest-dev)") + include(FetchContent) + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG 58d77fa8070e8cec2dc1ed015d66b454c8d78850 # 1.12.1 + ) + set(BUILD_GMOCK OFF) + set(INSTALL_GTEST OFF) + FetchContent_MakeAvailable(googletest) + add_library(GTest::gtest ALIAS gtest) + add_library(GTest::gtest_main ALIAS gtest_main) + endif() endif() add_subdirectory(common) diff --git a/doc/UnitTests.md b/doc/UnitTests.md index 6ea18e2280..d1bbbed0ae 100644 --- a/doc/UnitTests.md +++ b/doc/UnitTests.md @@ -8,8 +8,9 @@ explaining how to test with cmake and ctest; it is a suggested read, and the following just lists the main points of how to compile the tests and how to add new ones. -At the time of writing, only the NR RLC tests have been integrated. The author -hopes that more tests follow suit. +GoogleTest is a C++ unit testing framework that has been added as an external dependency. While using GoogleTest is not a requirement it can simplify writing unit tests. +See [primer](http://google.github.io/googletest/primer.html) for a quick introduction. To add it to your test executable link against +`GTest::gtest` or `GTest::gtest_main`. # How to compile tests From 4a36f7dd7bb5807afe2042fc95128bfb6f67cf19 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 21 May 2024 19:02:56 +0200 Subject: [PATCH 36/39] Extract nr_common and nr_phy_common libs. Also add unit tests for nr_common --- CMakeLists.txt | 21 ++---- common/utils/CMakeLists.txt | 1 + common/utils/nr/CMakeLists.txt | 5 ++ common/utils/nr/nr_common.c | 32 --------- common/utils/nr/nr_common.h | 6 -- common/utils/nr/tests/CMakeLists.txt | 5 ++ common/utils/nr/tests/test_nr_common.cpp | 47 +++++++++++++ openair1/PHY/CMakeLists.txt | 1 + .../NR_ESTIMATION/nr_ul_channel_estimation.c | 1 + .../nr_dl_channel_estimation.c | 3 +- openair1/PHY/nr_phy_common/CMakeLists.txt | 2 + .../PHY/nr_phy_common/inc/nr_phy_common.h | 30 ++++++++ .../PHY/nr_phy_common/src/nr_phy_common.c | 69 +++++++++++++++++++ openair1/SCHED_NR_UE/defs.h | 2 - openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 17 ----- 15 files changed, 168 insertions(+), 74 deletions(-) create mode 100644 common/utils/nr/CMakeLists.txt create mode 100644 common/utils/nr/tests/CMakeLists.txt create mode 100644 common/utils/nr/tests/test_nr_common.cpp create mode 100644 openair1/PHY/nr_phy_common/CMakeLists.txt create mode 100644 openair1/PHY/nr_phy_common/inc/nr_phy_common.h create mode 100644 openair1/PHY/nr_phy_common/src/nr_phy_common.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5226e05c66..20b86b95dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1181,9 +1181,10 @@ target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${lapacke_INCLUDE add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON}) add_library(PHY_NR ${PHY_NR_SRC}) +target_link_libraries(PHY_NR nr_phy_common nr_common) add_library(PHY_NR_UE ${PHY_NR_UE_SRC}) -target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs) +target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs nr_phy_common nr_common) add_library(PHY_RU ${PHY_SRC_RU}) target_link_libraries(PHY_RU PRIVATE asn1_lte_rrc_hdrs) @@ -1481,7 +1482,7 @@ add_library(e1_if target_link_libraries(e1_if PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap SECURITY ${OPENSSL_LIBRARIES} e1ap GTPV1U) -target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc) +target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc nr_common) if(E2_AGENT) target_link_libraries(L2_NR PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup) target_compile_definitions(L2_NR PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT) @@ -1516,7 +1517,7 @@ target_link_libraries(L2_UE PRIVATE asn1_lte_rrc_hdrs) add_library( NR_L2_UE ${NR_L2_SRC_UE} ${MAC_NR_SRC_UE} ) target_link_libraries(NR_L2_UE PRIVATE f1ap nr_rlc) -target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common) add_library(MAC_NR_COMMON ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -2083,7 +2084,6 @@ add_executable(nr-softmodem ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR_DIR}/common/utils/lte/ue_power.c ${OPENAIR_DIR}/common/utils/lte/prach_utils.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ${PHY_INTERFACE_DIR}/queue_t.c ${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c ) @@ -2152,7 +2152,6 @@ add_executable(nr-uesoftmodem ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c ${OPENAIR2_DIR}/RRC/NAS/rb_config.c ${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c ) @@ -2207,7 +2206,6 @@ target_link_libraries(rftest PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) add_executable(polartest ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/polartest.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ) target_link_libraries(polartest PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_COMMON PHY_NR_UE CONFIG_LIB -Wl,--end-group @@ -2216,7 +2214,6 @@ target_link_libraries(polartest PRIVATE add_executable(smallblocktest ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/smallblocktest.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ) target_link_libraries(smallblocktest PRIVATE @@ -2242,7 +2239,6 @@ target_link_libraries(ldpctest PRIVATE add_executable(nr_dlschsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ) target_link_libraries(nr_dlschsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group @@ -2253,7 +2249,6 @@ target_link_libraries(nr_dlschsim PRIVATE asn1_nr_rrc_hdrs) add_executable(nr_pbchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pbchsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ) target_link_libraries(nr_pbchsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group @@ -2264,7 +2259,6 @@ target_link_libraries(nr_pbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_psbchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/psbchsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${NR_UE_RRC_DIR}/rrc_nsa.c @@ -2282,7 +2276,6 @@ target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_pucchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pucchsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ) target_link_libraries(nr_pucchsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group @@ -2293,7 +2286,6 @@ target_link_libraries(nr_pucchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_dlsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${NR_UE_RRC_DIR}/rrc_nsa.c @@ -2310,7 +2302,6 @@ target_link_libraries(nr_dlsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_prachsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/prachsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ) target_link_libraries(nr_prachsim PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB CONFIG_LIB -lz -Wl,--end-group @@ -2320,7 +2311,6 @@ target_link_libraries(nr_prachsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_ulschsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulschsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ${PHY_INTERFACE_DIR}/queue_t.c ) target_link_libraries(nr_ulschsim PRIVATE @@ -2332,7 +2322,6 @@ target_link_libraries(nr_ulschsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_ulsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim.c ${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c - ${OPENAIR_DIR}/common/utils/nr/nr_common.c ${OPENAIR_DIR}/executables/softmodem-common.c ${OPENAIR2_DIR}/RRC/NAS/nas_config.c ${NR_UE_RRC_DIR}/rrc_nsa.c @@ -2410,7 +2399,7 @@ if (${T_TRACER}) PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU SIMU_ETH OPENAIR0_LIB - ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc dfts config_internals) + ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc dfts config_internals nr_common) if (TARGET ${i}) add_dependencies(${i} generate_T) endif() diff --git a/common/utils/CMakeLists.txt b/common/utils/CMakeLists.txt index 094ca6b10d..c945f644bc 100644 --- a/common/utils/CMakeLists.txt +++ b/common/utils/CMakeLists.txt @@ -10,3 +10,4 @@ if(ENABLE_WEBSRV) endif() add_subdirectory(T) +add_subdirectory(nr) diff --git a/common/utils/nr/CMakeLists.txt b/common/utils/nr/CMakeLists.txt new file mode 100644 index 0000000000..6b58544a6d --- /dev/null +++ b/common/utils/nr/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(nr_common nr_common.c) +target_include_directories(nr_common PUBLIC .) +if (ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index fb9d9103e6..6b975e6419 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -1174,38 +1174,6 @@ void init_delay_table(uint16_t ofdm_symbol_size, } } -void freq2time(uint16_t ofdm_symbol_size, - int16_t *freq_signal, - int16_t *time_signal) -{ - const idft_size_idx_t idft_size = get_idft(ofdm_symbol_size); - idft(idft_size, freq_signal, time_signal, 1); -} - -void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay) -{ - freq2time(ofdm_symbol_size, (int16_t *)ls_est, (int16_t *)ch_estimates_time); - - int max_pos = delay->delay_max_pos; - int max_val = delay->delay_max_val; - const int sync_pos = 0; - - for (int i = 0; i < ofdm_symbol_size; i++) { - int temp = c16amp2(ch_estimates_time[i]) >> 1; - if (temp > max_val) { - max_pos = i; - max_val = temp; - } - } - - if (max_pos > ofdm_symbol_size / 2) - max_pos = max_pos - ofdm_symbol_size; - - delay->delay_max_pos = max_pos; - delay->delay_max_val = max_val; - delay->est_delay = max_pos - sync_pos; -} - void nr_timer_start(NR_timer_t *timer) { timer->active = true; diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index d044130412..6ed86cb7bd 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -241,12 +241,6 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int scs); int get_delay_idx(int delay, int max_delay_comp); -void freq2time(uint16_t ofdm_symbol_size, - int16_t *freq_signal, - int16_t *time_signal); - -void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay); - int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, diff --git a/common/utils/nr/tests/CMakeLists.txt b/common/utils/nr/tests/CMakeLists.txt new file mode 100644 index 0000000000..fb995d2ab8 --- /dev/null +++ b/common/utils/nr/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_nr_common test_nr_common.cpp) +target_link_libraries(test_nr_common PRIVATE nr_common GTest::gtest minimal_lib) +add_dependencies(tests test_nr_common) +add_test(NAME test_nr_common + COMMAND ./test_nr_common) diff --git a/common/utils/nr/tests/test_nr_common.cpp b/common/utils/nr/tests/test_nr_common.cpp new file mode 100644 index 0000000000..fede91b8ee --- /dev/null +++ b/common/utils/nr/tests/test_nr_common.cpp @@ -0,0 +1,47 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +extern "C" { +#include "nr_common.h" +#include "common/utils/LOG/log.h" +} + +TEST(nr_common, nr_timer) { + NR_timer_t timer; + nr_timer_setup(&timer, 10, 1); + nr_timer_start(&timer); + EXPECT_TRUE(is_nr_timer_active(timer)); + EXPECT_FALSE(nr_timer_expired(timer)); + for (auto i = 0; i < 10; i++) { + nr_timer_tick(&timer); + } + EXPECT_FALSE(is_nr_timer_active(timer)); + EXPECT_TRUE(nr_timer_expired(timer)); +} + + +int main(int argc, char **argv) +{ + logInit(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/openair1/PHY/CMakeLists.txt b/openair1/PHY/CMakeLists.txt index 0a53c969a7..6f364e4daf 100644 --- a/openair1/PHY/CMakeLists.txt +++ b/openair1/PHY/CMakeLists.txt @@ -4,3 +4,4 @@ add_boolean_option(ENABLE_NRSCOPE OFF "Whether to build the 5G scope" OFF) if(ENABLE_UESCOPE OR ENABLE_ENBSCOPE OR ENABLE_NRSCOPE) add_subdirectory(TOOLS) endif() +add_subdirectory(nr_phy_common) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index a7f0ef6682..5f49549d21 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -33,6 +33,7 @@ #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" #include "executables/softmodem-common.h" +#include "nr_phy_common.h" //#define DEBUG_CH diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 047f022d02..30c84e540e 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -29,12 +29,13 @@ #include "PHY/NR_REFSIG/nr_mod_table.h" #include "PHY/NR_TRANSPORT/nr_sch_dmrs.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" -#include "common/utils/nr/nr_common.h" +#include "nr_phy_common.h" #include "filt16a_32.h" #include "T.h" #include #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h" + extern openair0_config_t openair0_cfg[]; // #define DEBUG_PDSCH diff --git a/openair1/PHY/nr_phy_common/CMakeLists.txt b/openair1/PHY/nr_phy_common/CMakeLists.txt new file mode 100644 index 0000000000..79dc8dd7f3 --- /dev/null +++ b/openair1/PHY/nr_phy_common/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(nr_phy_common src/nr_phy_common.c) +target_include_directories(nr_phy_common PUBLIC inc/) diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h new file mode 100644 index 0000000000..8e8f7399f0 --- /dev/null +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -0,0 +1,30 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef __NR_PHY_COMMON__H__ +#define __NR_PHY_COMMON__H__ +#include "PHY/impl_defs_top.h" +#include "PHY/TOOLS/tools_defs.h" + +void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal); +void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay); +unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb); +#endif diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c new file mode 100644 index 0000000000..b67a94d8f6 --- /dev/null +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -0,0 +1,69 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "nr_phy_common.h" + +void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal) +{ + const idft_size_idx_t idft_size = get_idft(ofdm_symbol_size); + idft(idft_size, freq_signal, time_signal, 1); +} + +void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay) +{ + freq2time(ofdm_symbol_size, (int16_t *)ls_est, (int16_t *)ch_estimates_time); + + int max_pos = delay->delay_max_pos; + int max_val = delay->delay_max_val; + const int sync_pos = 0; + + for (int i = 0; i < ofdm_symbol_size; i++) { + int temp = c16amp2(ch_estimates_time[i]) >> 1; + if (temp > max_val) { + max_pos = i; + max_val = temp; + } + } + + if (max_pos > ofdm_symbol_size / 2) + max_pos = max_pos - ofdm_symbol_size; + + delay->delay_max_pos = max_pos; + delay->delay_max_val = max_val; + delay->est_delay = max_pos - sync_pos; +} + +unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb) +{ + // assume power at AMP is 20dBm + // if gain = 20 (power == 40) + int gain_dB = power_dBm - power_max_dBm; + double gain_lin; + + gain_lin = pow(10, .1 * gain_dB); + if ((nb_rb > 0) && (nb_rb <= total_nb_rb)) { + return ((int)(AMP * sqrt(gain_lin * total_nb_rb / (double)nb_rb))); + } else { + LOG_E(PHY, "Illegal nb_rb/N_RB_UL combination (%d/%d)\n", nb_rb, total_nb_rb); + // mac_xface->macphy_exit(""); + } + return (0); +} diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h index bdb3341387..1488a9433a 100644 --- a/openair1/SCHED_NR_UE/defs.h +++ b/openair1/SCHED_NR_UE/defs.h @@ -111,8 +111,6 @@ int8_t nr_find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB); */ void ue_ta_procedures(PHY_VARS_NR_UE *ue, int slot_tx, int frame_tx); -unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb); - void set_tx_harq_id(NR_UE_ULSCH_t *ulsch, int harq_pid, int slot_tx); int get_tx_harq_id(NR_UE_ULSCH_t *ulsch, int slot_tx); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index cbeda2e106..603120abdc 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -407,23 +407,6 @@ static int nr_ue_pbch_procedures(PHY_VARS_NR_UE *ue, return ret; } -unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb) -{ - - int gain_dB = power_dBm - power_max_dBm; - double gain_lin; - - gain_lin = pow(10,.1*gain_dB); - if ((nb_rb >0) && (nb_rb <= N_RB_UL)) { - return((int)(AMP*sqrt(gain_lin*N_RB_UL/(double)nb_rb))); - } - else { - LOG_E(PHY,"Illegal nb_rb/N_RB_UL combination (%d/%d)\n",nb_rb,N_RB_UL); - //mac_xface->macphy_exit(""); - } - return(0); -} - int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, int32_t pdcch_est_size, From 44dc8f8daa7265ab6e3667e3c5bc1254faa6ccd5 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 20 May 2024 13:39:20 +0200 Subject: [PATCH 37/39] Add google test testcases for nr_get_Pcmax. --- CMakeLists.txt | 7 +- openair2/LAYER2/CMakeLists.txt | 1 + openair2/LAYER2/NR_MAC_UE/CMakeLists.txt | 5 + openair2/LAYER2/NR_MAC_UE/mac_proto.h | 11 ++- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 11 ++- .../LAYER2/NR_MAC_UE/nr_ue_power_procedures.c | 98 +++++++++++++------ openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 23 ----- .../LAYER2/NR_MAC_UE/tests/CMakeLists.txt | 6 ++ .../tests/test_nr_ue_power_procedures.cpp | 64 ++++++++++++ 9 files changed, 167 insertions(+), 59 deletions(-) create mode 100644 openair2/LAYER2/NR_MAC_UE/CMakeLists.txt create mode 100644 openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt create mode 100644 openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b86b95dc..de7e300a67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -463,7 +463,7 @@ add_library(f1ap ${F1AP_DIR}/f1ap_handlers.c ${F1AP_DIR}/f1ap_itti_messaging.c) target_include_directories(f1ap PUBLIC F1AP_DIR) -target_link_libraries(f1ap PUBLIC asn1_f1ap) +target_link_libraries(f1ap PUBLIC asn1_f1ap L2_NR) target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE) # LPP @@ -1414,7 +1414,6 @@ set (MAC_NR_SRC_UE ${NR_UE_MAC_DIR}/nr_ue_scheduler.c ${NR_UE_MAC_DIR}/nr_ue_dci_configuration.c ${NR_UE_MAC_DIR}/nr_ra_procedures.c - ${NR_UE_MAC_DIR}/nr_ue_power_procedures.c ) set (ENB_APP_SRC @@ -1463,7 +1462,7 @@ endif() add_library(MAC_UE_NR ${MAC_NR_SRC_UE}) -target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) +target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs PUBLIC nr_ue_power_procedures) add_library(L2_LTE ${L2_LTE_SRC}) target_link_libraries(L2_LTE PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) @@ -1517,7 +1516,7 @@ target_link_libraries(L2_UE PRIVATE asn1_lte_rrc_hdrs) add_library( NR_L2_UE ${NR_L2_SRC_UE} ${MAC_NR_SRC_UE} ) target_link_libraries(NR_L2_UE PRIVATE f1ap nr_rlc) -target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common) +target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common nr_ue_power_procedures) add_library(MAC_NR_COMMON ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c diff --git a/openair2/LAYER2/CMakeLists.txt b/openair2/LAYER2/CMakeLists.txt index b8bc21e78c..9360ed7b2b 100644 --- a/openair2/LAYER2/CMakeLists.txt +++ b/openair2/LAYER2/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(nr_rlc) +add_subdirectory(NR_MAC_UE) diff --git a/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt b/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt new file mode 100644 index 0000000000..6589a2fda5 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(nr_ue_power_procedures nr_ue_power_procedures.c) +target_link_libraries(nr_ue_power_procedures PUBLIC asn1_nr_rrc ${T_LIB} MAC_NR_COMMON nr_common) +if (ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index a6a60fbd7f..01f49f8319 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -227,7 +227,16 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, fapi_nr_ul_config_pucch_pdu *pucch_pdu); -int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb); +int nr_get_Pcmax(int p_Max, + uint16_t nr_band, + frequency_range_t frequency_range, + int Qm, + bool powerBoostPi2BPSK, + int scs, + int N_RB_UL, + bool is_transform_precoding, + int n_prbs, + int start_prb); int get_sum_delta_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 5831bd2b11..1fc6f4b6e8 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -79,7 +79,16 @@ void init_RA(NR_UE_MAC_INST_t *mac, int n_prbs = get_N_RA_RB(prach_scs, mac->current_UL_BWP->scs); int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP->BWPStart; // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1) - prach_resources->RA_PCMAX = nr_get_Pcmax(mac, 2, false, prach_scs, cfg->carrier_config.dl_grid_size[prach_scs], true, n_prbs, start_prb); + prach_resources->RA_PCMAX = nr_get_Pcmax(mac->p_Max, + mac->nr_band, + mac->frequency_range, + 2, + false, + prach_scs, + cfg->carrier_config.dl_grid_size[prach_scs], + true, + n_prbs, + start_prb); prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1; prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER = 1; prach_resources->POWER_OFFSET_2STEP_RA = 0; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 3e9669775d..e826d95e4c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -85,16 +85,24 @@ static int get_deltatf(uint16_t nb_of_prbs, // -- Powerclass 3 capable UE (which is default power class unless otherwise stated) // -- Maximum power reduction (MPR_c) for power class 3 // -- no additional MPR (A_MPR_c) -int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb) +int nr_get_Pcmax(int p_Max, + uint16_t nr_band, + frequency_range_t frequency_range, + int Qm, + bool powerBoostPi2BPSK, + int scs, + int N_RB_UL, + bool is_transform_precoding, + int n_prbs, + int start_prb) { - int nr_band = mac->nr_band; - if(mac->frequency_range == FR1) { - - //TODO configure P-MAX from the upper layers according to 38.331 + if (frequency_range == FR1) { + // TODO configure P-MAX from the upper layers according to 38.331 int p_powerclass = 23; // dBm assuming poweclass 3 UE - int p_emax = mac->p_Max != INT_MIN ? mac->p_Max : p_powerclass; + int p_emax = p_Max != INT_MIN ? p_Max : p_powerclass; int delta_P_powerclass = 0; // for powerclass 2 needs to be changed - if(mac->p_Max && Qm == 1 && powerBoostPi2BPSK && (nr_band == 40 || nr_band == 41 || nr_band == 77 || nr_band == 78 || nr_band == 79)) { + if (p_Max && Qm == 1 && powerBoostPi2BPSK + && (nr_band == 40 || nr_band == 41 || nr_band == 77 || nr_band == 78 || nr_band == 79)) { p_emax += 3; delta_P_powerclass -= 3; } @@ -103,54 +111,52 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int delta_T_IB = 0; // TODO in case of band 41 and PRB allocation within 4MHz of the upper or lower limit of the band -> delta_TC = 1.5 - if(nr_band == 41) + if (nr_band == 41) LOG_E(NR_MAC, "Need to implement delta_TC for band 41\n"); int delta_TC = 0; float MPR = 0; frame_type_t frame_type = get_frame_type(nr_band, scs); - if(compare_relative_ul_channel_bw(nr_band, scs, N_RB_UL, frame_type)) { + if (compare_relative_ul_channel_bw(nr_band, scs, N_RB_UL, frame_type)) { int rb_low = (n_prbs / 2) > 1 ? (n_prbs / 2) : 1; int rb_high = N_RB_UL - rb_low - n_prbs; bool is_inner_rb = start_prb >= rb_low && start_prb <= rb_high && n_prbs <= ((N_RB_UL / 2) + (N_RB_UL & 1)); // Table 6.2.2-1 in 38.101 switch (Qm) { - case 1 : + case 1: AssertFatal(false, "MPR for Pi/2 BPSK not implemented yet\n"); break; - case 2 : + case 2: if (is_transform_precoding) { - if(!is_inner_rb) + if (!is_inner_rb) MPR = 1; - } - else { - if(is_inner_rb) + } else { + if (is_inner_rb) MPR = 1.5; else MPR = 3; } break; - case 4 : + case 4: if (is_transform_precoding) { - if(is_inner_rb) + if (is_inner_rb) MPR = 1; else MPR = 2; - } - else { - if(is_inner_rb) + } else { + if (is_inner_rb) MPR = 2; else MPR = 3; } break; - case 6 : + case 6: if (is_transform_precoding) MPR = 2.5; else MPR = 3.5; break; - case 8 : + case 8: if (is_transform_precoding) MPR = 4.5; else @@ -170,12 +176,12 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, if (P_MPR > total_reduction) total_reduction = P_MPR; int pcmax_high, pcmax_low; - if(mac->p_Max) { + if (p_Max) { pcmax_high = p_emax < (p_powerclass - delta_P_powerclass) ? p_emax : (p_powerclass - delta_P_powerclass); - pcmax_low = (p_emax - delta_TC) < (p_powerclass - delta_P_powerclass - total_reduction) ? - (p_emax - delta_TC) : (p_powerclass - delta_P_powerclass - total_reduction); - } - else { + pcmax_low = (p_emax - delta_TC) < (p_powerclass - delta_P_powerclass - total_reduction) + ? (p_emax - delta_TC) + : (p_powerclass - delta_P_powerclass - total_reduction); + } else { pcmax_high = p_powerclass - delta_P_powerclass; pcmax_low = p_powerclass - delta_P_powerclass - total_reduction; } @@ -183,8 +189,7 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int pcmax = (pcmax_low + pcmax_high) / 2; LOG_D(MAC, "Configured maximum output power: %d dBm <= PCMAX %d dBm <= %d dBm \n", pcmax_low, pcmax, pcmax_high); return pcmax; - } - else { + } else { // FR2 TODO it is even more complex because it is radiated power return 23; } @@ -294,7 +299,16 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac, // PUCCH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1) // TODO: P_CMAX for format 2 - int P_CMAX = nr_get_Pcmax(mac, 2, false, mac->current_UL_BWP->scs, mac->current_UL_BWP->BWPSize, true, 1, start_prb); + int P_CMAX = nr_get_Pcmax(mac->p_Max, + mac->nr_band, + mac->frequency_range, + 2, + false, + mac->current_UL_BWP->scs, + mac->current_UL_BWP->BWPSize, + true, + 1, + start_prb); int P_CMIN = -40; // TODO: minimum TX power, possibly 38.101-1 6.3.1 int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); @@ -358,3 +372,27 @@ static int get_deltatf(uint16_t nb_of_prbs, } return DELTA_TF; } + +// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission +// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16 +// Assumptions: +// - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE +// Measurement units: +// - referenceSignalPower: dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm) +int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm) +{ + fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; + int referenceSignalPower = cfg->ssb_config.ss_pbch_power; + //TODO improve PL measurements. Probably not correct as it is. + + int16_t pathloss = (int16_t)(referenceSignalPower - ssb_rsrp_dBm); + + LOG_D(NR_MAC, "pathloss %d dB, referenceSignalPower %d dBm/RE (%f mW), RSRP %d dBm (%f mW)\n", + pathloss, + referenceSignalPower, + pow(10, referenceSignalPower/10), + ssb_rsrp_dBm, + pow(10, ssb_rsrp_dBm/10)); + + return pathloss; +} diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 2a7801afb8..47464d8fb3 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -3945,26 +3945,3 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d return; } -// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission -// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16 -// Assumptions: -// - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE -// Measurement units: -// - referenceSignalPower: dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm) -int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm) -{ - fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; - int referenceSignalPower = cfg->ssb_config.ss_pbch_power; - //TODO improve PL measurements. Probably not correct as it is. - - int16_t pathloss = (int16_t)(referenceSignalPower - ssb_rsrp_dBm); - - LOG_D(NR_MAC, "pathloss %d dB, referenceSignalPower %d dBm/RE (%f mW), RSRP %d dBm (%f mW)\n", - pathloss, - referenceSignalPower, - pow(10, referenceSignalPower/10), - ssb_rsrp_dBm, - pow(10, ssb_rsrp_dBm/10)); - - return pathloss; -} diff --git a/openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt b/openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt new file mode 100644 index 0000000000..40c8c5372b --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(test_nr_ue_power_procedures + test_nr_ue_power_procedures.cpp) +target_link_libraries(test_nr_ue_power_procedures PRIVATE nr_ue_power_procedures GTest::gtest minimal_lib) +add_dependencies(tests test_nr_ue_power_procedures) +add_test(NAME test_nr_ue_power_procedures + COMMAND ./test_nr_ue_power_procedures) diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp new file mode 100644 index 0000000000..179d94bd1b --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp @@ -0,0 +1,64 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + + +#include "gtest/gtest.h" +extern "C" { +#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h" +#include "executables/softmodem-common.h" +uint64_t get_softmodem_optmask(void) {return 0;} +static softmodem_params_t softmodem_params; +softmodem_params_t *get_softmodem_params(void) { + return &softmodem_params; + +} +} +#include +#include "common/utils/LOG/log.h" + +TEST(power_procedures_fr1, test_prach_max_tx_power_mpr) +{ + // Inner PRB, MPR = 1.5 + int prb_start = 4; + int N_RB_UL = 51; // 10Mhz + EXPECT_EQ(22, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start)); + + // Outer PRB, MPR = 3 + prb_start = 0; + EXPECT_EQ(21, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start)); + + // Channel bandwidth conditon not met, no MPR + N_RB_UL = 106; + EXPECT_EQ(23, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start)); +} + +TEST(power_procedures_fr1, test_not_implemented) +{ + int N_RB_UL = 51; + EXPECT_DEATH(nr_get_Pcmax(23, 20, FR1, 1, false, 1, N_RB_UL, false, 6, 0), "MPR for Pi/2 BPSK not implemented yet"); +} + +int main(int argc, char** argv) +{ + logInit(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From fadd3d00833bd48aefebd93fafed5698ea3a089b Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 12 Jun 2024 16:03:59 +0200 Subject: [PATCH 38/39] Add unit test build log to artifacts --- ci-scripts/cls_containerize.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index db34e38feb..5d353f2b77 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -680,6 +680,8 @@ class Containerize(): dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu20" ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {lSourcePath}/cmake_targets/log/unittest-build.log') if ret.returncode != 0: + build_log_name = f'build_log_{self.testCase_id}' + CopyLogsToExecutor(cmd, lSourcePath, build_log_name) logging.error(f'Cannot build unit tests') HTML.CreateHtmlTestRow("Unit test build failed", 'KO', [dockerfile]) HTML.CreateHtmlTabFooter(False) From b20561c4515c4b673adb20cee1b0387859226893 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 13 Jun 2024 07:36:42 +0200 Subject: [PATCH 39/39] Add libgtest-dev package to unittest image --- ci-scripts/docker/Dockerfile.unittest.ubuntu20 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci-scripts/docker/Dockerfile.unittest.ubuntu20 b/ci-scripts/docker/Dockerfile.unittest.ubuntu20 index 7e47988719..57bc7f3bef 100644 --- a/ci-scripts/docker/Dockerfile.unittest.ubuntu20 +++ b/ci-scripts/docker/Dockerfile.unittest.ubuntu20 @@ -27,6 +27,11 @@ FROM ran-base:develop as ran-tests +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + libgtest-dev + RUN rm -Rf /oai-ran WORKDIR /oai-ran COPY . .