Compare commits

...

5 Commits

Author SHA1 Message Date
Cedric Roux
b01fac1dc0 bypass oai_api for RLC SRBs
- introduce l2 queues to transfer data between RLC and PDCP
- introduce a pdcp thread per l2 queue to proceed data from RLC
  (for data from PDCP to RLC the MAC scheduler asks for it, no
  need for a thread)

Only SRB0 and SRB1 in monolithic mode are functional in the gNB at
this point. Any other scenario is expected to fail.
2025-06-02 12:21:22 +02:00
Cedric Roux
83575ecb75 bypass oai_api for sdap and pdcp in cuup
This is only for the gNB, with F1 and E1 (cu-cp/cu-up/du).
Any other configuration may fail to compile and/or execute.
2025-02-11 16:56:24 +01:00
Cedric Roux
899375f20a bypass nr_pdpcp_oai_api.c for SRBs in F1/E1 mode
This is only for the gNB, with F1 and E1 (cu-cp/cu-up/du).
Any other configuration may fail to compile and/or execute.
2025-01-24 11:52:29 +01:00
Cedric Roux
8537e6dd11 nr pdcp: pass the buffer as const 2025-01-08 16:22:40 +01:00
Cedric Roux
89eb3eb416 nr pdcp: set buffers' type to 'uint8_t'
and propagate until compilation does not warn anymore
2025-01-08 16:08:57 +01:00
39 changed files with 1293 additions and 399 deletions

View File

@@ -74,6 +74,9 @@
#define MAX_DRBS_PER_UE (32) /* Maximum number of Data Radio Bearers per UE
* defined for NGAP in TS 38.413 - maxnoofDRBs */
#define MAX_PDUS_PER_UE (8) /* Maximum number of PDU Sessions per UE */
#define MAX_DRBS_PER_PDU_SESSION 32 /* in 38.331 DRB-Identity is in [1..32]
* 37.483 9.3.1.16 seems to allow more IDs, not
* sure where is the truth, let's keep 32 */
#define NB_RB_MBMS_MAX (29 * 16) /* 29 = LTE_maxSessionPerPMCH + 16 = LTE_maxServiceCount from LTE_asn_constant.h */

View File

@@ -13,7 +13,7 @@ add_subdirectory(T)
add_subdirectory(nr)
add_subdirectory(LOG)
add_subdirectory(threadPool)
add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c)
add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c l2_queue.c)
target_include_directories(utils PUBLIC .)
target_link_libraries(utils PRIVATE ${T_LIB})
if (ENABLE_TESTS)

153
common/utils/l2_queue.c Normal file
View File

@@ -0,0 +1,153 @@
/*
* 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 "l2_queue.h"
#include "utils.h"
l2_queue_t *new_l2_queue(int capacity)
{
l2_queue_t *q = calloc_or_fail(1, sizeof(*q));
q->array = malloc_or_fail(capacity * sizeof(*q->array));
q->capacity = capacity;
int ret = pthread_mutex_init(&q->mutex, NULL);
DevAssert(ret == 0);
ret = pthread_cond_init(&q->cond, NULL);
DevAssert(ret == 0);
return q;
}
void delete_l2_queue(l2_queue_t *q)
{
free(q->array);
free(q);
}
void l2_enqueue(l2_queue_t *q, uint8_t *buffer, int size)
{
int ret = pthread_mutex_lock(&q->mutex);
DevAssert(ret == 0);
AssertFatal(q->packets_count < q->capacity, "l2 queue is full\n");
q->array[q->write_index].buffer = buffer;
q->array[q->write_index].size = size;
q->packets_count++;
q->bytes_count += size;
q->write_index++;
q->write_index %= q->capacity;
ret = pthread_cond_broadcast(&q->cond);
DevAssert(ret == 0);
ret = pthread_mutex_unlock(&q->mutex);
DevAssert(ret == 0);
}
l2_buffer_t l2_dequeue_wait(l2_queue_t *q)
{
int ret = pthread_mutex_lock(&q->mutex);
DevAssert(ret == 0);
while (q->packets_count == 0) {
ret = pthread_cond_wait(&q->cond, &q->mutex);
DevAssert(ret == 0);
}
l2_buffer_t l2_buf = q->array[q->read_index];
q->packets_count--;
q->bytes_count -= l2_buf.size;
q->read_index++;
q->read_index %= q->capacity;
ret = pthread_mutex_unlock(&q->mutex);
DevAssert(ret == 0);
return l2_buf;
}
l2_buffer_t l2_dequeue(l2_queue_t *q)
{
int ret = pthread_mutex_lock(&q->mutex);
DevAssert(ret == 0);
AssertFatal(q->packets_count != 0, "l2 queue is empty\n");
l2_buffer_t l2_buf = q->array[q->read_index];
q->packets_count--;
q->bytes_count -= l2_buf.size;
q->read_index++;
q->read_index %= q->capacity;
ret = pthread_mutex_unlock(&q->mutex);
DevAssert(ret == 0);
return l2_buf;
}
l2_queue_size_t l2_queue_size(l2_queue_t *q)
{
int ret = pthread_mutex_lock(&q->mutex);
DevAssert(ret == 0);
l2_queue_size_t l2_size = {
.packets_count = q->packets_count,
.bytes_count = q->bytes_count,
.packets_capacity = q->capacity
};
ret = pthread_mutex_unlock(&q->mutex);
DevAssert(ret == 0);
return l2_size;
}
void l2_queue_double_capacity(l2_queue_t *q)
{
int ret = pthread_mutex_lock(&q->mutex);
DevAssert(ret == 0);
l2_buffer_t *array = malloc_or_fail(q->capacity * 2);
int n = q->capacity - q->read_index;
int n2 = 0;
if (n > q->packets_count) {
n = q->packets_count;
} else {
n2 = q->packets_count - n;
}
memcpy(array, q->array + q->read_index, n * sizeof(l2_buffer_t));
memcpy(array + n, q->array, n2 * sizeof(l2_buffer_t));
free(q->array);
q->array = array;
q->capacity *= 2;
q->read_index = 0;
q->write_index = q->packets_count;
ret = pthread_mutex_unlock(&q->mutex);
DevAssert(ret == 0);
}

59
common/utils/l2_queue.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* 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 COMMON_UTILS_DS_L2_QUEUE
#define COMMON_UTILS_DS_L2_QUEUE
#include <pthread.h>
#include <stdint.h>
typedef struct {
uint8_t *buffer;
int size;
} l2_buffer_t;
typedef struct {
int packets_capacity;
int packets_count;
int bytes_count;
} l2_queue_size_t;
typedef struct {
l2_buffer_t *array;
int capacity;
int read_index;
int write_index;
int packets_count;
int bytes_count;
pthread_mutex_t mutex;
pthread_cond_t cond;
} l2_queue_t;
l2_queue_t *new_l2_queue(int capacity);
void delete_l2_queue(l2_queue_t *queue);
void l2_enqueue(l2_queue_t *queue, uint8_t *buffer, int size);
l2_buffer_t l2_dequeue(l2_queue_t *queue);
l2_buffer_t l2_dequeue_wait(l2_queue_t *queue);
l2_queue_size_t l2_queue_size(l2_queue_t *queue);
#endif /* COMMON_UTILS_DS_QUEUE */

View File

@@ -1,7 +1,7 @@
add_subdirectory(MESSAGES)
add_subdirectory(lib)
add_library(e1ap e1ap.c e1ap_common.c)
add_library(e1ap e1ap.c e1ap_common.c e1ap_context.c)
target_link_libraries(e1ap
PUBLIC asn1_e1ap e1ap_lib
PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap UTIL e1_if)

View File

@@ -0,0 +1,85 @@
#include "openair2/E1AP/e1ap_context.h"
#include "common/utils/utils.h"
static int e1ap_context_cmp(e1ap_cuup_context_t *a, e1ap_cuup_context_t *b)
{
if (a->cu_up_ue_id < b->cu_up_ue_id)
return -1;
if (a->cu_up_ue_id > b->cu_up_ue_id)
return 1;
if (a->sessionId < b->sessionId)
return -1;
if (a->sessionId > b->sessionId)
return 1;
return 0;
}
RB_GENERATE_STATIC(cuup_pdu_sessions_rbtree_t, e1ap_cuup_context_t, rb_opaque, e1ap_context_cmp);
static cuup_pdu_sessions_rbtree_t e1_contexts;
e1ap_cuup_context_t *new_e1ap_cuup_context(uint64_t cu_up_ue_id, long sessionId)
{
e1ap_cuup_context_t *ctx = calloc_or_fail(1, sizeof(*ctx));
ctx->cu_up_ue_id = cu_up_ue_id;
ctx->sessionId = sessionId;
e1ap_cuup_context_t *ret = RB_INSERT(cuup_pdu_sessions_rbtree_t, &e1_contexts, ctx);
DevAssert(ret == NULL);
return ctx;
}
e1ap_cuup_context_t *get_e1ap_cuup_context(uint64_t cu_up_ue_id, long sessionId)
{
e1ap_cuup_context_t ctx;
ctx.cu_up_ue_id = cu_up_ue_id;
ctx.sessionId = sessionId;
return RB_FIND(cuup_pdu_sessions_rbtree_t, &e1_contexts, &ctx);
}
void remove_e1ap_cuup_ue(uint64_t cu_up_ue_id)
{
e1ap_cuup_context_t *e1_context;
/* remove all PDU sessions for the UE */
/* It's not clear if calling RB_REMOVE inside RB_FOREACH is safe
* (what is the state of the RB tree after a RB_REMOVE? can the RB_FOREACH
* continue?) so we first look for a session for this UE, then remove it
* then restart the search from the beginning until all sessions for the
* UE have been removed.
* Maybe we can call RB_REMOVE inside RB_FOREACH safely in which case
* this code may be greatly simplified.
*/
while (true) {
/* look for one session */
RB_FOREACH(e1_context, cuup_pdu_sessions_rbtree_t, &e1_contexts) {
/* once found, break from the search */
if (e1_context->cu_up_ue_id == cu_up_ue_id) break;
}
/* stop if no more session for this UE */
if (e1_context == NULL)
break;
RB_REMOVE(cuup_pdu_sessions_rbtree_t, &e1_contexts, e1_context);
/* release the session */
/* SDAP entity */
if (e1_context->sdap != NULL) {
e1_context->sdap->remove(e1_context->sdap);
e1_context->sdap = NULL;
}
/* PDCP bearers */
for (int i = 0; i < MAX_DRBS_PER_PDU_SESSION; i++)
if (e1_context->drbs[i].pdcp != NULL) {
e1_context->drbs[i].pdcp->delete_entity(e1_context->drbs[i].pdcp);
e1_context->drbs[i].pdcp = NULL;
}
free(e1_context);
/* the search will now restart from the beginning of the RB tree */
}
}

View File

@@ -0,0 +1,35 @@
#ifndef E1AP_CONTEXT_H_
#define E1AP_CONTEXT_H_
#include <stdint.h>
#define __unused __attribute__((unused))
#include "common/utils/collection/tree.h"
#include "nr_pdcp/nr_pdcp_entity.h"
#include "SDAP/nr_sdap/nr_sdap_entity.h"
#include "common/platform_constants.h"
RB_HEAD(cuup_pdu_sessions_rbtree_t, e1ap_cuup_context_t);
typedef struct cuup_pdu_sessions_rbtree_t cuup_pdu_sessions_rbtree_t;
typedef struct {
nr_pdcp_entity_t *pdcp;
teid_t gtpu_tunnel_id;
} e1ap_drb_context_t;
typedef struct e1ap_cuup_context_t {
/* ID of a context is made of cu_ue_id and sessionId */
uint64_t cu_up_ue_id;
long sessionId;
uint32_t n3_tunnel_id;
nr_sdap_entity_t *sdap;
e1ap_drb_context_t drbs[MAX_DRBS_PER_PDU_SESSION]; /* index this array with drb_id - 1 */
RB_ENTRY(e1ap_cuup_context_t) rb_opaque;
} e1ap_cuup_context_t;
e1ap_cuup_context_t *new_e1ap_cuup_context(uint64_t cu_up_ue_id, long sessionId);
e1ap_cuup_context_t *get_e1ap_cuup_context(uint64_t cu_up_ue_id, long sessionId);
void remove_e1ap_cuup_ue(uint64_t cu_up_ue_id);
#endif /* E1AP_CONTEXT_H_ */

View File

