mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-20 08:00:31 +00:00
Compare commits
5 Commits
beam_api
...
remove-pdc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b01fac1dc0 | ||
|
|
83575ecb75 | ||
|
|
899375f20a | ||
|
|
8537e6dd11 | ||
|
|
89eb3eb416 |
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
153
common/utils/l2_queue.c
Normal 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
59
common/utils/l2_queue.h
Normal 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 */
|
||||
@@ -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)
|
||||
|
||||
85
openair2/E1AP/e1ap_context.c
Normal file
85
openair2/E1AP/e1ap_context.c
Normal 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 */
|
||||
}
|
||||
}
|
||||
35
openair2/E1AP/e1ap_context.h
Normal file
35
openair2/E1AP/e1ap_context.h
Normal 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_ */
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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__*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user