Commit b86f157c authored by Raphael Defosseux's avatar Raphael Defosseux

Merge remote-tracking branch 'origin/f1-ho-prep' into integration_2024_w36

parents 5043f6e2 ab89324b
......@@ -62,12 +62,12 @@ nr_measurement_configuration = {
};
A3 = ({
cell_id = -1; #Default
physCellId = -1; #Default
offset = 10;
hysteresis = 0;
timeToTrigger = 1
}, {
cell_id = 2;
physCellId = 2;
offset = 5;
hysteresis = 1;
timeToTrigger = 2
......
......@@ -1161,9 +1161,9 @@ void nr_timer_stop(NR_timer_t *timer)
timer->counter = 0;
}
bool is_nr_timer_active(NR_timer_t timer)
bool nr_timer_is_active(const NR_timer_t *timer)
{
return timer.active;
return timer->active;
}
bool nr_timer_tick(NR_timer_t *timer)
......@@ -1173,23 +1173,23 @@ bool nr_timer_tick(NR_timer_t *timer)
timer->counter += timer->step;
if (timer->target == UINT_MAX) // infinite target, never expires
return false;
expired = nr_timer_expired(*timer);
expired = nr_timer_expired(timer);
if (expired)
timer->active = false;
}
return expired;
}
bool nr_timer_expired(NR_timer_t timer)
bool nr_timer_expired(const NR_timer_t *timer)
{
if (timer.target == UINT_MAX) // infinite target, never expires
if (timer->target == UINT_MAX) // infinite target, never expires
return false;
return (timer.counter >= timer.target);
return timer->counter >= timer->target;
}
uint32_t nr_timer_elapsed_time(NR_timer_t timer)
uint32_t nr_timer_elapsed_time(const NR_timer_t *timer)
{
return timer.counter;
return timer->counter;
}
void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step)
......
......@@ -163,19 +163,19 @@ void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t ste
* @param timer Timer to be checked
* @return Indication if the timer is expired or not
*/
bool nr_timer_expired(NR_timer_t timer);
bool nr_timer_expired(const NR_timer_t *timer);
/**
* @brief To check if a timer is active
* @param timer Timer to be checked
* @return Indication if the timer is active or not
*/
bool is_nr_timer_active(NR_timer_t timer);
bool nr_timer_is_active(const NR_timer_t *timer);
/**
* @brief To return how much time has passed since start of timer
* @param timer Timer to be checked
* @return Time passed since start of timer
*/
uint32_t nr_timer_elapsed_time(NR_timer_t timer);
uint32_t nr_timer_elapsed_time(const NR_timer_t *timer);
extern const nr_bandentry_t nr_bandtable[];
......
......@@ -29,13 +29,13 @@ TEST(nr_common, nr_timer) {
NR_timer_t timer;
nr_timer_setup(&timer, 10, 1);
nr_timer_start(&timer);
EXPECT_TRUE(is_nr_timer_active(timer));
EXPECT_FALSE(nr_timer_expired(timer));
EXPECT_TRUE(nr_timer_is_active(&timer));
EXPECT_FALSE(nr_timer_expired(&timer));
for (auto i = 0; i < 10; i++) {
nr_timer_tick(&timer);
}
EXPECT_FALSE(is_nr_timer_active(timer));
EXPECT_TRUE(nr_timer_expired(timer));
EXPECT_FALSE(nr_timer_is_active(&timer));
EXPECT_TRUE(nr_timer_expired(&timer));
}
......
......@@ -320,7 +320,7 @@ typedef struct timer_elm_s {
(char *)itti_get_task_name(task_id),
-1,
OAI_PRIORITY_RT);
LOG_I(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) );
LOG_D(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) );
return 0;
}
......
......@@ -278,8 +278,6 @@ typedef struct pdusession_s {
transport_layer_addr_t upf_addr;
/* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
uint32_t gtp_teid;
/* Stores the DRB ID of the DRBs used by this PDU Session */
uint8_t used_drbs[MAX_DRBS_PER_UE];
/* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */
uint32_t gNB_teid_N3;
transport_layer_addr_t gNB_addr_N3;
......
......@@ -64,27 +64,17 @@ static void cu_task_handle_sctp_association_ind(instance_t instance,
static void cu_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
DevAssert(sctp_new_association_resp != NULL);
if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) {
enum sctp_state_e state = sctp_new_association_resp->sctp_state;
if (state != SCTP_STATE_ESTABLISHED) {
f1ap_cudu_inst_t *f1ap_cu_data = getCxt(instance);
AssertFatal(f1ap_cu_data != NULL, "illegal state: SCTP shutdown for non-existing F1AP endpoint\n");
LOG_I(F1AP, "Received SCTP shutdown for assoc_id %d, removing endpoint\n", sctp_new_association_resp->assoc_id);
LOG_I(F1AP, "Received SCTP state %d for assoc_id %d, removing endpoint\n", state, sctp_new_association_resp->assoc_id);
/* inform RRC that the DU is gone */
MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_LOST_CONNECTION);
message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id;
itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
return;
}
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
LOG_W(F1AP, "Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n",
sctp_new_association_resp->sctp_state,
instance,
sctp_new_association_resp->ulp_cnx_id);
//if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN)
//proto_agent_stop(instance);
//f1ap_handle_setup_message(instance, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
return; // exit -1 for debugging
}
}
static void cu_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) {
......
......@@ -281,12 +281,9 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i
memcpy(f1ap_ue_context_setup_req->rrc_container,
ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size);
f1ap_ue_context_setup_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size;
// AssertFatal(0, "check configuration, send to appropriate handler\n");
} else {
LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n");
}
} else {
LOG_W(F1AP, "can't find RRCContainer in UEContextSetupRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer);
}
ue_context_setup_request(f1ap_ue_context_setup_req);
......@@ -596,6 +593,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set
F1AP_SRBs_Setup_Item_t *srbs_setup_item=&srbs_setup_item_ies->value.choice.SRBs_Setup_Item;
/* sRBID */
srbs_setup_item->sRBID = resp->srbs_to_be_setup[i].srb_id;
srbs_setup_item->lCID = resp->srbs_to_be_setup[i].lcid;
}
}
......
......@@ -40,13 +40,13 @@ int f1ap_encode_pdu(F1AP_F1AP_PDU_t *pdu, uint8_t **buffer, uint32_t *length) {
LOG_E(F1AP, "----------------- ASN1 ENCODER PRINT END----------------- \n");
}
char errbuf[128]; /* Buffer for error message */
char errbuf[4096]; /* Buffer for error message */
size_t errlen = sizeof(errbuf); /* Size of the buffer */
int ret = asn_check_constraints(&asn_DEF_F1AP_F1AP_PDU, pdu, errbuf, &errlen);
/* assert(errlen < sizeof(errbuf)); // Guaranteed: you may rely on that */
if(ret) {
fprintf(stderr, "Constraint validation failed: %s\n", errbuf);
xer_fprint(stdout, &asn_DEF_F1AP_F1AP_PDU, pdu);
LOG_E(F1AP, "Constraint validation failed: %s\n", errbuf);
}
encoded = aper_encode_to_new_buffer(&asn_DEF_F1AP_F1AP_PDU, 0, pdu, (void **)buffer);
......
......@@ -1598,7 +1598,7 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc
paramdef_t NeighbourCellParams[] = GNBNEIGHBOURCELLPARAMS_DESC;
paramlist_def_t NeighbourCellParamList = {GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, NULL, 0};
config_getlist(config_get_if(), &NeighbourCellParamList, NeighbourCellParams, sizeofArray(NeighbourCellParams), neighbourpath);
LOG_D(GNB_APP, "HO LOG: For the Cell: %d Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt);
LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt);
if (NeighbourCellParamList.numelt < 1)
continue;
......@@ -1696,12 +1696,17 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
for (int i = 0; i < A3_EventList.numelt; i++) {
nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t));
AssertFatal(a3_event != NULL, "out of memory\n");
a3_event->cell_id = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_CELL_ID_IDX].i64ptr;
a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr;
AssertFatal(a3_event->pci >= -1 && a3_event->pci < 1024,
"entry %s.%s must be -1<=PCI<1024, but is %d\n",
measurement_path,
MEASUREMENT_EVENTS_PCI_ID,
a3_event->pci);
a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr;
a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr;
a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr;
if (a3_event->cell_id == -1)
if (a3_event->pci == -1)
measurementConfig->is_default_a3_configuration_exists = true;
seq_arr_push_back(measurementConfig->a3_event_list, a3_event, sizeof(nr_a3_event_t));
......
......@@ -324,12 +324,12 @@ typedef enum {
#define MEASUREMENT_EVENTS_THRESHOLD "threshold"
#define MEASUREMENT_EVENTS_PERIODICAL_BEAM_MEASUREMENT "includeBeamMeasurements"
#define MEASUREMENT_EVENTS_PERIODICAL_NR_OF_RS_INDEXES "maxNrofRS_IndexesToReport"
#define MEASUREMENT_EVENTS_CELL_ID "cell_id"
#define MEASUREMENT_EVENTS_PCI_ID "physCellId"
#define MEASUREMENT_EVENT_ENABLE "enable"
// clang-format off
#define MEASUREMENT_A3_GLOBALPARAMS_DESC \
{ \
{MEASUREMENT_EVENTS_CELL_ID, "neighbour cellId for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_PCI_ID, "neighbour PCI for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_TIME_TO_TRIGGER, "a3 time to trigger", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_OFFSET, "a3 offset", 0, .i64ptr = NULL, .defint64val = 60, TYPE_INT64, 0}, \
{MEASUREMENT_EVENTS_HYSTERESIS, "a3 hysteresis", 0, .i64ptr = NULL, .defint64val = 0, TYPE_INT64, 0}, \
......@@ -350,7 +350,7 @@ typedef enum {
}
// clang-format on
#define MEASUREMENT_EVENTS_CELL_ID_IDX 0
#define MEASUREMENT_EVENTS_PCI_ID_IDX 0
#define MEASUREMENT_EVENTS_ENABLE_IDX 0
#define MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX 1
#define MEASUREMENT_EVENTS_A2_THRESHOLD_IDX 2
......
......@@ -790,7 +790,7 @@ void nr_ue_get_rach(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB
}
}
if (is_nr_timer_active(ra->contention_resolution_timer)) {
if (nr_timer_is_active(&ra->contention_resolution_timer)) {
nr_ue_contention_resolution(mac, CC_id, frame, nr_slot_tx, prach_resources);
}
}
......@@ -851,7 +851,7 @@ void nr_ue_contention_resolution(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame
{
RA_config_t *ra = &mac->ra;
if (nr_timer_expired(ra->contention_resolution_timer)) {
if (nr_timer_expired(&ra->contention_resolution_timer)) {
ra->t_crnti = 0;
nr_timer_stop(&ra->contention_resolution_timer);
// Signal PHY to quit RA procedure
......
......@@ -2543,7 +2543,7 @@ int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_Schedu
sr_id); // todo
// TODO check if the PUCCH resource for the SR transmission occasion does not overlap with a UL-SCH resource
if (!sr_info->pending || is_nr_timer_active(sr_info->prohibitTimer))
if (!sr_info->pending || nr_timer_is_active(&sr_info->prohibitTimer))
return 0;
if (sr_info->counter < sr_info->maxTransmissions) {
......
......@@ -1297,7 +1297,7 @@ static void nr_update_sr(NR_UE_MAC_INST_t *mac)
// if a Regular BSR has been triggered and logicalChannelSR-DelayTimer is not running
if (((sched_info->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0)
|| is_nr_timer_active(sched_info->sr_DelayTimer))
|| nr_timer_is_active(&sched_info->sr_DelayTimer))
return;
nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, sched_info->regularBSR_trigger_lcid);
......@@ -1527,7 +1527,7 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
int32_t bj = sched_info->Bj;
if (lc_info->pbr < UINT_MAX) {
uint32_t slots_elapsed = nr_timer_elapsed_time(sched_info->Bj_timer); // slots elapsed since Bj was last incremented
uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented
// it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s
uint32_t pbr_ms = lc_info->pbr / 1000;
bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms
......
......@@ -560,7 +560,7 @@ static void start_ra_contention_resolution_timer(NR_RA_t *ra, const long ra_Cont
// Value sf8 corresponds to 8 subframes, value sf16 corresponds to 16 subframes, and so on.
// We add 2 * K2 because the timer runs from Msg2 transmission till Msg4 ACK reception
ra->contention_resolution_timer = ((((int)ra_ContentionResolutionTimer + 1) * 8) << scs) + 2 * K2;
LOG_I(NR_MAC,
LOG_D(NR_MAC,
"Starting RA Contention Resolution timer with %d ms + 2 * %d K2 (%d slots) duration\n",
((int)ra_ContentionResolutionTimer + 1) * 8,
K2,
......
......@@ -860,12 +860,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
// re-initialize ta update variables after RA procedure completion
UE->UE_sched_ctrl.ta_frame = frameP;
LOG_I(NR_MAC,
"[gNB %d][RAPROC] PUSCH with TC_RNTI 0x%04x received correctly, "
"adding UE MAC Context RNTI 0x%04x\n",
gnb_mod_idP,
current_rnti,
ra->rnti);
LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frameP, slotP, current_rnti);
NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
if (ul_cqi != 0xff) {
......@@ -884,7 +879,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, ra->CellGroup->rlc_BearerToAddModList);
nr_clear_ra_proc(ra);
} else {
LOG_A(NR_MAC, "[RAPROC] RA-Msg3 received (sdu_lenP %d)\n", sdu_lenP);
LOG_D(NR_MAC, "[RAPROC] Received Msg3:\n");
for (uint32_t k = 0; k < sdu_lenP; k++) {
LOG_D(NR_MAC, "(%i): 0x%x\n", k, sduP[k]);
......
......@@ -233,7 +233,8 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE,
nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .priority = priority};
nr_mac_add_lcid(&UE->UE_sched_ctrl, &c);
(*resp_srbs)[i] = *srb;
(*resp_srbs)[i].srb_id = srb->srb_id;
(*resp_srbs)[i].lcid = c.lcid;
int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
DevAssert(ret == 0);
......@@ -669,8 +670,12 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd)
NR_SCHED_LOCK(&mac->sched_lock);
NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, cmd->gNB_DU_ue_id);
if (UE == NULL) {
LOG_E(MAC, "ERROR: unknown UE with RNTI %04x, ignoring UE Context Release Command\n", cmd->gNB_DU_ue_id);
NR_SCHED_UNLOCK(&mac->sched_lock);
f1ap_ue_context_release_complete_t complete = {
.gNB_CU_ue_id = cmd->gNB_CU_ue_id,
.gNB_DU_ue_id = cmd->gNB_DU_ue_id,
};
mac->mac_rrc.ue_context_release_complete(&complete);
return;
}
......@@ -743,7 +748,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
* the new UE context (with new C-RNTI), but set up everything to reuse the
* old config. */
NR_UE_info_t *oldUE = find_nr_UE(&mac->UE_info, *dl_rrc->old_gNB_DU_ue_id);
DevAssert(oldUE);
AssertFatal(oldUE, "CU claims we should know UE %04x, but we don't\n", *dl_rrc->old_gNB_DU_ue_id);
pthread_mutex_lock(&mac->sched_lock);
/* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it
* from the current configuration. Also, expect the reconfiguration from
......
......@@ -1165,10 +1165,9 @@ static NR_ReportConfigToAddMod_t *prepare_a2_event_report(const nr_a2_event_t *a
static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event)
{
NR_ReportConfigToAddMod_t *rc_A3 = calloc(1, sizeof(*rc_A3));
rc_A3->reportConfigId =
a3_event->cell_id == -1
? 3
: a3_event->cell_id + 4; // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID starts from 4
// 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID
// starts from 4
rc_A3->reportConfigId = a3_event->pci == -1 ? 3 : a3_event->pci + 4;
rc_A3->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR;
NR_EventTriggerConfig_t *etrc_A3 = calloc(1, sizeof(*etrc_A3));
etrc_A3->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA3;
......@@ -1194,7 +1193,7 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a
return rc_A3;
}
const nr_a3_event_t *get_a3_configuration(int nr_cellid)
const nr_a3_event_t *get_a3_configuration(int pci)
{
gNB_RRC_INST *rrc = RC.nrrrc[0];
nr_measurement_configuration_t *measurementConfiguration = &rrc->measurementConfiguration;
......@@ -1203,7 +1202,7 @@ const nr_a3_event_t *get_a3_configuration(int nr_cellid)
for (uint8_t i = 0; i < measurementConfiguration->a3_event_list->size; i++) {
nr_a3_event_t *a3_event = (nr_a3_event_t *)seq_arr_at(measurementConfiguration->a3_event_list, i);
if (a3_event->cell_id == nr_cellid)
if (a3_event->pci == pci)
return a3_event;
}
......@@ -1262,11 +1261,11 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
if (!neighbourCell->isIntraFrequencyNeighbour)
continue;
const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->nrcell_id);
const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->physicalCellId);
if (!a3Event || is_default_a3_added)
continue;
if (a3Event->cell_id == -1)
if (a3Event->pci == -1)
is_default_a3_added = true;
NR_ReportConfigToAddMod_t *rc_A3 = prepare_a3_event_report(a3Event);
......@@ -1368,7 +1367,7 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi)
LOG_D(NR_RRC, "[gNB %d] do_Paging paging_record: PagingRecordList.count %d\n",
Mod_id, c1->choice.paging->pagingRecordList->list.count);
asn_enc_rval_t enc_rval = uper_encode_to_buffer(
&asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, RRC_BUF_SIZE);
&asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, NR_RRC_BUF_SIZE);
if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
xer_fprint(stdout, &asn_DEF_NR_PCCH_Message, (void *)&pcch_msg);
......
......@@ -143,7 +143,7 @@ int do_RRCReestablishment(rrc_gNB_ue_context_t *const ue_context_pP,
int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t rrc_TransactionIdentifier);
const nr_a3_event_t *get_a3_configuration(int nr_cellid);
const nr_a3_event_t *get_a3_configuration(int pci);
NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
int band,
int scs,
......
......@@ -26,17 +26,9 @@
#include <stdlib.h>
#include <stdint.h>
#define NR_RRC_HEADER_SIZE_MAX 64
#define NR_RRC_BUFFER_SIZE_MAX 1024
#define NR_NUM_SRB 4 /* Number of Signalling Radio Bearers according to clause 4.2.2 of 3GPP TS 38.331 */
#define NR_K_KEY_SIZE 16 /* K keys have 128 bits length */
typedef struct {
char Payload[NR_RRC_BUFFER_SIZE_MAX];
char Header[NR_RRC_HEADER_SIZE_MAX];
uint16_t payload_size;
} NR_RRC_BUFFER;
typedef enum UE_STATE_NR_e {
NR_RRC_INACTIVE=0,
NR_RRC_IDLE,
......
......@@ -2805,6 +2805,8 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
&& servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count > 0) {
n_dl_bwp = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count;
}
int default_dl_bwp = 0;
int first_active_dl_bwp = 0;
if (n_dl_bwp > 0) {
SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList =
calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList));
......@@ -2813,15 +2815,13 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
config_downlinkBWP(bwp, scc, servingcellconfigdedicated, NULL, 0, false, bwp_loop, true);
asn1cSeqAdd(&SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp);
}
SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id =
calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id));
*SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id =
servingcellconfigdedicated->firstActiveDownlinkBWP_Id ? *servingcellconfigdedicated->firstActiveDownlinkBWP_Id : 1;
SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id =
calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id));
*SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id =
servingcellconfigdedicated->defaultDownlinkBWP_Id ? *servingcellconfigdedicated->defaultDownlinkBWP_Id : 1;
const NR_BWP_Id_t *firstActiveDownlinkBWP_Id = servingcellconfigdedicated->firstActiveDownlinkBWP_Id;
first_active_dl_bwp = firstActiveDownlinkBWP_Id ? *firstActiveDownlinkBWP_Id : 1;
const NR_BWP_Id_t *defaultDownlinkBWP_Id = servingcellconfigdedicated->defaultDownlinkBWP_Id;
default_dl_bwp = defaultDownlinkBWP_Id ? *defaultDownlinkBWP_Id : 1;
}
asn1cCallocOne(SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id, first_active_dl_bwp);
asn1cCallocOne(SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id, default_dl_bwp);
// Uplink BWPs
int n_ul_bwp = 0;
......@@ -2830,6 +2830,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
&& servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count > 0) {
n_ul_bwp = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count;
}
int first_active_ul_bwp = 0;
if (n_ul_bwp > 0) {
uplinkConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList));
for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) {
......@@ -2837,11 +2838,10 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
config_uplinkBWP(ubwp, bwp_loop, true, uid, configuration, servingcellconfigdedicated, scc, NULL);
asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp);
}
uplinkConfig->firstActiveUplinkBWP_Id = calloc(1, sizeof(*uplinkConfig->firstActiveUplinkBWP_Id));
*uplinkConfig->firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id
? *servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id
: 1;
const NR_BWP_Id_t *firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id;
first_active_ul_bwp = firstActiveUplinkBWP_Id ? *firstActiveUplinkBWP_Id : 1;
}
asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_ul_bwp);
SpCellConfig->spCellConfigDedicated->csi_MeasConfig = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig));
SpCellConfig->spCellConfigDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup;
......
......@@ -88,15 +88,6 @@
#define NR_RRC_RECONFIGURATION_DELAY_MS 10
#define NR_RRC_BWP_SWITCHING_DELAY_MS 6
// 3GPP TS 38.133 - Section 8 - Table 8.2.1.2.7-2: Parameters which cause interruption other than SCS
// This table was recently added to 3GPP. It shows that changing the parameters locationAndBandwidth, nrofSRS-Ports or
// maxMIMO-Layers-r16 causes an interruption. This parameter is not yet being used in code, but has been placed here
// for future reference.
#define NR_OF_SRS_PORTS_SWITCHING_DELAY_MS 30
#define NR_UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!!
#define NR_UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1
typedef enum {
NR_RRC_OK=0,
NR_RRC_ConnSetup_failed,
......@@ -105,17 +96,11 @@ typedef enum {
NR_RRC_HO_STARTED
} NR_RRC_status_t;
#define RRM_FREE(p) if ( (p) != NULL) { free(p) ; p=NULL ; }
#define RRM_MALLOC(t,n) (t *) malloc16( sizeof(t) * n )
#define RRM_CALLOC(t,n) (t *) malloc16( sizeof(t) * n)
#define RRM_CALLOC2(t,s) (t *) malloc16( s )
#define MAX_MEAS_OBJ 7
#define MAX_MEAS_CONFIG 7
#define MAX_MEAS_ID 7
#define PAYLOAD_SIZE_MAX 1024
#define RRC_BUF_SIZE 1024
#define NR_RRC_BUF_SIZE 4096
#define UNDEF_SECURITY_MODE 0xff
#define NO_SECURITY_MODE 0x20
......@@ -129,14 +114,6 @@ typedef struct UE_S_TMSI_NR_s {
uint32_t fiveg_tmsi;
} __attribute__ ((__packed__)) NR_UE_S_TMSI;
typedef enum nr_e_rab_satus_e {
NR_E_RAB_STATUS_NEW,
NR_E_RAB_STATUS_DONE, // from the gNB perspective
NR_E_RAB_STATUS_ESTABLISHED, // get the reconfigurationcomplete form UE
NR_E_RAB_STATUS_FAILED,
} nr_e_rab_status_t;
typedef struct nr_e_rab_param_s {
e_rab_t param;
uint8_t status;
......@@ -156,12 +133,10 @@ typedef struct HANDOVER_INFO_NR_s {
//AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */
//AS_Context_t as_context; /* They are mandatory for HO */
uint8_t buf[RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */
uint8_t buf[NR_RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */
int size; /* size of above message in bytes */
} NR_HANDOVER_INFO;
#define NR_RRC_BUFFER_SIZE sizeof(RRC_BUFFER_NR)
typedef struct nr_rrc_guami_s {
uint16_t mcc;
uint16_t mnc;
......@@ -194,19 +169,15 @@ typedef struct pdu_session_param_s {
* @brief F1-U tunnel configuration
*/
typedef struct f1u_tunnel_s {
/* Downlink F1-U Tunnel Endpoint Identifier (CU-UP/DU) */
uint32_t cuup_teid_f1u;
/* DL F1-U Transport Layer */
transport_layer_addr_t cuup_addr_f1u;
/* F1-U Tunnel Endpoint Identifier (on DU side) */
uint32_t teid;
/* Downlink F1-U Transport Layer (on DU side) */
transport_layer_addr_t addr;
} f1u_tunnel_t;
typedef struct drb_s {
int status;
int defaultDRBid;
int drb_id;
int reestablishPDCP;
int recoverPDCP;
int daps_Config_r16;
struct cnAssociation_s {
int present;
int eps_BearerIdentity;
......@@ -232,8 +203,10 @@ typedef struct drb_s {
int cipheringDisabled;
} ext1;
} pdcp_config;
// F1-U
f1u_tunnel_t f1u_tunnel_config;
// F1-U Downlink Tunnel Config (on DU side)
f1u_tunnel_t du_tunnel_config;
// F1-U Uplink Tunnel Config (on CU-UP side)
f1u_tunnel_t cuup_tunnel_config;
} drb_t;
typedef enum {
......@@ -284,7 +257,6 @@ typedef struct gNB_RRC_UE_s {
NR_CipheringAlgorithm_t ciphering_algorithm;
e_NR_IntegrityProtAlgorithm integrity_algorithm;
NR_UE_STATE_t StatusRrc;
rnti_t rnti;
uint64_t random_ue_identity;
......@@ -317,6 +289,8 @@ typedef struct gNB_RRC_UE_s {
uint32_t ue_reestablishment_counter;
uint32_t ue_reconfiguration_counter;
bool an_release; // flag if core requested UE release
/* NGUEContextSetup might come with PDU sessions, but setup needs to be
* delayed after security (and capability); PDU sessions are stored here */
int n_initial_pdu;
......@@ -368,7 +342,7 @@ typedef struct {
} nr_a2_event_t;
typedef struct {
int cell_id;
int pci;
long a3_offset;
long hysteresis;
long timeToTrigger;
......@@ -393,7 +367,7 @@ typedef struct {
} nr_neighbour_gnb_configuration_t;
typedef struct neighbour_cell_configuration_s {
int nr_cell_id;
uint64_t nr_cell_id;
seq_arr_t *neighbour_cells;
} neighbour_cell_configuration_t;
......
This diff is collapsed.
......@@ -1180,6 +1180,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_
}
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
UE->an_release = true;
#ifdef E2_AGENT
signal_rrc_state_changed_to(UE, RC_SM_RRC_IDLE);
#endif
......
......@@ -40,14 +40,19 @@ int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info)
return cell_info->mode == F1AP_MODE_TDD ? cell_info->tdd.tbw.scs : cell_info->fdd.dl_tbw.scs;
}
int get_ssb_arfcn(const struct nr_rrc_du_container_t *du)
static int ssb_arfcn_mtc(const NR_MeasurementTimingConfiguration_t *mtc)
{
DevAssert(du != NULL && du->mtc != NULL);
/* format has been verified when accepting MeasurementTimingConfiguration */
NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
NR_MeasTimingList_t *mtlist = mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
return mtlist->list.array[0]->frequencyAndTiming->carrierFreq;
}
int get_ssb_arfcn(const struct nr_rrc_du_container_t *du)
{
DevAssert(du != NULL && du->mtc != NULL);
return ssb_arfcn_mtc(du->mtc);
}
static int du_compare(const nr_rrc_du_container_t *a, const nr_rrc_du_container_t *b)
{
if (a->assoc_id > b->assoc_id)
......@@ -197,6 +202,58 @@ static void label_intra_frequency_neighbours(gNB_RRC_INST *rrc,
for_each(cell_neighbour_list, (void *)&ssb_arfcn, is_intra_frequency_neighbour);
}
static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_configuration, const f1ap_served_cell_info_t *cell, int ssb_arfcn)
{
for (int c = 0; c < neighbour_cell_configuration->size; c++) {
const neighbour_cell_configuration_t *neighbour_config = seq_arr_at(neighbour_cell_configuration, c);
for (int ni = 0; ni < neighbour_config->neighbour_cells->size; ni++) {
const nr_neighbour_gnb_configuration_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni);
if (nc->nrcell_id != cell->nr_cellid)
continue;
// current cell is in the nc config, check that config matches
if (nc->physicalCellId != cell->nr_pci) {
LOG_W(NR_RRC, "Cell %ld in neighbour config: PCI mismatch (%d vs %d)\n", cell->nr_cellid, cell->nr_pci, nc->physicalCellId);
return false;
}
if (cell->tac && nc->tac != *cell->tac) {
LOG_W(NR_RRC, "Cell %ld in neighbour config: TAC mismatch (%d vs %d)\n", cell->nr_cellid, *cell->tac, nc->tac);
return false;
}
if (ssb_arfcn != nc->absoluteFrequencySSB) {
LOG_W(NR_RRC,
"Cell %ld in neighbour config: SSB ARFCN mismatch (%d vs %d)\n",
cell->nr_cellid,
ssb_arfcn,
nc->absoluteFrequencySSB);
return false;
}
if (get_ssb_scs(cell) != nc->subcarrierSpacing) {
LOG_W(NR_RRC,
"Cell %ld in neighbour config: SCS mismatch (%d vs %d)\n",
cell->nr_cellid,
get_ssb_scs(cell),
nc->subcarrierSpacing);
return false;
}
if (cell->plmn.mcc != nc->plmn.mcc || cell->plmn.mnc != nc->plmn.mnc
|| cell->plmn.mnc_digit_length != nc->plmn.mnc_digit_length) {
LOG_W(NR_RRC,
"Cell %ld in neighbour config: PLMN mismatch (%03d.%0*d vs %03d.%0*d)\n",
cell->nr_cellid,
cell->plmn.mcc,
cell->plmn.mnc_digit_length,
cell->plmn.mnc,
nc->plmn.mcc,
nc->plmn.mnc_digit_length,
nc->plmn.mnc);
return false;
}
LOG_D(NR_RRC, "Cell %ld is neighbor of cell %ld\n", cell->nr_cellid, neighbour_config->nr_cell_id);
}
}
return true;
}
void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
{
AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
......@@ -219,10 +276,12 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
f1ap_served_cell_info_t *cell_info = &req->cell[0].info;
if (!rrc_gNB_plmn_matches(rrc, cell_info)) {
LOG_E(NR_RRC,
"PLMN mismatch: CU %d%d, DU %d%d\n",
"PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n",
rrc->configuration.mcc[0],
rrc->configuration.mnc_digit_length[0],
rrc->configuration.mnc[0],
cell_info->plmn.mcc,
cell_info->plmn.mnc_digit_length,
cell_info->plmn.mnc);
f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU};
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
......@@ -264,6 +323,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
NR_MeasurementTimingConfiguration_t *mtc =
extract_mtc(cell_info->measurement_timing_config, cell_info->measurement_timing_config_len);
if (rrc->neighbour_cell_configuration
&& !valid_du_in_neighbour_configs(rrc->neighbour_cell_configuration, cell_info, ssb_arfcn_mtc(mtc))) {
LOG_E(NR_RRC, "problem with DU %ld in neighbor configuration, rejecting DU\n", req->gNB_DU_id);
f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified};
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
return;
}
const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
NR_MIB_t *mib = NULL;
NR_SIB1_t *sib1 = NULL;
......@@ -501,7 +569,7 @@ void dump_du_info(const gNB_RRC_INST *rrc, FILE *f)
fprintf(f, "assoc_id %d", du->assoc_id);
}
const f1ap_served_cell_info_t *info = &sr->cell[0].info;
fprintf(f, ": nrCellID %ld, PCI %d\n", info->nr_cellid, info->nr_pci);
fprintf(f, ": nrCellID %ld, PCI %d, SSB ARFCN %d\n", info->nr_cellid, info->nr_pci, get_ssb_arfcn(du));
if (info->mode == F1AP_MODE_TDD) {
const f1ap_nr_frequency_info_t *fi = &info->tdd.freqinfo;
......
......@@ -51,7 +51,7 @@ rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id
drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id)
{
DevAssert(drb_id > 0 && drb_id < 32);
DevAssert(drb_id > 0 && drb_id <= 32);
DevAssert(ue != NULL);
return &ue->established_drbs[drb_id - 1];
......@@ -96,10 +96,7 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue,
est_drb->status = DRB_ACTIVE;
est_drb->drb_id = drb_id;
est_drb->reestablishPDCP = -1;
est_drb->recoverPDCP = -1;
est_drb->cnAssociation.sdap_config.defaultDRB = true;
est_drb->defaultDRBid = drb_id;
/* SDAP Configuration */
est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config;
......
......@@ -479,7 +479,7 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc,
// Actions following cell selection while T311 is running
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
if (is_nr_timer_active(timers->T311)) {
if (nr_timer_is_active(&timers->T311)) {
nr_timer_stop(&timers->T311);
rrc->ra_trigger = RRC_CONNECTION_REESTABLISHMENT;
......@@ -1695,7 +1695,7 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc,
void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded)
{
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
if (ra_succeeded && is_nr_timer_active(timers->T304)) {
if (ra_succeeded && nr_timer_is_active(&timers->T304)) {
// successful Random Access procedure triggered by reconfigurationWithSync
nr_timer_stop(&timers->T304);
// TODO handle the rest of procedures as described in 5.3.5.3 for when
......@@ -2130,7 +2130,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l
process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, nr_SecondaryCellGroup_buffer, nr_SecondaryCellGroup_size);
process_nsa_message(NR_UE_rrc_inst, nr_RadioBearerConfigX_r15, nr_RadioBearer_buffer, nr_RadioBearer_size);
LOG_I(NR_RRC, "Calling do_NR_RRCReconfigurationComplete. t_id %ld \n", t_id);
uint8_t buffer[RRC_BUF_SIZE];
uint8_t buffer[NR_RRC_BUF_SIZE];
size_t size = do_NR_RRCReconfigurationComplete_for_nsa(buffer, sizeof(buffer), t_id);
nsa_sendmsg_to_lte_ue(buffer, size, NR_RRC_CONFIG_COMPLETE_REQ);
break;
......@@ -2138,7 +2138,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l
case OAI_TUN_IFACE_NSA: {
LOG_I(NR_RRC, "We got an OAI_TUN_IFACE_NSA!!\n");
char cmd_line[RRC_BUF_SIZE];
char cmd_line[NR_RRC_BUF_SIZE];
memcpy(cmd_line, msg_buffer, sizeof(cmd_line));
LOG_D(NR_RRC, "Command line: %s\n", cmd_line);
if (background_system(cmd_line) != 0)
......@@ -2218,14 +2218,14 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
}
}
if (!waitTime) {
if (is_nr_timer_active(tac->T302)) {
if (nr_timer_is_active(&tac->T302)) {
nr_timer_stop(&tac->T302);
// TODO barring alleviation as in 5.3.14.4
// not implemented
LOG_E(NR_RRC,"Go to IDLE. Barring alleviation not implemented\n");
}
}
if (is_nr_timer_active(tac->T390)) {
if (nr_timer_is_active(&tac->T390)) {
nr_timer_stop(&tac->T390);
// TODO barring alleviation as in 5.3.14.4
// not implemented
......
......@@ -560,7 +560,7 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
{
if (sync_msg == IN_SYNC) {
tac->N310_cnt = 0;
if (is_nr_timer_active(tac->T310)) {
if (nr_timer_is_active(&tac->T310)) {
tac->N311_cnt++;
// Upon receiving N311 consecutive "in-sync" indications
if (tac->N311_cnt >= tac->N311_k) {
......@@ -573,12 +573,12 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
else {
// OUT_OF_SYNC
tac->N311_cnt = 0;
if(is_nr_timer_active(tac->T300) ||
is_nr_timer_active(tac->T301) ||
is_nr_timer_active(tac->T304) ||
is_nr_timer_active(tac->T310) ||
is_nr_timer_active(tac->T311) ||
is_nr_timer_active(tac->T319))
if(nr_timer_is_active(&tac->T300) ||
nr_timer_is_active(&tac->T301) ||
nr_timer_is_active(&tac->T304) ||
nr_timer_is_active(&tac->T310) ||
nr_timer_is_active(&tac->T311) ||
nr_timer_is_active(&tac->T319))
return;
tac->N310_cnt++;
// upon receiving N310 consecutive "out-of-sync" indications
......
......@@ -787,7 +787,7 @@ sctp_eNB_read_from_socket(
SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno);
sctp_itti_send_association_resp(
sctp_cnx->task_id, sctp_cnx->instance, -1,
sctp_cnx->task_id, sctp_cnx->instance, sctp_cnx->assoc_id,
sctp_cnx->cnx_id, SCTP_STATE_UNREACHABLE, 0, 0);
close(sctp_cnx->sd);
......
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