@@ -117,9 +117,6 @@ int CU_handle_UL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id
return -1;
}
/* the RLC-PDCP does not transport the DU UE ID (yet), so we drop it here.
* For the moment, let's hope this won't become relevant; to sleep in peace,
* let's put an assert to check that it is the expected DU UE ID. */
f1_ue_data_t ue_data = cu_get_f1_ue_data(msg.gNB_CU_ue_id);
if (ue_data.secondary_ue != msg.gNB_DU_ue_id) {
LOG_E(F1AP, "unexpected DU UE ID %u received, expected it to be %u\n", ue_data.secondary_ue, msg.gNB_DU_ue_id);
@@ -132,30 +129,21 @@ int CU_handle_UL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id
else
LOG_D(F1AP, "UL RRC MESSAGE for SRB %d in DCCH \n", msg.srb_id);
protocol_ctxt_t ctxt = {
.instance = instance,
.module_id = instance,
.enb_flag = 1,
.eNB_index = 0,
.rntiMaybeUEid = msg.gNB_CU_ue_id,
};
LOG_D(F1AP,
"[UE %lx] calling pdcp_data_ind for SRB %d with size %d (DCCH) \n",
ctxt.rntiMaybeUEid,
"[UE %x] sending F1AP_UL_RRC_MESSAGE to RRC for SRB %d with size %d (DCCH) \n",
msg.gNB_CU_ue_id,
msg.srb_id,
msg.rrc_container_length);
uint8_t *mb = malloc16(msg.rrc_container_length);
memcpy(mb, msg.rrc_container, msg.rrc_container_length);
nr_pdcp_data_ind(&ctxt,
1, // srb_flag
0, // embms_flag
msg.srb_id,
msg.rrc_container_length,
mb,
NULL,
NULL);
MessageDef *rrc_msg = itti_alloc_new_message(TASK_PDCP_GNB, 0, F1AP_UL_RRC_MESSAGE);
AssertFatal(rrc_msg != NULL, "OUT OF MEMORY\n");
f1ap_ul_rrc_message_t *ul_rrc = &F1AP_UL_RRC_MESSAGE(rrc_msg);
*ul_rrc = msg;
ul_rrc->rrc_container = malloc(msg.rrc_container_length);
AssertFatal(ul_rrc->rrc_container != NULL, "OUT OF MEMORY\n");
memcpy(ul_rrc->rrc_container, msg.rrc_container, msg.rrc_container_length);
itti_send_msg_to_task(TASK_RRC_GNB, 0, rrc_msg);
/* Free UL RRC Message Transfer */
free_ul_rrc_message_transfer(&msg);
return 0;

View File

@@ -1953,19 +1953,36 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
logical_chan_id_t lcid = DL_SCH_LCID_CCCH;
if (current_harq_pid < 0) {
// Check for data on SRB0 (RRCSetup)
mac_rlc_status_resp_t srb_status = mac_rlc_status_ind(module_idP, ra->rnti, module_idP, frameP, slotP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, 0, 0);
nr_rlc_entity_buffer_status_t srb_status;
int bytes_in_buffer = 0;
if (srb_status.bytes_in_buffer == 0) {
// Check for data on SRB0 (RRCSetup)
if (UE->srb[0]) {
UE->srb[0]->set_time(UE->srb[0], get_nr_rlc_current_time());
srb_status = UE->srb[0]->buffer_status(UE->srb[0], 10000);
bytes_in_buffer = srb_status.status_size
+ srb_status.retx_size
+ srb_status.tx_size;
}
if (bytes_in_buffer == 0) {
lcid = DL_SCH_LCID_DCCH;
// Check for data on SRB1 (RRCReestablishment, RRCReconfiguration)
srb_status = mac_rlc_status_ind(module_idP, ra->rnti, module_idP, frameP, slotP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, 0, 0);
nr_rlc_rb_type rb_type = UE->lcid2rb[lcid].type;
int rb_id = UE->lcid2rb[lcid].choice.srb_id;
if (rb_type == NR_RLC_SRB && UE->srb[rb_id]) {
UE->srb[rb_id]->set_time(UE->srb[rb_id], get_nr_rlc_current_time());
srb_status = UE->srb[rb_id]->buffer_status(UE->srb[rb_id], 10000);
bytes_in_buffer = srb_status.status_size
+ srb_status.retx_size
+ srb_status.tx_size;
}
}
// Need to wait until data for Msg4 is ready
if (srb_status.bytes_in_buffer == 0)
if (bytes_in_buffer == 0)
return;
mac_sdu_length = srb_status.bytes_in_buffer;
mac_sdu_length = bytes_in_buffer;
}
const int n_slots_frame = nr_slots_per_frame[dl_bwp->scs];
@@ -2137,17 +2154,16 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
uint8_t buffer[CCCH_SDU_SIZE];
uint8_t mac_subheader_len = sizeof(NR_MAC_SUBHEADER_SHORT);
// Get RLC data on the SRB (RRCSetup, RRCReestablishment)
mac_sdu_length = mac_rlc_data_req(module_idP,
ra->rnti,
module_idP,
frameP,
ENB_FLAG_YES,
MBMS_FLAG_NO,
lcid,
CCCH_SDU_SIZE,
(char *)buffer,
0,
0);
nr_rlc_rb_type rb_type = UE->lcid2rb[lcid].type;
int rb_id = UE->lcid2rb[lcid].choice.srb_id;
if (rb_type == NR_RLC_SRB && UE->srb[rb_id]) {
nr_rlc_entity_t *rlc = UE->srb[rb_id];
rlc->set_time(rlc, get_nr_rlc_current_time());
/* todo: convert buffer argument to uint8_t * to remove the cast */
mac_sdu_length = rlc->generate_pdu(rlc, (char *)buffer, CCCH_SDU_SIZE);
} else {
mac_sdu_length = 0;
}
if (mac_sdu_length < 256) {
((NR_MAC_SUBHEADER_SHORT *)&buf[mac_pdu_length])->R = 0;

View File

@@ -36,6 +36,7 @@
#include "NR_MAC_COMMON/nr_mac_extern.h"
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
#include "LAYER2/RLC/rlc.h"
#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
/*TAG*/
#include "NR_TAG-Id.h"
@@ -337,16 +338,31 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_fram
if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt))
continue;
start_meas(&RC.nrmac[module_id]->rlc_status_ind);
sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id,
rnti,
module_id,
frame,
slot,
ENB_FLAG_YES,
MBMS_FLAG_NO,
lcid,
0,
0);
nr_rlc_rb_type rb_type = UE->lcid2rb[lcid].type;
if (rb_type == NR_RLC_NONE)
continue;
int rb_id;
nr_rlc_entity_t *rlc;
if (rb_type == NR_RLC_SRB) {
rb_id = UE->lcid2rb[lcid].choice.srb_id;
rlc = UE->srb[rb_id];
} else {
rb_id = UE->lcid2rb[lcid].choice.drb_id;
rlc = UE->drb[rb_id];
}
if (rlc == NULL)
continue;
rlc->set_time(rlc, get_nr_rlc_current_time());
nr_rlc_entity_buffer_status_t status = rlc->buffer_status(rlc, 1000*1000);
sched_ctrl->rlc_status[lcid] = (mac_rlc_status_resp_t){
.bytes_in_buffer = status.status_size
+ status.retx_size
+ status.tx_size,
.pdus_in_buffer = 0, /* todo: report this value */
.head_sdu_creation_time = 0,
.head_sdu_remaining_size_to_send = 0,
.head_sdu_is_segmented = false
};
stop_meas(&RC.nrmac[module_id]->rlc_status_ind);
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
@@ -1292,17 +1308,25 @@ void nr_schedule_ue_spec(module_id_t module_id,
* such that TBS is full */
const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer,
bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG));
tbs_size_t len = mac_rlc_data_req(module_id,
rnti,
module_id,
frame,
ENB_FLAG_YES,
MBMS_FLAG_NO,
lcid,
ndata,
(char *)buf+sizeof(NR_MAC_SUBHEADER_LONG),
0,
0);
nr_rlc_entity_t *rlc = NULL;
switch (UE->lcid2rb[lcid].type) {
case NR_RLC_SRB:
rlc = UE->srb[UE->lcid2rb[lcid].choice.srb_id];
break;
case NR_RLC_DRB:
rlc = UE->drb[UE->lcid2rb[lcid].choice.drb_id];
break;
case NR_RLC_NONE:
/* nothing to do */
break;
}
if (rlc == NULL)
break;
rlc->set_time(rlc, get_nr_rlc_current_time());
/* todo: remove cast to char * */
tbs_size_t len = rlc->generate_pdu(rlc, (char *)buf+sizeof(NR_MAC_SUBHEADER_LONG), ndata);
LOG_D(NR_MAC,
"%4d.%2d RNTI %04x: %d bytes from %s %d (ndata %d, remaining size %ld)\n",
frame,

View File

@@ -3222,10 +3222,9 @@ void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_
}
}
void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data)
void send_initial_ul_rrc_message(NR_UE_info_t *UE, uint8_t *sdu, sdu_size_t sdu_len)
{
gNB_MAC_INST *mac = RC.nrmac[0];
NR_UE_info_t *UE = (NR_UE_info_t *)data;
NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
uint8_t du2cu[1024];
@@ -3236,9 +3235,9 @@ void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_le
const f1ap_initial_ul_rrc_message_t ul_rrc_msg = {
.plmn = mac->f1_config.setup_req->cell[0].info.plmn,
.nr_cellid = mac->f1_config.setup_req->cell[0].info.nr_cellid,
.gNB_DU_ue_id = rnti,
.crnti = rnti,
.rrc_container = (uint8_t *) sdu,
.gNB_DU_ue_id = UE->rnti,
.crnti = UE->rnti,
.rrc_container = sdu,
.rrc_container_length = sdu_len,
.du2cu_rrc_container = (uint8_t *) du2cu,
.du2cu_rrc_container_length = encoded
@@ -3246,14 +3245,48 @@ void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_le
mac->mac_rrc.initial_ul_rrc_message_transfer(0, &ul_rrc_msg);
}
static void deliver_sdu_srb0(void *deliver_sdu_data, struct nr_rlc_entity_t *entity,
char *buf, int size)
{
NR_UE_info_t *UE = deliver_sdu_data;
send_initial_ul_rrc_message(UE, (unsigned char *)buf, size);
}
static void deliver_sdu_srb1(void *_ue, nr_rlc_entity_t *entity, char *buf, int size)
{
NR_UE_info_t *UE = _ue;
int srb_id = 1;
uint8_t *buf_copy = malloc(size);
AssertFatal(buf_copy, "out of memory\n");
memcpy(buf_copy, buf, size);
l2_enqueue(UE->srb_queue_ul[srb_id], (uint8_t *)buf_copy, size);
}
static void successful_delivery_srb1(void *ue, nr_rlc_entity_t *entity, int sdu_id)
{
LOG_D(MAC, "successful_delivery_srb1 sdu_id %d\n", sdu_id);
/* todo: report successful delivery to rrc (or f1ap) */
}
static void max_retx_reached(void *ue, nr_rlc_entity_t *entity)
{
LOG_E(MAC, "max_retx_reached\n");
exit(1);
}
bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE)
{
NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
/* activate SRB0 */
if (!nr_rlc_activate_srb0(UE->rnti, UE, send_initial_ul_rrc_message))
if (UE->srb[0] != NULL)
return false;
UE->srb[0] = new_nr_rlc_entity_tm(10000, deliver_sdu_srb0, UE);
UE->lcid2rb[0].type = NR_RLC_SRB;
UE->lcid2rb[0].choice.srb_id = 0;
/* create this UE's initial CellGroup */
int CC_id = 0;
int srb_id = 1;
@@ -3267,7 +3300,13 @@ bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE)
DevAssert(cellGroupConfig->rlc_BearerToAddModList->list.count == 1);
const NR_RLC_BearerConfig_t *bearer = cellGroupConfig->rlc_BearerToAddModList->list.array[0];
DevAssert(bearer->servedRadioBearer->choice.srb_Identity == srb_id);
nr_rlc_add_srb(UE->rnti, bearer->servedRadioBearer->choice.srb_Identity, bearer);
UE->srb_queue_dl[srb_id] = new_l2_queue(1024);
UE->srb_queue_ul[srb_id] = new_l2_queue(1024);
UE->srb[srb_id] = nr_rlc_new_srb(bearer, deliver_sdu_srb1, successful_delivery_srb1, max_retx_reached, UE);
int lcid = bearer->logicalChannelIdentity;
DevAssert(lcid >= 1 && lcid <= 32);
UE->lcid2rb[lcid].type = NR_RLC_SRB;
UE->lcid2rb[lcid].choice.srb_id = srb_id;
int priority = bearer->mac_LogicalChannelConfig->ul_SpecificParameters->priority;
nr_lc_config_t c = {.lcid = bearer->logicalChannelIdentity, .priority = priority};

View File

