Commit c775073a authored by Remi Hardy's avatar Remi Hardy
Browse files

Merge remote-tracking branch 'origin/nr-pdcp-improvements' into integration_2021_wk10

parents c12dd11d 9edc8cce
......@@ -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
)
......
......@@ -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);
}
......
......@@ -21,24 +21,222 @@
#include "nr_pdcp_entity.h"
#include "nr_pdcp_entity_drb_am.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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->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.delete = nr_pdcp_entity_drb_am_delete;
ret->delete = nr_pdcp_entity_delete;
ret->common.deliver_sdu = deliver_sdu;
ret->common.deliver_sdu_data = deliver_sdu_data;
ret->deliver_sdu = deliver_sdu;
ret->deliver_sdu_data = deliver_sdu_data;
ret->common.deliver_pdu = deliver_pdu;
ret->common.deliver_pdu_data = deliver_pdu_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;
}
......@@ -19,18 +19,29 @@
* contact@openairinterface.org
*/
#include <stdint.h>
#ifndef _NR_PDCP_ENTITY_H_
#define _NR_PDCP_ENTITY_H_
#include <stdint.h>
#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;
} 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);
/* 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_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),
......
......@@ -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);
}
}
/*
* 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 <stdlib.h>
#include <string.h>
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);
}
......@@ -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 <stdint.h>
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_ */