diff --git a/openair2/LAYER2/nr_pdcp/asn1_utils.c b/openair2/LAYER2/nr_pdcp/asn1_utils.c index 473c5f2331..6b45a73acf 100644 --- a/openair2/LAYER2/nr_pdcp/asn1_utils.c +++ b/openair2/LAYER2/nr_pdcp/asn1_utils.c @@ -20,6 +20,7 @@ */ #include "common/utils/LOG/log.h" +#include "nr_pdcp_entity.h" int decode_t_reordering(int v) { @@ -36,16 +37,16 @@ int decode_t_reordering(int v) int decode_sn_size_ul(long s) { - if (s == 0) return 12; - if (s == 1) return 18; + if (s == 0) return SHORT_SN_SIZE; + if (s == 1) return LONG_SN_SIZE; LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); exit(1); } int decode_sn_size_dl(long s) { - if (s == 0) return 12; - if (s == 1) return 18; + if (s == 0) return SHORT_SN_SIZE; + if (s == 1) return LONG_SN_SIZE; LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); exit(1); } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index cea73170dc..2a197c3c4f 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -32,6 +32,16 @@ #include "LOG/log.h" +/** + * @brief returns the maximum PDCP PDU size + * which corresponds to data PDU for DRBs with 18 bits PDCP SN + * and integrity enabled +*/ +int nr_max_pdcp_pdu_size(sdu_size_t sdu_size) +{ + return (sdu_size + LONG_PDCP_HEADER_SIZE + PDCP_INTEGRITY_SIZE); +} + static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, char *_buffer, int size) { @@ -46,6 +56,11 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, int rx_deliv_sn; uint32_t rx_deliv_hfn; + if (entity->entity_suspended) { + LOG_W(PDCP, "PDCP entity %d is suspended. Quit RX procedure.\n", entity->rb_id); + return; + } + if (size < 1) { LOG_E(PDCP, "bad PDU received (size = %d)\n", size); return; @@ -65,21 +80,21 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, if (entity->has_sdap_rx) sdap_header_size = 1; // SDAP Header is one byte - if (entity->sn_size == 12) { + if (entity->sn_size == SHORT_SN_SIZE) { rcvd_sn = ((buffer[0] & 0xf) << 8) | buffer[1]; - header_size = 2; + header_size = SHORT_PDCP_HEADER_SIZE; } else { rcvd_sn = ((buffer[0] & 0x3) << 16) | (buffer[1] << 8) | buffer[2]; - header_size = 3; + header_size = LONG_PDCP_HEADER_SIZE; } entity->stats.rxpdu_sn = rcvd_sn; /* SRBs always have MAC-I, even if integrity is not active */ if (entity->has_integrity || entity->type == NR_PDCP_SRB) { - integrity_size = 4; + integrity_size = PDCP_INTEGRITY_SIZE; } else { integrity_size = 0; } @@ -113,11 +128,11 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); if (entity->has_integrity) { - unsigned char integrity[4] = {0}; + unsigned char integrity[PDCP_INTEGRITY_SIZE] = {0}; entity->integrity(entity->integrity_context, integrity, buffer, size - integrity_size, entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); - if (memcmp(integrity, buffer + size - integrity_size, 4) != 0) { + if (memcmp(integrity, buffer + size - integrity_size, PDCP_INTEGRITY_SIZE) != 0) { LOG_E(PDCP, "discard NR PDU, integrity failed\n"); entity->stats.rxpdu_dd_pkts++; entity->stats.rxpdu_dd_bytes += size; @@ -189,8 +204,14 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity, int integrity_size; int sdap_header_size = 0; char *buf = pdu_buffer; - DevAssert(size + 3 + 4 <= pdu_max_size); + DevAssert(nr_max_pdcp_pdu_size(size) <= pdu_max_size); int dc_bit; + + if (entity->entity_suspended) { + LOG_W(PDCP, "PDCP entity %d is suspended. Quit SDU processing.\n", entity->rb_id); + return -1; + } + entity->stats.rxsdu_pkts++; entity->stats.rxsdu_bytes += size; @@ -207,20 +228,20 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity, dc_bit = 0; } - if (entity->sn_size == 12) { + if (entity->sn_size == SHORT_SN_SIZE) { buf[0] = dc_bit | ((sn >> 8) & 0xf); buf[1] = sn & 0xff; - header_size = 2; + header_size = SHORT_PDCP_HEADER_SIZE; } else { buf[0] = dc_bit | ((sn >> 16) & 0x3); buf[1] = (sn >> 8) & 0xff; buf[2] = sn & 0xff; - header_size = 3; + header_size = LONG_PDCP_HEADER_SIZE; } /* SRBs always have MAC-I, even if integrity is not active */ if (entity->has_integrity || entity->type == NR_PDCP_SRB) { - integrity_size = 4; + integrity_size = PDCP_INTEGRITY_SIZE; } else { integrity_size = 0; } @@ -228,16 +249,16 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity, memcpy(buf + header_size, buffer, size); if (entity->has_integrity) { - uint8_t integrity[4] = {0}; + uint8_t integrity[PDCP_INTEGRITY_SIZE] = {0}; entity->integrity(entity->integrity_context, integrity, (unsigned char *)buf, header_size + size, entity->rb_id, count, entity->is_gnb ? 1 : 0); - memcpy((unsigned char *)buf + header_size + size, integrity, 4); - } else if (integrity_size == 4) { + memcpy((unsigned char *)buf + header_size + size, integrity, PDCP_INTEGRITY_SIZE); + } else if (integrity_size == PDCP_INTEGRITY_SIZE) { // set MAC-I to 0 for SRBs with integrity not active - memset(buf + header_size + size, 0, 4); + memset(buf + header_size + size, 0, PDCP_INTEGRITY_SIZE); } if (entity->has_ciphering && (entity->is_gnb || entity->security_mode_completed)) { @@ -400,6 +421,7 @@ static void nr_pdcp_entity_suspend(nr_pdcp_entity_t *entity) } entity->rx_next = 0; entity->rx_deliv = 0; + entity->entity_suspended = true; } static void free_rx_list(nr_pdcp_entity_t *entity) @@ -427,6 +449,9 @@ static void nr_pdcp_entity_reestablish_drb_am(nr_pdcp_entity_t *entity) /* receiving entity procedures */ /* todo: deal with ciphering/integrity algos and keys */ + + /* Flag PDCP entity as re-established */ + entity->entity_suspended = false; } static void nr_pdcp_entity_reestablish_drb_um(nr_pdcp_entity_t *entity) @@ -445,6 +470,9 @@ static void nr_pdcp_entity_reestablish_drb_um(nr_pdcp_entity_t *entity) entity->rx_next = 0; entity->rx_deliv = 0; /* todo: deal with ciphering/integrity algos and keys */ + + /* Flag PDCP entity as re-established */ + entity->entity_suspended = false; } static void nr_pdcp_entity_reestablish_srb(nr_pdcp_entity_t *entity) @@ -461,6 +489,9 @@ static void nr_pdcp_entity_reestablish_srb(nr_pdcp_entity_t *entity) entity->rx_next = 0; entity->rx_deliv = 0; /* todo: deal with ciphering/integrity algos and keys */ + + /* Flag PDCP entity as re-established */ + entity->entity_suspended = false; } static void nr_pdcp_entity_release(nr_pdcp_entity_t *entity) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h index 8d342a8206..aae1ffb317 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h @@ -29,6 +29,18 @@ #include "nr_pdcp_sdu.h" #include "openair2/RRC/NR/rrc_gNB_radio_bearers.h" +/* PDCP Formats according to clause 6.2 of 3GPP TS 38.323 */ +/* SN Size applicable to SRBs, UM DRBs and AM DRBs */ +#define SHORT_SN_SIZE 12 +/* SN Size applicable to UM DRBs and AM DRBs */ +#define LONG_SN_SIZE 18 +/* Data PDU for SRBs and DRBs with 12 bits PDCP SN (unit: byte) */ +#define SHORT_PDCP_HEADER_SIZE 2 +/* Data PDU for DRBs with 18 bits PDCP SN (unit: byte) */ +#define LONG_PDCP_HEADER_SIZE 3 +/* MAC-I size (unit: byte) */ +#define PDCP_INTEGRITY_SIZE 4 + typedef enum { NR_PDCP_DRB_AM, NR_PDCP_DRB_UM, @@ -167,6 +179,9 @@ typedef struct nr_pdcp_entity_t { // 4- The ITTI task, forwards the message ciphering (e.g., nea2) it. // 5- The gNB cannot understand the ciphered Security Mode Complete message. bool security_mode_completed; + + /* Keep tracks of whether the PDCP entity was suspended or not */ + bool entity_suspended; } nr_pdcp_entity_t; nr_pdcp_entity_t *new_nr_pdcp_entity( @@ -190,4 +205,7 @@ nr_pdcp_entity_t *new_nr_pdcp_entity( unsigned char *ciphering_key, unsigned char *integrity_key); +/* Get maximum PDCP PDU size */ +int nr_max_pdcp_pdu_size(sdu_size_t sdu_size); + #endif /* _NR_PDCP_ENTITY_H_ */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index ef2da07d57..b2380e3b2f 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -817,10 +817,19 @@ void add_srb(int is_gnb, if (nr_pdcp_get_rb(ue, srb_id, true) != NULL) { LOG_E(PDCP, "warning SRB %d already exist for UE ID %ld, do nothing\n", srb_id, UEid); } else { - pdcp_srb = new_nr_pdcp_entity(NR_PDCP_SRB, is_gnb, srb_id, - 0, false, false, // sdap parameters - deliver_sdu_srb, ue, NULL, ue, - 12, t_Reordering, -1, + pdcp_srb = new_nr_pdcp_entity(NR_PDCP_SRB, + is_gnb, + srb_id, + 0, // PDU session ID (not relevant) + false, // has SDAP RX (not relevant) + false, // has SDAP TX (not relevant) + deliver_sdu_srb, + ue, + NULL, + ue, + SHORT_SN_SIZE, + t_Reordering, + -1, ciphering_algorithm, integrity_algorithm, ciphering_key, @@ -1075,9 +1084,13 @@ bool nr_pdcp_data_req_srb(ue_id_t ue_id, return 0; } - int max_size = sdu_buffer_size + 3 + 4; // 3: max header, 4: max integrity + int max_size = nr_max_pdcp_pdu_size(sdu_buffer_size); char pdu_buf[max_size]; int pdu_size = rb->process_sdu(rb, (char *)sdu_buffer, sdu_buffer_size, muiP, pdu_buf, max_size); + if (pdu_size == -1) { + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return 0; + } AssertFatal(rb->deliver_pdu == NULL, "SRB callback should be NULL, to be provided on every invocation\n"); nr_pdcp_manager_unlock(nr_pdcp_ue_manager); @@ -1098,6 +1111,7 @@ void nr_pdcp_suspend_srb(ue_id_t ue_id, int srb_id) return; } srb->suspend_entity(srb); + LOG_D(PDCP, "SRB %d suspended\n", srb_id); nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } @@ -1112,6 +1126,7 @@ void nr_pdcp_suspend_drb(ue_id_t ue_id, int drb_id) return; } drb->suspend_entity(drb); + LOG_D(PDCP, "DRB %d suspended\n", drb_id); nr_pdcp_manager_unlock(nr_pdcp_ue_manager); } @@ -1211,6 +1226,7 @@ void nr_pdcp_reestablishment(ue_id_t ue_id, int rb_id, bool srb_flag) if (rb != NULL) { LOG_D(PDCP, "UE %4.4lx re-establishment of %sRB %d\n", ue_id, srb_flag ? "S" : "D", rb_id); rb->reestablish_entity(rb); + LOG_I(PDCP, "%s %d re-established\n", srb_flag ? "SRB" : "DRB" , rb_id); } else { LOG_W(PDCP, "UE %4.4lx cannot re-establish %sRB %d, RB not found\n", ue_id, srb_flag ? "S" : "D", rb_id); } @@ -1252,14 +1268,19 @@ bool nr_pdcp_data_req_drb(protocol_ctxt_t *ctxt_pP, rb = nr_pdcp_get_rb(ue, rb_id, false); if (rb == NULL) { - LOG_E(PDCP, "no DRB found (ue_id %lx, rb_id %ld)\n", ue_id, rb_id); + LOG_E(PDCP, "[UE %lx] DRB %ld not found\n", rb_id, ue_id); nr_pdcp_manager_unlock(nr_pdcp_ue_manager); return 0; } - int max_size = sdu_buffer_size + 3 + 4; // 3: max header, 4: max integrity + int max_size = nr_max_pdcp_pdu_size(sdu_buffer_size); char pdu_buf[max_size]; int pdu_size = rb->process_sdu(rb, (char *)sdu_buffer, sdu_buffer_size, muiP, pdu_buf, max_size); + if (pdu_size == -1) { + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return 0; + } + deliver_pdu deliver_pdu_cb = rb->deliver_pdu; nr_pdcp_manager_unlock(nr_pdcp_ue_manager);