diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt index e11c850b8e..58530a5ae4 100644 --- a/cmake_targets/CMakeLists.txt +++ b/cmake_targets/CMakeLists.txt @@ -1967,7 +1967,8 @@ set(NR_PDCP_SRC ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_oai_api.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_entity.c - ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c + ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_sdu.c + ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c ) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index ede68b11ef..3c300c5f9d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -364,7 +364,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, /* send tick to RLC and RRC every ms */ if ((slot & ((1 << *scc->ssbSubcarrierSpacing) - 1)) == 0) { void nr_rlc_tick(int frame, int subframe); + void nr_pdcp_tick(int frame, int subframe); nr_rlc_tick(frame, slot >> *scc->ssbSubcarrierSpacing); + nr_pdcp_tick(frame, slot >> *scc->ssbSubcarrierSpacing); nr_rrc_trigger(&ctxt, 0 /*CC_id*/, frame, slot >> *scc->ssbSubcarrierSpacing); } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index ffc669a461..eda6888ecd 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -21,24 +21,222 @@ #include "nr_pdcp_entity.h" -#include "nr_pdcp_entity_drb_am.h" +#include +#include +#include + #include "nr_pdcp_security_nea2.h" +#include "nr_pdcp_sdu.h" #include "LOG/log.h" -nr_pdcp_entity_t *new_nr_pdcp_entity_srb( - int is_gnb, int rb_id, - void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity, - char *buf, int size), - void *deliver_sdu_data, - void (*deliver_pdu)(void *deliver_pdu_data, struct nr_pdcp_entity_t *entity, - char *buf, int size, int sdu_id), - void *deliver_pdu_data) +static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, + char *_buffer, int size) { - abort(); + unsigned char *buffer = (unsigned char *)_buffer; + nr_pdcp_sdu_t *sdu; + int rcvd_sn; + uint32_t rcvd_hfn; + uint32_t rcvd_count; + int header_size; + int integrity_size; + int rx_deliv_sn; + uint32_t rx_deliv_hfn; + + if (size < 1) { + LOG_E(PDCP, "bad PDU received (size = %d)\n", size); + return; + } + + if (!(buffer[0] & 0x80)) { + LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } + + if (entity->sn_size == 12) { + rcvd_sn = (((unsigned char)buffer[0] & 0xf) << 8) | + (unsigned char)buffer[1]; + header_size = 2; + } else { + rcvd_sn = (((unsigned char)buffer[0] & 0x3) << 16) | + ((unsigned char)buffer[1] << 8) | + (unsigned char)buffer[2]; + header_size = 3; + } + + integrity_size = 0; + + if (size < header_size + integrity_size + 1) { + LOG_E(PDCP, "bad PDU received (size = %d)\n", size); + return; + } + + rx_deliv_sn = entity->rx_deliv & entity->sn_max; + rx_deliv_hfn = (entity->rx_deliv >> entity->sn_size) & ~entity->sn_max; + + if (rcvd_sn < rx_deliv_sn - entity->window_size) { + rcvd_hfn = rx_deliv_hfn + 1; + } else if (rcvd_sn >= rx_deliv_sn + entity->window_size) { + rcvd_hfn = rx_deliv_hfn - 1; + } else { + rcvd_hfn = rx_deliv_hfn; + } + + rcvd_count = (rcvd_hfn << entity->sn_size) | rcvd_sn; + + if (entity->has_ciphering) + entity->cipher(entity->security_context, + (unsigned char *)buffer+header_size, size-header_size, + entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); + + if (rcvd_count < entity->rx_deliv + || nr_pdcp_sdu_in_list(entity->rx_list, rcvd_count)) { + LOG_D(PDCP, "discard NR PDU rcvd_count=%d\n", rcvd_count); + return; + } + + sdu = nr_pdcp_new_sdu(rcvd_count, + (char *)buffer + header_size, + size - header_size - integrity_size); + entity->rx_list = nr_pdcp_sdu_list_add(entity->rx_list, sdu); + entity->rx_size += size-header_size; + + if (rcvd_count >= entity->rx_next) { + entity->rx_next = rcvd_count + 1; + } + + /* TODO(?): out of order delivery */ + + if (rcvd_count == entity->rx_deliv) { + /* deliver all SDUs starting from rx_deliv up to discontinuity or end of list */ + uint32_t count = entity->rx_deliv; + while (entity->rx_list != NULL && count == entity->rx_list->count) { + nr_pdcp_sdu_t *cur = entity->rx_list; + entity->deliver_sdu(entity->deliver_sdu_data, entity, + cur->buffer, cur->size); + entity->rx_list = cur->next; + entity->rx_size -= cur->size; + nr_pdcp_free_sdu(cur); + count++; + } + entity->rx_deliv = count; + } + + if (entity->t_reordering_start != 0 && entity->rx_deliv > entity->rx_reord) { + /* stop and reset t-Reordering */ + entity->t_reordering_start = 0; + } + + if (entity->t_reordering_start == 0 && entity->rx_deliv < entity->rx_next) { + entity->rx_reord = entity->rx_next; + entity->t_reordering_start = entity->t_current; + } } -nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am( +static void nr_pdcp_entity_recv_sdu(nr_pdcp_entity_t *entity, + char *buffer, int size, int sdu_id) +{ + uint32_t count; + int sn; + int header_size; + char buf[size+3+4]; + + count = entity->tx_next; + sn = entity->tx_next & entity->sn_max; + + if (entity->sn_size == 12) { + buf[0] = 0x80 | ((sn >> 8) & 0xf); + buf[1] = sn & 0xff; + header_size = 2; + } else { + buf[0] = 0x80 | ((sn >> 16) & 0x3); + buf[1] = (sn >> 8) & 0xff; + buf[2] = sn & 0xff; + header_size = 3; + } + + memcpy(buf+header_size, buffer, size); + + if (entity->has_ciphering) + entity->cipher(entity->security_context, + (unsigned char *)buf+header_size, size, + entity->rb_id, count, entity->is_gnb ? 1 : 0); + + entity->tx_next++; + + entity->deliver_pdu(entity->deliver_pdu_data, entity, buf, + size+header_size, sdu_id); +} + +static void nr_pdcp_entity_set_integrity_key(nr_pdcp_entity_t *entity, + char *key) +{ + memcpy(entity->integrity_key, key, 16); +} + +static void check_t_reordering(nr_pdcp_entity_t *entity) +{ + uint32_t count; + + if (entity->t_reordering_start == 0 + || entity->t_current <= entity->t_reordering_start + entity->t_reordering) + return; + + /* stop timer */ + entity->t_reordering_start = 0; + + /* deliver all SDUs with count < rx_reord */ + while (entity->rx_list != NULL && entity->rx_list->count < entity->rx_reord) { + nr_pdcp_sdu_t *cur = entity->rx_list; + entity->deliver_sdu(entity->deliver_sdu_data, entity, + cur->buffer, cur->size); + entity->rx_list = cur->next; + entity->rx_size -= cur->size; + nr_pdcp_free_sdu(cur); + } + + /* deliver all SDUs starting from rx_reord up to discontinuity or end of list */ + count = entity->rx_reord; + while (entity->rx_list != NULL && count == entity->rx_list->count) { + nr_pdcp_sdu_t *cur = entity->rx_list; + entity->deliver_sdu(entity->deliver_sdu_data, entity, + cur->buffer, cur->size); + entity->rx_list = cur->next; + entity->rx_size -= cur->size; + nr_pdcp_free_sdu(cur); + count++; + } + + entity->rx_deliv = count; + + if (entity->rx_deliv < entity->rx_next) { + entity->rx_reord = entity->rx_next; + entity->t_reordering_start = entity->t_current; + } +} + +void nr_pdcp_entity_set_time(struct nr_pdcp_entity_t *entity, uint64_t now) +{ + entity->t_current = now; + + check_t_reordering(entity); +} + +void nr_pdcp_entity_delete(nr_pdcp_entity_t *entity) +{ + nr_pdcp_sdu_t *cur = entity->rx_list; + while (cur != NULL) { + nr_pdcp_sdu_t *next = cur->next; + nr_pdcp_free_sdu(cur); + cur = next; + } + if (entity->free_security != NULL) + entity->free_security(entity->security_context); + free(entity); +} + +nr_pdcp_entity_t *new_nr_pdcp_entity( + nr_pdcp_entity_type_t type, int is_gnb, int rb_id, void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity, char *buf, int size), @@ -54,52 +252,56 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am( unsigned char *ciphering_key, unsigned char *integrity_key) { - nr_pdcp_entity_drb_am_t *ret; + nr_pdcp_entity_t *ret; - ret = calloc(1, sizeof(nr_pdcp_entity_drb_am_t)); + ret = calloc(1, sizeof(nr_pdcp_entity_t)); if (ret == NULL) { LOG_E(PDCP, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__); exit(1); } - ret->common.recv_pdu = nr_pdcp_entity_drb_am_recv_pdu; - ret->common.recv_sdu = nr_pdcp_entity_drb_am_recv_sdu; - ret->common.set_integrity_key = nr_pdcp_entity_drb_am_set_integrity_key; + ret->type = type; - ret->common.delete = nr_pdcp_entity_drb_am_delete; + ret->recv_pdu = nr_pdcp_entity_recv_pdu; + ret->recv_sdu = nr_pdcp_entity_recv_sdu; + ret->set_integrity_key = nr_pdcp_entity_set_integrity_key; + ret->set_time = nr_pdcp_entity_set_time; - ret->common.deliver_sdu = deliver_sdu; - ret->common.deliver_sdu_data = deliver_sdu_data; + ret->delete = nr_pdcp_entity_delete; - ret->common.deliver_pdu = deliver_pdu; - ret->common.deliver_pdu_data = deliver_pdu_data; + ret->deliver_sdu = deliver_sdu; + ret->deliver_sdu_data = deliver_sdu_data; + + ret->deliver_pdu = deliver_pdu; + ret->deliver_pdu_data = deliver_pdu_data; ret->rb_id = rb_id; ret->sn_size = sn_size; ret->t_reordering = t_reordering; ret->discard_timer = discard_timer; - ret->common.maximum_nr_pdcp_sn = (1 << sn_size) - 1; + ret->sn_max = (1 << sn_size) - 1; + ret->window_size = 1 << (sn_size - 1); if (ciphering_key != NULL && ciphering_algorithm != 0) { if (ciphering_algorithm != 2) { LOG_E(PDCP, "FATAL: only nea2 supported for the moment\n"); exit(1); } - ret->common.has_ciphering = 1; - ret->common.ciphering_algorithm = ciphering_algorithm; - memcpy(ret->common.ciphering_key, ciphering_key, 16); + ret->has_ciphering = 1; + ret->ciphering_algorithm = ciphering_algorithm; + memcpy(ret->ciphering_key, ciphering_key, 16); - ret->common.security_context = nr_pdcp_security_nea2_init(ciphering_key); - ret->common.cipher = nr_pdcp_security_nea2_cipher; - ret->common.free_security = nr_pdcp_security_nea2_free_security; + ret->security_context = nr_pdcp_security_nea2_init(ciphering_key); + ret->cipher = nr_pdcp_security_nea2_cipher; + ret->free_security = nr_pdcp_security_nea2_free_security; } - ret->common.is_gnb = is_gnb; + ret->is_gnb = is_gnb; if (integrity_key != NULL) { printf("%s:%d:%s: TODO\n", __FILE__, __LINE__, __FUNCTION__); exit(1); } - return (nr_pdcp_entity_t *)ret; + return ret; } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h index 58d79835ec..36e7a540c4 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h @@ -19,18 +19,29 @@ * contact@openairinterface.org */ -#include - #ifndef _NR_PDCP_ENTITY_H_ #define _NR_PDCP_ENTITY_H_ +#include + +#include "nr_pdcp_sdu.h" + +typedef enum { + NR_PDCP_DRB_AM, + NR_PDCP_DRB_UM, + NR_PDCP_SRB +} nr_pdcp_entity_type_t; + typedef struct nr_pdcp_entity_t { + nr_pdcp_entity_type_t type; + /* functions provided by the PDCP module */ void (*recv_pdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size); void (*recv_sdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size, int sdu_id); void (*delete)(struct nr_pdcp_entity_t *entity); void (*set_integrity_key)(struct nr_pdcp_entity_t *entity, char *key); + void (*set_time)(struct nr_pdcp_entity_t *entity, uint64_t now); /* callbacks provided to the PDCP module */ void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity, @@ -39,9 +50,28 @@ typedef struct nr_pdcp_entity_t { void (*deliver_pdu)(void *deliver_pdu_data, struct nr_pdcp_entity_t *entity, char *buf, int size, int sdu_id); void *deliver_pdu_data; - int tx_hfn; - int next_nr_pdcp_tx_sn; - int maximum_nr_pdcp_sn; + + /* configuration variables */ + int rb_id; + + int sn_size; /* SN size, in bits */ + int t_reordering; /* unit: ms */ + int discard_timer; /* unit: ms */ + + int sn_max; /* (2^SN_size) - 1 */ + int window_size; /* 2^(SN_size - 1) */ + + /* state variables */ + uint32_t tx_next; + uint32_t rx_next; + uint32_t rx_deliv; + uint32_t rx_reord; + + /* set to the latest know time by the user of the module. Unit: ms */ + uint64_t t_current; + + /* timers (stores the ms of activation, 0 means not active) */ + int t_reordering_start; /* security */ int has_ciphering; @@ -60,18 +90,15 @@ typedef struct nr_pdcp_entity_t { * pdcp entity is for a gnb or an ue */ int is_gnb; + + /* rx management */ + nr_pdcp_sdu_t *rx_list; + int rx_size; + int rx_maxsize; } nr_pdcp_entity_t; -nr_pdcp_entity_t *new_nr_pdcp_entity_srb( - int is_gnb, int rb_id, - void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity, - char *buf, int size), - void *deliver_sdu_data, - void (*deliver_pdu)(void *deliver_pdu_data, struct nr_pdcp_entity_t *entity, - char *buf, int size, int sdu_id), - void *deliver_pdu_data); - -nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am( +nr_pdcp_entity_t *new_nr_pdcp_entity( + nr_pdcp_entity_type_t type, int is_gnb, int rb_id, void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity, char *buf, int size), diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c deleted file mode 100644 index 62881c184e..0000000000 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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_pdcp_entity_drb_am.h" - -#include -#include -#include -#include "common/utils/LOG/log.h" - -void nr_pdcp_entity_drb_am_recv_pdu(nr_pdcp_entity_t *_entity, char *buffer, int size) -{ - nr_pdcp_entity_drb_am_t *entity = (nr_pdcp_entity_drb_am_t *)_entity; - int sn; - - if (size < 3) abort(); - - if (!(buffer[0] & 0x80)) - LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - - sn = (((unsigned char)buffer[0] & 0x3) << 16) | - ((unsigned char)buffer[1] << 8) | - (unsigned char)buffer[2]; - - if (entity->common.has_ciphering) - entity->common.cipher(entity->common.security_context, (unsigned char *)buffer+3, size-3, - entity->rb_id, sn, entity->common.is_gnb ? 0 : 1); - - entity->common.deliver_sdu(entity->common.deliver_sdu_data, - (nr_pdcp_entity_t *)entity, buffer+3, size-3); -} - -void nr_pdcp_entity_drb_am_recv_sdu(nr_pdcp_entity_t *_entity, char *buffer, int size, - int sdu_id) -{ - nr_pdcp_entity_drb_am_t *entity = (nr_pdcp_entity_drb_am_t *)_entity; - int sn; - char buf[size+3]; - - sn = entity->common.next_nr_pdcp_tx_sn; - - entity->common.next_nr_pdcp_tx_sn++; - if (entity->common.next_nr_pdcp_tx_sn > entity->common.maximum_nr_pdcp_sn) { - entity->common.next_nr_pdcp_tx_sn = 0; - entity->common.tx_hfn++; - } - - buf[0] = 0x80 | ((sn >> 16) & 0x3); - buf[1] = (sn >> 8) & 0xff; - buf[2] = sn & 0xff; - memcpy(buf+3, buffer, size); - - if (entity->common.has_ciphering) - entity->common.cipher(entity->common.security_context, (unsigned char *)buf+3, size, - entity->rb_id, sn, entity->common.is_gnb ? 1 : 0); - - entity->common.deliver_pdu(entity->common.deliver_pdu_data, - (nr_pdcp_entity_t *)entity, buf, size+3, sdu_id); -} - -void nr_pdcp_entity_drb_am_set_integrity_key(nr_pdcp_entity_t *_entity, char *key) -{ - /* nothing to do */ -} - -void nr_pdcp_entity_drb_am_delete(nr_pdcp_entity_t *_entity) -{ - nr_pdcp_entity_drb_am_t *entity = (nr_pdcp_entity_drb_am_t *)_entity; - if (entity->common.free_security != NULL) - entity->common.free_security(entity->common.security_context); - free(entity); -} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index f14d25b145..597cba7bf5 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -24,6 +24,7 @@ #endif #include "asn1_utils.h" #include "nr_pdcp_ue_manager.h" +#include "nr_pdcp_timer_thread.h" #include "NR_RadioBearerConfig.h" #include "NR_RLC-BearerConfig.h" #include "NR_RLC-Config.h" @@ -41,6 +42,11 @@ static nr_pdcp_ue_manager_t *nr_pdcp_ue_manager; +/* TODO: handle time a bit more properly */ +static uint64_t nr_pdcp_current_time; +static int nr_pdcp_current_time_last_frame; +static int nr_pdcp_current_time_last_subframe; + /* necessary globals for OAI, not used internally */ hash_table_t *pdcp_coll_p; static uint64_t pdcp_optmask; @@ -339,6 +345,8 @@ void pdcp_layer_init(void) nr_pdcp_ue_manager = new_nr_pdcp_ue_manager(1); init_nr_rlc_data_req_queue(); + + nr_pdcp_init_timer_thread(nr_pdcp_ue_manager); } #include "nfapi/oai_integration/vendor_ext.h" @@ -625,11 +633,11 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s, LOG_D(PDCP, "%s:%d:%s: warning DRB %d already exist for ue %d, do nothing\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); } else { - pdcp_drb = new_nr_pdcp_entity_drb_am(is_gnb, drb_id, - deliver_sdu_drb, ue, deliver_pdu_drb, ue, - sn_size_dl, t_reordering, discard_timer, - ciphering_algorithm, integrity_algorithm, - ciphering_key, integrity_key); + pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, drb_id, + deliver_sdu_drb, ue, deliver_pdu_drb, ue, + sn_size_dl, t_reordering, discard_timer, + ciphering_algorithm, integrity_algorithm, + ciphering_key, integrity_key); nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb); LOG_D(PDCP, "%s:%d:%s: added drb %d to ue rnti %x\n", __FILE__, __LINE__, __FUNCTION__, drb_id, rnti); @@ -976,3 +984,14 @@ void pdcp_mbms_run ( const protocol_ctxt_t *const ctxt_pP){ /* nothing to do */ } + +void nr_pdcp_tick(int frame, int subframe) +{ + if (frame != nr_pdcp_current_time_last_frame || + subframe != nr_pdcp_current_time_last_subframe) { + nr_pdcp_current_time_last_frame = frame; + nr_pdcp_current_time_last_subframe = subframe; + nr_pdcp_current_time++; + nr_pdcp_wakeup_timer_thread(nr_pdcp_current_time); + } +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.c new file mode 100644 index 0000000000..47d95156e3 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.c @@ -0,0 +1,78 @@ +/* + * 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_pdcp_sdu.h" + +#include +#include + +nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size) +{ + nr_pdcp_sdu_t *ret = calloc(1, sizeof(nr_pdcp_sdu_t)); + if (ret == NULL) + exit(1); + ret->count = count; + ret->buffer = malloc(size); + if (ret->buffer == NULL) + exit(1); + memcpy(ret->buffer, buffer, size); + ret->size = size; + return ret; +} + +nr_pdcp_sdu_t *nr_pdcp_sdu_list_add(nr_pdcp_sdu_t *l, nr_pdcp_sdu_t *sdu) +{ + nr_pdcp_sdu_t head; + nr_pdcp_sdu_t *cur; + nr_pdcp_sdu_t *prev; + + head.next = l; + cur = l; + prev = &head; + + /* order is by 'count' */ + while (cur != NULL) { + /* check if 'sdu' is before 'cur' in the list */ + if (sdu->count < cur->count) + break; + prev = cur; + cur = cur->next; + } + prev->next = sdu; + sdu->next = cur; + return head.next; +} + +int nr_pdcp_sdu_in_list(nr_pdcp_sdu_t *l, uint32_t count) +{ + while (l != NULL) { + if (l->count == count) + return 1; + l = l->next; + } + return 0; +} + +void nr_pdcp_free_sdu(nr_pdcp_sdu_t *sdu) +{ + free(sdu->buffer); + free(sdu); +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.h similarity index 58% rename from openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h rename to openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.h index d7c42e6a62..3d4e50a4ce 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.h @@ -19,23 +19,21 @@ * contact@openairinterface.org */ -#ifndef _NR_PDCP_ENTITY_DRB_AM_H_ -#define _NR_PDCP_ENTITY_DRB_AM_H_ +#ifndef _NR_PDCP_SDU_H_ +#define _NR_PDCP_SDU_H_ -#include "nr_pdcp_entity.h" +#include -typedef struct { - nr_pdcp_entity_t common; - int rb_id; - int sn_size; /* unit: bits */ - int t_reordering; /* unit: ms */ - int discard_timer; /* unit: ms, -1 means infinity */ -} nr_pdcp_entity_drb_am_t; +typedef struct nr_pdcp_sdu_t { + uint32_t count; + char *buffer; + int size; + struct nr_pdcp_sdu_t *next; +} nr_pdcp_sdu_t; -void nr_pdcp_entity_drb_am_recv_pdu(nr_pdcp_entity_t *entity, char *buffer, int size); -void nr_pdcp_entity_drb_am_recv_sdu(nr_pdcp_entity_t *entity, char *buffer, int size, - int sdu_id); -void nr_pdcp_entity_drb_am_set_integrity_key(nr_pdcp_entity_t *entity, char *key); -void nr_pdcp_entity_drb_am_delete(nr_pdcp_entity_t *entity); +nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size); +nr_pdcp_sdu_t *nr_pdcp_sdu_list_add(nr_pdcp_sdu_t *l, nr_pdcp_sdu_t *sdu); +int nr_pdcp_sdu_in_list(nr_pdcp_sdu_t *l, uint32_t count); +void nr_pdcp_free_sdu(nr_pdcp_sdu_t *sdu); -#endif /* _NR_PDCP_ENTITY_DRB_AM_H_ */ +#endif /* _NR_PDCP_SDU_H_ */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c new file mode 100644 index 0000000000..36e9b16024 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c @@ -0,0 +1,87 @@ +/* + * 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_pdcp_timer_thread.h" + +#include +#include +#include + +#include "LOG/log.h" + +static pthread_mutex_t timer_thread_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t timer_thread_cond = PTHREAD_COND_INITIALIZER; +static volatile uint64_t timer_thread_curtime = 0; + +static void *nr_pdcp_timer_thread(void *_nr_pdcp_ue_manager) +{ + nr_pdcp_ue_manager_t *nr_pdcp_ue_manager = (nr_pdcp_ue_manager_t *)_nr_pdcp_ue_manager; + nr_pdcp_ue_t **ue_list; + int ue_count; + int i; + int j; + uint64_t curtime = 0; + + while (1) { + if (pthread_mutex_lock(&timer_thread_mutex) != 0) abort(); + while (curtime == timer_thread_curtime) + if (pthread_cond_wait(&timer_thread_cond, &timer_thread_mutex) != 0) abort(); + curtime = timer_thread_curtime; + if (pthread_mutex_unlock(&timer_thread_mutex) != 0) abort(); + + nr_pdcp_manager_lock(nr_pdcp_ue_manager); + + ue_list = nr_pdcp_manager_get_ue_list(nr_pdcp_ue_manager); + ue_count = nr_pdcp_manager_get_ue_count(nr_pdcp_ue_manager); + for (i = 0; i < ue_count; i++) { + for (j = 0; j < 2; j++) { + if (ue_list[i]->srb[j] != NULL) + ue_list[i]->srb[j]->set_time(ue_list[i]->srb[j], curtime); + } + for (j = 0; j < 5; j++) { + if (ue_list[i]->drb[j] != NULL) + ue_list[i]->drb[j]->set_time(ue_list[i]->drb[j], curtime); + } + } + + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + } + + return NULL; +} + +void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager) +{ + pthread_t t; + + if (pthread_create(&t, NULL, nr_pdcp_timer_thread, nr_pdcp_ue_manager) != 0) { + LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); + exit(1); + } +} + +void nr_pdcp_wakeup_timer_thread(uint64_t time) +{ + if (pthread_mutex_lock(&timer_thread_mutex)) abort(); + timer_thread_curtime = time; + if (pthread_cond_broadcast(&timer_thread_cond)) abort(); + if (pthread_mutex_unlock(&timer_thread_mutex)) abort(); +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h new file mode 100644 index 0000000000..db8282f940 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h @@ -0,0 +1,32 @@ +/* + * 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_PDCP_TIMER_THREAD_H_ +#define _NR_PDCP_TIMER_THREAD_H_ + +#include "nr_pdcp_ue_manager.h" + +#include + +void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager); +void nr_pdcp_wakeup_timer_thread(uint64_t time); + +#endif /* _NR_PDCP_TIMER_THREAD_H_ */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c index ca51da3d5f..f89a18f94e 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c @@ -189,6 +189,20 @@ void nr_pdcp_ue_add_drb_pdcp_entity(nr_pdcp_ue_t *ue, int drb_id, nr_pdcp_entity ue->drb[drb_id] = entity; } +/* must be called with lock acquired */ +nr_pdcp_ue_t **nr_pdcp_manager_get_ue_list(nr_pdcp_ue_manager_t *_m) +{ + nr_pdcp_ue_manager_internal_t *m = _m; + return m->ue_list; +} + +/* must be called with lock acquired */ +int nr_pdcp_manager_get_ue_count(nr_pdcp_ue_manager_t *_m) +{ + nr_pdcp_ue_manager_internal_t *m = _m; + return m->ue_count; +} + int nr_pdcp_get_first_rnti(nr_pdcp_ue_manager_t *_m) { nr_pdcp_ue_manager_internal_t *m = _m; diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h index 0de2f024b3..3329f856b7 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h @@ -46,6 +46,9 @@ void nr_pdcp_manager_unlock(nr_pdcp_ue_manager_t *m); nr_pdcp_ue_t *nr_pdcp_manager_get_ue(nr_pdcp_ue_manager_t *m, int rnti); void nr_pdcp_manager_remove_ue(nr_pdcp_ue_manager_t *m, int rnti); +nr_pdcp_ue_t **nr_pdcp_manager_get_ue_list(nr_pdcp_ue_manager_t *_m); +int nr_pdcp_manager_get_ue_count(nr_pdcp_ue_manager_t *_m); + /***********************************************************************/ /* ue functions */ /***********************************************************************/