@@ -347,17 +347,9 @@ static int nr_process_mac_pdu(instance_t module_idP,
LOG_I(MAC, "[RAPROC] Received SDU for CCCH length %d for UE %04x\n", mac_len, UE->rnti);
if (prepare_initial_ul_rrc_message(RC.nrmac[module_idP], UE)) {
mac_rlc_data_ind(module_idP,
UE->rnti,
module_idP,
frameP,
ENB_FLAG_YES,
MBMS_FLAG_NO,
0,
(char *)(pduP + mac_subheader_len),
mac_len,
1,
NULL);
UE->srb[0]->set_time(UE->srb[0], get_nr_rlc_current_time());
/* todo: change pdu type to uint8_t * everywhere */
UE->srb[0]->recv_pdu(UE->srb[0], (char *)pduP + mac_subheader_len, mac_len);
} else {
LOG_E(NR_MAC, "prepare_initial_ul_rrc_message() returned false, cannot forward CCCH message\n");
}
@@ -372,20 +364,19 @@ static int nr_process_mac_pdu(instance_t module_idP,
slot,
lcid);
mac_rlc_data_ind(module_idP,
UE->rnti,
module_idP,
frameP,
ENB_FLAG_YES,
MBMS_FLAG_NO,
lcid,
(char *)(pduP + mac_subheader_len),
mac_len,
1,
NULL);
nr_rlc_rb_type rb_type = UE->lcid2rb[lcid].type;
int rb_id = UE->lcid2rb[lcid].choice.srb_id;
if (rb_type != NR_RLC_SRB)
LOG_E(MAC, "no RLC SRB entity found for LCID %d UE ID %d\n", lcid, UE->rnti);
else {
nr_rlc_entity_t *rlc = UE->srb[rb_id];
rlc->set_time(rlc, get_nr_rlc_current_time());
/* todo: uint8_t * to remove cast to char * */
rlc->recv_pdu(rlc, (char *)(pduP + mac_subheader_len), mac_len);
UE->mac_stats.ul.total_sdu_bytes += mac_len;
UE->mac_stats.ul.lc_bytes[lcid] += mac_len;
UE->mac_stats.ul.total_sdu_bytes += mac_len;
UE->mac_stats.ul.lc_bytes[lcid] += mac_len;
}
break;
case UL_SCH_LCID_DTCH ...(UL_SCH_LCID_DTCH + 28):

View File

@@ -456,7 +456,6 @@ long get_lcid_from_drbid(int drb_id);
long get_lcid_from_srbid(int srb_id);
bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE);
void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data);
void finish_nr_dl_harq(NR_UE_sched_ctrl_t *sched_ctrl, int harq_pid);
void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid);
@@ -481,4 +480,6 @@ bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid);
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti);
void nr_mac_get_l2_queues_srb(int rnti, int srb_id, l2_queue_t **dl, l2_queue_t **ul);
#endif /*__LAYER2_NR_MAC_PROTO_H__*/

View File

@@ -890,6 +890,9 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
gtpv1u_update_ue_id(f1inst, *dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id);
}
/* the DU ue id is the RNTI */
nr_rlc_srb_recv_sdu(dl_rrc->gNB_DU_ue_id, dl_rrc->srb_id, dl_rrc->rrc_container, dl_rrc->rrc_container_length);
nr_rlc_entity_t *rlc = UE->srb[dl_rrc->srb_id];
DevAssert(rlc);
rlc->set_time(rlc, get_nr_rlc_current_time());
/* todo: change type of pdu buffer to uint8_t * everywhere */
rlc->recv_sdu(rlc, (char *)dl_rrc->rrc_container, dl_rrc->rrc_container_length, -1);
}

View File

@@ -351,3 +351,20 @@ void nr_mac_send_f1_setup_req(void)
DevAssert(mac);
mac->mac_rrc.f1_setup_request(mac->f1_config.setup_req);
}
void nr_mac_get_l2_queues_srb(int rnti, int srb_id, l2_queue_t **dl, l2_queue_t **ul)
{
gNB_MAC_INST *mac = RC.nrmac[0];
DevAssert(mac);
/* todo: speedup, no list search */
UE_iterator(RC.nrmac[0]->UE_info.list, UE) {
if (UE->rnti == rnti) {
*dl = UE->srb_queue_dl[srb_id];
*ul = UE->srb_queue_ul[srb_id];
return;
}
}
LOG_E(MAC, "l2 get queues: UE rnti %d not found\n", rnti);
*dl = NULL;
*ul = NULL;
}

View File

