Commit 0f43c2c7 authored by Robert Schmidt's avatar Robert Schmidt

PDCP DL handling: unlock PDCP before forwarding PDU

nr_pdcp_entity_recv_sdu() processes PDCP SDUs, and forwards the PDU at the
end of the function, while having the PDCP lock. This can lead to
deadlocks, e.g., when another thread goes through RLC and tries to
access the PDCP while the PDCP tries to lock the RLC.

This commit changes the logic: instead of having recv_sdu() forward the
PDU directly, it fills a buffer with the PDU (thus the name change to
process_sdu()), and returns. We then unlock the PDCP, before forwarding
the PDU, thus eliminating potential deadlocks.
parent c405ad16
......@@ -176,14 +176,19 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
}
}
static void nr_pdcp_entity_recv_sdu(nr_pdcp_entity_t *entity,
char *buffer, int size, int sdu_id)
static int nr_pdcp_entity_process_sdu(nr_pdcp_entity_t *entity,
char *buffer,
int size,
int sdu_id,
char *pdu_buffer,
int pdu_max_size)
{
uint32_t count;
int sn;
int header_size;
int integrity_size;
char buf[size + 3 + 4];
char *buf = pdu_buffer;
DevAssert(size + 3 + 4 <= pdu_max_size);
int dc_bit;
entity->stats.rxsdu_pkts++;
entity->stats.rxsdu_bytes += size;
......@@ -243,13 +248,11 @@ static void nr_pdcp_entity_recv_sdu(nr_pdcp_entity_t *entity,
entity->tx_next++;
entity->deliver_pdu(entity->deliver_pdu_data, entity, buf,
header_size + size + integrity_size, sdu_id);
entity->stats.txpdu_pkts++;
entity->stats.txpdu_bytes += header_size + size + integrity_size;
entity->stats.txpdu_sn = sn;
return header_size + size + integrity_size;
}
/* may be called several times, take care to clean previous settings */
......@@ -420,7 +423,7 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
ret->type = type;
ret->recv_pdu = nr_pdcp_entity_recv_pdu;
ret->recv_sdu = nr_pdcp_entity_recv_sdu;
ret->process_sdu = nr_pdcp_entity_process_sdu;
ret->set_security = nr_pdcp_entity_set_security;
ret->set_time = nr_pdcp_entity_set_time;
......
......@@ -73,8 +73,8 @@ typedef struct nr_pdcp_entity_t {
/* functions provided by the PDCP module */
void (*recv_pdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size);
void (*recv_sdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size,
int sdu_id);
int (*process_sdu)(struct nr_pdcp_entity_t *entity, char *buffer, int size,
int sdu_id, char *pdu_buffer, int pdu_max_size);
void (*delete_entity)(struct nr_pdcp_entity_t *entity);
void (*get_stats)(struct nr_pdcp_entity_t *entity, nr_pdcp_statistics_t *out);
......
......@@ -1173,10 +1173,15 @@ bool nr_pdcp_data_req_srb(ue_id_t ue_id,
return 0;
}
rb->recv_sdu(rb, (char *)sdu_buffer, sdu_buffer_size, muiP);
int max_size = sdu_buffer_size + 3 + 4; // 3: max header, 4: max integrity
char pdu_buf[max_size];
int pdu_size = rb->process_sdu(rb, (char *)sdu_buffer, sdu_buffer_size, muiP, pdu_buf, max_size);
deliver_pdu deliver_pdu_cb = rb->deliver_pdu;
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
deliver_pdu_cb(rb->deliver_pdu_data, rb, pdu_buf, pdu_size, muiP);
return 1;
}
......@@ -1223,10 +1228,15 @@ bool nr_pdcp_data_req_drb(protocol_ctxt_t *ctxt_pP,
return 0;
}
rb->recv_sdu(rb, (char *)sdu_buffer, sdu_buffer_size, muiP);
int max_size = sdu_buffer_size + 3 + 4; // 3: max header, 4: max integrity
char pdu_buf[max_size];
int pdu_size = rb->process_sdu(rb, (char *)sdu_buffer, sdu_buffer_size, muiP, pdu_buf, max_size);
deliver_pdu deliver_pdu_cb = rb->deliver_pdu;
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
deliver_pdu_cb(rb->deliver_pdu_data, rb, pdu_buf, pdu_size, muiP);
return 1;
}
......
......@@ -77,6 +77,8 @@ bool cu_f1u_data_req(protocol_ctxt_t *ctxt_pP,
const uint32_t *const sourceL2Id,
const uint32_t *const destinationL2Id);
typedef void (*deliver_pdu)(void *data, nr_pdcp_entity_t *entity,
char *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,
......
......@@ -39,11 +39,18 @@ instance_t *N3GTPUInst = NULL;
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
{
nr_pdcp_ue_t *ue;
nr_pdcp_ue_manager_t *nr_pdcp_ue_manager;
nr_pdcp_ue_manager = nr_pdcp_sdap_get_ue_manager();
ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
ue->drb[sdap_ctrl_pdu_drb-1]->recv_sdu(ue->drb[sdap_ctrl_pdu_drb-1], (char*)&ctrl_pdu, SDAP_HDR_LENGTH, RLC_MUI_UNDEFINED);
protocol_ctxt_t ctxt = { .rntiMaybeUEid = ue_id };
nr_pdcp_data_req_drb(&ctxt,
SRB_FLAG_NO,
sdap_ctrl_pdu_drb,
RLC_MUI_UNDEFINED,
SDU_CONFIRM_NO,
SDAP_HDR_LENGTH,
(unsigned char *)&ctrl_pdu,
PDCP_TRANSMISSION_MODE_UNKNOWN,
NULL,
NULL);
LOG_D(SDAP, "Control PDU - Submitting Control PDU to DRB ID: %ld\n", sdap_ctrl_pdu_drb);
LOG_D(SDAP, "QFI: %u\n R: %u\n D/C: %u\n", ctrl_pdu.QFI, ctrl_pdu.R, ctrl_pdu.DC);
return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment