mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Merge remote-tracking branch 'GuidoCasati/sdap-header-fix' into integration_2026_w28
SDAP header handling fixes (#249) OAI SDAP treated SDAP header presence as a single PDU-session flag (enable_sdap), so a valid asymmetric RRC config (UL header present, DL header absent) caused the UE to parse downlink payload as an SDAP QFI and drop traffic (e.g. IPv4 0x45 -> bogus QFI 5). SDAP now follows RRC SDAP-Config per DRB and per direction from (TS 38.331 / TS 37.324). Header presence, QFI-to-DRB mapping, and default-DRB fallback all derive from what RRC configured for each DRB. In the new implementation, RRC (SDAP-Config IE) fills sdap_config_t per DRB (role, defaultDRB, mapped QFIs), SDAP entity stores it in qfi2drb_table + default_drb row to be used in the TX/RX data path. Also, simplify mapping logic, improves E1 QoS-flow remap, and completes UE reflective QoS mapping with the correct entity_role on new QFI rows. Reviewed-by: Robert Schmidt <robert.schmidt@openairinterface.org> Reviewed-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
This commit is contained in:
@@ -90,9 +90,9 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration.
|
|||||||
`0xffffff` is a reserved value and means "no SD"
|
`0xffffff` is a reserved value and means "no SD"
|
||||||
Note that: SST=1, no SD is "eMBB"; SST=2, no SD is "URLLC"; SST=3, no SD
|
Note that: SST=1, no SD is "eMBB"; SST=2, no SD is "URLLC"; SST=3, no SD
|
||||||
is "mMTC"
|
is "mMTC"
|
||||||
- `enable_sdap` (default: true): enable the use of the SDAP layer. If
|
- `enable_sdap` (default: true): set `sdap-HeaderUL` and `sdap-HeaderDL` to
|
||||||
deactivated, a transparent SDAP header is prepended to packets, but no
|
present in the RRC `SDAP-Config` IE for SA PDU sessions. If false, both
|
||||||
further processing is being done.
|
headers are absent (per DRB). SDAP entities are still created, SDAP layer always enabled.
|
||||||
- `cu_sibs` (default: `[]`) list of SIBs to give to the DU for transmission.
|
- `cu_sibs` (default: `[]`) list of SIBs to give to the DU for transmission.
|
||||||
Currently supported:
|
Currently supported:
|
||||||
- SIB2: serving-cell reselection parameters (configured in `sib2_config`)
|
- SIB2: serving-cell reselection parameters (configured in `sib2_config`)
|
||||||
|
|||||||
@@ -2443,7 +2443,7 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
|||||||
|
|
||||||
nrrrc_config.num_plmn = set_plmn_config(nrrrc_config.plmn, k);
|
nrrrc_config.num_plmn = set_plmn_config(nrrrc_config.plmn, k);
|
||||||
nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr;
|
nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr;
|
||||||
LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled");
|
LOG_I(GNB_APP, "SDAP UL/DL headers in RRC are %s\n", nrrrc_config.enable_sdap ? "present" : "absent");
|
||||||
nrrrc_config.um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr);
|
nrrrc_config.um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr);
|
||||||
|
|
||||||
}//
|
}//
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ typedef enum {
|
|||||||
#define GNB_CONFIG_STRING_1ST_ACTIVE_BWP "first_active_bwp"
|
#define GNB_CONFIG_STRING_1ST_ACTIVE_BWP "first_active_bwp"
|
||||||
#define GNB_CONFIG_STRING_LIMIT_RSRP_REPORT "max_num_RSRP_reported"
|
#define GNB_CONFIG_STRING_LIMIT_RSRP_REPORT "max_num_RSRP_reported"
|
||||||
|
|
||||||
#define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n"
|
#define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "set sdap-HeaderUL/DL present in RRC SDAP-Config (false = both absent)\n"
|
||||||
#define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support"
|
#define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support"
|
||||||
#define GNB_CONFIG_HLP_MAXMIMOLAYERS "limit on maxMIMO-layers for DL"
|
#define GNB_CONFIG_HLP_MAXMIMOLAYERS "limit on maxMIMO-layers for DL"
|
||||||
#define GNB_CONFIG_HLP_DISABLE_HARQ "disable feedback for all HARQ processes (REL17 feature)"
|
#define GNB_CONFIG_HLP_DISABLE_HARQ "disable feedback for all HARQ processes (REL17 feature)"
|
||||||
|
|||||||
@@ -427,9 +427,15 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
|
|||||||
DevAssert(to_modif->numQosFlowsMod <= E1AP_MAX_NUM_QOS_FLOWS);
|
DevAssert(to_modif->numQosFlowsMod <= E1AP_MAX_NUM_QOS_FLOWS);
|
||||||
modified->numQosFlowSetup = to_modif->numQosFlowsMod;
|
modified->numQosFlowSetup = to_modif->numQosFlowsMod;
|
||||||
|
|
||||||
uint8_t qfi_list[E1AP_MAX_NUM_QOS_FLOWS];
|
sdap_config_t sdap = {
|
||||||
|
.pdusession_id = req_pdu_mod->sessionId,
|
||||||
|
.drb_id = to_modif->id,
|
||||||
|
.mappedQFIs2AddCount = to_modif->numQosFlowsMod,
|
||||||
|
};
|
||||||
|
|
||||||
for (int q = 0; q < to_modif->numQosFlowsMod; q++) {
|
for (int q = 0; q < to_modif->numQosFlowsMod; q++) {
|
||||||
modified->qosFlows[q].qfi = qfi_list[q] = to_modif->qosFlows[q].qfi;
|
sdap.mappedQFIs2Add[q] = to_modif->qosFlows[q].qfi;
|
||||||
|
modified->qosFlows[q].qfi = to_modif->qosFlows[q].qfi;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_D(NR_RRC,
|
LOG_D(NR_RRC,
|
||||||
@@ -438,11 +444,7 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
|
|||||||
req_pdu_mod->sessionId,
|
req_pdu_mod->sessionId,
|
||||||
to_modif->id,
|
to_modif->id,
|
||||||
to_modif->numQosFlowsMod);
|
to_modif->numQosFlowsMod);
|
||||||
nr_sdap_entity_update_qos_flows(req->gNB_cu_up_ue_id,
|
nr_sdap_entity_update_qos_flows(req->gNB_cu_up_ue_id, &sdap);
|
||||||
req_pdu_mod->sessionId,
|
|
||||||
to_modif->id,
|
|
||||||
qfi_list,
|
|
||||||
to_modif->numQosFlowsMod);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_modif->pdcp_config && to_modif->pdcp_config->pDCP_Reestablishment) {
|
if (to_modif->pdcp_config && to_modif->pdcp_config->pDCP_Reestablishment) {
|
||||||
|
|||||||
@@ -345,8 +345,8 @@ static DRB_nGRAN_to_setup_t fill_e1_drb_to_setup(const drb_t *rrc_drb,
|
|||||||
drb_ngran.id = rrc_drb->drb_id;
|
drb_ngran.id = rrc_drb->drb_id;
|
||||||
|
|
||||||
drb_ngran.sdap_config.defaultDRB = (session->sdap_config.default_drb == drb_ngran.id);
|
drb_ngran.sdap_config.defaultDRB = (session->sdap_config.default_drb == drb_ngran.id);
|
||||||
drb_ngran.sdap_config.sDAP_Header_UL = session->sdap_config.header_ul_absent ? false : true;
|
drb_ngran.sdap_config.sDAP_Header_UL = !session->sdap_config.header_ul_absent;
|
||||||
drb_ngran.sdap_config.sDAP_Header_DL = session->sdap_config.header_dl_absent ? false : true;
|
drb_ngran.sdap_config.sDAP_Header_DL = !session->sdap_config.header_dl_absent;
|
||||||
|
|
||||||
drb_ngran.pdcp_config = set_bearer_context_pdcp_config(rrc_drb->pdcp_config, um_on_default_drb, redcap_cap);
|
drb_ngran.pdcp_config = set_bearer_context_pdcp_config(rrc_drb->pdcp_config, um_on_default_drb, redcap_cap);
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
|
|||||||
rqi);
|
rqi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdap_data_ind(int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_id, char *buf, int size)
|
void sdap_data_ind(int drb_id, int is_gnb, int pdusession_id, ue_id_t ue_id, char *buf, int size)
|
||||||
{
|
{
|
||||||
nr_sdap_entity_t *sdap_entity;
|
nr_sdap_entity_t *sdap_entity;
|
||||||
sdap_entity = nr_sdap_get_entity(ue_id, pdusession_id);
|
sdap_entity = nr_sdap_get_entity(ue_id, pdusession_id);
|
||||||
@@ -172,13 +172,7 @@ void sdap_data_ind(int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_id
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdap_entity->rx_entity(sdap_entity,
|
sdap_entity->rx_entity(sdap_entity, drb_id, is_gnb, pdusession_id, ue_id, buf, size);
|
||||||
pdcp_entity,
|
|
||||||
is_gnb,
|
|
||||||
pdusession_id,
|
|
||||||
ue_id,
|
|
||||||
buf,
|
|
||||||
size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *sdap_tun_read_thread(void *arg)
|
static void *sdap_tun_read_thread(void *arg)
|
||||||
@@ -213,14 +207,6 @@ static void *sdap_tun_read_thread(void *arg)
|
|||||||
|
|
||||||
LOG_D(SDAP, "read data of size %d\n", len);
|
LOG_D(SDAP, "read data of size %d\n", len);
|
||||||
|
|
||||||
if (!entity->is_gnb && entity->enable_sdap && (entity->qfi < 0 || entity->qfi >= SDAP_MAX_QFI)) {
|
|
||||||
LOG_W(SDAP,
|
|
||||||
"Dropping UL SDU for UE %ld PDU session %d: no QoS rule QFI available for SDAP header\n",
|
|
||||||
entity->ue_id,
|
|
||||||
entity->pdusession_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol_ctxt_t ctxt = {.enb_flag = entity->is_gnb, .rntiMaybeUEid = entity->ue_id};
|
protocol_ctxt_t ctxt = {.enb_flag = entity->is_gnb, .rntiMaybeUEid = entity->ue_id};
|
||||||
|
|
||||||
bool dc = entity->is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
|
bool dc = entity->is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
|
|||||||
* Uplink - gNB
|
* Uplink - gNB
|
||||||
* Downlink - nrUE
|
* Downlink - nrUE
|
||||||
*/
|
*/
|
||||||
void sdap_data_ind(int pdcp_entity, int is_gnb, int pdusession_id, ue_id_t ue_id, char *buf, int size);
|
void sdap_data_ind(int drb_id, int is_gnb, int pdusession_id, ue_id_t ue_id, char *buf, int size);
|
||||||
|
|
||||||
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id);
|
void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id, int pdu_session_id);
|
||||||
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default);
|
void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id, bool is_default);
|
||||||
|
|||||||
@@ -43,14 +43,35 @@ static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config)
|
|||||||
{
|
{
|
||||||
sdap_role_t role_ul = is_gnb ? SDAP_UL_RX : SDAP_UL_TX;
|
sdap_role_t role_ul = is_gnb ? SDAP_UL_RX : SDAP_UL_TX;
|
||||||
sdap_role_t role_dl = is_gnb ? SDAP_DL_TX : SDAP_DL_RX;
|
sdap_role_t role_dl = is_gnb ? SDAP_DL_TX : SDAP_DL_RX;
|
||||||
|
const bool ul_hdr = sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present;
|
||||||
|
const bool dl_hdr = sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present;
|
||||||
int role = NO_SDAP_HEADER;
|
int role = NO_SDAP_HEADER;
|
||||||
if (sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present)
|
if (ul_hdr)
|
||||||
role |= role_ul;
|
role |= role_ul;
|
||||||
if (sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present)
|
if (dl_hdr)
|
||||||
role |= role_dl;
|
role |= role_dl;
|
||||||
|
LOG_D(SDAP,
|
||||||
|
"PDU session %ld %s: sdap-HeaderUL %s, sdap-HeaderDL %s (role 0x%x)\n",
|
||||||
|
sdap_config->pdu_Session,
|
||||||
|
is_gnb ? "gNB" : "UE",
|
||||||
|
ul_hdr ? "present" : "absent",
|
||||||
|
dl_hdr ? "present" : "absent",
|
||||||
|
role);
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return the first table row for drb_id (all QFIs on a DRB share entity_role) */
|
||||||
|
static const qfi2drb_t *nr_sdap_drb_lookup(const nr_sdap_entity_t *entity, int drb_id)
|
||||||
|
{
|
||||||
|
for (int qfi = 0; qfi < SDAP_MAX_QFI; qfi++) {
|
||||||
|
if (entity->qfi2drb_table[qfi].drb_id == drb_id)
|
||||||
|
return &entity->qfi2drb_table[qfi];
|
||||||
|
}
|
||||||
|
if (entity->default_drb.drb_id == drb_id)
|
||||||
|
return &entity->default_drb;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
|
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -94,19 +115,20 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sdap_buf[SDAP_MAX_PDU];
|
uint8_t sdap_buf[SDAP_MAX_PDU];
|
||||||
int drb_id = entity->qfi2drb_map(entity, qfi);
|
const qfi2drb_t *map = entity->qfi2drb_map(entity, qfi);
|
||||||
|
if (!map) {
|
||||||
if (drb_id != SDAP_MAP_RULE_EMPTY) {
|
LOG_W(SDAP, "Dropping TX SDAP SDU: no DRB mapping for QFI %u (pdu_session=%d)\n", qfi, entity->pdusession_id);
|
||||||
sdap_ul_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX; // UE TX entity
|
|
||||||
sdap_dl_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_TX; // gNB TX entity
|
|
||||||
LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, entity->qfi2drb_table[qfi].drb_id);
|
|
||||||
} else {
|
|
||||||
LOG_E(SDAP, "QFI %u not mapped to any DRB - dropping SDU of size %d\n", qfi, sdu_buffer_size);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const int drb_id = map->drb_id;
|
||||||
|
const int drb_role = map->entity_role;
|
||||||
|
|
||||||
|
sdap_ul_tx = drb_role & SDAP_UL_TX;
|
||||||
|
sdap_dl_tx = drb_role & SDAP_DL_TX;
|
||||||
|
LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, drb_id);
|
||||||
|
|
||||||
if (!sdap_ul_tx && !sdap_dl_tx) {
|
if (!sdap_ul_tx && !sdap_dl_tx) {
|
||||||
LOG_D(SDAP, "TX - DRB ID: %d does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id);
|
LOG_D(SDAP, "TX - DRB ID: %d does not have SDAP header\n", drb_id);
|
||||||
ret = nr_pdcp_data_req_drb(ctxt_p,
|
ret = nr_pdcp_data_req_drb(ctxt_p,
|
||||||
srb_flag,
|
srb_flag,
|
||||||
drb_id,
|
drb_id,
|
||||||
@@ -192,55 +214,47 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
|
static void
|
||||||
int pdcp_entity,
|
nr_sdap_rx_entity(nr_sdap_entity_t *entity, int drb_id, int is_gnb, int pdusession_id, ue_id_t ue_id, char *buf, int size)
|
||||||
int is_gnb,
|
|
||||||
int pdusession_id,
|
|
||||||
ue_id_t ue_id,
|
|
||||||
char *buf,
|
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
bool sdap_ul_rx = false;
|
|
||||||
bool sdap_dl_rx = false;
|
|
||||||
int qfi = -1;
|
int qfi = -1;
|
||||||
/* If SDAP header is disabled for this entity, bypass header parsing */
|
const qfi2drb_t *map = nr_sdap_drb_lookup(entity, drb_id);
|
||||||
if (entity->enable_sdap) {
|
if (!map) {
|
||||||
/** Extract QFI from SDAP header for UL direction
|
LOG_W(SDAP, "Dropping RX payload: DRB %d has no qfi2drb_table entry (ue=%ld, pdu_session=%d)\n", drb_id, ue_id, pdusession_id);
|
||||||
* Per TS 37.324 §6.2.2, QFI is carried in SDAP header when SDAP header is present
|
return;
|
||||||
* This QFI will be used in GTP-U extension header (PDU Session Container)
|
|
||||||
* for N3-U tunnel (the first 6 bits in the first octet) */
|
|
||||||
qfi = buf[0] & 0x3F;
|
|
||||||
if (qfi >= SDAP_MAX_QFI) {
|
|
||||||
LOG_E(SDAP, "Invalid QFI %d received in SDAP header\n", qfi);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Accept SDAP packets only for QFIs that still have an active mapping.
|
|
||||||
const qfi2drb_t *mapping = &entity->qfi2drb_table[qfi];
|
|
||||||
/* If the QFI has no active mapping, drop the packet: it can happen
|
|
||||||
* after QoS-flow removal/reconfiguration due to packets that were already enqueued in PDCP */
|
|
||||||
if (mapping->drb_id == SDAP_NO_MAPPING_RULE) {
|
|
||||||
LOG_W(SDAP,
|
|
||||||
"Dropping UL SDAP PDU with unmapped QFI=%d (ue=%ld pdu_session=%d drb=%d)\n",
|
|
||||||
qfi,
|
|
||||||
ue_id,
|
|
||||||
pdusession_id,
|
|
||||||
pdcp_entity);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sdap_ul_rx = mapping->entity_role & SDAP_UL_RX; // gNB RX entity
|
|
||||||
sdap_dl_rx = mapping->entity_role & SDAP_DL_RX; // UE RX entity
|
|
||||||
}
|
}
|
||||||
|
const int drb_role = map->entity_role;
|
||||||
|
bool sdap_header_rx = is_gnb ? (drb_role & SDAP_UL_RX) : (drb_role & SDAP_DL_RX);
|
||||||
|
|
||||||
|
if (is_gnb) {
|
||||||
|
if (sdap_header_rx) {
|
||||||
|
/** Extract QFI from SDAP header for gNB UL RX
|
||||||
|
* Per TS 37.324 §6.2.2, QFI is carried in SDAP header when SDAP header is present
|
||||||
|
* This QFI will be used in GTP-U extension header (PDU Session Container)
|
||||||
|
* for N3-U tunnel (the first 6 bits in the first octet) */
|
||||||
|
const nr_sdap_ul_hdr_t *sdap_hdr = (const nr_sdap_ul_hdr_t *)buf;
|
||||||
|
qfi = sdap_hdr->QFI;
|
||||||
|
if (qfi >= SDAP_MAX_QFI) {
|
||||||
|
LOG_E(SDAP, "Invalid QFI %d received in SDAP header\n", qfi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* TS 37.324 §5.2.1: with no stored rule, map to the default DRB when configured
|
||||||
|
* TS 38.331: default DRB always has a UL SDAP header
|
||||||
|
* Drop only when neither a stored rule nor default DRB applies to this QFI */
|
||||||
|
const qfi2drb_t *qfi_map = entity->qfi2drb_map(entity, qfi);
|
||||||
|
if (!qfi_map || qfi_map->drb_id != drb_id) {
|
||||||
|
LOG_W(SDAP,
|
||||||
|
"Dropping UL PDU: QFI=%d %s (ue=%ld, pdu_session=%d, receiving_drb=%d)\n",
|
||||||
|
qfi,
|
||||||
|
!qfi_map ? "no rule/default DRB" : "wrong DRB",
|
||||||
|
ue_id,
|
||||||
|
pdusession_id,
|
||||||
|
drb_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_gnb) { // gNB
|
|
||||||
/** QFI extracted from SDAP header for UL direction (N3-U tunnel)
|
|
||||||
* QFI range: 0..63 (6 bits) */
|
|
||||||
if (sdap_ul_rx) { // UL Data/Control PDU with SDAP header
|
|
||||||
DevAssert(qfi >= 0 && qfi < SDAP_MAX_QFI);
|
|
||||||
int offset = SDAP_HDR_LENGTH;
|
int offset = SDAP_HDR_LENGTH;
|
||||||
nr_sdap_ul_hdr_t *sdap_hdr = (nr_sdap_ul_hdr_t *)buf;
|
LOG_D(SDAP, "RX Entity Received QFI: %u\n", sdap_hdr->QFI);
|
||||||
DevAssert(sdap_hdr->QFI == qfi);
|
|
||||||
LOG_D(SDAP, "RX Entity Received QFI: %u\n", qfi);
|
|
||||||
LOG_D(SDAP, "RX Entity Received R bit: %u\n", sdap_hdr->R);
|
LOG_D(SDAP, "RX Entity Received R bit: %u\n", sdap_hdr->R);
|
||||||
LOG_D(SDAP, "RX Entity Received DC bit: %u\n", sdap_hdr->DC);
|
LOG_D(SDAP, "RX Entity Received DC bit: %u\n", sdap_hdr->DC);
|
||||||
|
|
||||||
@@ -279,7 +293,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
|
|||||||
* if the DRB from which this SDAP data PDU is received is configured by RRC with the presence of SDAP header.
|
* if the DRB from which this SDAP data PDU is received is configured by RRC with the presence of SDAP header.
|
||||||
*/
|
*/
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
if (sdap_dl_rx) { // DL Data/Control PDU with SDAP header
|
if (sdap_header_rx) { // DL Data/Control PDU with SDAP header
|
||||||
offset = SDAP_HDR_LENGTH;
|
offset = SDAP_HDR_LENGTH;
|
||||||
/*
|
/*
|
||||||
* TS 37.324 5.2 Data transfer
|
* TS 37.324 5.2 Data transfer
|
||||||
@@ -303,7 +317,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
|
|||||||
* 5.3.2 Reflective mapping
|
* 5.3.2 Reflective mapping
|
||||||
* If there is no stored QoS flow to DRB mapping rule for the QoS flow and a default DRB is configured.
|
* If there is no stored QoS flow to DRB mapping rule for the QoS flow and a default DRB is configured.
|
||||||
*/
|
*/
|
||||||
if(!entity->qfi2drb_table[sdap_hdr->QFI].drb_id && entity->default_drb){
|
if (!entity->qfi2drb_table[sdap_hdr->QFI].drb_id && entity->default_drb.drb_id) {
|
||||||
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
|
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
|
||||||
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI);
|
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI);
|
||||||
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
|
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
|
||||||
@@ -318,18 +332,19 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
|
|||||||
* the DRB according to the stored QoS flow to DRB mapping rule is configured by RRC
|
* the DRB according to the stored QoS flow to DRB mapping rule is configured by RRC
|
||||||
* with the presence of UL SDAP header
|
* with the presence of UL SDAP header
|
||||||
*/
|
*/
|
||||||
if (pdcp_entity != entity->qfi2drb_table[sdap_hdr->QFI].drb_id) {
|
if (drb_id != entity->qfi2drb_table[sdap_hdr->QFI].drb_id) {
|
||||||
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
|
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
|
||||||
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI);
|
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI);
|
||||||
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
|
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TS 37.324 5.3 QoS flow to DRB Mapping
|
* TS 37.324 §5.3.2 Reflective mapping: store the DL QoS flow to DRB mapping
|
||||||
* 5.3.2 Reflective mapping
|
* as the UL mapping rule. sdap-HeaderUL/DL are per DRB: copy the
|
||||||
* store the QoS flow to DRB mapping of the DL SDAP data PDU as the QoS flow to DRB mapping rule for the UL.
|
* receiving DRB role onto the QFI row together with drb_id.
|
||||||
*/
|
*/
|
||||||
entity->qfi2drb_table[sdap_hdr->QFI].drb_id = pdcp_entity;
|
entity->qfi2drb_table[sdap_hdr->QFI].drb_id = drb_id;
|
||||||
|
entity->qfi2drb_table[sdap_hdr->QFI].entity_role = drb_role;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -382,31 +397,31 @@ static void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, const uint8_t qfi)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get the DRB ID mapped to the QFI, for both DL and UL
|
* @brief get the DRB ID mapped to the QFI, for both DL and UL
|
||||||
* @return DRB that is mapped to the QFI
|
* @return qfi2drb_table entry for the QFI {drb_id, entity_role},
|
||||||
* or the default DRB if no mapping rule exists
|
* or the default DRB row if no mapping rule exists,
|
||||||
* or 0 if no mapping and no default DRB exists for that QFI
|
* or NULL if no mapping and no default DRB exists for that QFI
|
||||||
* @ref TS 37.324, 5.2.1 Uplink
|
* @ref TS 37.324, 5.2.1 Uplink
|
||||||
* If there is no stored QoS flow to DRB mapping rule for the
|
* If there is no stored QoS flow to DRB mapping rule for the
|
||||||
* QoS flow as specified in the subclause 5.3, and a default DRB is configured,
|
* QoS flow as specified in the subclause 5.3, and a default DRB is configured,
|
||||||
* map the SDAP SDU to the default DRB else, map the SDAP SDU to the DRB according
|
* map the SDAP SDU to the default DRB else, map the SDAP SDU to the DRB according
|
||||||
* to the stored QoS flow to DRB mapping rule. */
|
* to the stored QoS flow to DRB mapping rule. */
|
||||||
static int nr_sdap_qfi2drb(nr_sdap_entity_t *entity, uint8_t qfi)
|
static const qfi2drb_t *nr_sdap_qfi2drb(const nr_sdap_entity_t *entity, uint8_t qfi)
|
||||||
{
|
{
|
||||||
/* Fetch DRB ID mapped to QFI */
|
/* Fetch DRB ID mapped to QFI */
|
||||||
int drb_id = entity->qfi2drb_table[qfi].drb_id;
|
const qfi2drb_t *row = &entity->qfi2drb_table[qfi];
|
||||||
if (drb_id) {
|
if (row->drb_id) {
|
||||||
/* QoS flow to DRB mapping rule exists, return corresponding DRB ID */
|
/* QoS flow to DRB mapping rule exists, return corresponding DRB ID */
|
||||||
LOG_D(SDAP, "Existing QoS flow to DRB mapping rule: QFI %u to DRB %d\n", qfi, drb_id);
|
LOG_D(SDAP, "Existing QoS flow to DRB mapping rule: QFI %u to DRB %d\n", qfi, row->drb_id);
|
||||||
return drb_id;
|
return row;
|
||||||
} else if (entity->default_drb) {
|
} else if (entity->default_drb.drb_id) {
|
||||||
/* QoS flow to DRB mapping rule does not exist, map SDAP SDU to default DRB, e.g. return default DRB of the SDAP entity */
|
/* QoS flow to DRB mapping rule does not exist: map SDAP SDU to default DRB */
|
||||||
LOG_D(SDAP, "QoS flow to DRB mapping rule does not exists! mapping SDU to Default DRB: %d\n", entity->default_drb);
|
LOG_D(SDAP, "QoS flow to DRB mapping rule does not exists! mapping SDU to Default DRB: %d\n", entity->default_drb.drb_id);
|
||||||
return entity->default_drb;
|
return &entity->default_drb;
|
||||||
} else {
|
} else {
|
||||||
/* Note: UE undefined behaviour when neither a default DRB
|
/* Note: UE undefined behaviour when neither a default DRB
|
||||||
nor a stored QoS flow to DRB mapping rule exists */
|
nor a stored QoS flow to DRB mapping rule exists */
|
||||||
LOG_E(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi);
|
LOG_E(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi);
|
||||||
return SDAP_MAP_RULE_EMPTY;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,11 +440,16 @@ int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi)
|
|||||||
{
|
{
|
||||||
int drb_of_endmarker = 0;
|
int drb_of_endmarker = 0;
|
||||||
if(map_type == SDAP_CTRL_PDU_MAP_DEF_DRB){
|
if(map_type == SDAP_CTRL_PDU_MAP_DEF_DRB){
|
||||||
drb_of_endmarker = entity->default_drb;
|
drb_of_endmarker = entity->default_drb.drb_id;
|
||||||
LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %d\n", dl_qfi, drb_of_endmarker);
|
LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %d\n", dl_qfi, drb_of_endmarker);
|
||||||
}
|
}
|
||||||
if(map_type == SDAP_CTRL_PDU_MAP_RULE_DRB){
|
if(map_type == SDAP_CTRL_PDU_MAP_RULE_DRB){
|
||||||
drb_of_endmarker = entity->qfi2drb_map(entity, dl_qfi);
|
const qfi2drb_t *map = entity->qfi2drb_map(entity, dl_qfi);
|
||||||
|
if (!map) {
|
||||||
|
LOG_E(SDAP, "No DRB mapping for control PDU QFI %u\n", dl_qfi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
drb_of_endmarker = map->drb_id;
|
||||||
LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %d\n", dl_qfi, drb_of_endmarker);
|
LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %d\n", dl_qfi, drb_of_endmarker);
|
||||||
}
|
}
|
||||||
return drb_of_endmarker;
|
return drb_of_endmarker;
|
||||||
@@ -454,7 +474,7 @@ static void nr_sdap_ue_control_pdu_config(nr_sdap_entity_t *entity, const ue_id_
|
|||||||
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
|
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
|
||||||
uint8_t qfi = sdap->mappedQFIs2Add[i];
|
uint8_t qfi = sdap->mappedQFIs2Add[i];
|
||||||
/* a default DRB exists and there is no stored QFI to DRB mapping rule for the QFI */
|
/* a default DRB exists and there is no stored QFI to DRB mapping rule for the QFI */
|
||||||
if (entity->default_drb && entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) {
|
if (entity->default_drb.drb_id && entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) {
|
||||||
// construct an end-marker control PDU (6.2.3 TS 37.324)
|
// construct an end-marker control PDU (6.2.3 TS 37.324)
|
||||||
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi);
|
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi);
|
||||||
// map the end-marker control PDU to the default DRB
|
// map the end-marker control PDU to the default DRB
|
||||||
@@ -481,7 +501,7 @@ static void nr_sdap_add_qos_flows_to_drb(nr_sdap_entity_t *entity, const sdap_co
|
|||||||
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
|
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
|
||||||
uint8_t qfi = sdap->mappedQFIs2Add[i];
|
uint8_t qfi = sdap->mappedQFIs2Add[i];
|
||||||
LOG_D(SDAP, "Adding QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id);
|
LOG_D(SDAP, "Adding QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id);
|
||||||
if (qfi < SDAP_MAX_QFI && sdap->drb_id > SDAP_MAP_RULE_EMPTY && sdap->drb_id <= MAX_DRBS_PER_UE) {
|
if (qfi < SDAP_MAX_QFI && sdap->drb_id > SDAP_NO_MAPPING_RULE && sdap->drb_id <= MAX_DRBS_PER_UE) {
|
||||||
entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role);
|
entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role);
|
||||||
} else {
|
} else {
|
||||||
LOG_E(SDAP, "Failed to add qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id);
|
LOG_E(SDAP, "Failed to add qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id);
|
||||||
@@ -504,24 +524,31 @@ static void nr_sdap_rm_qos_flows_from_drb(nr_sdap_entity_t *entity, const sdap_c
|
|||||||
* @param drb the DRB ID to be mapped */
|
* @param drb the DRB ID to be mapped */
|
||||||
static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
|
static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
|
||||||
{
|
{
|
||||||
/* disabled SDAP: only one DRB per PDU session existing qfi2drb_table entries must match the DRB to be updated */
|
|
||||||
if (!entity->enable_sdap) {
|
|
||||||
for (int i = 0; i < SDAP_MAX_QFI; i++) {
|
|
||||||
int mapped = entity->qfi2drb_table[i].drb_id;
|
|
||||||
if (mapped != SDAP_NO_MAPPING_RULE) {
|
|
||||||
AssertFatal(mapped == sdap->drb_id,
|
|
||||||
"PDU session %d: disabled SDAP allows only one DRB per PDU session (qfi2drb_table[%d] maps to DRB %d)\n",
|
|
||||||
entity->pdusession_id,
|
|
||||||
i,
|
|
||||||
mapped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!entity->is_gnb) { // UE control PDU configuration
|
if (!entity->is_gnb) { // UE control PDU configuration
|
||||||
nr_sdap_ue_control_pdu_config(entity, entity->ue_id, sdap);
|
nr_sdap_ue_control_pdu_config(entity, entity->ue_id, sdap);
|
||||||
}
|
}
|
||||||
nr_sdap_add_qos_flows_to_drb(entity, sdap);
|
nr_sdap_add_qos_flows_to_drb(entity, sdap);
|
||||||
nr_sdap_rm_qos_flows_from_drb(entity, sdap);
|
nr_sdap_rm_qos_flows_from_drb(entity, sdap);
|
||||||
|
|
||||||
|
/* TS 38.331: all QFIs on a DRB share the same sdap-HeaderUL/DL role */
|
||||||
|
for (int i = 0; i < SDAP_MAX_QFI; i++) {
|
||||||
|
if (entity->qfi2drb_table[i].drb_id == sdap->drb_id)
|
||||||
|
entity->qfi2drb_table[i].entity_role = sdap->role;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdap->role == NO_SDAP_HEADER) {
|
||||||
|
/* TS 37.324 §6.2.2.1: with both headers absent, only one DRB per PDU session is allowed */
|
||||||
|
int mapped_drbs = 0;
|
||||||
|
for (int drb = 1; drb <= MAX_DRBS_PER_UE; drb++) {
|
||||||
|
for (int qfi = 0; qfi < SDAP_MAX_QFI; qfi++) {
|
||||||
|
if (entity->qfi2drb_table[qfi].drb_id == drb) {
|
||||||
|
mapped_drbs++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssertFatal(mapped_drbs <= 1, "PDU session %d: disabled SDAP but %d DRBs mapped\n", entity->pdusession_id, mapped_drbs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -540,7 +567,6 @@ static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap
|
|||||||
sdap_entity->ue_id = ue_id;
|
sdap_entity->ue_id = ue_id;
|
||||||
sdap_entity->pdusession_id = sdap->pdusession_id;
|
sdap_entity->pdusession_id = sdap->pdusession_id;
|
||||||
sdap_entity->is_gnb = is_gnb;
|
sdap_entity->is_gnb = is_gnb;
|
||||||
sdap_entity->enable_sdap = (sdap->role != NO_SDAP_HEADER);
|
|
||||||
|
|
||||||
// rx/tx entities
|
// rx/tx entities
|
||||||
sdap_entity->tx_entity = nr_sdap_tx_entity;
|
sdap_entity->tx_entity = nr_sdap_tx_entity;
|
||||||
@@ -560,13 +586,14 @@ static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap
|
|||||||
|
|
||||||
// set default DRB
|
// set default DRB
|
||||||
if (sdap->defaultDRB) {
|
if (sdap->defaultDRB) {
|
||||||
sdap_entity->default_drb = sdap->drb_id;
|
sdap_entity->default_drb.drb_id = sdap->drb_id;
|
||||||
LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb);
|
sdap_entity->default_drb.entity_role = sdap->role;
|
||||||
|
LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb.drb_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sdap_entity->enable_sdap) {
|
if (sdap->role == NO_SDAP_HEADER) {
|
||||||
AssertFatal(sdap->mappedQFIs2AddCount <= 1,
|
AssertFatal(sdap->mappedQFIs2AddCount <= 1,
|
||||||
"PDU session %d: disabled SDAP allows at most one QoS flow to add at entity creation\n",
|
"PDU session %d: both SDAP headers absent: at most one QoS flow at entity creation\n",
|
||||||
sdap->pdusession_id);
|
sdap->pdusession_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,61 +672,46 @@ void nr_sdap_release_drb(ue_id_t ue_id, int drb_id, int pdusession_id)
|
|||||||
* On E1 Bearer Context Modification (CP to UP), Flow Mapping Information in DRB To Modify
|
* On E1 Bearer Context Modification (CP to UP), Flow Mapping Information in DRB To Modify
|
||||||
* carries the QoS Flow QoS Parameters List for that DRB. Per TS 38.463, when present the
|
* carries the QoS Flow QoS Parameters List for that DRB. Per TS 38.463, when present the
|
||||||
* CU-UP replaces the previous mapping for that DRB.
|
* CU-UP replaces the previous mapping for that DRB.
|
||||||
* Remove every QFI currently mapped to the DRB that is absent from the list of QFIs to be mapped.
|
* @param sdap mapped QoS flows to add */
|
||||||
* @param qfis[] list of QFIs to be mapped to the DRB
|
void nr_sdap_entity_update_qos_flows(ue_id_t ue_id, sdap_config_t *sdap)
|
||||||
* @param n_qfis number of QFIs in the list
|
|
||||||
* @param drb_id the DRB ID to be mapped */
|
|
||||||
void nr_sdap_entity_update_qos_flows(ue_id_t ue_id, int pdusession_id, int drb_id, const uint8_t *qfis, int n_qfis)
|
|
||||||
{
|
{
|
||||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdusession_id);
|
DevAssert(sdap);
|
||||||
|
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, sdap->pdusession_id);
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
LOG_W(SDAP, "gNB SDAP: no entity for UE %lu PDU session %d when updating QoS flows for DRB %d\n", ue_id, pdusession_id, drb_id);
|
LOG_W(SDAP, "No entity when updating QoS flows for DRB %d (pdu_session=%d)\n", sdap->drb_id, sdap->pdusession_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Derive SDAP role from entity configuration */
|
const qfi2drb_t *drb_map = nr_sdap_drb_lookup(entity, sdap->drb_id);
|
||||||
uint8_t role = NO_SDAP_HEADER;
|
if (!drb_map) {
|
||||||
if (entity->enable_sdap) {
|
LOG_E(SDAP, "DRB %d: no qfi2drb_table entry, skip QoS-flow mapping update (pdu_session=%d)\n", sdap->drb_id, sdap->pdusession_id);
|
||||||
if (entity->is_gnb) {
|
return;
|
||||||
role |= SDAP_UL_RX;
|
|
||||||
role |= SDAP_DL_TX;
|
|
||||||
} else {
|
|
||||||
role |= SDAP_UL_TX;
|
|
||||||
role |= SDAP_DL_RX;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* TS 38.331: sdap-HeaderUL/DL cannot change after DRB establishment */
|
||||||
|
sdap->role = drb_map->entity_role;
|
||||||
|
sdap->defaultDRB = (entity->default_drb.drb_id == sdap->drb_id);
|
||||||
|
|
||||||
sdap_config_t sdap = {.pdusession_id = pdusession_id,
|
/* TS 37.324 clause 5.3.1 mappedQoS-FlowsToRelease: QFIs on this DRB not in the new list */
|
||||||
.drb_id = drb_id,
|
|
||||||
.role = role,
|
|
||||||
.defaultDRB = (entity->default_drb == drb_id),
|
|
||||||
.mappedQFIs2AddCount = n_qfis};
|
|
||||||
|
|
||||||
/* Build list of QFIs to be released */
|
|
||||||
for (int q = 0; q < SDAP_MAX_QFI; q++) {
|
for (int q = 0; q < SDAP_MAX_QFI; q++) {
|
||||||
if (entity->qfi2drb_table[q].drb_id != drb_id)
|
if (entity->qfi2drb_table[q].drb_id != sdap->drb_id)
|
||||||
continue;
|
continue;
|
||||||
bool keep = false;
|
bool keep = false;
|
||||||
for (int i = 0; i < n_qfis; i++) {
|
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
|
||||||
if (qfis[i] == q) {
|
if (sdap->mappedQFIs2Add[i] == q) {
|
||||||
keep = true;
|
keep = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
DevAssert(sdap.mappedQFIs2ReleaseCount < SDAP_MAX_QFI);
|
DevAssert(sdap->mappedQFIs2ReleaseCount < SDAP_MAX_QFI);
|
||||||
sdap.mappedQFIs2Release[sdap.mappedQFIs2ReleaseCount++] = q;
|
sdap->mappedQFIs2Release[sdap->mappedQFIs2ReleaseCount++] = q;
|
||||||
LOG_I(SDAP, "gNB SDAP mapping update: UE %lu pduSession %d DRB %d release_qfi=%d\n", ue_id, pdusession_id, drb_id, q);
|
LOG_I(SDAP, "Update: release QFI %d from DRB %d (pdu_session=%d)\n", q, sdap->drb_id, sdap->pdusession_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build list of QFIs to be added */
|
LOG_I(SDAP, "Update: add %d QFIs to DRB %d (pdu_session=%d)\n", sdap->mappedQFIs2AddCount, sdap->drb_id, sdap->pdusession_id);
|
||||||
for (int i = 0; i < n_qfis; i++)
|
/* TS 37.324 clause 5.3.1: mappedQoS-FlowsToAdd and apply mapping on the DRB */
|
||||||
sdap.mappedQFIs2Add[i] = qfis[i];
|
entity->qfi2drb_map_update(entity, sdap);
|
||||||
|
|
||||||
LOG_I(SDAP, "gNB SDAP mapping update: UE %lu pduSession %d DRB %d n_qfis=%d\n", ue_id, pdusession_id, drb_id, n_qfis);
|
|
||||||
|
|
||||||
entity->qfi2drb_map_update(entity, &sdap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||||
@@ -783,7 +795,6 @@ sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_
|
|||||||
sdap_config_t sdapConfig = {0};
|
sdap_config_t sdapConfig = {0};
|
||||||
sdapConfig.drb_id = drb_id;
|
sdapConfig.drb_id = drb_id;
|
||||||
sdapConfig.role = get_sdap_role(is_gnb, sdap_Config);
|
sdapConfig.role = get_sdap_role(is_gnb, sdap_Config);
|
||||||
LOG_D(SDAP, "SDAP headers %s\n", sdapConfig.role == NO_SDAP_HEADER ? "absent" : "present");
|
|
||||||
sdapConfig.defaultDRB = sdap_Config->defaultDRB;
|
sdapConfig.defaultDRB = sdap_Config->defaultDRB;
|
||||||
// 3GPP TS 38.331 The network sets sdap-HeaderUL to present if the field defaultDRB is set to true
|
// 3GPP TS 38.331 The network sets sdap-HeaderUL to present if the field defaultDRB is set to true
|
||||||
if (sdapConfig.defaultDRB && (sdap_Config->sdap_HeaderUL != NR_SDAP_Config__sdap_HeaderUL_present))
|
if (sdapConfig.defaultDRB && (sdap_Config->sdap_HeaderUL != NR_SDAP_Config__sdap_HeaderUL_present))
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#define SDAP_HDR_UL_CTRL_PDU (0)
|
#define SDAP_HDR_UL_CTRL_PDU (0)
|
||||||
#define SDAP_HDR_LENGTH (1)
|
#define SDAP_HDR_LENGTH (1)
|
||||||
#define SDAP_MAX_QFI (64)
|
#define SDAP_MAX_QFI (64)
|
||||||
#define SDAP_MAP_RULE_EMPTY (0)
|
|
||||||
#define SDAP_NO_MAPPING_RULE (0)
|
#define SDAP_NO_MAPPING_RULE (0)
|
||||||
#define SDAP_REFLECTIVE_MAPPING (1)
|
#define SDAP_REFLECTIVE_MAPPING (1)
|
||||||
#define SDAP_RQI_HANDLING (1)
|
#define SDAP_RQI_HANDLING (1)
|
||||||
@@ -78,17 +77,16 @@ typedef struct sdap_configuration_s {
|
|||||||
|
|
||||||
typedef struct nr_sdap_entity_s {
|
typedef struct nr_sdap_entity_s {
|
||||||
ue_id_t ue_id;
|
ue_id_t ue_id;
|
||||||
int default_drb;
|
|
||||||
/// sdap_tun_read_thread needs to know if we are gNB/UE, so for noS1 mode,
|
/// sdap_tun_read_thread needs to know if we are gNB/UE, so for noS1 mode,
|
||||||
/// store which one we are
|
/// store which one we are
|
||||||
bool is_gnb;
|
bool is_gnb;
|
||||||
bool enable_sdap;
|
|
||||||
int pdusession_id;
|
int pdusession_id;
|
||||||
int pdusession_sock;
|
int pdusession_sock;
|
||||||
pthread_t pdusession_thread;
|
pthread_t pdusession_thread;
|
||||||
bool stop_thread;
|
bool stop_thread;
|
||||||
int qfi;
|
int qfi;
|
||||||
|
|
||||||
|
qfi2drb_t default_drb;
|
||||||
qfi2drb_t qfi2drb_table[SDAP_MAX_QFI];
|
qfi2drb_t qfi2drb_table[SDAP_MAX_QFI];
|
||||||
|
|
||||||
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, const sdap_config_t *sdap);
|
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, const sdap_config_t *sdap);
|
||||||
@@ -97,7 +95,7 @@ typedef struct nr_sdap_entity_s {
|
|||||||
const uint8_t qfi,
|
const uint8_t qfi,
|
||||||
const uint8_t drb_id,
|
const uint8_t drb_id,
|
||||||
const uint8_t role);
|
const uint8_t role);
|
||||||
int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi);
|
const qfi2drb_t *(*qfi2drb_map)(const struct nr_sdap_entity_s *entity, uint8_t qfi);
|
||||||
|
|
||||||
nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi);
|
nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi);
|
||||||
int (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, int map_type, uint8_t dl_qfi);
|
int (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, int map_type, uint8_t dl_qfi);
|
||||||
@@ -116,13 +114,7 @@ typedef struct nr_sdap_entity_s {
|
|||||||
const uint8_t qfi,
|
const uint8_t qfi,
|
||||||
const bool rqi);
|
const bool rqi);
|
||||||
|
|
||||||
void (*rx_entity)(struct nr_sdap_entity_s *entity,
|
void (*rx_entity)(struct nr_sdap_entity_s *entity, int drb_id, int is_gnb, int pdusession_id, ue_id_t ue_id, char *buf, int size);
|
||||||
int pdcp_entity,
|
|
||||||
int is_gnb,
|
|
||||||
int pdusession_id,
|
|
||||||
ue_id_t ue_id,
|
|
||||||
char *buf,
|
|
||||||
int size);
|
|
||||||
|
|
||||||
/* List of entities */
|
/* List of entities */
|
||||||
struct nr_sdap_entity_s *next_entity;
|
struct nr_sdap_entity_s *next_entity;
|
||||||
@@ -182,7 +174,7 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id);
|
|||||||
*/
|
*/
|
||||||
void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, int pdusession_id, int drb_id);
|
void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, int pdusession_id, int drb_id);
|
||||||
|
|
||||||
void nr_sdap_entity_update_qos_flows(ue_id_t ue_id, int pdusession_id, int drb_id, const uint8_t *qfis, int n_qfis);
|
void nr_sdap_entity_update_qos_flows(ue_id_t ue_id, sdap_config_t *sdap);
|
||||||
|
|
||||||
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id);
|
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user