@@ -44,6 +44,7 @@
#include <pthread.h>
#include "common/utils/ds/seq_arr.h"
#include "common/utils/nr/nr_common.h"
#include "common/utils/l2_queue.h"
#define NR_SCHED_LOCK(lock) \
do { \
@@ -75,6 +76,9 @@
#include "NR_BCCH-DL-SCH-Message.h"
#include "openair2/RRC/NR/nr_rrc_config.h"
/* RLC */
#include "nr_rlc/nr_rlc_entity.h"
/* PHY */
#include "time_meas.h"
@@ -747,6 +751,11 @@ typedef enum interrupt_followup_action { FOLLOW_INSYNC, FOLLOW_INSYNC_RECONFIG,
typedef struct {
rnti_t rnti;
uid_t uid; // unique ID of this UE
nr_rlc_entity_t *srb[4];
l2_queue_t *srb_queue_ul[4];
l2_queue_t *srb_queue_dl[4];
nr_rlc_entity_t *drb[MAX_DRBS_PER_UE];
nr_rlc_rb_t lcid2rb[33]; /* we access indexes 1..32 */
/// scheduling control info
nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG];
NR_UE_sched_ctrl_t UE_sched_ctrl;

View File

@@ -39,94 +39,17 @@
#include "constr_TYPE.h"
#include "cuup_cucp_if.h"
#include "gtpv1_u_messages_types.h"
#include "nr_pdcp/nr_pdcp_asn1_utils.h"
#include "nr_pdcp/nr_pdcp_entity.h"
#include "nr_pdcp_oai_api.h"
#include "openair2/COMMON/e1ap_messages_types.h"
#include "openair2/E1AP/e1ap_common.h"
#include "openair2/E1AP/e1ap_context.h"
#include "openair2/F1AP/f1ap_common.h"
#include "openair2/F1AP/f1ap_ids.h"
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "openair3/ocp-gtpu/gtp_itf.h"
static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, const pdu_session_to_setup_t *pdu)
{
for (int i = 0; i < pdu->numDRB2Setup; i++) {
const DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + i;
asn1cSequenceAdd(DRB_configList->list, struct NR_DRB_ToAddMod, ie);
ie->drb_Identity = drb->id;
ie->cnAssociation = CALLOC(1, sizeof(*ie->cnAssociation));
ie->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config;
// sdap_Config
asn1cCalloc(ie->cnAssociation->choice.sdap_Config, sdap_config);
sdap_config->pdu_Session = pdu->sessionId;
/* SDAP */
sdap_config->sdap_HeaderDL = drb->sdap_config.sDAP_Header_DL;
sdap_config->sdap_HeaderUL = drb->sdap_config.sDAP_Header_UL;
sdap_config->defaultDRB = drb->sdap_config.defaultDRB;
asn1cCalloc(sdap_config->mappedQoS_FlowsToAdd, FlowsToAdd);
for (int j = 0; j < drb->numQosFlow2Setup; j++) {
asn1cSequenceAdd(FlowsToAdd->list, NR_QFI_t, qfi);
*qfi = drb->qosFlows[j].qfi;
}
sdap_config->mappedQoS_FlowsToRelease = NULL;
// pdcp_Config
ie->reestablishPDCP = NULL;
ie->recoverPDCP = NULL;
asn1cCalloc(ie->pdcp_Config, pdcp_config);
asn1cCalloc(pdcp_config->drb, drbCfg);
asn1cCallocOne(drbCfg->discardTimer, drb->pdcp_config.discardTimer);
asn1cCallocOne(drbCfg->pdcp_SN_SizeUL, drb->pdcp_config.pDCP_SN_Size_UL);
asn1cCallocOne(drbCfg->pdcp_SN_SizeDL, drb->pdcp_config.pDCP_SN_Size_DL);
drbCfg->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed;
drbCfg->headerCompression.choice.notUsed = 0;
drbCfg->integrityProtection = NULL;
drbCfg->statusReportRequired = NULL;
drbCfg->outOfOrderDelivery = NULL;
pdcp_config->moreThanOneRLC = NULL;
pdcp_config->t_Reordering = calloc(1, sizeof(*pdcp_config->t_Reordering));
*pdcp_config->t_Reordering = drb->pdcp_config.reorderingTimer;
pdcp_config->ext1 = NULL;
const security_indication_t *sec = &pdu->securityIndication;
if (sec->integrityProtectionIndication == SECURITY_REQUIRED ||
sec->integrityProtectionIndication == SECURITY_PREFERRED) {
asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled);
}
if (sec->confidentialityProtectionIndication == SECURITY_NOT_NEEDED) {
asn1cCalloc(pdcp_config->ext1, ext1);
asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true);
}
}
}
static int drb_gtpu_create(instance_t instance,
uint32_t ue_id,
int incoming_id,
int outgoing_id,
int qfi,
in_addr_t tlAddress, // only IPv4 now
teid_t outgoing_teid,
gtpCallback callBack,
gtpCallbackSDAP callBackSDAP,
gtpv1u_gnb_create_tunnel_resp_t *create_tunnel_resp)
{
gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0};
create_tunnel_req.incoming_rb_id[0] = incoming_id;
create_tunnel_req.pdusession_id[0] = outgoing_id;
memcpy(&create_tunnel_req.dst_addr[0].buffer, &tlAddress, sizeof(uint8_t) * 4);
create_tunnel_req.dst_addr[0].length = 32;
create_tunnel_req.outgoing_teid[0] = outgoing_teid;
create_tunnel_req.outgoing_qfi[0] = qfi;
create_tunnel_req.num_tunnels = 1;
create_tunnel_req.ue_id = ue_id;
// we use gtpv1u_create_ngu_tunnel because it returns the interface
// address and port of the interface; apart from that, we also might call
// newGtpuCreateTunnel() directly
return gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, create_tunnel_resp, callBack, callBackSDAP);
}
static instance_t get_n3_gtp_instance(void)
{
const e1ap_upcp_inst_t *inst = getCxtE1(0);
@@ -142,6 +65,99 @@ static instance_t get_f1_gtp_instance(void)
return inst->gtpInst;
}
static void deliver_pdcp_sdu(void *deliver_sdu_data,
nr_pdcp_entity_t *entity,
uint8_t *buf,
int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
e1ap_cuup_context_t *e1_context = deliver_sdu_data;
if (e1_context->sdap == NULL)
return;
e1_context->sdap->recv_pdu(e1_context->sdap, buf, size, entity->rb_id, entity->has_sdap_rx);
}
static void deliver_pdcp_pdu(void *deliver_pdu_data,
ue_id_t ue_id,
int rb_id,
uint8_t *buf,
int size,
int sdu_id)
{
abort();
}
static void deliver_sdap_pdu(void *deliver_pdu_data, int rb_id, uint8_t *buf, int size)
{
e1ap_cuup_context_t *e1_context = deliver_pdu_data;
if (e1_context->drbs[rb_id - 1].pdcp == NULL) {
LOG_E(SDAP, "no PDCP context found for DRB %d\n", rb_id);
return;
}
int max_size = nr_max_pdcp_pdu_size(size);
uint8_t pdu_buf[max_size];
int pdu_size = e1_context->drbs[rb_id - 1].pdcp->process_sdu(e1_context->drbs[rb_id - 1].pdcp,
buf,
size,
0, /* sdu_id, not used */
pdu_buf,
max_size);
if (pdu_size == -1) {
LOG_E(PDCP, "failure to process SDAP PDU\n");
return;
}
gtpv1uSendDirect(get_f1_gtp_instance(), e1_context->cu_up_ue_id, rb_id, pdu_buf, pdu_size, false, false);
}
static bool gtp_f1_ul_callback(void *gtp_callback_data,
ue_id_t ue_id,
int pdu_session_id,
int rb_id,
int qfi,
int rqi,
uint8_t *buf,
int size)
{
DevAssert(rb_id >= 1 && rb_id <= MAX_DRBS_PER_PDU_SESSION);
e1ap_cuup_context_t *e1_context = gtp_callback_data;
if (e1_context->drbs[rb_id - 1].pdcp == NULL) {
LOG_W(E1AP, "no DRB %d found for ue %ld, ignore input data of size %d\n", rb_id, ue_id, size);
return false;
}
e1_context->drbs[rb_id - 1].pdcp->recv_pdu(e1_context->drbs[rb_id - 1].pdcp, buf, size);
return true;
}
static bool gtp_n3_dl_callback(void *gtp_callback_data,
ue_id_t ue_id,
int pdu_session_id,
int rb_id,
int qfi,
int rqi,
uint8_t *buf,
int size)
{
DevAssert(rb_id >= 1 && rb_id <= MAX_DRBS_PER_PDU_SESSION);
e1ap_cuup_context_t *e1_context = gtp_callback_data;
if (e1_context->sdap == NULL) {
LOG_W(E1AP, "no SDAP for pdu session %d found for ue %ld, ignore input data of size %d\n", pdu_session_id, ue_id, size);
return false;
}
e1_context->sdap->recv_sdu(e1_context->sdap, buf, size, rb_id, qfi);
return true;
}
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
{
bool need_ue_id_mgmt = e1_used();
@@ -157,11 +173,17 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
instance_t n3inst = get_n3_gtp_instance();
instance_t f1inst = get_f1_gtp_instance();
if (f1inst < 0) abort();
e1ap_bearer_setup_resp_t resp = {
.gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id,
.gNB_cu_up_ue_id = cu_up_ue_id,
};
resp.numPDUSessions = req->numPDUSessions;
/* to check that all DRB IDs are unique across all PDU sessions */
bool drb_in_use[32] = { false };
for (int i = 0; i < resp.numPDUSessions; ++i) {
pdu_session_setup_t *resp_pdu = resp.pduSession + i;
const pdu_session_to_setup_t *req_pdu = req->pduSession + i;
@@ -181,58 +203,146 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
qosflowSetup->qfi = qosflow2Setup->qfi;
}
// GTP tunnel for N3/to core
gtpv1u_gnb_create_tunnel_resp_t resp_n3 = {0};
int qfi = req_drb->qosFlows[0].qfi;
int ret = drb_gtpu_create(n3inst,
cu_up_ue_id,
req_drb->id,
req_pdu->sessionId,
qfi,
req_pdu->UP_TL_information.tlAddress,
req_pdu->UP_TL_information.teId,
nr_pdcp_data_req_drb,
sdap_data_req,
&resp_n3);
AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n");
AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n");
resp_pdu->teId = resp_n3.gnb_NGu_teid[0];
memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4);
e1ap_cuup_context_t *e1_context = new_e1ap_cuup_context(cu_up_ue_id, req_pdu->sessionId);
// create PDCP bearers. This will also create SDAP bearers
NR_DRB_ToAddModList_t DRB_configList = {0};
fill_DRB_configList_e1(&DRB_configList, req_pdu);
nr_pdcp_entity_security_keys_and_algos_t security_parameters;
security_parameters.ciphering_algorithm = req->cipheringAlgorithm;
security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE);
nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE
cu_up_ue_id,
&DRB_configList,
&security_parameters);
ASN_STRUCT_RESET(asn_DEF_NR_DRB_ToAddModList, &DRB_configList.list);
if (f1inst >= 0) { /* we have F1(-U) */
teid_t dummy_teid = 0xffff; // we will update later with answer from DU
in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU
gtpv1u_gnb_create_tunnel_resp_t resp_f1 = {0};
int qfi = -1; // don't put PDU session marker in GTP
int ret = drb_gtpu_create(f1inst,
cu_up_ue_id,
req_drb->id,
req_drb->id,
qfi,
dummy_address,
dummy_teid,
cu_f1u_data_req,
NULL,
&resp_f1);
resp_drb->numUpParam = 1;
AssertFatal(ret >= 0, "Unable to create GTP Tunnel for F1-U\n");
memcpy(&resp_drb->UpParamList[0].tlAddress, &resp_f1.gnb_addr.buffer, 4);
resp_drb->UpParamList[0].teId = resp_f1.gnb_NGu_teid[0];
/* create SDAP entity */
e1_context->sdap = new_nr_sdap_entity2_gnb(cu_up_ue_id,
req_pdu->sessionId,
deliver_sdap_pdu,
e1_context);
/* check that all QFIs are unique in the PDU session */
/* we also need all DRB IDs to be unique across all sessions
* (this restriction may be removed if needed, as far as the
* specifications are understood correctly it should be possible
* to have the same DRB ID used in two different PDU sessions, but
* as of writing this comment, the GTP module needs unique DRB IDs)
*/
bool check_qfi[SDAP_MAX_QFI] = { false };
for (int i = 0; i < req_pdu->numDRB2Setup; i++) {
const DRB_nGRAN_to_setup_t *drb = &req_pdu->DRBnGRanList[i];
DevAssert(drb->id >= 1 && drb->id <= 32);
DevAssert(drb_in_use[drb->id - 1] == false);
drb_in_use[drb->id - 1] = true;
for (int j = 0; j < drb->numQosFlow2Setup; j++) {
DevAssert(drb->qosFlows[j].qfi >= 1 && drb->qosFlows[j].qfi <= SDAP_MAX_QFI);
DevAssert(check_qfi[drb->qosFlows[j].qfi - 1] == false);
check_qfi[drb->qosFlows[j].qfi - 1] = true;
}
}
/* create PDCP bearers, SDAP QoS flows and GTP-U UL UP endpoints */
nr_pdcp_entity_security_keys_and_algos_t security_parameters;
if (req_pdu->securityIndication.confidentialityProtectionIndication == SECURITY_NOT_NEEDED) {
security_parameters.ciphering_algorithm = 0;
memset(security_parameters.ciphering_key, 0, NR_K_KEY_SIZE);
} else {
security_parameters.ciphering_algorithm = req->cipheringAlgorithm;
memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE);
}
if (req_pdu->securityIndication.integrityProtectionIndication == SECURITY_NOT_NEEDED) {
security_parameters.integrity_algorithm = 0;
memset(security_parameters.integrity_key, 0, NR_K_KEY_SIZE);
} else {
security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm;
memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE);
}
for (int i = 0; i < req_pdu->numDRB2Setup; i++) {
const DRB_nGRAN_to_setup_t *drb = &req_pdu->DRBnGRanList[i];
int rb_id = drb->id;
/* only accept IDs in [1..32], to be refined if needed */
DevAssert(rb_id >= 1 && rb_id <= MAX_DRBS_PER_PDU_SESSION);
/* for gNB: SDAP rx is UL and SDAP tx is DL */
/* 38.331 forces the use of UL header for the default bearer, see the definition of 'SDAP-Config' */
/* 37.324 5.2.1 Note 2 says the same */
AssertFatal(!drb->sdap_config.defaultDRB || drb->sdap_config.sDAP_Header_UL == NR_SDAP_Config__sdap_HeaderUL_present,
"default DRB must have Header UL present\n");
bool has_sdap_rx_header = drb->sdap_config.sDAP_Header_UL == NR_SDAP_Config__sdap_HeaderUL_present;
bool has_sdap_tx_header = drb->sdap_config.sDAP_Header_DL == NR_SDAP_Config__sdap_HeaderDL_present;
/* accept only one default DRB */
DevAssert(!drb->sdap_config.defaultDRB || e1_context->sdap->default_drb == 0);
if (drb->sdap_config.defaultDRB) {
e1_context->sdap->default_drb = rb_id;
e1_context->sdap->default_drb_has_sdap_rx = has_sdap_rx_header;
e1_context->sdap->default_drb_has_sdap_tx = has_sdap_tx_header;
}
/* PDCP entity */
/* limitation: SN size for DL and UL must be equal (to be removed if needed) */
DevAssert(drb->pdcp_config.pDCP_SN_Size_UL == drb->pdcp_config.pDCP_SN_Size_DL);
e1_context->drbs[rb_id - 1].pdcp = new_nr_pdcp_entity(NR_PDCP_DRB_AM,
true, /* is_gnb */
cu_up_ue_id,
rb_id,
req_pdu->sessionId,
has_sdap_rx_header,
has_sdap_tx_header,
deliver_pdcp_sdu,
e1_context,
deliver_pdcp_pdu,
e1_context,
decode_sn_size_ul(drb->pdcp_config.pDCP_SN_Size_UL),
decode_t_reordering(drb->pdcp_config.reorderingTimer),
decode_discard_timer(drb->pdcp_config.discardTimer),
&security_parameters);
/* SDAP QoS flows */
for (int j = 0; j < drb->numQosFlow2Setup; j++)
e1_context->sdap->qfi2drb_map_update(e1_context->sdap,
drb->qosFlows[j].qfi,
rb_id,
has_sdap_rx_header,
has_sdap_tx_header);
/* GTP-U UL UP endpoint for this bearer */
uint8_t addr[64] = { 0 };
int addr_len = 0;
int port = 0;
gtpu_get_instance_address_and_port(f1inst, addr, &addr_len, &port);
AssertFatal(addr_len == 4, "only IPv4 supported for the moment\n");
transport_layer_addr_t dummy_addr = { 0 };
dummy_addr.length = 32;
teid_t teid = newGtpuCreateTunnel(f1inst,
cu_up_ue_id,
rb_id,
rb_id, //should be req_pdu->sessionId but does not work... todo: fix
0xffff, /* outgoing teid - will be sent by DU */
-1, /* QoS flow is not used for this GTP-U tunnel */
dummy_addr,
port,
NULL,
NULL);
gtpu_set_callback2(teid, gtp_f1_ul_callback, e1_context);
AssertFatal(teid != GTPNOK, "Unable to create GTP Tunnel for F1-U\n");
e1_context->drbs[rb_id - 1].gtpu_tunnel_id = teid;
memcpy(&resp_drb->UpParamList[resp_drb->numUpParam].tlAddress, addr, 4);
resp_drb->UpParamList[resp_drb->numUpParam].teId = teid;
resp_drb->numUpParam++;
}
// GTP tunnel for N3/to core
transport_layer_addr_t n3_addr = { 0 };
n3_addr.length = 32; /* unit: bits */
uint32_t n3_addr_ip = /*htonl*/(req_pdu->UP_TL_information.tlAddress);
memcpy(n3_addr.buffer, &n3_addr_ip, 4);
int addr_len = 0;
int port = 0;
uint8_t dummy_addr[64] = { 0 };
/* get the port */
gtpu_get_instance_address_and_port(n3inst, dummy_addr, &addr_len, &port);
teid_t teid = newGtpuCreateTunnel(n3inst,
cu_up_ue_id,
req_drb->id,
req_pdu->sessionId, //should be req_pdu->sessionId but does not work... todo: fix
req_pdu->UP_TL_information.teId,
1, /* QoS flow is not used for this GTP-U tunnel */
n3_addr,
port,
NULL,
NULL);
gtpu_set_callback2(teid, gtp_n3_dl_callback, e1_context);
AssertFatal(teid != GTPNOK, "Unable to create GTP Tunnel for F1-U\n");
e1_context->n3_tunnel_id = teid;
resp_pdu->teId = teid;
memcpy(&resp_pdu->tlAddress, dummy_addr, 4);
// We assume all DRBs to setup have been setup successfully, so we always
// send successful outcome in response and no failed DRBs
resp_pdu->numDRBFailed = 0;
@@ -259,6 +369,8 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
/* PDU Session Resource To Modify List (see 9.3.3.11 of TS 38.463) */
for (int i = 0; i < req->numPDUSessionsMod; i++) {
DevAssert(req->pduSessionMod[i].sessionId > 0);
e1ap_cuup_context_t *e1_context = get_e1ap_cuup_context(req->gNB_cu_up_ue_id, req->pduSessionMod[i].sessionId);
AssertFatal(e1_context != NULL, "pdu session %ld not found for UE %d\n", req->pduSessionMod[i].sessionId, req->gNB_cu_up_ue_id);
LOG_I(E1AP,
"UE %d: updating PDU session ID %ld (%ld bearers)\n",
req->gNB_cu_up_ue_id,
@@ -271,6 +383,7 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
const DRB_nGRAN_to_mod_t *to_modif = &req->pduSessionMod[i].DRBnGRanModList[j];
DRB_nGRAN_modified_t *modified = &modif.pduSessionMod[i].DRBnGRanModList[j];
modified->id = to_modif->id;
DevAssert(to_modif->id >= 1 && to_modif->id <= MAX_DRBS_PER_PDU_SESSION);
if (to_modif->pdcp_config.pDCP_Reestablishment) {
nr_pdcp_entity_security_keys_and_algos_t security_parameters;
@@ -278,10 +391,10 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE);
nr_pdcp_reestablishment(req->gNB_cu_up_ue_id,
to_modif->id,
false,
&security_parameters);
nr_pdcp_entity_t *pdcp = e1_context->drbs[to_modif->id - 1].pdcp;
AssertFatal(pdcp != NULL, "pdu session %ld for UE %d does not have DRB %ld to modify\n",
req->pduSessionMod[i].sessionId, req->gNB_cu_up_ue_id, to_modif->id);
pdcp->reestablish_entity(pdcp, &security_parameters);
}
if (f1inst < 0) // no F1-U?
@@ -301,8 +414,6 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd)
{
bool need_ue_id_mgmt = e1_used();
instance_t n3inst = get_n3_gtp_instance();
instance_t f1inst = get_f1_gtp_instance();
@@ -311,12 +422,8 @@ void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd)
newGtpuDeleteAllTunnels(n3inst, cmd->gNB_cu_up_ue_id);
if (f1inst >= 0) // is there F1-U?
newGtpuDeleteAllTunnels(f1inst, cmd->gNB_cu_up_ue_id);
if (need_ue_id_mgmt) {
// see issue #706: in monolithic, gNB will free PDCP of UE
nr_pdcp_remove_UE(cmd->gNB_cu_up_ue_id);
cu_remove_f1_ue_data(cmd->gNB_cu_up_ue_id);
}
nr_sdap_delete_ue_entities(cmd->gNB_cu_up_ue_id);
remove_e1ap_cuup_ue(cmd->gNB_cu_up_ue_id);
e1ap_bearer_release_cplt_t cplt = {
.gNB_cu_cp_ue_id = cmd->gNB_cu_cp_ue_id,

View File

@@ -44,9 +44,8 @@ int nr_max_pdcp_pdu_size(sdu_size_t sdu_size)
}
static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
char *_buffer, int size)
uint8_t *buffer, int size)
{
unsigned char *buffer = (unsigned char *)_buffer;
nr_pdcp_sdu_t *sdu;
int rcvd_sn;
uint32_t rcvd_hfn;
@@ -142,7 +141,7 @@ 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[PDCP_INTEGRITY_SIZE] = {0};
uint8_t 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);
@@ -165,7 +164,7 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
}
sdu = nr_pdcp_new_sdu(rcvd_count,
(char *)buffer + header_size,
buffer + header_size,
size - header_size - integrity_size,
&msg_integrity);
entity->rx_list = nr_pdcp_sdu_list_add(entity->rx_list, sdu);
@@ -215,10 +214,10 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
}
static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity,
char *buffer,
const uint8_t *buffer,
int size,
int sdu_id,
char *pdu_buffer,
uint8_t *pdu_buffer,
int pdu_max_size)
{
uint32_t count;
@@ -226,7 +225,6 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity,
int header_size;
int integrity_size;
int sdap_header_size = 0;
char *buf = pdu_buffer;
DevAssert(nr_max_pdcp_pdu_size(size) <= pdu_max_size);
int dc_bit;
@@ -255,13 +253,13 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity,
}
if (entity->sn_size == SHORT_SN_SIZE) {
buf[0] = dc_bit | ((sn >> 8) & 0xf);
buf[1] = sn & 0xff;
pdu_buffer[0] = dc_bit | ((sn >> 8) & 0xf);
pdu_buffer[1] = sn & 0xff;
header_size = SHORT_PDCP_HEADER_SIZE;
} else {
buf[0] = dc_bit | ((sn >> 16) & 0x3);
buf[1] = (sn >> 8) & 0xff;
buf[2] = sn & 0xff;
pdu_buffer[0] = dc_bit | ((sn >> 16) & 0x3);
pdu_buffer[1] = (sn >> 8) & 0xff;
pdu_buffer[2] = sn & 0xff;
header_size = LONG_PDCP_HEADER_SIZE;
}
@@ -272,24 +270,24 @@ static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity,
integrity_size = 0;
}
memcpy(buf + header_size, buffer, size);
memcpy(pdu_buffer + header_size, buffer, size);
if (entity->has_integrity) {
uint8_t integrity[PDCP_INTEGRITY_SIZE] = {0};
entity->integrity(entity->integrity_context,
integrity,
(unsigned char *)buf, header_size + size,
pdu_buffer, header_size + size,
entity->rb_id, count, entity->is_gnb ? 1 : 0);
memcpy((unsigned char *)buf + header_size + size, integrity, PDCP_INTEGRITY_SIZE);
memcpy(pdu_buffer + 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, PDCP_INTEGRITY_SIZE);
memset(pdu_buffer + header_size + size, 0, PDCP_INTEGRITY_SIZE);
}
if (entity->has_ciphering) {
entity->cipher(entity->security_context,
(unsigned char *)buf + header_size + sdap_header_size,
pdu_buffer + header_size + sdap_header_size,
size + integrity_size - sdap_header_size,
entity->rb_id, count, entity->is_gnb ? 1 : 0);
}
@@ -320,7 +318,7 @@ static bool nr_pdcp_entity_check_integrity(struct nr_pdcp_entity_t *entity,
memcpy(b + header_size, buffer, buffer_size);
unsigned char mac[4];
uint8_t mac[4];
entity->integrity(entity->integrity_context, mac,
b, buffer_size + header_size,
entity->rb_id, msg_integrity->count, entity->is_gnb ? 0 : 1);
@@ -603,16 +601,17 @@ static void nr_pdcp_entity_get_stats(nr_pdcp_entity_t *entity,
nr_pdcp_entity_t *new_nr_pdcp_entity(
nr_pdcp_entity_type_t type,
int is_gnb,
uint64_t ue_id,
int rb_id,
int pdusession_id,
bool has_sdap_rx,
bool has_sdap_tx,
void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
char *buf, int size,
uint8_t *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity),
void *deliver_sdu_data,
void (*deliver_pdu)(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id),
uint8_t *buf, int size, int sdu_id),
void *deliver_pdu_data,
int sn_size,
int t_reordering,
@@ -658,6 +657,7 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
ret->deliver_pdu = deliver_pdu;
ret->deliver_pdu_data = deliver_pdu_data;
ret->ue_id = ue_id;
ret->rb_id = rb_id;
ret->pdusession_id = pdusession_id;
ret->has_sdap_rx = has_sdap_rx;

View File

@@ -25,9 +25,10 @@
#include <stdbool.h>
#include <stdint.h>
#include "common/platform_types.h"
#include "common/platform_constants.h"
#include "nr_pdcp_sdu.h"
#include "openair2/RRC/NR/rrc_gNB_radio_bearers.h"
#include "openair2/RRC/NR/nr_rrc_common.h"
#include "openair3/SECU/secu_defs.h"
/* PDCP Formats according to clause 6.2 of 3GPP TS 38.323 */
@@ -92,9 +93,9 @@ 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);
int (*process_sdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size,
int sdu_id, char *pdu_buffer, int pdu_max_size);
void (*recv_pdu)(struct nr_pdcp_entity_t *entity, uint8_t *buffer, int size);
int (*process_sdu)(struct nr_pdcp_entity_t *entity, const uint8_t *buffer, int size,
int sdu_id, uint8_t *pdu_buffer, int pdu_max_size);
void (*delete_entity)(struct nr_pdcp_entity_t *entity);
void (*release_entity)(struct nr_pdcp_entity_t *entity);
void (*suspend_entity)(struct nr_pdcp_entity_t *entity);
@@ -117,14 +118,15 @@ typedef struct nr_pdcp_entity_t {
/* callbacks provided to the PDCP module */
void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
char *buf, int size,
uint8_t *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity);
void *deliver_sdu_data;
void (*deliver_pdu)(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id);
uint8_t *buf, int size, int sdu_id);
void *deliver_pdu_data;
/* configuration variables */
uint64_t ue_id;
int rb_id;
int pdusession_id;
bool has_sdap_rx;
@@ -154,13 +156,13 @@ typedef struct nr_pdcp_entity_t {
nr_pdcp_entity_security_keys_and_algos_t security_keys_and_algos;
stream_security_context_t *security_context;
void (*cipher)(stream_security_context_t *security_context,
unsigned char *buffer, int length,
uint8_t *buffer, int length,
int bearer, int count, int direction);
void (*free_security)(stream_security_context_t *security_context);
stream_security_context_t *integrity_context;
void (*integrity)(stream_security_context_t *integrity_context,
unsigned char *out,
unsigned char *buffer, int length,
uint8_t *out,
uint8_t *buffer, int length,
int bearer, int count, int direction);
void (*free_integrity)(stream_security_context_t *integrity_context);
/* security/integrity algorithms need to know uplink/downlink information
@@ -182,16 +184,17 @@ typedef struct nr_pdcp_entity_t {
nr_pdcp_entity_t *new_nr_pdcp_entity(
nr_pdcp_entity_type_t type,
int is_gnb,
uint64_t ue_id,
int rb_id,
int pdusession_id,
bool has_sdap_rx,
bool has_sdap_tx,
void (*deliver_sdu)(void *deliver_sdu_data, struct nr_pdcp_entity_t *entity,
char *buf, int size,
uint8_t *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity),
void *deliver_sdu_data,
void (*deliver_pdu)(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id),
uint8_t *buf, int size, int sdu_id),
void *deliver_pdu_data,
int sn_size,
int t_reordering,

View File

@@ -305,7 +305,7 @@ static void do_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP,
rb = nr_pdcp_get_rb(ue, rb_id, srb_flagP);
if (rb != NULL) {
rb->recv_pdu(rb, (char *)sdu_buffer, sdu_buffer_size);
rb->recv_pdu(rb, sdu_buffer, sdu_buffer_size);
} else {
LOG_E(PDCP, "pdcp_data_ind: no RB found (rb_id %ld, srb_flag %d)\n", rb_id, srb_flagP);
}
@@ -433,7 +433,7 @@ static void reblock_tun_socket(void)
static void *enb_tun_read_thread(void *_)
{
extern int nas_sock_fd[];
char rx_buf[NL_MAX_PAYLOAD];
uint8_t rx_buf[NL_MAX_PAYLOAD];
int len;
protocol_ctxt_t ctxt;
ue_id_t UEid;
@@ -476,7 +476,7 @@ static void *enb_tun_read_thread(void *_)
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
len,
(unsigned char *)rx_buf,
rx_buf,
PDCP_TRANSMISSION_MODE_DATA,
NULL,
NULL,
@@ -491,7 +491,7 @@ static void *enb_tun_read_thread(void *_)
static void *ue_tun_read_thread(void *_)
{
extern int nas_sock_fd[];
char rx_buf[NL_MAX_PAYLOAD];
uint8_t rx_buf[NL_MAX_PAYLOAD];
int len;
protocol_ctxt_t ctxt;
ue_id_t UEid;
@@ -534,7 +534,7 @@ static void *ue_tun_read_thread(void *_)
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
len,
(unsigned char *)rx_buf,
rx_buf,
PDCP_TRANSMISSION_MODE_DATA,
NULL,
NULL,
@@ -660,7 +660,7 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id)
}
static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
char *buf, int size,
uint8_t *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
nr_pdcp_ue_t *ue = _ue;
@@ -699,7 +699,7 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
}
static void deliver_pdu_drb_ue(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id)
uint8_t *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data == NULL);
protocol_ctxt_t ctxt = { .enb_flag = 0, .rntiMaybeUEid = ue_id };
@@ -711,7 +711,7 @@ static void deliver_pdu_drb_ue(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
}
static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id,
char *buf, int size, int sdu_id)
uint8_t *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data == NULL);
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
@@ -720,7 +720,7 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id
if (NODE_IS_CU(node_type)) {
LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size);
extern instance_t CUuniqInstance;
gtpv1uSendDirect(CUuniqInstance, ue_id, rb_id, (uint8_t *)buf, size, false, false);
gtpv1uSendDirect(CUuniqInstance, ue_id, rb_id, buf, size, false, false);
} else {
uint8_t *memblock = malloc16(size);
memcpy(memblock, buf, size);
@@ -730,7 +730,7 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id
}
static void deliver_sdu_srb(void *_ue, nr_pdcp_entity_t *entity,
char *buf, int size,
uint8_t *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
nr_pdcp_ue_t *ue = _ue;
@@ -779,7 +779,7 @@ srb_found:
}
void deliver_pdu_srb_rlc(void *deliver_pdu_data, ue_id_t ue_id, int srb_id,
char *buf, int size, int sdu_id)
uint8_t *buf, int size, int sdu_id)
{
protocol_ctxt_t ctxt = { .enb_flag = 1, .rntiMaybeUEid = ue_id };
uint8_t *memblock = malloc16(size);
@@ -807,6 +807,7 @@ void add_srb(int is_gnb,
} else {
pdcp_srb = new_nr_pdcp_entity(NR_PDCP_SRB,
is_gnb,
UEid,
srb_id,
0, // PDU session ID (not relevant)
false, // has SDAP RX (not relevant)
@@ -903,7 +904,7 @@ void add_drb(int is_gnb,
if (nr_pdcp_get_rb(ue, drb_id, false) != NULL) {
LOG_W(PDCP, "warning DRB %d already exist for UE ID %ld, do nothing\n", drb_id, UEid);
} else {
pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, drb_id, pdusession_id,
pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, UEid, drb_id, pdusession_id,
has_sdap_rx, has_sdap_tx, deliver_sdu_drb, ue,
is_gnb ?
deliver_pdu_drb_gnb : deliver_pdu_drb_ue,
@@ -1079,8 +1080,8 @@ bool nr_pdcp_data_req_srb(ue_id_t ue_id,
}
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);
uint8_t pdu_buf[max_size];
int pdu_size = rb->process_sdu(rb, sdu_buffer, sdu_buffer_size, muiP, pdu_buf, max_size);
if (pdu_size == -1) {
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return 0;
@@ -1271,8 +1272,8 @@ bool nr_pdcp_data_req_drb(protocol_ctxt_t *ctxt_pP,
}
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);
uint8_t pdu_buf[max_size];
int pdu_size = rb->process_sdu(rb, sdu_buffer, sdu_buffer_size, muiP, pdu_buf, max_size);
if (pdu_size == -1) {
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return 0;

View File

@@ -111,9 +111,9 @@ bool cu_f1u_data_req(protocol_ctxt_t *ctxt_pP,
const uint32_t *const destinationL2Id);
typedef void (*deliver_pdu)(void *data, ue_id_t ue_id, int srb_id,
char *buf, int size, int sdu_id);
uint8_t *buf, int size, int sdu_id);
/* default implementation of deliver_pdu */
void deliver_pdu_srb_rlc(void *data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id);
void deliver_pdu_srb_rlc(void *data, ue_id_t ue_id, int srb_id, uint8_t *buf, int size, int sdu_id);
bool nr_pdcp_data_req_srb(ue_id_t ue_id,
const rb_id_t rb_id,
const mui_t muiP,

View File

@@ -24,7 +24,7 @@
#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 *nr_pdcp_new_sdu(uint32_t count, uint8_t *buffer, int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
nr_pdcp_sdu_t *ret = calloc(1, sizeof(nr_pdcp_sdu_t));

View File

@@ -28,13 +28,13 @@
typedef struct nr_pdcp_sdu_t {
uint32_t count;
char *buffer;
uint8_t *buffer;
int size;
nr_pdcp_integrity_data_t msg_integrity;
struct nr_pdcp_sdu_t *next;
} nr_pdcp_sdu_t;
nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, char *buffer, int size,
nr_pdcp_sdu_t *nr_pdcp_new_sdu(uint32_t count, uint8_t *buffer, int size,
const nr_pdcp_integrity_data_t *msg_integrity);
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);

View File

@@ -28,6 +28,16 @@
#define NR_SDU_MAX 16000 /* max NR PDCP SDU size is 9000, let's take more */
typedef enum nr_rlc_rb_type { NR_RLC_NONE = 0, NR_RLC_SRB = 1, NR_RLC_DRB = 2 } nr_rlc_rb_type;
typedef struct nr_rlc_rb_t {
nr_rlc_rb_type type;
union {
int srb_id;
int drb_id;
} choice;
} nr_rlc_rb_t;
typedef enum {
NR_RLC_AM,
NR_RLC_UM,

View File

@@ -68,7 +68,7 @@ void unlock_nr_rlc_current_time(void)
AssertFatal(0, "error locking mutex");
}
static uint64_t get_nr_rlc_current_time(void)
uint64_t get_nr_rlc_current_time(void)
{
lock_nr_rlc_current_time();
@@ -747,6 +747,61 @@ void nr_rlc_reconfigure_entity(int ue_id, int lc_id, NR_RLC_Config_t *rlc_Config
nr_rlc_manager_unlock(nr_rlc_ue_manager);
}
nr_rlc_entity_t *nr_rlc_new_srb(const NR_RLC_BearerConfig_t *rlc_BearerConfig,
void (*deliver_sdu)(void *ue, nr_rlc_entity_t *entity, char *buf, int size),
void (*successful_delivery)(void *ue, nr_rlc_entity_t *entity, int sdu_id),
void (*max_retx_reached)(void *ue, nr_rlc_entity_t *entity),
void *ue)
{
struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config;
int t_status_prohibit;
int t_poll_retransmit;
int poll_pdu;
int poll_byte;
int max_retx_threshold;
int t_reassembly;
int sn_field_length;
if (r && r->present == NR_RLC_Config_PR_am) {
struct NR_RLC_Config__am *am;
am = r->choice.am;
t_reassembly = decode_t_reassembly(am->dl_AM_RLC.t_Reassembly);
t_status_prohibit = decode_t_status_prohibit(am->dl_AM_RLC.t_StatusProhibit);
t_poll_retransmit = decode_t_poll_retransmit(am->ul_AM_RLC.t_PollRetransmit);
poll_pdu = decode_poll_pdu(am->ul_AM_RLC.pollPDU);
poll_byte = decode_poll_byte(am->ul_AM_RLC.pollByte);
max_retx_threshold = decode_max_retx_threshold(am->ul_AM_RLC.maxRetxThreshold);
DevAssert(*am->dl_AM_RLC.sn_FieldLength == *am->ul_AM_RLC.sn_FieldLength);
sn_field_length = decode_sn_field_length_am(*am->dl_AM_RLC.sn_FieldLength);
} else {
// default values as in 9.2.1 of 38.331
t_reassembly = 35;
t_status_prohibit = 0;
t_poll_retransmit = 45;
poll_pdu = -1;
poll_byte = -1;
max_retx_threshold = 8;
sn_field_length = 12;
}
AssertFatal(rlc_BearerConfig->servedRadioBearer &&
(rlc_BearerConfig->servedRadioBearer->present ==
NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity),
"servedRadioBearer for SRB mandatory present when setting up an SRB RLC entity\n");
nr_rlc_entity_t *nr_rlc_am = new_nr_rlc_entity_am(RLC_RX_MAXSIZE,
RLC_TX_MAXSIZE,
deliver_sdu, ue,
successful_delivery, ue,
max_retx_reached, ue,
t_poll_retransmit,
t_reassembly, t_status_prohibit,
poll_pdu, poll_byte, max_retx_threshold,
sn_field_length);
LOG_I(RLC, "created new SRB\n");
return (nr_rlc_entity_t *)nr_rlc_am;
}
void nr_rlc_add_srb(int ue_id, int srb_id, const NR_RLC_BearerConfig_t *rlc_BearerConfig)
{
struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config;

View File

@@ -29,6 +29,9 @@
*/
#ifndef NR_RLC_OAI_API_H
#define NR_RLC_OAI_API_H
#include "NR_RLC-BearerConfig.h"
#include "NR_RLC-Config.h"
#include "NR_LogicalChannelIdentity.h"
@@ -69,3 +72,13 @@ bool nr_rlc_activate_srb0(int ue_id,
void (*send_initial_ul_rrc_message)(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data));
bool nr_rlc_get_statistics(int ue_id, int srb_flag, int rb_id, nr_rlc_statistics_t *out);
uint64_t get_nr_rlc_current_time(void);
nr_rlc_entity_t *nr_rlc_new_srb(const NR_RLC_BearerConfig_t *rlc_BearerConfig,
void (*deliver_sdu)(void *ue, nr_rlc_entity_t *entity, char *buf, int size),
void (*successful_delivery)(void *ue, nr_rlc_entity_t *entity, int sdu_id),
void (*max_retx_reached)(void *ue, nr_rlc_entity_t *entity),
void *ue);
#endif /* NR_RLC_OAI_API_H */

View File

@@ -27,16 +27,6 @@
typedef void nr_rlc_ue_manager_t;
typedef enum nr_rlc_rb_type { NR_RLC_NONE = 0, NR_RLC_SRB = 1, NR_RLC_DRB = 2 } nr_rlc_rb_type;
typedef struct nr_rlc_rb_t {
nr_rlc_rb_type type;
union {
int srb_id;
int drb_id;
} choice;
} nr_rlc_rb_t;
typedef void (*rlf_handler_t)(int rnti);
typedef struct nr_rlc_ue_t {

View File

@@ -52,9 +52,4 @@ typedef struct RB_INFO_NR_s {
//MAC_MEAS_REQ_ENTRY *Meas_entry; //may not needed for NB-IoT
} NR_RB_INFO;
typedef struct SRB_INFO_TABLE_ENTRY_NR_s {
uint8_t Active;
uint8_t status;
} NR_SRB_INFO_TABLE_ENTRY;
#endif

View File

@@ -54,6 +54,8 @@
#include "NR_UE-MRDC-Capability.h"
#include "NR_UE-NR-Capability.h"
#include "intertask_interface.h"
#include "nr_pdcp/nr_pdcp_entity.h"
#include "common/utils/l2_queue.h"
// 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs
#define NR_RRC_SETUP_DELAY_MS 10
@@ -180,6 +182,15 @@ typedef enum {
/* forward declaration */
typedef struct nr_handover_context_s nr_handover_context_t;
typedef struct SRB_INFO_TABLE_ENTRY_NR_s {
uint8_t Active;
uint8_t status;
nr_pdcp_entity_t *pdcp;
l2_queue_t *l2_dl_queue;
l2_queue_t *l2_ul_queue;
pthread_t l2_pdcp_srb1_thread;
} NR_SRB_INFO_TABLE_ENTRY;
typedef struct gNB_RRC_UE_s {
time_t last_seen; // last time this UE has been accessed

View File

@@ -47,6 +47,7 @@
#include "F1AP_CauseRadioNetwork.h"
#include "NGAP_CauseRadioNetwork.h"
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "OCTET_STRING.h"
#include "PHY/defs_common.h"
#include "RRC/NR/MESSAGES/asn1_msg.h"
@@ -74,7 +75,6 @@
#include "linear_alloc.h"
#include "ngap_messages_types.h"
#include "nr_pdcp/nr_pdcp_entity.h"
#include "nr_pdcp/nr_pdcp_oai_api.h"
#include "nr_rrc_defs.h"
#include "nr_rrc_extern.h"
#include "oai_asn1.h"
@@ -95,6 +95,7 @@
#include "x2ap_messages_types.h"
#include "xer_encoder.h"
#include "E1AP/lib/e1ap_bearer_context_management.h"
#include "common/utils/system.h"
#ifdef E2_AGENT
#include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h"
@@ -112,11 +113,11 @@ typedef struct deliver_ue_ctxt_release_data_t {
sctp_assoc_t assoc_id;
} deliver_ue_ctxt_release_data_t;
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, uint8_t *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data != NULL);
deliver_ue_ctxt_release_data_t *data = deliver_pdu_data;
data->release_cmd->rrc_container = (uint8_t*) buf;
data->release_cmd->rrc_container = buf;
data->release_cmd->rrc_container_length = size;
data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd);
}
@@ -179,11 +180,11 @@ typedef struct deliver_dl_rrc_message_data_s {
f1ap_dl_rrc_message_t *dl_rrc;
sctp_assoc_t assoc_id;
} deliver_dl_rrc_message_data_t;
static void rrc_deliver_dl_rrc_message(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
static void rrc_deliver_dl_rrc_message(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, uint8_t *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data != NULL);
deliver_dl_rrc_message_data_t *data = (deliver_dl_rrc_message_data_t *)deliver_pdu_data;
data->dl_rrc->rrc_container = (uint8_t *)buf;
data->dl_rrc->rrc_container = buf;
data->dl_rrc->rrc_container_length = size;
DevAssert(data->dl_rrc->srb_id == srb_id);
data->rrc->mac_rrc.dl_rrc_message_transfer(data->assoc_id, data->dl_rrc);
@@ -200,13 +201,21 @@ void nr_rrc_transfer_protected_rrc_message(const gNB_RRC_INST *rrc,
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, .srb_id = srb_id};
deliver_dl_rrc_message_data_t data = {.rrc = rrc, .dl_rrc = &dl_rrc, .assoc_id = ue_data.du_assoc_id};
nr_pdcp_data_req_srb(ue_p->rrc_ue_id,
srb_id,
rrc_gNB_mui++,
size,
(unsigned char *const)buffer,
rrc_deliver_dl_rrc_message,
&data);
int pdu_max_size = nr_max_pdcp_pdu_size(size);
uint8_t pdu_buf[pdu_max_size];
mui_t mui = rrc_gNB_mui;
rrc_gNB_mui++;
int pdu_size = ue_p->Srb[srb_id].pdcp->process_sdu(ue_p->Srb[srb_id].pdcp,
buffer,
size,
mui,
pdu_buf,
pdu_max_size);
if (pdu_size == -1) {
LOG_E(NR_RRC, "PDCP process_sdu failed\n");
return;
}
rrc_deliver_dl_rrc_message(&data, ue_p->rrc_ue_id, srb_id, pdu_buf, pdu_size, mui);
}
///---------------------------------------------------------------------------------------------------------------///
@@ -367,7 +376,34 @@ static void freeSRBlist(NR_SRB_ToAddModList_t *l)
LOG_E(NR_RRC, "Call free SRB list on NULL pointer\n");
}
static void activate_srb(gNB_RRC_UE_t *UE, int srb_id)
static int rrc_gNB_decode_dcch(gNB_RRC_INST *rrc, const f1ap_ul_rrc_message_t *msg);
static void srb_deliver_sdu(void *_rrc, nr_pdcp_entity_t *entity,
uint8_t *buf, int size,
const nr_pdcp_integrity_data_t *msg_integrity)
{
gNB_RRC_INST *rrc = _rrc;
f1ap_ul_rrc_message_t msg = {
.gNB_CU_ue_id = entity->ue_id,
.srb_id = entity->rb_id,
.rrc_container = buf,
.rrc_container_length = size
};
rrc_gNB_decode_dcch(rrc, &msg);
}
static void *srb_pdcp_srb1_thread(void *_ue)
{
gNB_RRC_UE_t *UE = _ue;
while (true) {
l2_buffer_t b = l2_dequeue_wait(UE->Srb[1].l2_ul_queue);
UE->Srb[1].pdcp->recv_pdu(UE->Srb[1].pdcp, b.buffer, b.size);
free(b.buffer);
}
return 0;
}
static void activate_srb(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int srb_id)
{
AssertFatal(srb_id == 1 || srb_id == 2, "handling only SRB 1 or 2\n");
if (UE->Srb[srb_id].Active == 1) {
@@ -377,26 +413,38 @@ static void activate_srb(gNB_RRC_UE_t *UE, int srb_id)
LOG_I(RRC, "activate SRB %d of UE %d\n", srb_id, UE->rrc_ue_id);
UE->Srb[srb_id].Active = 1;
NR_SRB_ToAddModList_t *list = CALLOC(sizeof(*list), 1);
asn1cSequenceAdd(list->list, NR_SRB_ToAddMod_t, srb);
srb->srb_Identity = srb_id;
nr_pdcp_entity_security_keys_and_algos_t security_parameters = { 0 };
if (srb_id == 1) {
nr_pdcp_entity_security_keys_and_algos_t null_security_parameters = {0};
nr_pdcp_add_srbs(true, UE->rrc_ue_id, list, &null_security_parameters);
} else {
nr_pdcp_entity_security_keys_and_algos_t security_parameters;
if (srb_id != 1) {
security_parameters.ciphering_algorithm = UE->ciphering_algorithm;
security_parameters.integrity_algorithm = UE->integrity_algorithm;
nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, security_parameters.ciphering_key);
nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, security_parameters.integrity_key);
nr_pdcp_add_srbs(true,
UE->rrc_ue_id,
list,
&security_parameters);
}
freeSRBlist(list);
int t_Reordering = -1; // infinity as per default SRB configuration in 9.2.1 of 38.331
UE->Srb[srb_id].pdcp = new_nr_pdcp_entity(NR_PDCP_SRB,
true, /* is_gnb */
UE->rrc_ue_id,
srb_id,
0, // PDU session ID (not relevant)
false, // has SDAP RX (not relevant)
false, // has SDAP TX (not relevant)
srb_deliver_sdu,
(void *)rrc,
NULL,
NULL,
SHORT_SN_SIZE,
t_Reordering,
-1,
&security_parameters);
if (NODE_IS_MONOLITHIC(rrc->node_type)) {
nr_mac_get_l2_queues_srb(UE->rnti,
srb_id,
&UE->Srb[srb_id].l2_dl_queue,
&UE->Srb[srb_id].l2_ul_queue);
threadCreate(&UE->Srb[srb_id].l2_pdcp_srb1_thread, srb_pdcp_srb1_thread, UE, "srb1 pdcp", -1, OAI_PRIORITY_RT_LOW);
}
}
//-----------------------------------------------------------------------------
@@ -854,30 +902,43 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context
/* SRBs */
for (int srb_id = 1; srb_id < NR_NUM_SRB; srb_id++) {
if (ue_p->Srb[srb_id].Active)
nr_pdcp_config_set_security(ue_p->rrc_ue_id, srb_id, true, &security_parameters);
ue_p->Srb[srb_id].pdcp->set_security(ue_p->Srb[srb_id].pdcp, &security_parameters);
}
/* Re-establish PDCP for SRB1, according to 5.3.7.4 of 3GPP TS 38.331 */
nr_pdcp_reestablishment(ue_p->rrc_ue_id,
1,
true,
&security_parameters);
ue_p->Srb[1].pdcp->reestablish_entity(ue_p->Srb[1].pdcp, &security_parameters);
/* F1AP DL RRC Message Transfer */
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
uint32_t old_gNB_DU_ue_id = old_rnti;
int srb_id = DL_SCH_LCID_DCCH;
f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
.srb_id = DL_SCH_LCID_DCCH,
.srb_id = srb_id,
.old_gNB_DU_ue_id = &old_gNB_DU_ue_id};
deliver_dl_rrc_message_data_t data = {.rrc = rrc, .dl_rrc = &dl_rrc, .assoc_id = ue_data.du_assoc_id};
nr_pdcp_data_req_srb(ue_p->rrc_ue_id, DL_SCH_LCID_DCCH, rrc_gNB_mui++, size, (unsigned char *const)buffer, rrc_deliver_dl_rrc_message, &data);
int pdu_max_size = nr_max_pdcp_pdu_size(size);
uint8_t pdu_buf[pdu_max_size];
mui_t mui = rrc_gNB_mui;
rrc_gNB_mui++;
int pdu_size = ue_p->Srb[srb_id].pdcp->process_sdu(ue_p->Srb[srb_id].pdcp,
buffer,
size,
mui,
pdu_buf,
pdu_max_size);
if (pdu_size == -1) {
LOG_E(NR_RRC, "PDCP process_sdu failed\n");
return;
}
rrc_deliver_dl_rrc_message(&data, ue_p->rrc_ue_id, srb_id, pdu_buf, pdu_size, mui);
/* RRCReestablishment has been generated, let's enable ciphering now. */
security_parameters.ciphering_algorithm = ue_p->ciphering_algorithm;
/* SRBs */
for (int srb_id = 1; srb_id < NR_NUM_SRB; srb_id++) {
if (ue_p->Srb[srb_id].Active)
nr_pdcp_config_set_security(ue_p->rrc_ue_id, srb_id, true, &security_parameters);
ue_p->Srb[srb_id].pdcp->set_security(ue_p->Srb[srb_id].pdcp, &security_parameters);
}
}
@@ -938,7 +999,7 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR
nr_derive_key(RRC_ENC_ALG, ue_p->ciphering_algorithm, ue_p->kgnb, security_parameters.ciphering_key);
nr_derive_key(RRC_INT_ALG, ue_p->integrity_algorithm, ue_p->kgnb, security_parameters.integrity_key);
nr_pdcp_reestablishment(ue_p->rrc_ue_id, srb_id, true, &security_parameters);
ue_p->Srb[srb_id].pdcp->reestablish_entity(ue_p->Srb[srb_id].pdcp, &security_parameters);
}
/* PDCP Reestablishment of DRBs according to 5.3.5.6.5 of 3GPP TS 38.331 (over E1) */
cuup_notify_reestablishment(rrc, ue_p);
@@ -1061,7 +1122,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc,
UE->establishment_cause = rrcSetupRequest->establishmentCause;
UE->nr_cellid = msg->nr_cellid;
UE->masterCellGroup = cellGroupConfig;
activate_srb(UE, 1);
activate_srb(rrc, UE, 1);
rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length);
}
@@ -1227,7 +1288,7 @@ fallback_rrc_setup:
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, ue_context_p, NGAP_CAUSE_RADIO_NETWORK, ngap_cause);
rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id);
activate_srb(&new->ue_context, 1);
activate_srb(rrc, &new->ue_context, 1);
rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length);
return;
}
@@ -1765,6 +1826,33 @@ static int rrc_gNB_decode_dcch(gNB_RRC_INST *rrc, const f1ap_ul_rrc_message_t *m
return 0;
}
static int rrc_gNB_process_F1AP_UL_RRC_MESSAGE(MessageDef *msg_p, instance_t instance)
{
f1ap_ul_rrc_message_t *msg = &F1AP_UL_RRC_MESSAGE(msg_p);
gNB_RRC_INST *rrc = RC.nrrrc[instance];
/* we look up by CU UE ID! Do NOT change back to RNTI! */
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, msg->gNB_CU_ue_id);
if (!ue_context_p) {
LOG_E(RRC, "could not find UE context for CU UE ID %u, aborting transaction\n", msg->gNB_CU_ue_id);
return -1;
}
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
/* only accept srb 1 and 2 (may be changed if needed) */
AssertFatal(msg->srb_id >= 1 && msg->srb_id <= 2, "bad srb_id, should be in [1..2] but is %d\n", msg->srb_id);
if (UE->Srb[msg->srb_id].pdcp == NULL) {
LOG_E(RRC, "srb %d does not exist for UE %x\n", msg->srb_id, UE->rnti);
return -1;
}
UE->Srb[msg->srb_id].pdcp->recv_pdu(UE->Srb[msg->srb_id].pdcp, msg->rrc_container, msg->rrc_container_length);
return 0;
}
void rrc_gNB_process_initial_ul_rrc_message(sctp_assoc_t assoc_id, const f1ap_initial_ul_rrc_message_t *ul_rrc)
{
AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
@@ -1989,18 +2077,7 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id);
// TODO what happens if no AMF connected? should also handle, set an_release true
if (!ue_context_p) {
LOG_W(RRC, "could not find UE context for CU UE ID %u: auto-generate release command\n", req->gNB_CU_ue_id);
uint8_t buffer[RRC_BUF_SIZE] = {0};
int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(0));
f1ap_ue_context_release_cmd_t ue_context_release_cmd = {
.gNB_CU_ue_id = req->gNB_CU_ue_id,
.gNB_DU_ue_id = req->gNB_DU_ue_id,
.cause = F1AP_CAUSE_RADIO_NETWORK,
.cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release
.srb_id = DCCH,
};
deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd};
nr_pdcp_data_req_srb(req->gNB_CU_ue_id, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data);
LOG_W(RRC, "could not find UE context for CU UE ID %u, abandon UE Context Release Request\n", req->gNB_CU_ue_id);
return;
}
@@ -2048,10 +2125,12 @@ static void rrc_delete_ue_data(gNB_RRC_UE_t *UE)
void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p)
{
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
/* we call nr_pdcp_remove_UE() in the handler of E1 bearer release, but if we
* are in E1, we also need to free the UE in the CU-CP, so call it twice to
* cover all cases */
nr_pdcp_remove_UE(UE->rrc_ue_id);
for (int i = 0; i < NR_NUM_SRB; i++) {
if (UE->Srb[i].pdcp != NULL) {
UE->Srb[i].pdcp->delete_entity(UE->Srb[i].pdcp);
UE->Srb[i].pdcp = NULL;
}
}
uint32_t pdu_sessions[256];
for (int i = 0; i < UE->nb_of_pdusessions && i < 256; ++i)
pdu_sessions[i] = UE->pduSession[i].param.pdusession_id;
@@ -2522,7 +2601,7 @@ void *rrc_gnb_task(void *args_p) {
/* Messages from PDCP */
/* From DU -> CU */
case F1AP_UL_RRC_MESSAGE:
rrc_gNB_decode_dcch(RC.nrrrc[instance], &F1AP_UL_RRC_MESSAGE(msg_p));
rrc_gNB_process_F1AP_UL_RRC_MESSAGE(msg_p, instance);
free_ul_rrc_message_transfer(&F1AP_UL_RRC_MESSAGE(msg_p));
break;
@@ -2684,15 +2763,30 @@ void rrc_gNB_generate_RRCRelease(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
LOG_UE_DL_EVENT(UE, "Send RRC Release\n");
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
int srb_id = DL_SCH_LCID_DCCH;
f1ap_ue_context_release_cmd_t ue_context_release_cmd = {
.gNB_CU_ue_id = UE->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
.cause = F1AP_CAUSE_RADIO_NETWORK,
.cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release
.srb_id = DL_SCH_LCID_DCCH,
.srb_id = srb_id,
};
deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd, .assoc_id = ue_data.du_assoc_id};
nr_pdcp_data_req_srb(UE->rrc_ue_id, DL_SCH_LCID_DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data);
int pdu_max_size = nr_max_pdcp_pdu_size(size);
uint8_t pdu_buf[pdu_max_size];
mui_t mui = rrc_gNB_mui;
rrc_gNB_mui++;
int pdu_size = UE->Srb[srb_id].pdcp->process_sdu(UE->Srb[srb_id].pdcp,
buffer,
size,
mui,
pdu_buf,
pdu_max_size);
if (pdu_size == -1) {
LOG_E(NR_RRC, "PDCP process_sdu failed\n");
return;
}
rrc_deliver_ue_ctxt_release_cmd(&data, UE->rrc_ue_id, srb_id, pdu_buf, pdu_size, mui);
}
int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint32_t tmsi, uint8_t paging_drx)
@@ -2805,7 +2899,7 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc,
int nb_srb = 1;
f1ap_srb_to_be_setup_t srbs[1] = {{.srb_id = 2, .lcid = 2}};
activate_srb(ue_p, 2);
activate_srb(rrc, ue_p, 2);
/* the callback will fill the UE context setup request and forward it */
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);

View File

@@ -148,7 +148,7 @@ void nr_rrc_pdcp_config_security(gNB_RRC_UE_t *UE, bool enable_ciphering)
}
}
nr_pdcp_config_set_security(UE->rrc_ue_id, DL_SCH_LCID_DCCH, true, &security_parameters);
UE->Srb[DL_SCH_LCID_DCCH].pdcp->set_security(UE->Srb[DL_SCH_LCID_DCCH].pdcp, &security_parameters);
}
//------------------------------------------------------------------------------

View File

@@ -212,11 +212,11 @@ typedef struct deliver_ue_ctxt_modification_data_t {
f1ap_ue_context_modif_req_t *modification_req;
sctp_assoc_t assoc_id;
} deliver_ue_ctxt_modification_data_t;
static void rrc_deliver_ue_ctxt_modif_req(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
static void rrc_deliver_ue_ctxt_modif_req(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, uint8_t *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data != NULL);
deliver_ue_ctxt_modification_data_t *data = deliver_pdu_data;
data->modification_req->rrc_container = (uint8_t*)buf;
data->modification_req->rrc_container = buf;
data->modification_req->rrc_container_length = size;
data->rrc->mac_rrc.ue_context_modification_request(data->assoc_id, data->modification_req);
}

View File

@@ -115,7 +115,9 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue,
est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present;
} else {
est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent;
est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent;
/* SDAP header is present for the default DRB, see in 38.331 the definition of 'SDAP-Config' */
/* see also SDAP 37.324 5.2.1 Note 2 */
est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present;
}
for (int qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) {
est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi;

View File

@@ -71,7 +71,7 @@ void sdap_data_ind(rb_id_t pdcp_entity,
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
uint8_t *buf,
int size) {
nr_sdap_entity_t *sdap_entity;
sdap_entity = nr_sdap_get_entity(ue_id, pdusession_id);

View File

@@ -58,7 +58,7 @@ void sdap_data_ind(rb_id_t pdcp_entity,
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
uint8_t *buf,
int size);
void set_qfi_pduid(uint8_t qfi, uint8_t pduid);

View File

@@ -88,6 +88,114 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s
return;
}
static void nr_sdap_recv_ul_pdu(nr_sdap_entity_t *entity,
uint8_t *buf,
int size,
int rb_id,
bool has_sdap_header)
{
bool is_control = false;
int qfi = -1;
if (has_sdap_header) {
qfi = buf[0] & 0x3f;
is_control = (buf[0] >> 7) == 0;
}
if (is_control) {
/* todo: deal with end marker */
LOG_W(SDAP, "end-marker control UL PDU received (qfi %d), discarding\n", qfi);
return;
}
// very very dirty hack gloabl var N3GTPUInst
instance_t inst = *N3GTPUInst;
if (has_sdap_header) {
buf++;
size--;
}
if (size <= 0) {
LOG_E(SDAP, "empty buffer received, discard\n");
return;
}
gtpv1uSendDirect(inst, entity->ue_id, entity->pdusession_id, buf, size, false, false);
}
static void nr_sdap_recv_dl_sdu(nr_sdap_entity_t *entity, uint8_t *buf, int size, int rb_id, int qfi)
{
int rb_to_use = entity->default_drb;
bool has_header = entity->default_drb_has_sdap_tx;
/* use configured RB if a mapping exists (37.324 5.2.1) */
if (qfi >= 1 && qfi <= SDAP_MAX_QFI && entity->qfi2drb_table[qfi].drb_id > 0) {
rb_to_use = entity->qfi2drb_table[qfi].drb_id;
has_header = entity->qfi2drb_table[qfi].has_sdap_tx;
}
/* no default drb and no mapping? 37.324 5.2.1 note 1 says undefined behavior:
* we choose to reject the SDU */
if (rb_to_use == 0) {
LOG_E(SDAP, "SDAP SDU rejected, no QoS flow exists for qfi %d\n", qfi);
return;
}
uint8_t sdap_buf[size + 1];
uint8_t *out_buf;
int out_size = size;
if (has_header) {
out_size++;
memcpy(sdap_buf + 1, buf, size);
/* hardcoded values for the moment */
int rdi = 0;
int rqi = 0;
sdap_buf[0] = (rdi << 7) | (rqi << 6) | qfi;
out_buf = sdap_buf;
} else {
out_buf = buf;
}
entity->deliver_pdu(entity->deliver_pdu_data, rb_to_use, out_buf, out_size);
}
static void nr_sdap_remove_entity(nr_sdap_entity_t *entity)
{
memset(entity, 0, sizeof(*entity));
free(entity);
}
nr_sdap_entity_t *new_nr_sdap_entity2_gnb(ue_id_t ue_id,
int pdusession_id,
void (*deliver_pdu)(void *deliver_pdu_data, int rb_id, uint8_t *buf, int size),
void *deliver_pdu_data)
{
if (nr_sdap_get_entity(ue_id, pdusession_id)) {
LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, pdusession_id);
DevAssert(0);
}
nr_sdap_entity_t *sdap_entity = calloc(1, sizeof(nr_sdap_entity_t));
AssertFatal(sdap_entity != NULL, "SDAP Entity creation failed, out of memory\n");
sdap_entity->ue_id = ue_id;
sdap_entity->pdusession_id = pdusession_id;
sdap_entity->recv_sdu = nr_sdap_recv_dl_sdu;
sdap_entity->recv_pdu = nr_sdap_recv_ul_pdu;
sdap_entity->deliver_pdu = deliver_pdu;
sdap_entity->deliver_pdu_data = deliver_pdu_data;
sdap_entity->remove = nr_sdap_remove_entity;
sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update;
sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del;
sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map;
return sdap_entity;
}
static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
protocol_ctxt_t *ctxt_p,
const srb_flag_t srb_flag,
@@ -215,7 +323,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
uint8_t *buf,
int size)
{
/* The offset of the SDAP header, it might be 0 if has_sdap_rx is not true in the pdcp entity. */
@@ -240,7 +348,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
}
}
uint8_t *gtp_buf = (uint8_t *)(buf + offset);
uint8_t *gtp_buf = buf + offset;
size_t gtp_len = size - offset;
// Pushing SDAP SDU to GTP-U Layer

View File

@@ -79,8 +79,10 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s
typedef struct nr_sdap_entity_s {
ue_id_t ue_id;
rb_id_t default_drb;
int pdusession_id;
rb_id_t default_drb;
bool default_drb_has_sdap_rx;
bool default_drb_has_sdap_tx;
qfi2drb_t qfi2drb_table[SDAP_MAX_QFI];
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx);
@@ -111,11 +113,27 @@ typedef struct nr_sdap_entity_s {
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
uint8_t *buf,
int size);
void (*recv_sdu)(struct nr_sdap_entity_s *entity,
uint8_t *buf,
int size,
int rb_id,
int qfi);
void (*recv_pdu)(struct nr_sdap_entity_s *entity,
uint8_t *buf,
int size,
int rb_id,
bool has_sdap_header);
/* List of entities */
struct nr_sdap_entity_s *next_entity;
void (*deliver_pdu)(void *deliver_pdu_data, int rb_id, uint8_t *buf, int size);
void *deliver_pdu_data;
void (*remove)(struct nr_sdap_entity_s *entity);
} nr_sdap_entity_t;
/* QFI to DRB Mapping Related Function */
@@ -155,6 +173,11 @@ rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int
*/
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
nr_sdap_entity_t *new_nr_sdap_entity2_gnb(ue_id_t ue_id,
int pdusession_id,
void (*deliver_pdu)(void *deliver_pdu_data, int rb_id, uint8_t *buf, int size),
void *deliver_pdu_data);
/*
* TS 37.324 4.4 5.1.1 SDAP entity establishment
* Establish an SDAP entity.

View File

@@ -118,6 +118,8 @@ typedef struct {
gtpCallback callBack;
teid_t outgoing_teid;
gtpCallbackSDAP callBackSDAP;
gtpCallback2 callback2;
void *callback2_data;
int pdusession_id;
} ueidData_t;
@@ -604,6 +606,7 @@ teid_t newGtpuCreateTunnel(instance_t instance,
globGtp.te2ue_mapping[incoming_teid].outgoing_teid = outgoing_teid;
globGtp.te2ue_mapping[incoming_teid].callBack = callBack;
globGtp.te2ue_mapping[incoming_teid].callBackSDAP = callBackSDAP;
globGtp.te2ue_mapping[incoming_teid].callback2 = NULL;
globGtp.te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id;
gtpv1u_bearer_t *tmp=&inst->ue2te_mapping[ue_id].bearers[outgoing_bearer_id];
@@ -770,6 +773,35 @@ int gtpv1u_create_ngu_tunnel(const instance_t instance,
return !GTPNOK;
}
void gtpu_get_instance_address_and_port(const instance_t instance, uint8_t *addr, int *addr_len, int *port)
{
getInstRetVoid(compatInst(instance));
pthread_mutex_lock(&globGtp.gtp_lock);
*port = inst->get_dstport();
memcpy(addr, inst->foundAddr, inst->foundAddrLen);
*addr_len = inst->foundAddrLen;
pthread_mutex_unlock(&globGtp.gtp_lock);
}
void gtpu_set_callback2(teid_t teid, gtpCallback2 callback, void *callback_data)
{
pthread_mutex_lock(&globGtp.gtp_lock);
auto tunnel = globGtp.te2ue_mapping.find(teid);
if (tunnel == globGtp.te2ue_mapping.end()) {
LOG_E(GTPU,"unknown teid (%x), cannot setup callback\n", teid);
pthread_mutex_unlock(&globGtp.gtp_lock);
return;
}
globGtp.te2ue_mapping[teid].callback2 = callback;
globGtp.te2ue_mapping[teid].callback2_data = callback_data;
pthread_mutex_unlock(&globGtp.gtp_lock);
}
int gtpv1u_update_ue_id(const instance_t instanceP, ue_id_t old_ue_id, ue_id_t new_ue_id)
{
pthread_mutex_lock(&globGtp.gtp_lock);
@@ -1161,34 +1193,46 @@ static int Gtpv1uHandleGpdu(int h,
pthread_mutex_unlock(&globGtp.gtp_lock);
if (sdu_buffer_size > 0) {
if (qfi != -1 && tunnel->second.callBackSDAP) {
if ( !tunnel->second.callBackSDAP(&ctxt,
tunnel->second.ue_id,
srb_flag,
rb_id,
mui,
confirm,
sdu_buffer_size,
sdu_buffer,
mode,
&sourceL2Id,
&destinationL2Id,
qfi,
rqi,
tunnel->second.pdusession_id) )
if (tunnel->second.callback2) {
if (!tunnel->second.callback2(tunnel->second.callback2_data,
tunnel->second.ue_id,
tunnel->second.pdusession_id,
rb_id,
qfi,
rqi,
sdu_buffer,
sdu_buffer_size))
LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
} else {
if ( !tunnel->second.callBack(&ctxt,
srb_flag,
rb_id,
mui,
confirm,
sdu_buffer_size,
sdu_buffer,
mode,
&sourceL2Id,
&destinationL2Id) )
LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
if (qfi != -1 && tunnel->second.callBackSDAP) {
if ( !tunnel->second.callBackSDAP(&ctxt,
tunnel->second.ue_id,
srb_flag,
rb_id,
mui,
confirm,
sdu_buffer_size,
sdu_buffer,
mode,
&sourceL2Id,
&destinationL2Id,
qfi,
rqi,
tunnel->second.pdusession_id) )
LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
} else {
if ( !tunnel->second.callBack(&ctxt,
srb_flag,
rb_id,
mui,
confirm,
sdu_buffer_size,
sdu_buffer,
mode,
&sourceL2Id,
&destinationL2Id) )
LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h);
}
}
}

View File

@@ -5,6 +5,7 @@
# define GTPU_HEADER_OVERHEAD_MAX 64
#include "openair2/COMMON/gtpv1_u_messages_types.h"
#include "common/utils/hashtable/hashtable.h"
#ifdef __cplusplus
extern "C" {
@@ -36,6 +37,17 @@ extern "C" {
const bool rqi,
const int pdusession_id);
/* a simpler callback, for a simpler interface */
typedef bool (*gtpCallback2)(void *gtp_callback_data,
ue_id_t ue_id,
int pdu_session_id,
int rb_id,
int qfi,
int rqi,
uint8_t *buf,
int size);
typedef struct openAddr_s {
char originHost[HOST_NAME_MAX];
char originService[HOST_NAME_MAX];
@@ -77,6 +89,9 @@ extern "C" {
gtpCallback callBack,
gtpCallbackSDAP callBackSDAP);
void gtpu_get_instance_address_and_port(const instance_t instance, uint8_t *addr, int *addr_len, int *port);
void gtpu_set_callback2(teid_t teid, gtpCallback2 callback, void *callback_data);
int gtpv1u_delete_ngu_tunnel( const instance_t instance,
gtpv1u_gnb_delete_tunnel_req_t *req);