Commit fe4b3c0a authored by zhenghuangkun's avatar zhenghuangkun

Create ngap files

parent 0a375bc0
......@@ -226,6 +226,7 @@ typedef enum {
X2AP,
M2AP,
M3AP,
NGAP,
GNB_APP,
NR_RRC,
NR_MAC,
......
/*
* 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
*/
/* Messages for NGAP logging */
MESSAGE_DEF(NGAP_UPLINK_NAS_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_uplink_nas_log)
MESSAGE_DEF(NGAP_UE_CAPABILITY_IND_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_ue_capability_ind_log)
MESSAGE_DEF(NGAP_INITIAL_CONTEXT_SETUP_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_initial_context_setup_log)
MESSAGE_DEF(NGAP_NAS_NON_DELIVERY_IND_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_nas_non_delivery_ind_log)
MESSAGE_DEF(NGAP_DOWNLINK_NAS_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_downlink_nas_log)
MESSAGE_DEF(NGAP_S1_SETUP_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_s1_setup_log)
MESSAGE_DEF(NGAP_INITIAL_UE_MESSAGE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_initial_ue_message_log)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_REQ_LOG, MESSAGE_PRIORITY_MED, IttiMsgText , ngap_ue_context_release_req_log)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMMAND_LOG, MESSAGE_PRIORITY_MED, IttiMsgText , ngap_ue_context_release_command_log)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMPLETE_LOG, MESSAGE_PRIORITY_MED, IttiMsgText , ngap_ue_context_release_complete_log)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_ue_context_release_log)
MESSAGE_DEF(NGAP_E_RAB_SETUP_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_e_rab_setup_request_log)
MESSAGE_DEF(NGAP_E_RAB_SETUP_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_e_rab_setup_response_log)
MESSAGE_DEF(NGAP_E_RAB_MODIFY_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_e_rab_modify_request_log)
MESSAGE_DEF(NGAP_E_RAB_MODIFY_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_e_rab_modify_response_log)
MESSAGE_DEF(NGAP_PAGING_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_paging_log)
MESSAGE_DEF(NGAP_E_RAB_RELEASE_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_e_rab_release_request_log)
MESSAGE_DEF(NGAP_E_RAB_RELEASE_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_e_rab_release_response_log)
MESSAGE_DEF(NGAP_ERROR_INDICATION_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_error_indication_log)
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_path_switch_req_log)
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_path_switch_req_ack_log)
/* gNB application layer -> NGAP messages */
MESSAGE_DEF(NGAP_REGISTER_GNB_REQ , MESSAGE_PRIORITY_MED, ngap_register_enb_req_t , ngap_register_enb_req)
/* NGAP -> gNB application layer messages */
MESSAGE_DEF(NGAP_REGISTER_GNB_CNF , MESSAGE_PRIORITY_MED, ngap_register_enb_cnf_t , ngap_register_enb_cnf)
MESSAGE_DEF(NGAP_DEREGISTERED_GNB_IND , MESSAGE_PRIORITY_MED, ngap_deregistered_enb_ind_t , ngap_deregistered_enb_ind)
/* RRC -> NGAP messages */
MESSAGE_DEF(NGAP_NAS_FIRST_REQ , MESSAGE_PRIORITY_MED, ngap_nas_first_req_t , ngap_nas_first_req)
MESSAGE_DEF(NGAP_UPLINK_NAS , MESSAGE_PRIORITY_MED, ngap_uplink_nas_t , ngap_uplink_nas)
MESSAGE_DEF(NGAP_UE_CAPABILITIES_IND , MESSAGE_PRIORITY_MED, ngap_ue_cap_info_ind_t , ngap_ue_cap_info_ind)
MESSAGE_DEF(NGAP_INITIAL_CONTEXT_SETUP_RESP, MESSAGE_PRIORITY_MED, ngap_initial_context_setup_resp_t, ngap_initial_context_setup_resp)
MESSAGE_DEF(NGAP_INITIAL_CONTEXT_SETUP_FAIL, MESSAGE_PRIORITY_MED, ngap_initial_context_setup_fail_t, ngap_initial_context_setup_fail)
MESSAGE_DEF(NGAP_NAS_NON_DELIVERY_IND , MESSAGE_PRIORITY_MED, ngap_nas_non_delivery_ind_t , ngap_nas_non_delivery_ind)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_RESP , MESSAGE_PRIORITY_MED, ngap_ue_release_resp_t , ngap_ue_release_resp)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMPLETE, MESSAGE_PRIORITY_MED, ngap_ue_release_complete_t , ngap_ue_release_complete)
MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_RESP , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_modification_resp_t , ngap_ue_ctxt_modification_resp)
MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_modification_fail_t , ngap_ue_ctxt_modification_fail)
MESSAGE_DEF(NGAP_E_RAB_SETUP_RESP , MESSAGE_PRIORITY_MED, ngap_e_rab_setup_resp_t , ngap_e_rab_setup_resp)
MESSAGE_DEF(NGAP_E_RAB_SETUP_REQUEST_FAIL , MESSAGE_PRIORITY_MED, ngap_e_rab_setup_req_fail_t , ngap_e_rab_setup_request_fail)
MESSAGE_DEF(NGAP_E_RAB_MODIFY_RESP , MESSAGE_PRIORITY_MED, ngap_e_rab_modify_resp_t , ngap_e_rab_modify_resp)
MESSAGE_DEF(NGAP_E_RAB_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, ngap_e_rab_release_resp_t , ngap_e_rab_release_resp)
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ , MESSAGE_PRIORITY_MED, ngap_path_switch_req_t , ngap_path_switch_req)
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK , MESSAGE_PRIORITY_MED, ngap_path_switch_req_ack_t , ngap_path_switch_req_ack)
MESSAGE_DEF(NGAP_E_RAB_MODIFICATION_IND , MESSAGE_PRIORITY_MED, ngap_e_rab_modification_ind_t , ngap_e_rab_modification_ind)
/* NGAP -> RRC messages */
MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas )
MESSAGE_DEF(NGAP_INITIAL_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED, ngap_initial_context_setup_req_t , ngap_initial_context_setup_req )
MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_REQ , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_modification_req_t , ngap_ue_ctxt_modification_req)
MESSAGE_DEF(NGAP_PAGING_IND , MESSAGE_PRIORITY_MED, ngap_paging_ind_t , ngap_paging_ind )
MESSAGE_DEF(NGAP_E_RAB_SETUP_REQ , MESSAGE_PRIORITY_MED, ngap_e_rab_setup_req_t , ngap_e_rab_setup_req )
MESSAGE_DEF(NGAP_E_RAB_MODIFY_REQ , MESSAGE_PRIORITY_MED, ngap_e_rab_modify_req_t , ngap_e_rab_modify_req )
MESSAGE_DEF(NGAP_E_RAB_RELEASE_COMMAND , MESSAGE_PRIORITY_MED, ngap_e_rab_release_command_t , ngap_e_rab_release_command)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMMAND, MESSAGE_PRIORITY_MED, ngap_ue_release_command_t , ngap_ue_release_command)
/* NGAP <-> RRC messages (can be initiated either by MME or gNB) */
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_REQ , MESSAGE_PRIORITY_MED, ngap_ue_release_req_t , ngap_ue_release_req)
/*
* 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 NGAP_MESSAGES_TYPES_H_
#define NGAP_MESSAGES_TYPES_H_
#include "LTE_asn_constant.h"
//-------------------------------------------------------------------------------------------//
// Defines to access message fields.
#define NGAP_REGISTER_GNB_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_register_enb_req
#define NGAP_REGISTER_GNB_CNF(mSGpTR) (mSGpTR)->ittiMsg.ngap_register_enb_cnf
#define NGAP_DEREGISTERED_GNB_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_deregistered_enb_ind
#define NGAP_NAS_FIRST_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_nas_first_req
#define NGAP_UPLINK_NAS(mSGpTR) (mSGpTR)->ittiMsg.ngap_uplink_nas
#define NGAP_UE_CAPABILITIES_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_cap_info_ind
#define NGAP_INITIAL_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.ngap_initial_context_setup_resp
#define NGAP_INITIAL_CONTEXT_SETUP_FAIL(mSGpTR) (mSGpTR)->ittiMsg.ngap_initial_context_setup_fail
#define NGAP_UE_CONTEXT_RELEASE_RESP(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_resp
#define NGAP_NAS_NON_DELIVERY_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_nas_non_delivery_ind
#define NGAP_UE_CTXT_MODIFICATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_ctxt_modification_resp
#define NGAP_UE_CTXT_MODIFICATION_FAIL(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_ctxt_modification_fail
#define NGAP_E_RAB_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_setup_resp
#define NGAP_E_RAB_SETUP_FAIL(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_setup_req_fail
#define NGAP_E_RAB_MODIFY_RESP(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_modify_resp
#define NGAP_PATH_SWITCH_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_path_switch_req
#define NGAP_PATH_SWITCH_REQ_ACK(mSGpTR) (mSGpTR)->ittiMsg.ngap_path_switch_req_ack
#define NGAP_E_RAB_MODIFICATION_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_modification_ind
#define NGAP_DOWNLINK_NAS(mSGpTR) (mSGpTR)->ittiMsg.ngap_downlink_nas
#define NGAP_INITIAL_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_initial_context_setup_req
#define NGAP_UE_CTXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_ctxt_modification_req
#define NGAP_UE_CONTEXT_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_command
#define NGAP_UE_CONTEXT_RELEASE_COMPLETE(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_complete
#define NGAP_E_RAB_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_setup_req
#define NGAP_E_RAB_MODIFY_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_modify_req
#define NGAP_PAGING_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_paging_ind
#define NGAP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_req
#define NGAP_E_RAB_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_release_command
#define NGAP_E_RAB_RELEASE_RESPONSE(mSGpTR) (mSGpTR)->ittiMsg.ngap_e_rab_release_resp
//-------------------------------------------------------------------------------------------//
/* Maximum number of e-rabs to be setup/deleted in a single message.
* Even if only one bearer will be modified by message.
*/
#define NGAP_MAX_E_RAB (LTE_maxDRB + 3)
/* Length of the transport layer address string
* 160 bits / 8 bits by char.
*/
#define NGAP_TRANSPORT_LAYER_ADDRESS_SIZE (160 / 8)
#define NGAP_MAX_NB_MME_IP_ADDRESS 10
#define NGAP_IMSI_LENGTH 16
/* Security key length used within gNB
* Even if only 16 bytes will be effectively used,
* the key length is 32 bytes (256 bits)
*/
#define SECURITY_KEY_LENGTH 32
typedef enum cell_type_e {
CELL_MACRO_GNB,
CELL_HOME_GNB,
CELL_MACRO_GNB
} cell_type_t;
typedef enum paging_drx_e {
PAGING_DRX_32 = 0x0,
PAGING_DRX_64 = 0x1,
PAGING_DRX_128 = 0x2,
PAGING_DRX_256 = 0x3
} paging_drx_t;
/* Lower value codepoint
* indicates higher priority.
*/
typedef enum paging_priority_s {
PAGING_PRIO_LEVEL1 = 0,
PAGING_PRIO_LEVEL2 = 1,
PAGING_PRIO_LEVEL3 = 2,
PAGING_PRIO_LEVEL4 = 3,
PAGING_PRIO_LEVEL5 = 4,
PAGING_PRIO_LEVEL6 = 5,
PAGING_PRIO_LEVEL7 = 6,
PAGING_PRIO_LEVEL8 = 7
} paging_priority_t;
typedef enum cn_domain_s {
CN_DOMAIN_PS = 1,
CN_DOMAIN_CS = 2
} cn_domain_t;
typedef struct net_ip_address_s {
unsigned ipv4:1;
unsigned ipv6:1;
char ipv4_address[16];
char ipv6_address[46];
} net_ip_address_t;
typedef uint64_t bitrate_t;
typedef struct ambr_s {
bitrate_t br_ul;
bitrate_t br_dl;
} ambr_t;
typedef enum priority_level_s {
PRIORITY_LEVEL_SPARE = 0,
PRIORITY_LEVEL_HIGHEST = 1,
PRIORITY_LEVEL_LOWEST = 14,
PRIORITY_LEVEL_NO_PRIORITY = 15
} priority_level_t;
typedef enum pre_emp_capability_e {
PRE_EMPTION_CAPABILITY_ENABLED = 0,
PRE_EMPTION_CAPABILITY_DISABLED = 1,
PRE_EMPTION_CAPABILITY_MAX,
} pre_emp_capability_t;
typedef enum pre_emp_vulnerability_e {
PRE_EMPTION_VULNERABILITY_ENABLED = 0,
PRE_EMPTION_VULNERABILITY_DISABLED = 1,
PRE_EMPTION_VULNERABILITY_MAX,
} pre_emp_vulnerability_t;
typedef struct allocation_retention_priority_s {
priority_level_t priority_level;
pre_emp_capability_t pre_emp_capability;
pre_emp_vulnerability_t pre_emp_vulnerability;
} allocation_retention_priority_t;
typedef struct security_capabilities_s {
uint16_t encryption_algorithms;
uint16_t integrity_algorithms;
} security_capabilities_t;
/* Provides the establishment cause for the RRC connection request as provided
* by the upper layers. W.r.t. the cause value names: highPriorityAccess
* concerns AC11..AC15, ‘mt’ stands for ‘Mobile Terminating’ and ‘mo’ for
* 'Mobile Originating'. Defined in TS 36.331.
*/
typedef enum rrc_establishment_cause_e {
RRC_CAUSE_EMERGENCY = 0x0,
RRC_CAUSE_HIGH_PRIO_ACCESS = 0x1,
RRC_CAUSE_MT_ACCESS = 0x2,
RRC_CAUSE_MO_SIGNALLING = 0x3,
RRC_CAUSE_MO_DATA = 0x4,
#if defined(UPDATE_RELEASE_10)
RRC_CAUSE_DELAY_TOLERANT_ACCESS = 0x5,
#endif
RRC_CAUSE_LAST
} rrc_establishment_cause_t;
typedef struct ngap_gummei_s {
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_len;
uint8_t mme_code;
uint16_t mme_group_id;
} ngap_gummei_t;
typedef struct ngap_imsi_s {
uint8_t buffer[NGAP_IMSI_LENGTH];
uint8_t length;
} ngap_imsi_t;
typedef struct s_tmsi_s {
uint8_t mme_code;
uint32_t m_tmsi;
} s_tmsi_t;
typedef enum ue_paging_identity_presenceMask_e {
UE_PAGING_IDENTITY_NONE = 0,
UE_PAGING_IDENTITY_imsi = (1 << 1),
UE_PAGING_IDENTITY_s_tmsi = (1 << 2),
} ue_paging_identity_presenceMask_t;
typedef struct ue_paging_identity_s {
ue_paging_identity_presenceMask_t presenceMask;
union {
ngap_imsi_t imsi;
s_tmsi_t s_tmsi;
} choice;
} ue_paging_identity_t;
typedef enum ue_identities_presenceMask_e {
UE_IDENTITIES_NONE = 0,
UE_IDENTITIES_s_tmsi = 1 << 1,
UE_IDENTITIES_gummei = 1 << 2,
} ue_identities_presenceMask_t;
typedef struct ue_identity_s {
ue_identities_presenceMask_t presenceMask;
s_tmsi_t s_tmsi;
ngap_gummei_t gummei;
} ue_identity_t;
typedef struct nas_pdu_s {
/* Octet string data */
uint8_t *buffer;
/* Length of the octet string */
uint32_t length;
} nas_pdu_t, ue_radio_cap_t;
typedef struct transport_layer_addr_s {
/* Length of the transport layer address buffer in bits. NGAP layer received a
* bit string<1..160> containing one of the following addresses: ipv4,
* ipv6, or ipv4 and ipv6. The layer doesn't interpret the buffer but
* silently forward it to S1-U.
*/
uint8_t length;
uint8_t buffer[20]; // in network byte order
} transport_layer_addr_t;
#define TRANSPORT_LAYER_ADDR_COPY(dEST,sOURCE) \
do { \
AssertFatal(sOURCE.len <= 20); \
memcpy(dEST.buffer, sOURCE.buffer, sOURCE.len); \
dEST.length = sOURCE.length; \
} while (0)
typedef struct e_rab_level_qos_parameter_s {
uint8_t qci;
allocation_retention_priority_t allocation_retention_priority;
} e_rab_level_qos_parameter_t;
typedef struct e_rab_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
/* Quality of service for this e_rab */
e_rab_level_qos_parameter_t qos;
/* The NAS PDU should be forwarded by the RRC layer to the NAS layer */
nas_pdu_t nas_pdu;
/* The transport layer address for the IP packets */
transport_layer_addr_t sgw_addr;
/* S-GW Tunnel endpoint identifier */
uint32_t gtp_teid;
} e_rab_t;
typedef struct e_rab_setup_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
/* The transport layer address for the IP packets */
transport_layer_addr_t gNB_addr;
/* S-GW Tunnel endpoint identifier */
uint32_t gtp_teid;
} e_rab_setup_t;
typedef struct e_rab_tobe_added_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
/* Unique drb_ID for the UE. */
uint8_t drb_ID;
/* The transport layer address for the IP packets */
transport_layer_addr_t sgw_addr;
/* S-GW Tunnel endpoint identifier */
uint32_t gtp_teid;
} e_rab_tobe_added_t;
typedef struct e_rab_admitted_tobe_added_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
/* Unique drb_ID for the UE. */
uint8_t drb_ID;
/* The transport layer address for the IP packets */
transport_layer_addr_t gnb_addr;
/* S-GW Tunnel endpoint identifier */
uint32_t gtp_teid;
} e_rab_admitted_tobe_added_t;
typedef struct e_rab_tobeswitched_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
/* The transport layer address for the IP packets */
transport_layer_addr_t sgw_addr;
/* S-GW Tunnel endpoint identifier */
uint32_t gtp_teid;
} e_rab_tobeswitched_t;
typedef struct e_rab_modify_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
} e_rab_modify_t;
typedef enum S1ap_Cause_e {
NGAP_CAUSE_NOTHING, /* No components present */
NGAP_CAUSE_RADIO_NETWORK,
NGAP_CAUSE_TRANSPORT,
NGAP_CAUSE_NAS,
NGAP_CAUSE_PROTOCOL,
NGAP_CAUSE_MISC,
/* Extensions may appear below */
} ngap_Cause_t;
typedef struct e_rab_failed_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
/* Cause of the failure */
// cause_t cause;
ngap_Cause_t cause;
uint8_t cause_value;
} e_rab_failed_t;
typedef enum ngap_ue_ctxt_modification_present_s {
NGAP_UE_CONTEXT_MODIFICATION_SECURITY_KEY = (1 << 0),
NGAP_UE_CONTEXT_MODIFICATION_UE_AMBR = (1 << 1),
NGAP_UE_CONTEXT_MODIFICATION_UE_SECU_CAP = (1 << 2),
} ngap_ue_ctxt_modification_present_t;
typedef enum ngap_paging_ind_present_s {
NGAP_PAGING_IND_PAGING_DRX = (1 << 0),
NGAP_PAGING_IND_PAGING_PRIORITY = (1 << 1),
} ngap_paging_ind_present_t;
//-------------------------------------------------------------------------------------------//
// gNB application layer -> NGAP messages
typedef struct ngap_register_enb_req_s {
/* Unique gNB_id to identify the gNB within EPC.
* For macro gNB ids this field should be 20 bits long.
* For home gNB ids this field should be 28 bits long.
*/
uint32_t gNB_id;
/* The type of the cell */
enum cell_type_e cell_type;
/* Optional name for the cell
* NOTE: the name can be NULL (i.e no name) and will be cropped to 150
* characters.
*/
char *gNB_name;
/* Tracking area code */
uint16_t tac;
#define PLMN_LIST_MAX_SIZE 6
/* Mobile Country Code
* Mobile Network Code
*/
uint16_t mcc[PLMN_LIST_MAX_SIZE];
uint16_t mnc[PLMN_LIST_MAX_SIZE];
uint8_t mnc_digit_length[PLMN_LIST_MAX_SIZE];
uint8_t num_plmn;
/* Default Paging DRX of the gNB as defined in TS 36.304 */
paging_drx_t default_drx;
/* The gNB IP address to bind */
net_ip_address_t enb_ip_address;
/* Nb of MME to connect to */
uint8_t nb_mme;
/* List of MME to connect to */
net_ip_address_t mme_ip_address[NGAP_MAX_NB_MME_IP_ADDRESS];
uint8_t broadcast_plmn_num[NGAP_MAX_NB_MME_IP_ADDRESS];
uint8_t broadcast_plmn_index[NGAP_MAX_NB_MME_IP_ADDRESS][PLMN_LIST_MAX_SIZE];
/* Number of SCTP streams used for a mme association */
uint16_t sctp_in_streams;
uint16_t sctp_out_streams;
} ngap_register_enb_req_t;
//-------------------------------------------------------------------------------------------//
// NGAP -> gNB application layer messages
typedef struct ngap_register_enb_cnf_s {
/* Nb of MME connected */
uint8_t nb_mme;
} ngap_register_enb_cnf_t;
typedef struct ngap_deregistered_enb_ind_s {
/* Nb of MME connected */
uint8_t nb_mme;
} ngap_deregistered_enb_ind_t;
//-------------------------------------------------------------------------------------------//
// RRC -> NGAP messages
/* The NAS First Req is the first message exchanged between RRC and NGAP
* for an UE.
* The rnti uniquely identifies an UE within a cell. Later the enb_ue_ngap_id
* will be the unique identifier used between RRC and NGAP.
*/
typedef struct ngap_nas_first_req_s {
/* UE id for initial connection to NGAP */
uint16_t ue_initial_id;
/* the chosen PLMN identity as index, see TS 36.331 6.2.2 RRC Connection
* Setup Complete. This index here is zero-based, unlike the standard! */
int selected_plmn_identity;
/* Establishment cause as sent by UE */
rrc_establishment_cause_t establishment_cause;
/* NAS PDU */
nas_pdu_t nas_pdu;
/* If this flag is set NGAP layer is expecting the GUMMEI. If = 0,
* the temporary s-tmsi is used.
*/
ue_identity_t ue_identity;
} ngap_nas_first_req_t;
typedef struct ngap_uplink_nas_s {
/* Unique UE identifier within an gNB */
unsigned gNB_ue_ngap_id:24;
/* NAS pdu */
nas_pdu_t nas_pdu;
} ngap_uplink_nas_t;
typedef struct ngap_ue_cap_info_ind_s {
unsigned gNB_ue_ngap_id:24;
ue_radio_cap_t ue_radio_cap;
} ngap_ue_cap_info_ind_t;
typedef struct ngap_initial_context_setup_resp_s {
unsigned gNB_ue_ngap_id:24;
/* Number of e_rab setup-ed in the list */
uint8_t nb_of_e_rabs;
/* list of e_rab setup-ed by RRC layers */
e_rab_setup_t e_rabs[NGAP_MAX_E_RAB];
/* Number of e_rab failed to be setup in list */
uint8_t nb_of_e_rabs_failed;
/* list of e_rabs that failed to be setup */
e_rab_failed_t e_rabs_failed[NGAP_MAX_E_RAB];
} ngap_initial_context_setup_resp_t;
typedef struct ngap_initial_context_setup_fail_s {
unsigned gNB_ue_ngap_id:24;
/* TODO add cause */
} ngap_initial_context_setup_fail_t, ngap_ue_ctxt_modification_fail_t, ngap_e_rab_setup_req_fail_t;
typedef struct ngap_nas_non_delivery_ind_s {
unsigned gNB_ue_ngap_id:24;
nas_pdu_t nas_pdu;
/* TODO: add cause */
} ngap_nas_non_delivery_ind_t;
typedef struct ngap_ue_ctxt_modification_req_s {
unsigned gNB_ue_ngap_id:24;
/* Bit-mask of possible present parameters */
ngap_ue_ctxt_modification_present_t present;
/* Following fields are optionnaly present */
/* Security key */
uint8_t security_key[SECURITY_KEY_LENGTH];
/* UE aggregate maximum bitrate */
ambr_t ue_ambr;
/* Security capabilities */
security_capabilities_t security_capabilities;
} ngap_ue_ctxt_modification_req_t;
typedef struct ngap_ue_ctxt_modification_resp_s {
unsigned gNB_ue_ngap_id:24;
} ngap_ue_ctxt_modification_resp_t;
typedef struct ngap_ue_release_complete_s {
unsigned gNB_ue_ngap_id:24;
} ngap_ue_release_complete_t;
//-------------------------------------------------------------------------------------------//
// NGAP -> RRC messages
typedef struct ngap_downlink_nas_s {
/* UE id for initial connection to NGAP */
uint16_t ue_initial_id;
/* Unique UE identifier within an gNB */
unsigned gNB_ue_ngap_id:24;
/* NAS pdu */
nas_pdu_t nas_pdu;
} ngap_downlink_nas_t;
typedef struct ngap_initial_context_setup_req_s {
/* UE id for initial connection to NGAP */
uint16_t ue_initial_id;
/* gNB ue ngap id as initialized by NGAP layer */
unsigned gNB_ue_ngap_id:24;
uint32_t mme_ue_ngap_id;
/* UE aggregate maximum bitrate */
ambr_t ue_ambr;
/* Security algorithms */
security_capabilities_t security_capabilities;
/* Security key */
uint8_t security_key[SECURITY_KEY_LENGTH];
/* Number of e_rab to be setup in the list */
uint8_t nb_of_e_rabs;
/* list of e_rab to be setup by RRC layers */
e_rab_t e_rab_param[NGAP_MAX_E_RAB];
} ngap_initial_context_setup_req_t;
typedef struct tai_plmn_identity_s {
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
} plmn_identity_t;
typedef struct ngap_paging_ind_s {
/* UE identity index value.
* Specified in 3GPP TS 36.304
*/
unsigned ue_index_value:10;
/* UE paging identity */
ue_paging_identity_t ue_paging_identity;
/* Indicates origin of paging */
cn_domain_t cn_domain;
/* PLMN_identity in TAI of Paging*/
plmn_identity_t plmn_identity[256];
/* TAC in TAIList of Paging*/
int16_t tac[256];
/* size of TAIList*/
int16_t tai_size;
/* Optional fields */
paging_drx_t paging_drx;
paging_priority_t paging_priority;
} ngap_paging_ind_t;
typedef struct ngap_e_rab_setup_req_s {
/* UE id for initial connection to NGAP */
uint16_t ue_initial_id;
/* MME UE id */
uint32_t mme_ue_ngap_id;
/* gNB ue ngap id as initialized by NGAP layer */
unsigned gNB_ue_ngap_id:24;
/* Number of e_rab to be setup in the list */
uint8_t nb_e_rabs_tosetup;
/* E RAB setup request */
e_rab_t e_rab_setup_params[NGAP_MAX_E_RAB];
} ngap_e_rab_setup_req_t;
typedef struct ngap_e_rab_setup_resp_s {
unsigned gNB_ue_ngap_id:24;
/* Number of e_rab setup-ed in the list */
uint8_t nb_of_e_rabs;
/* list of e_rab setup-ed by RRC layers */
e_rab_setup_t e_rabs[NGAP_MAX_E_RAB];
/* Number of e_rab failed to be setup in list */
uint8_t nb_of_e_rabs_failed;
/* list of e_rabs that failed to be setup */
e_rab_failed_t e_rabs_failed[NGAP_MAX_E_RAB];
} ngap_e_rab_setup_resp_t;
typedef struct ngap_path_switch_req_s {
unsigned gNB_ue_ngap_id:24;
/* Number of e_rab setup-ed in the list */
uint8_t nb_of_e_rabs;
/* list of e_rab setup-ed by RRC layers */
e_rab_setup_t e_rabs_tobeswitched[NGAP_MAX_E_RAB];
/* MME UE id */
uint32_t mme_ue_ngap_id;
ngap_gummei_t ue_gummei;
uint16_t ue_initial_id;
/* Security algorithms */
security_capabilities_t security_capabilities;
} ngap_path_switch_req_t;
typedef struct ngap_path_switch_req_ack_s {
/* UE id for initial connection to NGAP */
uint16_t ue_initial_id;
unsigned gNB_ue_ngap_id:24;
/* MME UE id */
uint32_t mme_ue_ngap_id;
/* UE aggregate maximum bitrate */
ambr_t ue_ambr;
/* Number of e_rab setup-ed in the list */
uint8_t nb_e_rabs_tobeswitched;
/* list of e_rab to be switched by RRC layers */
e_rab_tobeswitched_t e_rabs_tobeswitched[NGAP_MAX_E_RAB];
/* Number of e_rabs to be released by RRC */
uint8_t nb_e_rabs_tobereleased;
/* list of e_rabs to be released */
e_rab_failed_t e_rabs_tobereleased[NGAP_MAX_E_RAB];
/* Security key */
int next_hop_chain_count;
uint8_t next_security_key[SECURITY_KEY_LENGTH];
} ngap_path_switch_req_ack_t;
typedef struct ngap_e_rab_modification_ind_s {
unsigned gNB_ue_ngap_id:24;
/* MME UE id */
uint32_t mme_ue_ngap_id;
/* Number of e_rab setup-ed in the list */
uint8_t nb_of_e_rabs_tobemodified;
uint8_t nb_of_e_rabs_nottobemodified;
/* list of e_rab setup-ed by RRC layers */
e_rab_setup_t e_rabs_tobemodified[NGAP_MAX_E_RAB];
e_rab_setup_t e_rabs_nottobemodified[NGAP_MAX_E_RAB];
uint16_t ue_initial_id;
} ngap_e_rab_modification_ind_t;
// NGAP --> RRC messages
typedef struct ngap_ue_release_command_s {
unsigned gNB_ue_ngap_id:24;
} ngap_ue_release_command_t;
//-------------------------------------------------------------------------------------------//
// NGAP <-- RRC messages
typedef struct ngap_ue_release_req_s {
unsigned gNB_ue_ngap_id:24;
ngap_Cause_t cause;
long cause_value;
} ngap_ue_release_req_t, ngap_ue_release_resp_t;
typedef struct ngap_e_rab_modify_req_s {
/* UE id for initial connection to NGAP */
uint16_t ue_initial_id;
/* MME UE id */
uint32_t mme_ue_ngap_id;
/* gNB ue ngap id as initialized by NGAP layer */
unsigned gNB_ue_ngap_id:24;
/* Number of e_rab to be modify in the list */
uint8_t nb_e_rabs_tomodify;
/* E RAB modify request */
e_rab_t e_rab_modify_params[NGAP_MAX_E_RAB];
} ngap_e_rab_modify_req_t;
typedef struct ngap_e_rab_modify_resp_s {
unsigned gNB_ue_ngap_id:24;
/* Number of e_rab modify-ed in the list */
uint8_t nb_of_e_rabs;
/* list of e_rab modify-ed by RRC layers */
e_rab_modify_t e_rabs[NGAP_MAX_E_RAB];
/* Number of e_rab failed to be modify in list */
uint8_t nb_of_e_rabs_failed;
/* list of e_rabs that failed to be modify */
e_rab_failed_t e_rabs_failed[NGAP_MAX_E_RAB];
} ngap_e_rab_modify_resp_t;
typedef struct e_rab_release_s {
/* Unique e_rab_id for the UE. */
uint8_t e_rab_id;
} e_rab_release_t;
typedef struct ngap_e_rab_release_command_s {
/* MME UE id */
uint32_t mme_ue_ngap_id;
/* gNB ue ngap id as initialized by NGAP layer */
unsigned gNB_ue_ngap_id:24;
/* The NAS PDU should be forwarded by the RRC layer to the NAS layer */
nas_pdu_t nas_pdu;
/* Number of e_rab to be released in the list */
uint8_t nb_e_rabs_torelease;
/* E RAB release command */
e_rab_release_t e_rab_release_params[NGAP_MAX_E_RAB];
} ngap_e_rab_release_command_t;
typedef struct ngap_e_rab_release_resp_s {
/* MME UE id */
uint32_t mme_ue_ngap_id;
/* gNB ue ngap id as initialized by NGAP layer */
unsigned gNB_ue_ngap_id:24;
/* Number of e_rab released in the list */
uint8_t nb_of_e_rabs_released;
/* list of e_rabs released */
e_rab_release_t e_rab_release[NGAP_MAX_E_RAB];
/* Number of e_rab failed to be released in list */
uint8_t nb_of_e_rabs_failed;
/* list of e_rabs that failed to be released */
e_rab_failed_t e_rabs_failed[NGAP_MAX_E_RAB];
} ngap_e_rab_release_resp_t;
#endif /* NGAP_MESSAGES_TYPES_H_ */
......@@ -7449,7 +7449,7 @@ ShortMAC-I ::= BIT STRING (SIZE (16))
SINR-Range ::= INTEGER(0..127)
-- TAG-SINR-RANGE-STOP
-- TAGSI-REQUESTCONFIG-START
-- TAGCSI-REQUESTCONFIG-START
SI-RequestConfig::= SEQUENCE {
rach-OccasionsSI SEQUENCE {
......@@ -7466,7 +7466,7 @@ SI-RequestResources ::= SEQUENCE {
ra-ssb-OccasionMaskIndex INTEGER (0..15) OPTIONAL -- Need R
}
-- TAGSI-SCHEDULINGINFO-START
-- TAGCSI-SCHEDULINGINFO-START
SI-SchedulingInfo ::= SEQUENCE {
schedulingInfoList SEQUENCE (SIZE (1..maxSI-Message)) OF SchedulingInfo,
......
/*
* 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
*/
/*! \file ngap_common.c
* \brief ngap procedures for both gNB and AMF
* \author Sebastien ROUX and Navid Nikaein
* \email navid.nikaein@eurecom.fr
* \date 2012-2015
* \version 0.1
*/
#include <stdint.h>
#include "ngap_common.h"
#include "NGAP_NGAP-PDU.h"
int asn1_xer_print = 0;
void ngap_handle_criticality(NGAP_Criticality_t criticality)
{
}
/*
* 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
*/
/** @defgroup _ngap_impl_ NGAP Layer Reference Implementation
* @ingroup _ref_implementation_
* @{
*/
#if HAVE_CONFIG_H_
# include "config.h"
#endif
#ifndef NGAP_COMMON_H_
#define NGAP_COMMON_H_
#include "common/utils/LOG/log.h"
/* replace ASN_DEBUG defined in asn_internal.h by oai tracing system
Would be cleaner to modify asn_internal.h but it seems to come
from non oai source, with BSD license, so prefer to do that here..
*/
#ifdef ASN_DEBUG
# undef ASN_DEBUG
#endif
#define ASN_DEBUG( x... ) LOG_I(ASN, x)
#include "NGAP_ProtocolIE-Field.h"
#include "NGAP_NGAP-PDU.h"
#include "NGAP_InitiatingMessage.h"
#include "NGAP_SuccessfulOutcome.h"
#include "NGAP_UnsuccessfulOutcome.h"
#include "NGAP_ProtocolIE-Field.h"
#include "NGAP_ProtocolIE-FieldPair.h"
#include "NGAP_ProtocolIE-ContainerPair.h"
#include "NGAP_ProtocolExtensionField.h"
#include "NGAP_ProtocolExtensionContainer.h"
#include "NGAP_asn_constant.h"
#include "NGAP_SupportedTAs-Item.h"
#include "NGAP_ServedGUMMEIsItem.h"
/* Checking version of ASN1C compiler */
#if (ASN1C_ENVIRONMENT_VERSION < ASN1C_MINIMUM_VERSION)
# error "You are compiling ngap with the wrong version of ASN1C"
#endif
#ifndef FALSE
# define FALSE (0)
#endif
#ifndef TRUE
# define TRUE (!FALSE)
#endif
#define NGAP_UE_ID_FMT "0x%06"PRIX32
extern int asn_debug;
extern int asn1_xer_print;
#if defined(ENB_MODE)
# include "common/utils/LOG/log.h"
# include "ngap_eNB_default_values.h"
# define NGAP_ERROR(x, args...) LOG_E(NGAP, x, ##args)
# define NGAP_WARN(x, args...) LOG_W(NGAP, x, ##args)
# define NGAP_TRAF(x, args...) LOG_I(NGAP, x, ##args)
# define NGAP_INFO(x, args...) LOG_I(NGAP, x, ##args)
# define NGAP_DEBUG(x, args...) LOG_I(NGAP, x, ##args)
#else
# include "mme_default_values.h"
# define NGAP_ERROR(x, args...) do { fprintf(stdout, "[NGAP][E]"x, ##args); } while(0)
# define NGAP_WARN(x, args...) do { fprintf(stdout, "[NGAP][W]"x, ##args); } while(0)
# define NGAP_TRAF(x, args...) do { fprintf(stdout, "[NGAP][T]"x, ##args); } while(0)
# define NGAP_INFO(x, args...) do { fprintf(stdout, "[NGAP][I]"x, ##args); } while(0)
# define NGAP_DEBUG(x, args...) do { fprintf(stdout, "[NGAP][D]"x, ##args); } while(0)
#endif
#define NGAP_FIND_PROTOCOLIE_BY_ID(IE_TYPE, ie, container, IE_ID, mandatory) \
do {\
IE_TYPE **ptr; \
ie = NULL; \
for (ptr = container->protocolIEs.list.array; \
ptr < &container->protocolIEs.list.array[container->protocolIEs.list.count]; \
ptr++) { \
if((*ptr)->id == IE_ID) { \
ie = *ptr; \
break; \
} \
} \
if (ie == NULL ) { \
NGAP_ERROR("NGAP_FIND_PROTOCOLIE_BY_ID: %s %d: ie is NULL\n",__FILE__,__LINE__);\
} \
if (mandatory) DevAssert(ie != NULL); \
} while(0)
/** \brief Function callback prototype.
**/
typedef int (*ngap_message_decoded_callback)(
uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu
);
/** \brief Handle criticality
\param criticality Criticality of the IE
@returns void
**/
void ngap_handle_criticality(NGAP_Criticality_t criticality);
#endif /* NGAP_COMMON_H_ */
/*
* 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
*/
/*! \file ngap_gNB.c
* \brief NGAP gNB task
* \author S. Roux and Navid Nikaein
* \date 2010 - 2015
* \email: navid.nikaein@eurecom.fr
* \version 1.0
* @ingroup _ngap
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <crypt.h>
#include "tree.h"
#include "queue.h"
#include "intertask_interface.h"
#include "ngap_gNB_default_values.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB.h"
#include "ngap_gNB_encoder.h"
#include "ngap_gNB_handlers.h"
#include "ngap_gNB_nnsf.h"
#include "ngap_gNB_nas_procedures.h"
#include "ngap_gNB_management_procedures.h"
#include "ngap_gNB_context_management_procedures.h"
#include "ngap_gNB_itti_messaging.h"
#include "ngap_gNB_ue_context.h" // test, to be removed
#include "msc.h"
#include "assertions.h"
#include "conversions.h"
#if defined(TEST_S1C_MME)
#include "oaisim_mme_test_s1c.h"
#endif
ngap_gNB_config_t ngap_config;
static int ngap_gNB_generate_s1_setup_request(
ngap_gNB_instance_t *instance_p, ngap_gNB_mme_data_t *ngap_mme_data_p);
void ngap_gNB_handle_register_gNB(instance_t instance, ngap_register_enb_req_t *ngap_register_gNB);
void ngap_gNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
uint32_t ngap_generate_gNB_id(void) {
char *out;
char hostname[50];
int ret;
uint32_t gNB_id;
/* Retrieve the host name */
ret = gethostname(hostname, sizeof(hostname));
DevAssert(ret == 0);
out = crypt(hostname, "eurecom");
DevAssert(out != NULL);
gNB_id = ((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | out[3]);
return gNB_id;
}
static void ngap_gNB_register_mme(ngap_gNB_instance_t *instance_p,
net_ip_address_t *mme_ip_address,
net_ip_address_t *local_ip_addr,
uint16_t in_streams,
uint16_t out_streams,
uint8_t broadcast_plmn_num,
uint8_t broadcast_plmn_index[PLMN_LIST_MAX_SIZE]) {
MessageDef *message_p = NULL;
sctp_new_association_req_t *sctp_new_association_req_p = NULL;
ngap_gNB_mme_data_t *ngap_mme_data_p = NULL;
struct ngap_gNB_mme_data_s *mme = NULL;
DevAssert(instance_p != NULL);
DevAssert(mme_ip_address != NULL);
message_p = itti_alloc_new_message(TASK_NGAP, SCTP_NEW_ASSOCIATION_REQ);
sctp_new_association_req_p = &message_p->ittiMsg.sctp_new_association_req;
sctp_new_association_req_p->port = NGAP_PORT_NUMBER;
sctp_new_association_req_p->ppid = NGAP_SCTP_PPID;
sctp_new_association_req_p->in_streams = in_streams;
sctp_new_association_req_p->out_streams = out_streams;
memcpy(&sctp_new_association_req_p->remote_address,
mme_ip_address,
sizeof(*mme_ip_address));
memcpy(&sctp_new_association_req_p->local_address,
local_ip_addr,
sizeof(*local_ip_addr));
NGAP_INFO("[gNB %d] check the mme registration state\n",instance_p->instance);
mme = NULL;
if ( mme == NULL ) {
/* Create new MME descriptor */
ngap_mme_data_p = calloc(1, sizeof(*ngap_mme_data_p));
DevAssert(ngap_mme_data_p != NULL);
ngap_mme_data_p->cnx_id = ngap_gNB_fetch_add_global_cnx_id();
sctp_new_association_req_p->ulp_cnx_id = ngap_mme_data_p->cnx_id;
ngap_mme_data_p->assoc_id = -1;
ngap_mme_data_p->broadcast_plmn_num = broadcast_plmn_num;
memcpy(&ngap_mme_data_p->mme_s1_ip,
mme_ip_address,
sizeof(*mme_ip_address));
for (int i = 0; i < broadcast_plmn_num; ++i)
ngap_mme_data_p->broadcast_plmn_index[i] = broadcast_plmn_index[i];
ngap_mme_data_p->ngap_gNB_instance = instance_p;
STAILQ_INIT(&ngap_mme_data_p->served_gummei);
/* Insert the new descriptor in list of known MME
* but not yet associated.
*/
RB_INSERT(ngap_mme_map, &instance_p->ngap_mme_head, ngap_mme_data_p);
ngap_mme_data_p->state = NGAP_GNB_STATE_WAITING;
instance_p->ngap_mme_nb ++;
instance_p->ngap_mme_pending_nb ++;
} else if (mme->state == NGAP_GNB_STATE_WAITING) {
instance_p->ngap_mme_pending_nb ++;
sctp_new_association_req_p->ulp_cnx_id = mme->cnx_id;
NGAP_INFO("[gNB %d] MME already registered, retrive the data (state %d, cnx %d, mme_nb %d, mme_pending_nb %d)\n",
instance_p->instance,
mme->state, mme->cnx_id,
instance_p->ngap_mme_nb, instance_p->ngap_mme_pending_nb);
/*ngap_mme_data_p->cnx_id = mme->cnx_id;
sctp_new_association_req_p->ulp_cnx_id = mme->cnx_id;
ngap_mme_data_p->assoc_id = -1;
ngap_mme_data_p->ngap_gNB_instance = instance_p;
*/
} else {
NGAP_WARN("[gNB %d] MME already registered but not in the waiting state, retrive the data (state %d, cnx %d, mme_nb %d, mme_pending_nb %d)\n",
instance_p->instance,
mme->state, mme->cnx_id,
instance_p->ngap_mme_nb, instance_p->ngap_mme_pending_nb);
}
itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
}
void ngap_gNB_handle_register_gNB(instance_t instance, ngap_register_enb_req_t *ngap_register_gNB) {
ngap_gNB_instance_t *new_instance;
uint8_t index;
DevAssert(ngap_register_gNB != NULL);
/* Look if the provided instance already exists */
new_instance = ngap_gNB_get_instance(instance);
if (new_instance != NULL) {
/* Checks if it is a retry on the same gNB */
DevCheck(new_instance->gNB_id == ngap_register_gNB->gNB_id, new_instance->gNB_id, ngap_register_gNB->gNB_id, 0);
DevCheck(new_instance->cell_type == ngap_register_gNB->cell_type, new_instance->cell_type, ngap_register_gNB->cell_type, 0);
DevCheck(new_instance->num_plmn == ngap_register_gNB->num_plmn, new_instance->num_plmn, ngap_register_gNB->num_plmn, 0);
DevCheck(new_instance->tac == ngap_register_gNB->tac, new_instance->tac, ngap_register_gNB->tac, 0);
for (int i = 0; i < new_instance->num_plmn; i++) {
DevCheck(new_instance->mcc[i] == ngap_register_gNB->mcc[i], new_instance->mcc[i], ngap_register_gNB->mcc[i], 0);
DevCheck(new_instance->mnc[i] == ngap_register_gNB->mnc[i], new_instance->mnc[i], ngap_register_gNB->mnc[i], 0);
DevCheck(new_instance->mnc_digit_length[i] == ngap_register_gNB->mnc_digit_length[i], new_instance->mnc_digit_length[i], ngap_register_gNB->mnc_digit_length[i], 0);
}
DevCheck(new_instance->default_drx == ngap_register_gNB->default_drx, new_instance->default_drx, ngap_register_gNB->default_drx, 0);
} else {
new_instance = calloc(1, sizeof(ngap_gNB_instance_t));
DevAssert(new_instance != NULL);
RB_INIT(&new_instance->ngap_ue_head);
RB_INIT(&new_instance->ngap_mme_head);
/* Copy usefull parameters */
new_instance->instance = instance;
new_instance->gNB_name = ngap_register_gNB->gNB_name;
new_instance->gNB_id = ngap_register_gNB->gNB_id;
new_instance->cell_type = ngap_register_gNB->cell_type;
new_instance->tac = ngap_register_gNB->tac;
memcpy(&new_instance->gNB_s1_ip,
&ngap_register_gNB->enb_ip_address,
sizeof(ngap_register_gNB->enb_ip_address));
for (int i = 0; i < ngap_register_gNB->num_plmn; i++) {
new_instance->mcc[i] = ngap_register_gNB->mcc[i];
new_instance->mnc[i] = ngap_register_gNB->mnc[i];
new_instance->mnc_digit_length[i] = ngap_register_gNB->mnc_digit_length[i];
}
new_instance->num_plmn = ngap_register_gNB->num_plmn;
new_instance->default_drx = ngap_register_gNB->default_drx;
/* Add the new instance to the list of gNB (meaningfull in virtual mode) */
ngap_gNB_insert_new_instance(new_instance);
NGAP_INFO("Registered new gNB[%d] and %s gNB id %u\n",
instance,
ngap_register_gNB->cell_type == CELL_MACRO_GNB ? "macro" : "home",
ngap_register_gNB->gNB_id);
}
DevCheck(ngap_register_gNB->nb_mme <= NGAP_MAX_NB_MME_IP_ADDRESS,
NGAP_MAX_NB_MME_IP_ADDRESS, ngap_register_gNB->nb_mme, 0);
/* Trying to connect to provided list of MME ip address */
for (index = 0; index < ngap_register_gNB->nb_mme; index++) {
net_ip_address_t *mme_ip = &ngap_register_gNB->mme_ip_address[index];
struct ngap_gNB_mme_data_s *mme = NULL;
RB_FOREACH(mme, ngap_mme_map, &new_instance->ngap_mme_head) {
/* Compare whether IPv4 and IPv6 information is already present, in which
* wase we do not register again */
if (mme->mme_s1_ip.ipv4 == mme_ip->ipv4 && (!mme_ip->ipv4
|| strncmp(mme->mme_s1_ip.ipv4_address, mme_ip->ipv4_address, 16) == 0)
&& mme->mme_s1_ip.ipv6 == mme_ip->ipv6 && (!mme_ip->ipv6
|| strncmp(mme->mme_s1_ip.ipv6_address, mme_ip->ipv6_address, 46) == 0))
break;
}
if (mme)
continue;
ngap_gNB_register_mme(new_instance,
mme_ip,
&ngap_register_gNB->enb_ip_address,
ngap_register_gNB->sctp_in_streams,
ngap_register_gNB->sctp_out_streams,
ngap_register_gNB->broadcast_plmn_num[index],
ngap_register_gNB->broadcast_plmn_index[index]);
}
}
void ngap_gNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
ngap_gNB_instance_t *instance_p;
ngap_gNB_mme_data_t *ngap_mme_data_p;
DevAssert(sctp_new_association_resp != NULL);
instance_p = ngap_gNB_get_instance(instance);
DevAssert(instance_p != NULL);
ngap_mme_data_p = ngap_gNB_get_MME(instance_p, -1,
sctp_new_association_resp->ulp_cnx_id);
DevAssert(ngap_mme_data_p != NULL);
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
NGAP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
sctp_new_association_resp->sctp_state,
instance,
sctp_new_association_resp->ulp_cnx_id);
ngap_handle_s1_setup_message(ngap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
return;
}
/* Update parameters */
ngap_mme_data_p->assoc_id = sctp_new_association_resp->assoc_id;
ngap_mme_data_p->in_streams = sctp_new_association_resp->in_streams;
ngap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;
/* Prepare new S1 Setup Request */
ngap_gNB_generate_s1_setup_request(instance_p, ngap_mme_data_p);
}
static
void ngap_gNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind) {
int result;
DevAssert(sctp_data_ind != NULL);
#if defined(TEST_S1C_MME)
mme_test_s1_notify_sctp_data_ind(sctp_data_ind->assoc_id, sctp_data_ind->stream,
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
#else
ngap_gNB_handle_message(sctp_data_ind->assoc_id, sctp_data_ind->stream,
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
#endif
result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
}
void ngap_gNB_init(void) {
NGAP_DEBUG("Starting NGAP layer\n");
ngap_gNB_prepare_internal_data();
itti_mark_task_ready(TASK_NGAP);
MSC_START_USE();
}
void *ngap_gNB_process_itti_msg(void *notUsed) {
MessageDef *received_msg = NULL;
int result;
itti_receive_msg(TASK_NGAP, &received_msg);
switch (ITTI_MSG_ID(received_msg)) {
case TERMINATE_MESSAGE:
NGAP_WARN(" *** Exiting NGAP thread\n");
itti_exit_task();
break;
case NGAP_REGISTER_GNB_REQ: {
/* Register a new gNB.
* in Virtual mode gNBs will be distinguished using the mod_id/
* Each gNB has to send an NGAP_REGISTER_GNB message with its
* own parameters.
*/
ngap_gNB_handle_register_gNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_REGISTER_GNB_REQ(received_msg));
}
break;
case SCTP_NEW_ASSOCIATION_RESP: {
ngap_gNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&received_msg->ittiMsg.sctp_new_association_resp);
}
break;
case SCTP_DATA_IND: {
ngap_gNB_handle_sctp_data_ind(&received_msg->ittiMsg.sctp_data_ind);
}
break;
case NGAP_NAS_FIRST_REQ: {
ngap_gNB_handle_nas_first_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_NAS_FIRST_REQ(received_msg));
}
break;
case NGAP_UPLINK_NAS: {
ngap_gNB_nas_uplink(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_UPLINK_NAS(received_msg));
}
break;
case NGAP_UE_CAPABILITIES_IND: {
ngap_gNB_ue_capabilities(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_UE_CAPABILITIES_IND(received_msg));
}
break;
case NGAP_INITIAL_CONTEXT_SETUP_RESP: {
ngap_gNB_initial_ctxt_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_INITIAL_CONTEXT_SETUP_RESP(received_msg));
}
break;
case NGAP_E_RAB_SETUP_RESP: {
ngap_gNB_e_rab_setup_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_E_RAB_SETUP_RESP(received_msg));
}
break;
case NGAP_E_RAB_MODIFY_RESP: {
ngap_gNB_e_rab_modify_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_E_RAB_MODIFY_RESP(received_msg));
}
break;
case NGAP_NAS_NON_DELIVERY_IND: {
ngap_gNB_nas_non_delivery_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_NAS_NON_DELIVERY_IND(received_msg));
}
break;
case NGAP_PATH_SWITCH_REQ: {
ngap_gNB_path_switch_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_PATH_SWITCH_REQ(received_msg));
}
break;
case NGAP_E_RAB_MODIFICATION_IND: {
ngap_gNB_generate_E_RAB_Modification_Indication(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_E_RAB_MODIFICATION_IND(received_msg));
}
break;
case NGAP_UE_CONTEXT_RELEASE_COMPLETE: {
ngap_ue_context_release_complete(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_UE_CONTEXT_RELEASE_COMPLETE(received_msg));
}
break;
case NGAP_UE_CONTEXT_RELEASE_REQ: {
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL; // test
struct ngap_gNB_ue_context_s *ue_context_p = NULL; // test
ngap_ue_context_release_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_UE_CONTEXT_RELEASE_REQ(received_msg));
ngap_gNB_instance_p = ngap_gNB_get_instance(ITTI_MESSAGE_GET_INSTANCE(received_msg)); // test
DevAssert(ngap_gNB_instance_p != NULL); // test
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
NGAP_UE_CONTEXT_RELEASE_REQ(received_msg).gNB_ue_ngap_id)) == NULL) { // test
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_ERROR("Failed to find ue context associated with gNB ue ngap id: %u\n",
NGAP_UE_CONTEXT_RELEASE_REQ(received_msg).gNB_ue_ngap_id); // test
} // test
}
break;
case NGAP_E_RAB_RELEASE_RESPONSE: {
ngap_gNB_e_rab_release_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&NGAP_E_RAB_RELEASE_RESPONSE(received_msg));
}
break;
default:
NGAP_ERROR("Received unhandled message: %d:%s\n",
ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
break;
}
result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
received_msg = NULL;
return NULL;
}
void *ngap_gNB_task(void *arg) {
ngap_gNB_init();
while (1) {
(void) ngap_gNB_process_itti_msg(NULL);
}
return NULL;
}
//-----------------------------------------------------------------------------
/*
* gNB generate a S1 setup request towards MME
*/
static int ngap_gNB_generate_s1_setup_request(
ngap_gNB_instance_t *instance_p,
ngap_gNB_mme_data_t *ngap_mme_data_p)
//-----------------------------------------------------------------------------
{
NGAP_NGAP_PDU_t pdu;
NGAP_S1SetupRequest_t *out = NULL;
NGAP_S1SetupRequestIEs_t *ie = NULL;
NGAP_SupportedTAs_Item_t *ta = NULL;
NGAP_PLMNidentity_t *plmn = NULL;
uint8_t *buffer = NULL;
uint32_t len = 0;
int ret = 0;
DevAssert(instance_p != NULL);
DevAssert(ngap_mme_data_p != NULL);
ngap_mme_data_p->state = NGAP_GNB_STATE_WAITING;
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_S1Setup;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_reject;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_S1SetupRequest;
out = &pdu.choice.initiatingMessage.value.choice.S1SetupRequest;
/* mandatory */
ie = (NGAP_S1SetupRequestIEs_t *)calloc(1, sizeof(NGAP_S1SetupRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_Global_GNB_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_S1SetupRequestIEs__value_PR_Global_GNB_ID;
MCC_MNC_TO_PLMNID(instance_p->mcc[ngap_mme_data_p->broadcast_plmn_index[0]],
instance_p->mnc[ngap_mme_data_p->broadcast_plmn_index[0]],
instance_p->mnc_digit_length[ngap_mme_data_p->broadcast_plmn_index[0]],
&ie->value.choice.Global_GNB_ID.pLMNidentity);
ie->value.choice.Global_GNB_ID.gNB_ID.present = NGAP_GNB_ID_PR_macroGNB_ID;
MACRO_GNB_ID_TO_BIT_STRING(instance_p->gNB_id,
&ie->value.choice.Global_GNB_ID.gNB_ID.choice.macroGNB_ID);
NGAP_INFO("%d -> %02x%02x%02x\n", instance_p->gNB_id,
ie->value.choice.Global_GNB_ID.gNB_ID.choice.macroGNB_ID.buf[0],
ie->value.choice.Global_GNB_ID.gNB_ID.choice.macroGNB_ID.buf[1],
ie->value.choice.Global_GNB_ID.gNB_ID.choice.macroGNB_ID.buf[2]);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (instance_p->gNB_name) {
ie = (NGAP_S1SetupRequestIEs_t *)calloc(1, sizeof(NGAP_S1SetupRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNBname;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_S1SetupRequestIEs__value_PR_GNBname;
OCTET_STRING_fromBuf(&ie->value.choice.GNBname, instance_p->gNB_name,
strlen(instance_p->gNB_name));
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* mandatory */
ie = (NGAP_S1SetupRequestIEs_t *)calloc(1, sizeof(NGAP_S1SetupRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_SupportedTAs;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_S1SetupRequestIEs__value_PR_SupportedTAs;
{
ta = (NGAP_SupportedTAs_Item_t *)calloc(1, sizeof(NGAP_SupportedTAs_Item_t));
INT16_TO_OCTET_STRING(instance_p->tac, &ta->tAC);
{
for (int i = 0; i < ngap_mme_data_p->broadcast_plmn_num; ++i) {
plmn = (NGAP_PLMNidentity_t *)calloc(1, sizeof(NGAP_PLMNidentity_t));
MCC_MNC_TO_TBCD(instance_p->mcc[ngap_mme_data_p->broadcast_plmn_index[i]],
instance_p->mnc[ngap_mme_data_p->broadcast_plmn_index[i]],
instance_p->mnc_digit_length[ngap_mme_data_p->broadcast_plmn_index[i]],
plmn);
ASN_SEQUENCE_ADD(&ta->broadcastPLMNs.list, plmn);
}
}
ASN_SEQUENCE_ADD(&ie->value.choice.SupportedTAs.list, ta);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_S1SetupRequestIEs_t *)calloc(1, sizeof(NGAP_S1SetupRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_DefaultPagingDRX;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_S1SetupRequestIEs__value_PR_PagingDRX;
ie->value.choice.PagingDRX = instance_p->default_drx;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
if (ngap_gNB_encode_pdu(&pdu, &buffer, &len) < 0) {
NGAP_ERROR("Failed to encode S1 setup request\n");
return -1;
}
/* Non UE-Associated signalling -> stream = 0 */
ngap_gNB_itti_send_sctp_data_req(instance_p->instance, ngap_mme_data_p->assoc_id, buffer, len, 0);
return ret;
}
/*
* 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 <stdio.h>
#include <stdint.h>
/** @defgroup _ngap_impl_ NGAP Layer Reference Implementation for gNB
* @ingroup _ref_implementation_
* @{
*/
#ifndef NGAP_GNB_H_
#define NGAP_GNB_H_
typedef struct ngap_gNB_config_s {
// MME related params
unsigned char mme_enabled; ///< MME enabled ?
} ngap_gNB_config_t;
extern ngap_gNB_config_t ngap_config;
#define EPC_MODE_ENABLED ngap_config.mme_enabled
void *ngap_gNB_process_itti_msg(void*);
void ngap_gNB_init(void);
void *ngap_gNB_task(void *arg);
uint32_t ngap_generate_gNB_id(void);
#endif /* NGAP_GNB_H_ */
/**
* @}
*/
/*
* 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
*/
/*! \file ngap_gNB_context_management_procedures.c
* \brief NGAP context management procedures
* \author S. Roux and Navid Nikaein
* \date 2010 - 2015
* \email: navid.nikaein@eurecom.fr
* \version 1.0
* @ingroup _ngap
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "assertions.h"
#include "conversions.h"
#include "intertask_interface.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB_itti_messaging.h"
#include "ngap_gNB_encoder.h"
#include "ngap_gNB_nnsf.h"
#include "ngap_gNB_ue_context.h"
#include "ngap_gNB_nas_procedures.h"
#include "ngap_gNB_management_procedures.h"
#include "ngap_gNB_context_management_procedures.h"
#include "msc.h"
int ngap_ue_context_release_complete(instance_t instance,
ngap_ue_release_complete_t *ue_release_complete_p)
{
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_UEContextReleaseComplete_t *out;
NGAP_UEContextReleaseComplete_IEs_t *ie;
uint8_t *buffer;
uint32_t length;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(ue_release_complete_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
/*RB_FOREACH(ue_context_p, ngap_ue_map, &ngap_gNB_instance_p->ngap_ue_head) {
NGAP_WARN("in ngap_ue_map: UE context gNB_ue_ngap_id %u mme_ue_ngap_id %u state %u\n",
ue_context_p->gNB_ue_ngap_id, ue_context_p->mme_ue_ngap_id,
ue_context_p->ue_state);
}*/
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
ue_release_complete_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: %u\n",
ue_release_complete_p->gNB_ue_ngap_id);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome;
pdu.choice.successfulOutcome.procedureCode = NGAP_ProcedureCode_id_UEContextRelease;
pdu.choice.successfulOutcome.criticality = NGAP_Criticality_reject;
pdu.choice.successfulOutcome.value.present = NGAP_SuccessfulOutcome__value_PR_UEContextReleaseComplete;
out = &pdu.choice.successfulOutcome.value.choice.UEContextReleaseComplete;
/* mandatory */
ie = (NGAP_UEContextReleaseComplete_IEs_t *)calloc(1, sizeof(NGAP_UEContextReleaseComplete_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_UEContextReleaseComplete_IEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UEContextReleaseComplete_IEs_t *)calloc(1, sizeof(NGAP_UEContextReleaseComplete_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_UEContextReleaseComplete_IEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_release_complete_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
/* Encode procedure has failed... */
NGAP_ERROR("Failed to encode UE context release complete\n");
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
buffer,
length,
MSC_AS_TIME_FMT" UEContextRelease successfulOutcome gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0, //MSC_AS_TIME_ARGS(ctxt_pP),
ue_release_complete_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
//LG ngap_gNB_itti_send_sctp_close_association(ngap_gNB_instance_p->instance,
// ue_context_p->mme_ref->assoc_id);
// release UE context
struct ngap_gNB_ue_context_s *ue_context2_p = NULL;
if ((ue_context2_p = RB_REMOVE(ngap_ue_map, &ngap_gNB_instance_p->ngap_ue_head, ue_context_p))
!= NULL) {
NGAP_WARN("Removed UE context gNB_ue_ngap_id %u\n",
ue_context2_p->gNB_ue_ngap_id);
ngap_gNB_free_ue_context(ue_context2_p);
} else {
NGAP_WARN("Removing UE context gNB_ue_ngap_id %u: did not find context\n",
ue_context_p->gNB_ue_ngap_id);
}
/*RB_FOREACH(ue_context_p, ngap_ue_map, &ngap_gNB_instance_p->ngap_ue_head) {
NGAP_WARN("in ngap_ue_map: UE context gNB_ue_ngap_id %u mme_ue_ngap_id %u state %u\n",
ue_context_p->gNB_ue_ngap_id, ue_context_p->mme_ue_ngap_id,
ue_context_p->ue_state);
}*/
return 0;
}
int ngap_ue_context_release_req(instance_t instance,
ngap_ue_release_req_t *ue_release_req_p)
{
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_UEContextReleaseRequest_t *out;
NGAP_UEContextReleaseRequest_IEs_t *ie;
uint8_t *buffer = NULL;
uint32_t length;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(ue_release_req_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
ue_release_req_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: %u\n",
ue_release_req_p->gNB_ue_ngap_id);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_UEContextReleaseRequest;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_ignore;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_UEContextReleaseRequest;
out = &pdu.choice.initiatingMessage.value.choice.UEContextReleaseRequest;
/* mandatory */
ie = (NGAP_UEContextReleaseRequest_IEs_t *)calloc(1, sizeof(NGAP_UEContextReleaseRequest_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UEContextReleaseRequest_IEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UEContextReleaseRequest_IEs_t *)calloc(1, sizeof(NGAP_UEContextReleaseRequest_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UEContextReleaseRequest_IEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_release_req_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UEContextReleaseRequest_IEs_t *)calloc(1, sizeof(NGAP_UEContextReleaseRequest_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_Cause;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_UEContextReleaseRequest_IEs__value_PR_Cause;
switch (ue_release_req_p->cause) {
case NGAP_Cause_PR_radioNetwork:
ie->value.choice.Cause.present = NGAP_Cause_PR_radioNetwork;
ie->value.choice.Cause.choice.radioNetwork = ue_release_req_p->cause_value;
break;
case NGAP_Cause_PR_transport:
ie->value.choice.Cause.present = NGAP_Cause_PR_transport;
ie->value.choice.Cause.choice.transport = ue_release_req_p->cause_value;
break;
case NGAP_Cause_PR_nas:
ie->value.choice.Cause.present = NGAP_Cause_PR_nas;
ie->value.choice.Cause.choice.nas = ue_release_req_p->cause_value;
break;
case NGAP_Cause_PR_protocol:
ie->value.choice.Cause.present = NGAP_Cause_PR_protocol;
ie->value.choice.Cause.choice.protocol = ue_release_req_p->cause_value;
break;
case NGAP_Cause_PR_misc:
ie->value.choice.Cause.present = NGAP_Cause_PR_misc;
ie->value.choice.Cause.choice.misc = ue_release_req_p->cause_value;
break;
case NGAP_Cause_PR_NOTHING:
default:
ie->value.choice.Cause.present = NGAP_Cause_PR_NOTHING;
break;
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
/* Encode procedure has failed... */
NGAP_ERROR("Failed to encode UE context release complete\n");
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
buffer,
length,
MSC_AS_TIME_FMT" UEContextReleaseRequest initiatingMessage gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
ue_release_req_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
/*
* 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 NGAP_GNB_CONTEXT_MANAGEMENT_PROCEDURES_H_
#define NGAP_GNB_CONTEXT_MANAGEMENT_PROCEDURES_H_
int ngap_ue_context_release_complete(instance_t instance,
ngap_ue_release_complete_t *ue_release_complete_p);
int ngap_ue_context_release_req(instance_t instance,
ngap_ue_release_req_t *ue_release_req_p);
#endif /* NGAP_GNB_CONTEXT_MANAGEMENT_PROCEDURES_H_ */
/*
* 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
*/
/*! \file ngap_gNB_decoder.c
* \brief ngap pdu decode procedures for gNB
* \author Sebastien ROUX and Navid Nikaein
* \email navid.nikaein@eurecom.fr
* \date 2013 - 2015
* \version 0.1
*/
#include <stdio.h>
#include "assertions.h"
#include "intertask_interface.h"
#include "ngap_common.h"
#include "ngap_gNB_decoder.h"
static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) {
asn_encode_to_new_buffer_result_t res = { NULL, {0, NULL, NULL} };
DevAssert(pdu != NULL);
switch(pdu->choice.initiatingMessage.procedureCode) {
case NGAP_ProcedureCode_id_downlinkNASTransport:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_InitialContextSetup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_UEContextRelease:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_Paging:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
NGAP_INFO("Paging initiating message\n");
free(res.buffer);
break;
case NGAP_ProcedureCode_id_E_RABSetup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("E_RABSetup initiating message\n");
break;
case NGAP_ProcedureCode_id_E_RABModify:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("E_RABModify initiating message\n");
break;
case NGAP_ProcedureCode_id_E_RABRelease:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("TODO E_RABRelease initiating message\n");
break;
case NGAP_ProcedureCode_id_ErrorIndication:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("TODO ErrorIndication initiating message\n");
break;
default:
NGAP_ERROR("Unknown procedure ID (%d) for initiating message\n",
(int)pdu->choice.initiatingMessage.procedureCode);
AssertFatal( 0, "Unknown procedure ID (%d) for initiating message\n",
(int)pdu->choice.initiatingMessage.procedureCode);
return -1;
}
return 0;
}
static int ngap_gNB_decode_successful_outcome(NGAP_NGAP_PDU_t *pdu) {
asn_encode_to_new_buffer_result_t res = { NULL, {0, NULL, NULL} };
DevAssert(pdu != NULL);
switch(pdu->choice.successfulOutcome.procedureCode) {
case NGAP_ProcedureCode_id_S1Setup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_PathSwitchRequest:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_E_RABModificationIndication:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
default:
NGAP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n",
(int)pdu->choice.successfulOutcome.procedureCode);
return -1;
}
return 0;
}
static int ngap_gNB_decode_unsuccessful_outcome(NGAP_NGAP_PDU_t *pdu) {
asn_encode_to_new_buffer_result_t res = { NULL, {0, NULL, NULL} };
DevAssert(pdu != NULL);
switch(pdu->choice.unsuccessfulOutcome.procedureCode) {
case NGAP_ProcedureCode_id_S1Setup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_PathSwitchRequest:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
default:
NGAP_ERROR("Unknown procedure ID (%d) for unsuccessfull outcome message\n",
(int)pdu->choice.unsuccessfulOutcome.procedureCode);
return -1;
}
return 0;
}
int ngap_gNB_decode_pdu(NGAP_NGAP_PDU_t *pdu, const uint8_t *const buffer,
const uint32_t length) {
asn_dec_rval_t dec_ret;
DevAssert(pdu != NULL);
DevAssert(buffer != NULL);
dec_ret = aper_decode(NULL,
&asn_DEF_NGAP_NGAP_PDU,
(void **)&pdu,
buffer,
length,
0,
0);
if (dec_ret.code != RC_OK) {
NGAP_ERROR("Failed to decode pdu\n");
return -1;
}
switch(pdu->present) {
case NGAP_NGAP_PDU_PR_initiatingMessage:
return ngap_gNB_decode_initiating_message(pdu);
case NGAP_NGAP_PDU_PR_successfulOutcome:
return ngap_gNB_decode_successful_outcome(pdu);
case NGAP_NGAP_PDU_PR_unsuccessfulOutcome:
return ngap_gNB_decode_unsuccessful_outcome(pdu);
default:
NGAP_DEBUG("Unknown presence (%d) or not implemented\n", (int)pdu->present);
break;
}
return -1;
}
/*
* 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 <stdint.h>
#ifndef NGAP_GNB_DECODER_H_
#define NGAP_GNB_DECODER_H_
int ngap_gNB_decode_pdu(NGAP_NGAP_PDU_t *pdu, const uint8_t *const buffer,
const uint32_t length) __attribute__ ((warn_unused_result));
#endif /* NGAP_GNB_DECODER_H_ */
/*
* 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 NGAP_GNB_DEFAULT_VALUES_H_
#define NGAP_GNB_DEFAULT_VALUES_H_
#define GNB_TAC (1)
#define GNB_MCC (208)
#define GNB_MNC (92)
#define GNB_NAME "Eurecom GNB"
#define GNB_NAME_FORMAT (GNB_NAME" %u")
#define NGAP_PORT_NUMBER (36412)
#define NGAP_SCTP_PPID (18)
#define X2AP_PORT_NUMBER (36422)
#define X2AP_SCTP_PPID (27)
#endif /* NGAP_GNB_DEFAULT_VALUES_H_ */
/*
* 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 <stdint.h>
#include "queue.h"
#include "tree.h"
#include "sctp_gNB_defs.h"
#ifndef NGAP_GNB_DEFS_H_
#define NGAP_GNB_DEFS_H_
#define NGAP_GNB_NAME_LENGTH_MAX (150)
typedef enum {
/* Disconnected state: initial state for any association. */
NGAP_GNB_STATE_DISCONNECTED = 0x0,
/* State waiting for S1 Setup response message if gNB is MME accepted or
* S1 Setup failure if MME rejects the gNB.
*/
NGAP_GNB_STATE_WAITING = 0x1,
/* The gNB is successfully connected to MME, UE contexts can be created. */
NGAP_GNB_STATE_CONNECTED = 0x2,
/* The MME has sent an overload start message. Once the MME disables the
* OVERLOAD marker, the state of the association will be
* NGAP_GNB_STATE_CONNECTED.
*/
NGAP_GNB_OVERLOAD = 0x3,
/* Max number of states available */
NGAP_GNB_STATE_MAX,
} ngap_gNB_state_t;
/* If the Overload Action IE in the OVERLOAD START message is set to
* - “reject all RRC connection establishments for non-emergency mobile
* originated data transfer “ (i.e. reject traffic corresponding to RRC cause
* “mo-data “ (TS 36.331 [16])), or
* - “reject all RRC connection establishments for signalling “ (i.e. reject
* traffic corresponding to RRC cause “modata” and “mo-signalling”
* (TS 36.331 [16])),or
* - “only permit RRC connection establishments for emergency sessions and
* mobile terminated services” (i.e. only permit traffic corresponding to RRC
* cause “emergency” and “mt-Access” (TS 36.331 [16])).
*
* NOTE: When the Overload Action IE is set to “only permit RRC connection
* establishments for emergency sessions and mobile terminated services”,
* emergency calls with RRC cause “highPriorityAcess” from high priority users
* are rejected (TS 24.301 [24]).
*/
typedef enum {
NGAP_OVERLOAD_REJECT_MO_DATA = 0x0,
NGAP_OVERLOAD_REJECT_ALL_SIGNALLING = 0x1,
NGAP_OVERLOAD_ONLY_EMERGENCY_AND_MT = 0x2,
NGAP_NO_OVERLOAD = 0x3,
NGAP_OVERLOAD_MAX,
} ngap_overload_state_t;
/* Served PLMN identity element */
struct plmn_identity_s {
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
STAILQ_ENTRY(plmn_identity_s) next;
};
/* Served group id element */
struct served_group_id_s {
uint16_t mme_group_id;
STAILQ_ENTRY(served_group_id_s) next;
};
/* Served mme code for a particular MME */
struct mme_code_s {
uint8_t mme_code;
STAILQ_ENTRY(mme_code_s) next;
};
/* Served gummei element */
struct served_gummei_s {
/* Number of MME served PLMNs */
uint8_t nb_served_plmns;
/* List of served PLMNs by MME */
STAILQ_HEAD(served_plmns_s, plmn_identity_s) served_plmns;
/* Number of group id in list */
uint8_t nb_group_id;
/* Served group id list */
STAILQ_HEAD(served_group_ids_s, served_group_id_s) served_group_ids;
/* Number of MME code */
uint8_t nb_mme_code;
/* MME Code to uniquely identify an MME within an MME pool area */
STAILQ_HEAD(mme_codes_s, mme_code_s) mme_codes;
/* Next GUMMEI element */
STAILQ_ENTRY(served_gummei_s) next;
};
struct ngap_gNB_instance_s;
/* This structure describes association of a gNB to a MME */
typedef struct ngap_gNB_mme_data_s {
/* MME descriptors tree, ordered by sctp assoc id */
RB_ENTRY(ngap_gNB_mme_data_s) entry;
/* This is the optional name provided by the MME */
char *mme_name;
/* MME NGAP IP address */
net_ip_address_t mme_s1_ip;
/* List of served GUMMEI per MME. There is one GUMMEI per RAT with a max
* number of 8 RATs but in our case only one is used. The LTE related pool
* configuration is included on the first place in the list.
*/
STAILQ_HEAD(served_gummeis_s, served_gummei_s) served_gummei;
/* Relative processing capacity of an MME with respect to the other MMEs
* in the pool in order to load-balance MMEs within a pool as defined
* in TS 23.401.
*/
uint8_t relative_mme_capacity;
/* Current MME overload information (if any). */
ngap_overload_state_t overload_state;
/* Current gNB->MME NGAP association state */
ngap_gNB_state_t state;
/* Next usable stream for UE signalling */
int32_t nextstream;
/* Number of input/ouput streams */
uint16_t in_streams;
uint16_t out_streams;
/* Connexion id used between SCTP/NGAP */
uint16_t cnx_id;
/* SCTP association id */
int32_t assoc_id;
/* This is served PLMN IDs communicated to the MME via an index over the
* MCC/MNC array in ngap_gNB_instance */
uint8_t broadcast_plmn_num;
uint8_t broadcast_plmn_index[PLMN_LIST_MAX_SIZE];
/* Only meaningfull in virtual mode */
struct ngap_gNB_instance_s *ngap_gNB_instance;
} ngap_gNB_mme_data_t;
typedef struct ngap_gNB_instance_s {
/* Next ngap gNB association.
* Only used for virtual mode.
*/
STAILQ_ENTRY(ngap_gNB_instance_s) ngap_gNB_entries;
/* Number of MME requested by gNB (tree size) */
uint32_t ngap_mme_nb;
/* Number of MME for which association is pending */
uint32_t ngap_mme_pending_nb;
/* Number of MME successfully associated to gNB */
uint32_t ngap_mme_associated_nb;
/* Tree of NGAP MME associations ordered by association ID */
RB_HEAD(ngap_mme_map, ngap_gNB_mme_data_s) ngap_mme_head;
/* TODO: add a map ordered by relative MME capacity */
/* Tree of UE ordered by gNB_ue_ngap_id's */
RB_HEAD(ngap_ue_map, ngap_gNB_ue_context_s) ngap_ue_head;
/* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */
instance_t instance;
/* Displayable name of gNB */
char *gNB_name;
/* Unique gNB_id to identify the gNB within EPC.
* In our case the gNB is a macro gNB so the id will be 20 bits long.
* For Home gNB id, this field should be 28 bits long.
*/
uint32_t gNB_id;
/* The type of the cell */
enum cell_type_e cell_type;
/* Tracking area code */
uint16_t tac;
/* gNB NGAP IP address */
net_ip_address_t gNB_s1_ip;
/* Mobile Country Code
* Mobile Network Code
*/
uint16_t mcc[PLMN_LIST_MAX_SIZE];
uint16_t mnc[PLMN_LIST_MAX_SIZE];
uint8_t mnc_digit_length[PLMN_LIST_MAX_SIZE];
uint8_t num_plmn;
/* Default Paging DRX of the gNB as defined in TS 36.304 */
paging_drx_t default_drx;
} ngap_gNB_instance_t;
typedef struct {
/* List of served gNBs
* Only used for virtual mode
*/
STAILQ_HEAD(ngap_gNB_instances_head_s, ngap_gNB_instance_s) ngap_gNB_instances_head;
/* Nb of registered gNBs */
uint8_t nb_registered_gNBs;
/* Generate a unique connexion id used between NGAP and SCTP */
uint16_t global_cnx_id;
} ngap_gNB_internal_data_t;
int ngap_gNB_compare_assoc_id(
struct ngap_gNB_mme_data_s *p1, struct ngap_gNB_mme_data_s *p2);
/* Generate the tree management functions */
RB_PROTOTYPE(ngap_mme_map, ngap_gNB_mme_data_s, entry,
ngap_gNB_compare_assoc_id);
#endif /* NGAP_GNB_DEFS_H_ */
/*
* 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
*/
/*! \file ngap_gNB_encoder.c
* \brief ngap pdu encode procedures for gNB
* \author Sebastien ROUX and Navid Nikaein
* \email navid.nikaein@eurecom.fr
* \date 2013 - 2015
* \version 0.1
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "assertions.h"
#include "conversions.h"
#include "intertask_interface.h"
#include "ngap_common.h"
#include "ngap_gNB_encoder.h"
static inline int ngap_gNB_encode_initiating(NGAP_NGAP_PDU_t *pdu,
uint8_t **buffer,
uint32_t *len);
static inline int ngap_gNB_encode_successfull_outcome(NGAP_NGAP_PDU_t *pdu,
uint8_t **buffer, uint32_t *len);
static inline int ngap_gNB_encode_unsuccessfull_outcome(NGAP_NGAP_PDU_t *pdu,
uint8_t **buffer, uint32_t *len);
int ngap_gNB_encode_pdu(NGAP_NGAP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) {
int ret = -1;
DevAssert(pdu != NULL);
DevAssert(buffer != NULL);
DevAssert(len != NULL);
switch(pdu->present) {
case NGAP_NGAP_PDU_PR_initiatingMessage:
ret = ngap_gNB_encode_initiating(pdu, buffer, len);
break;
case NGAP_NGAP_PDU_PR_successfulOutcome:
ret = ngap_gNB_encode_successfull_outcome(pdu, buffer, len);
break;
case NGAP_NGAP_PDU_PR_unsuccessfulOutcome:
ret = ngap_gNB_encode_unsuccessfull_outcome(pdu, buffer, len);
break;
default:
NGAP_DEBUG("Unknown message outcome (%d) or not implemented",
(int)pdu->present);
return -1;
}
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, pdu);
return ret;
}
static inline
int ngap_gNB_encode_initiating(NGAP_NGAP_PDU_t *pdu,
uint8_t **buffer, uint32_t *len) {
asn_encode_to_new_buffer_result_t res = { NULL, {0, NULL, NULL} };
DevAssert(pdu != NULL);
switch(pdu->choice.initiatingMessage.procedureCode) {
case NGAP_ProcedureCode_id_S1Setup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_uplinkNASTransport:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_UECapabilityInfoIndication:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_initialUEMessage:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_NASNonDeliveryIndication:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_UEContextReleaseRequest:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_PathSwitchRequest:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_E_RABModificationIndication:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
default:
NGAP_DEBUG("Unknown procedure ID (%d) for initiating message\n",
(int)pdu->choice.initiatingMessage.procedureCode);
return -1;
}
if (asn1_xer_print) {
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, (void *)pdu);
}
memset(&res, 0, sizeof(res));
res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_NGAP_PDU, pdu);
*buffer = res.buffer;
*len = res.result.encoded;
return 0;
}
static inline
int ngap_gNB_encode_successfull_outcome(NGAP_NGAP_PDU_t *pdu,
uint8_t **buffer, uint32_t *len) {
asn_encode_to_new_buffer_result_t res = { NULL, {0, NULL, NULL} };
DevAssert(pdu != NULL);
switch(pdu->choice.successfulOutcome.procedureCode) {
case NGAP_ProcedureCode_id_InitialContextSetup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_UEContextRelease:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
case NGAP_ProcedureCode_id_E_RABSetup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("E_RABSetup successful message\n");
break;
case NGAP_ProcedureCode_id_E_RABModify:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("E_RABModify successful message\n");
break;
case NGAP_ProcedureCode_id_E_RABRelease:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("E_RAB Release successful message\n");
break;
default:
NGAP_WARN("Unknown procedure ID (%d) for successfull outcome message\n",
(int)pdu->choice.successfulOutcome.procedureCode);
return -1;
}
if (asn1_xer_print) {
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, (void *)pdu);
}
memset(&res, 0, sizeof(res));
res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_NGAP_PDU, pdu);
*buffer = res.buffer;
*len = res.result.encoded;
return 0;
}
static inline
int ngap_gNB_encode_unsuccessfull_outcome(NGAP_NGAP_PDU_t *pdu,
uint8_t **buffer, uint32_t *len) {
asn_encode_to_new_buffer_result_t res = { NULL, {0, NULL, NULL} };
DevAssert(pdu != NULL);
switch(pdu->choice.unsuccessfulOutcome.procedureCode) {
case NGAP_ProcedureCode_id_InitialContextSetup:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
default:
NGAP_DEBUG("Unknown procedure ID (%d) for unsuccessfull outcome message\n",
(int)pdu->choice.unsuccessfulOutcome.procedureCode);
return -1;
}
if (asn1_xer_print) {
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, (void *)pdu);
}
memset(&res, 0, sizeof(res));
res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_NGAP_PDU, pdu);
*buffer = res.buffer;
*len = res.result.encoded;
return 0;
}
/*
* 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 NGAP_GNB_ENCODER_H_
#define NGAP_GNB_ENCODER_H_
int ngap_gNB_encode_pdu(NGAP_NGAP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
__attribute__ ((warn_unused_result));
#endif /* NGAP_GNB_ENCODER_H_ */
/*
* 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
*/
/*! \file ngap_gNB_handlers.c
* \brief ngap messages handlers for gNB part
* \author Sebastien ROUX and Navid Nikaein
* \email navid.nikaein@eurecom.fr
* \date 2013 - 2015
* \version 0.1
*/
#include <stdint.h>
#include "intertask_interface.h"
#include "asn1_conversions.h"
#include "ngap_common.h"
// #include "ngap_gNB.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB_handlers.h"
#include "ngap_gNB_decoder.h"
#include "ngap_gNB_ue_context.h"
#include "ngap_gNB_trace.h"
#include "ngap_gNB_nas_procedures.h"
#include "ngap_gNB_management_procedures.h"
#include "ngap_gNB_default_values.h"
#include "assertions.h"
#include "conversions.h"
#include "msc.h"
static
int ngap_gNB_handle_s1_setup_response(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_s1_setup_failure(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_error_indication(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_initial_context_request(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_ue_context_release_command(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_e_rab_setup_request(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_paging(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_e_rab_modify_request(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_e_rab_release_command(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_s1_path_switch_request_ack(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_s1_path_switch_request_failure(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
static
int ngap_gNB_handle_s1_ENDC_e_rab_modification_confirm(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
/* Handlers matrix. Only gNB related procedure present here */
ngap_message_decoded_callback messages_callback[][3] = {
{ 0, 0, 0 }, /* HandoverPreparation */
{ 0, 0, 0 }, /* HandoverResourceAllocation */
{ 0, 0, 0 }, /* HandoverNotification */
{ 0, ngap_gNB_handle_s1_path_switch_request_ack, ngap_gNB_handle_s1_path_switch_request_failure }, /* PathSwitchRequest */
{ 0, 0, 0 }, /* HandoverCancel */
{ ngap_gNB_handle_e_rab_setup_request, 0, 0 }, /* E_RABSetup */
{ ngap_gNB_handle_e_rab_modify_request, 0, 0 }, /* E_RABModify */
{ ngap_gNB_handle_e_rab_release_command, 0, 0 }, /* E_RABRelease */
{ 0, 0, 0 }, /* E_RABReleaseIndication */
{ ngap_gNB_handle_initial_context_request, 0, 0 }, /* InitialContextSetup */
{ ngap_gNB_handle_paging, 0, 0 }, /* Paging */
{ ngap_gNB_handle_nas_downlink, 0, 0 }, /* downlinkNASTransport */
{ 0, 0, 0 }, /* initialUEMessage */
{ 0, 0, 0 }, /* uplinkNASTransport */
{ 0, 0, 0 }, /* Reset */
{ ngap_gNB_handle_error_indication, 0, 0 }, /* ErrorIndication */
{ 0, 0, 0 }, /* NASNonDeliveryIndication */
{ 0, ngap_gNB_handle_s1_setup_response, ngap_gNB_handle_s1_setup_failure }, /* S1Setup */
{ 0, 0, 0 }, /* UEContextReleaseRequest */
{ 0, 0, 0 }, /* DownlinkS1cdma2000tunneling */
{ 0, 0, 0 }, /* UplinkS1cdma2000tunneling */
{ 0, 0, 0 }, /* UEContextModification */
{ 0, 0, 0 }, /* UECapabilityInfoIndication */
{ ngap_gNB_handle_ue_context_release_command, 0, 0 }, /* UEContextRelease */
{ 0, 0, 0 }, /* gNBStatusTransfer */
{ 0, 0, 0 }, /* MMEStatusTransfer */
{ ngap_gNB_handle_deactivate_trace, 0, 0 }, /* DeactivateTrace */
{ ngap_gNB_handle_trace_start, 0, 0 }, /* TraceStart */
{ 0, 0, 0 }, /* TraceFailureIndication */
{ 0, 0, 0 }, /* GNBConfigurationUpdate */
{ 0, 0, 0 }, /* MMEConfigurationUpdate */
{ 0, 0, 0 }, /* LocationReportingControl */
{ 0, 0, 0 }, /* LocationReportingFailureIndication */
{ 0, 0, 0 }, /* LocationReport */
{ 0, 0, 0 }, /* OverloadStart */
{ 0, 0, 0 }, /* OverloadStop */
{ 0, 0, 0 }, /* WriteReplaceWarning */
{ 0, 0, 0 }, /* gNBDirectInformationTransfer */
{ 0, 0, 0 }, /* MMEDirectInformationTransfer */
{ 0, 0, 0 }, /* PrivateMessage */
{ 0, 0, 0 }, /* gNBConfigurationTransfer */
{ 0, 0, 0 }, /* MMEConfigurationTransfer */
{ 0, 0, 0 }, /* CellTrafficTrace */
{ 0, 0, 0 }, /* Kill */
{ 0, 0, 0 }, /* DownlinkUEAssociatedLPPaTransport */
{ 0, 0, 0 }, /* UplinkUEAssociatedLPPaTransport */
{ 0, 0, 0 }, /* DownlinkNonUEAssociatedLPPaTransport */
{ 0, 0, 0 }, /* UplinkNonUEAssociatedLPPaTransport */
{ 0, 0, 0 }, /* UERadioCapabilityMatch */
{ 0, 0, 0 }, /* PWSRestartIndication */
{ 0, ngap_gNB_handle_s1_ENDC_e_rab_modification_confirm, 0 }, /* E_RABModificationIndication */
};
char *ngap_direction2String(int ngap_dir) {
static char *ngap_direction_String[] = {
"", /* Nothing */
"Originating message", /* originating message */
"Successfull outcome", /* successfull outcome */
"UnSuccessfull outcome", /* successfull outcome */
};
return(ngap_direction_String[ngap_dir]);
}
void ngap_handle_s1_setup_message(ngap_gNB_mme_data_t *mme_desc_p, int sctp_shutdown) {
if (sctp_shutdown) {
/* A previously connected MME has been shutdown */
/* TODO check if it was used by some gNB and send a message to inform these gNB if there is no more associated MME */
if (mme_desc_p->state == NGAP_GNB_STATE_CONNECTED) {
mme_desc_p->state = NGAP_GNB_STATE_DISCONNECTED;
if (mme_desc_p->ngap_gNB_instance->ngap_mme_associated_nb > 0) {
/* Decrease associated MME number */
mme_desc_p->ngap_gNB_instance->ngap_mme_associated_nb --;
}
/* If there are no more associated MME, inform gNB app */
if (mme_desc_p->ngap_gNB_instance->ngap_mme_associated_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_DEREGISTERED_GNB_IND);
NGAP_DEREGISTERED_GNB_IND(message_p).nb_mme = 0;
itti_send_msg_to_task(TASK_GNB_APP, mme_desc_p->ngap_gNB_instance->instance, message_p);
}
}
} else {
/* Check that at least one setup message is pending */
DevCheck(mme_desc_p->ngap_gNB_instance->ngap_mme_pending_nb > 0, mme_desc_p->ngap_gNB_instance->instance,
mme_desc_p->ngap_gNB_instance->ngap_mme_pending_nb, 0);
if (mme_desc_p->ngap_gNB_instance->ngap_mme_pending_nb > 0) {
/* Decrease pending messages number */
mme_desc_p->ngap_gNB_instance->ngap_mme_pending_nb --;
}
/* If there are no more pending messages, inform gNB app */
if (mme_desc_p->ngap_gNB_instance->ngap_mme_pending_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_REGISTER_GNB_CNF);
NGAP_REGISTER_GNB_CNF(message_p).nb_mme = mme_desc_p->ngap_gNB_instance->ngap_mme_associated_nb;
itti_send_msg_to_task(TASK_GNB_APP, mme_desc_p->ngap_gNB_instance->instance, message_p);
}
}
}
int ngap_gNB_handle_message(uint32_t assoc_id, int32_t stream,
const uint8_t *const data, const uint32_t data_length) {
NGAP_NGAP_PDU_t pdu;
int ret;
DevAssert(data != NULL);
memset(&pdu, 0, sizeof(pdu));
if (ngap_gNB_decode_pdu(&pdu, data, data_length) < 0) {
NGAP_ERROR("Failed to decode PDU\n");
return -1;
}
/* Checking procedure Code and direction of message */
if (pdu.choice.initiatingMessage.procedureCode >= sizeof(messages_callback) / (3 * sizeof(
ngap_message_decoded_callback))
|| (pdu.present > NGAP_NGAP_PDU_PR_unsuccessfulOutcome)) {
NGAP_ERROR("[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n",
assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
return -1;
}
/* No handler present.
* This can mean not implemented or no procedure for gNB (wrong direction).
*/
if (messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) {
NGAP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
assoc_id, pdu.choice.initiatingMessage.procedureCode,
ngap_direction2String(pdu.present - 1));
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
return -1;
}
/* Calling the right handler */
ret = (*messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1])
(assoc_id, stream, &pdu);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
return ret;
}
static
int ngap_gNB_handle_s1_setup_failure(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
NGAP_S1SetupFailure_t *container;
NGAP_S1SetupFailureIEs_t *ie;
ngap_gNB_mme_data_t *mme_desc_p;
DevAssert(pdu != NULL);
container = &pdu->choice.unsuccessfulOutcome.value.choice.S1SetupFailure;
/* S1 Setup Failure == Non UE-related procedure -> stream 0 */
if (stream != 0) {
NGAP_WARN("[SCTP %d] Received s1 setup failure on stream != 0 (%d)\n",
assoc_id, stream);
}
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received S1 setup response for non existing "
"MME context\n", assoc_id);
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_S1SetupFailureIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_Cause,true);
if ((ie->value.choice.Cause.present == NGAP_Cause_PR_misc) &&
(ie->value.choice.Cause.choice.misc == NGAP_CauseMisc_unspecified)) {
NGAP_WARN("Received s1 setup failure for MME... MME is not ready\n");
} else {
NGAP_ERROR("Received s1 setup failure for MME... please check your parameters\n");
}
mme_desc_p->state = NGAP_GNB_STATE_WAITING;
ngap_handle_s1_setup_message(mme_desc_p, 0);
return 0;
}
static
int ngap_gNB_handle_s1_setup_response(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
NGAP_S1SetupResponse_t *container;
NGAP_S1SetupResponseIEs_t *ie;
ngap_gNB_mme_data_t *mme_desc_p;
int i;
DevAssert(pdu != NULL);
container = &pdu->choice.successfulOutcome.value.choice.S1SetupResponse;
/* S1 Setup Response == Non UE-related procedure -> stream 0 */
if (stream != 0) {
NGAP_ERROR("[SCTP %d] Received s1 setup response on stream != 0 (%d)\n",
assoc_id, stream);
return -1;
}
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received S1 setup response for non existing "
"MME context\n", assoc_id);
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_S1SetupResponseIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_ServedGUMMEIs, true);
/* The list of served gummei can contain at most 8 elements.
* LTE related gummei is the first element in the list, i.e with an id of 0.
*/
NGAP_DEBUG("servedGUMMEIs.list.count %d\n", ie->value.choice.ServedGUMMEIs.list.count);
DevAssert(ie->value.choice.ServedGUMMEIs.list.count > 0);
DevAssert(ie->value.choice.ServedGUMMEIs.list.count <= NGAP_maxnoofRATs);
for (i = 0; i < ie->value.choice.ServedGUMMEIs.list.count; i++) {
NGAP_ServedGUMMEIsItem_t *gummei_item_p;
struct served_gummei_s *new_gummei_p;
int j;
gummei_item_p = ie->value.choice.ServedGUMMEIs.list.array[i];
new_gummei_p = calloc(1, sizeof(struct served_gummei_s));
STAILQ_INIT(&new_gummei_p->served_plmns);
STAILQ_INIT(&new_gummei_p->served_group_ids);
STAILQ_INIT(&new_gummei_p->mme_codes);
NGAP_DEBUG("servedPLMNs.list.count %d\n", gummei_item_p->servedPLMNs.list.count);
for (j = 0; j < gummei_item_p->servedPLMNs.list.count; j++) {
NGAP_PLMNidentity_t *plmn_identity_p;
struct plmn_identity_s *new_plmn_identity_p;
plmn_identity_p = gummei_item_p->servedPLMNs.list.array[j];
new_plmn_identity_p = calloc(1, sizeof(struct plmn_identity_s));
TBCD_TO_MCC_MNC(plmn_identity_p, new_plmn_identity_p->mcc,
new_plmn_identity_p->mnc, new_plmn_identity_p->mnc_digit_length);
STAILQ_INSERT_TAIL(&new_gummei_p->served_plmns, new_plmn_identity_p, next);
new_gummei_p->nb_served_plmns++;
}
for (j = 0; j < gummei_item_p->servedGroupIDs.list.count; j++) {
NGAP_MME_Group_ID_t *mme_group_id_p;
struct served_group_id_s *new_group_id_p;
mme_group_id_p = gummei_item_p->servedGroupIDs.list.array[j];
new_group_id_p = calloc(1, sizeof(struct served_group_id_s));
OCTET_STRING_TO_INT16(mme_group_id_p, new_group_id_p->mme_group_id);
STAILQ_INSERT_TAIL(&new_gummei_p->served_group_ids, new_group_id_p, next);
new_gummei_p->nb_group_id++;
}
for (j = 0; j < gummei_item_p->servedMMECs.list.count; j++) {
NGAP_MME_Code_t *mme_code_p;
struct mme_code_s *new_mme_code_p;
mme_code_p = gummei_item_p->servedMMECs.list.array[j];
new_mme_code_p = calloc(1, sizeof(struct mme_code_s));
OCTET_STRING_TO_INT8(mme_code_p, new_mme_code_p->mme_code);
STAILQ_INSERT_TAIL(&new_gummei_p->mme_codes, new_mme_code_p, next);
new_gummei_p->nb_mme_code++;
}
STAILQ_INSERT_TAIL(&mme_desc_p->served_gummei, new_gummei_p, next);
}
/* Set the capacity of this MME */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_S1SetupResponseIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_RelativeMMECapacity, true);
mme_desc_p->relative_mme_capacity = ie->value.choice.RelativeMMECapacity;
/* Optionaly set the mme name */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_S1SetupResponseIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MMEname, false);
if (ie) {
mme_desc_p->mme_name = calloc(ie->value.choice.MMEname.size + 1, sizeof(char));
memcpy(mme_desc_p->mme_name, ie->value.choice.MMEname.buf,
ie->value.choice.MMEname.size);
/* Convert the mme name to a printable string */
mme_desc_p->mme_name[ie->value.choice.MMEname.size] = '\0';
}
/* The association is now ready as gNB and MME know parameters of each other.
* Mark the association as UP to enable UE contexts creation.
*/
mme_desc_p->state = NGAP_GNB_STATE_CONNECTED;
mme_desc_p->ngap_gNB_instance->ngap_mme_associated_nb ++;
ngap_handle_s1_setup_message(mme_desc_p, 0);
return 0;
}
static
int ngap_gNB_handle_error_indication(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
NGAP_ErrorIndication_t *container;
NGAP_ErrorIndicationIEs_t *ie;
ngap_gNB_mme_data_t *mme_desc_p;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.ErrorIndication;
/* S1 Setup Failure == Non UE-related procedure -> stream 0 */
if (stream != 0) {
NGAP_WARN("[SCTP %d] Received s1 Error indication on stream != 0 (%d)\n",
assoc_id, stream);
}
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received S1 Error indication for non existing "
"MME context\n", assoc_id);
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_ErrorIndicationIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID, false);
/* optional */
if (ie != NULL) {
NGAP_WARN("Received S1 Error indication MME UE NGAP ID 0x%lx\n", ie->value.choice.MME_UE_NGAP_ID);
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_ErrorIndicationIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, false);
/* optional */
if (ie != NULL) {
NGAP_WARN("Received S1 Error indication gNB UE NGAP ID 0x%lx\n", ie->value.choice.GNB_UE_NGAP_ID);
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_ErrorIndicationIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_Cause, false);
/* optional */
if (ie) {
switch(ie->value.choice.Cause.present) {
case NGAP_Cause_PR_NOTHING:
NGAP_WARN("Received S1 Error indication cause NOTHING\n");
break;
case NGAP_Cause_PR_radioNetwork:
switch (ie->value.choice.Cause.choice.radioNetwork) {
case NGAP_CauseRadioNetwork_unspecified:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_unspecified\n");
break;
case NGAP_CauseRadioNetwork_tx2relocoverall_expiry:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_tx2relocoverall_expiry\n");
break;
case NGAP_CauseRadioNetwork_successful_handover:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_successful_handover\n");
break;
case NGAP_CauseRadioNetwork_release_due_to_eutran_generated_reason:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_release_due_to_eutran_generated_reason\n");
break;
case NGAP_CauseRadioNetwork_handover_cancelled:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_handover_cancelled\n");
break;
case NGAP_CauseRadioNetwork_partial_handover:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_partial_handover\n");
break;
case NGAP_CauseRadioNetwork_ho_failure_in_target_EPC_gNB_or_target_system:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_ho_failure_in_target_EPC_gNB_or_target_system\n");
break;
case NGAP_CauseRadioNetwork_ho_target_not_allowed:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_ho_target_not_allowed\n");
break;
case NGAP_CauseRadioNetwork_tS1relocoverall_expiry:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_tS1relocoverall_expiry\n");
break;
case NGAP_CauseRadioNetwork_tS1relocprep_expiry:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_tS1relocprep_expiry\n");
break;
case NGAP_CauseRadioNetwork_cell_not_available:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_cell_not_available\n");
break;
case NGAP_CauseRadioNetwork_unknown_targetID:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_unknown_targetID\n");
break;
case NGAP_CauseRadioNetwork_no_radio_resources_available_in_target_cell:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_no_radio_resources_available_in_target_cell\n");
break;
case NGAP_CauseRadioNetwork_unknown_mme_ue_ngap_id:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_unknown_mme_ue_ngap_id\n");
break;
case NGAP_CauseRadioNetwork_unknown_enb_ue_ngap_id:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_unknown_enb_ue_ngap_id\n");
break;
case NGAP_CauseRadioNetwork_unknown_pair_ue_ngap_id:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_unknown_pair_ue_ngap_id\n");
break;
case NGAP_CauseRadioNetwork_handover_desirable_for_radio_reason:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_handover_desirable_for_radio_reason\n");
break;
case NGAP_CauseRadioNetwork_time_critical_handover:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_time_critical_handover\n");
break;
case NGAP_CauseRadioNetwork_resource_optimisation_handover:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_resource_optimisation_handover\n");
break;
case NGAP_CauseRadioNetwork_reduce_load_in_serving_cell:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_reduce_load_in_serving_cell\n");
break;
case NGAP_CauseRadioNetwork_user_inactivity:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_user_inactivity\n");
break;
case NGAP_CauseRadioNetwork_radio_connection_with_ue_lost:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_radio_connection_with_ue_lost\n");
break;
case NGAP_CauseRadioNetwork_load_balancing_tau_required:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_load_balancing_tau_required\n");
break;
case NGAP_CauseRadioNetwork_cs_fallback_triggered:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_cs_fallback_triggered\n");
break;
case NGAP_CauseRadioNetwork_ue_not_available_for_ps_service:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_ue_not_available_for_ps_service\n");
break;
case NGAP_CauseRadioNetwork_radio_resources_not_available:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_radio_resources_not_available\n");
break;
case NGAP_CauseRadioNetwork_failure_in_radio_interface_procedure:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_failure_in_radio_interface_procedure\n");
break;
case NGAP_CauseRadioNetwork_invalid_qos_combination:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_invalngap_id_qos_combination\n");
break;
case NGAP_CauseRadioNetwork_interrat_redirection:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_interrat_redirection\n");
break;
case NGAP_CauseRadioNetwork_interaction_with_other_procedure:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_interaction_with_other_procedure\n");
break;
case NGAP_CauseRadioNetwork_unknown_E_RAB_ID:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_unknown_E_RAB_ID\n");
break;
case NGAP_CauseRadioNetwork_multiple_E_RAB_ID_instances:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_multiple_E_RAB_ID_instances\n");
break;
case NGAP_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported\n");
break;
case NGAP_CauseRadioNetwork_s1_intra_system_handover_triggered:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_s1_intra_system_handover_triggered\n");
break;
case NGAP_CauseRadioNetwork_s1_inter_system_handover_triggered:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_s1_inter_system_handover_triggered\n");
break;
case NGAP_CauseRadioNetwork_x2_handover_triggered:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_x2_handover_triggered\n");
break;
case NGAP_CauseRadioNetwork_redirection_towards_1xRTT:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_redirection_towards_1xRTT\n");
break;
case NGAP_CauseRadioNetwork_not_supported_QCI_value:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_not_supported_QCI_value\n");
break;
case NGAP_CauseRadioNetwork_invalid_CSG_Id:
NGAP_WARN("Received S1 Error indication NGAP_CauseRadioNetwork_invalngap_id_CSG_Id\n");
break;
default:
NGAP_WARN("Received S1 Error indication cause radio network case not handled\n");
}
break;
case NGAP_Cause_PR_transport:
switch (ie->value.choice.Cause.choice.transport) {
case NGAP_CauseTransport_transport_resource_unavailable:
NGAP_WARN("Received S1 Error indication NGAP_CauseTransport_transport_resource_unavailable\n");
break;
case NGAP_CauseTransport_unspecified:
NGAP_WARN("Received S1 Error indication NGAP_CauseTransport_unspecified\n");
break;
default:
NGAP_WARN("Received S1 Error indication cause transport case not handled\n");
}
break;
case NGAP_Cause_PR_nas:
switch (ie->value.choice.Cause.choice.nas) {
case NGAP_CauseNas_normal_release:
NGAP_WARN("Received S1 Error indication NGAP_CauseNas_normal_release\n");
break;
case NGAP_CauseNas_authentication_failure:
NGAP_WARN("Received S1 Error indication NGAP_CauseNas_authentication_failure\n");
break;
case NGAP_CauseNas_detach:
NGAP_WARN("Received S1 Error indication NGAP_CauseNas_detach\n");
break;
case NGAP_CauseNas_unspecified:
NGAP_WARN("Received S1 Error indication NGAP_CauseNas_unspecified\n");
break;
case NGAP_CauseNas_csg_subscription_expiry:
NGAP_WARN("Received S1 Error indication NGAP_CauseNas_csg_subscription_expiry\n");
break;
default:
NGAP_WARN("Received S1 Error indication cause nas case not handled\n");
}
break;
case NGAP_Cause_PR_protocol:
switch (ie->value.choice.Cause.choice.protocol) {
case NGAP_CauseProtocol_transfer_syntax_error:
NGAP_WARN("Received S1 Error indication NGAP_CauseProtocol_transfer_syntax_error\n");
break;
case NGAP_CauseProtocol_abstract_syntax_error_reject:
NGAP_WARN("Received S1 Error indication NGAP_CauseProtocol_abstract_syntax_error_reject\n");
break;
case NGAP_CauseProtocol_abstract_syntax_error_ignore_and_notify:
NGAP_WARN("Received S1 Error indication NGAP_CauseProtocol_abstract_syntax_error_ignore_and_notify\n");
break;
case NGAP_CauseProtocol_message_not_compatible_with_receiver_state:
NGAP_WARN("Received S1 Error indication NGAP_CauseProtocol_message_not_compatible_with_receiver_state\n");
break;
case NGAP_CauseProtocol_semantic_error:
NGAP_WARN("Received S1 Error indication NGAP_CauseProtocol_semantic_error\n");
break;
case NGAP_CauseProtocol_abstract_syntax_error_falsely_constructed_message:
NGAP_WARN("Received S1 Error indication NGAP_CauseProtocol_abstract_syntax_error_falsely_constructed_message\n");
break;
case NGAP_CauseProtocol_unspecified:
NGAP_WARN("Received S1 Error indication NGAP_CauseProtocol_unspecified\n");
break;
default:
NGAP_WARN("Received S1 Error indication cause protocol case not handled\n");
}
break;
case NGAP_Cause_PR_misc:
switch (ie->value.choice.Cause.choice.protocol) {
case NGAP_CauseMisc_control_processing_overload:
NGAP_WARN("Received S1 Error indication NGAP_CauseMisc_control_processing_overload\n");
break;
case NGAP_CauseMisc_not_enough_user_plane_processing_resources:
NGAP_WARN("Received S1 Error indication NGAP_CauseMisc_not_enough_user_plane_processing_resources\n");
break;
case NGAP_CauseMisc_hardware_failure:
NGAP_WARN("Received S1 Error indication NGAP_CauseMisc_hardware_failure\n");
break;
case NGAP_CauseMisc_om_intervention:
NGAP_WARN("Received S1 Error indication NGAP_CauseMisc_om_intervention\n");
break;
case NGAP_CauseMisc_unspecified:
NGAP_WARN("Received S1 Error indication NGAP_CauseMisc_unspecified\n");
break;
case NGAP_CauseMisc_unknown_PLMN:
NGAP_WARN("Received S1 Error indication NGAP_CauseMisc_unknown_PLMN\n");
break;
default:
NGAP_WARN("Received S1 Error indication cause misc case not handled\n");
}
break;
}
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_ErrorIndicationIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_CriticalityDiagnostics, false);
if (ie) {
// TODO continue
}
// TODO continue
return 0;
}
static
int ngap_gNB_handle_initial_context_request(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
int i;
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_ue_context_t *ue_desc_p = NULL;
MessageDef *message_p = NULL;
NGAP_InitialContextSetupRequest_t *container;
NGAP_InitialContextSetupRequestIEs_t *ie;
NGAP_GNB_UE_NGAP_ID_t enb_ue_ngap_id;
NGAP_MME_UE_NGAP_ID_t mme_ue_ngap_id;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.InitialContextSetupRequest;
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing MME context\n", assoc_id);
return -1;
}
/* id-MME-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
mme_ue_ngap_id = ie->value.choice.MME_UE_NGAP_ID;
} else {
return -1;
}
/* id-gNB-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
enb_ue_ngap_id = ie->value.choice.GNB_UE_NGAP_ID;
if ((ue_desc_p = ngap_gNB_get_ue_context(mme_desc_p->ngap_gNB_instance,
enb_ue_ngap_id)) == NULL) {
NGAP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing UE context 0x%06lx\n", assoc_id,
enb_ue_ngap_id);
return -1;
}
} else {
return -1;
}
/* Initial context request = UE-related procedure -> stream != 0 */
if (stream == 0) {
NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n",
assoc_id, stream);
return -1;
}
ue_desc_p->rx_stream = stream;
ue_desc_p->mme_ue_ngap_id = mme_ue_ngap_id;
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_INITIAL_CONTEXT_SETUP_REQ);
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).ue_initial_id = ue_desc_p->ue_initial_id;
ue_desc_p->ue_initial_id = 0;
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).gNB_ue_ngap_id = ue_desc_p->gNB_ue_ngap_id;
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).mme_ue_ngap_id = ue_desc_p->mme_ue_ngap_id;
/* id-uEaggregateMaximumBitrate */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_uEaggregateMaximumBitrate, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL),
&(NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).ue_ambr.br_ul));
asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL),
&(NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).ue_ambr.br_dl));
/* id-E-RABToBeSetupListCtxtSUReq */
} else {
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_E_RABToBeSetupListCtxtSUReq, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).nb_of_e_rabs =
ie->value.choice.E_RABToBeSetupListCtxtSUReq.list.count;
for (i = 0; i < ie->value.choice.E_RABToBeSetupListCtxtSUReq.list.count; i++) {
NGAP_E_RABToBeSetupItemCtxtSUReq_t *item_p;
item_p = &(((NGAP_E_RABToBeSetupItemCtxtSUReqIEs_t *)ie->value.choice.E_RABToBeSetupListCtxtSUReq.list.array[i])->value.choice.E_RABToBeSetupItemCtxtSUReq);
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].e_rab_id = item_p->e_RAB_ID;
if (item_p->nAS_PDU != NULL) {
/* Only copy NAS pdu if present */
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].nas_pdu.length = item_p->nAS_PDU->size;
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].nas_pdu.buffer =
malloc(sizeof(uint8_t) * item_p->nAS_PDU->size);
memcpy(NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].nas_pdu.buffer,
item_p->nAS_PDU->buf, item_p->nAS_PDU->size);
NGAP_DEBUG("Received NAS message with the E_RAB setup procedure\n");
} else {
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].nas_pdu.length = 0;
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].nas_pdu.buffer = NULL;
}
/* Set the transport layer address */
memcpy(NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].sgw_addr.buffer,
item_p->transportLayerAddress.buf, item_p->transportLayerAddress.size);
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].sgw_addr.length =
item_p->transportLayerAddress.size * 8 - item_p->transportLayerAddress.bits_unused;
/* GTP tunnel endpoint ID */
OCTET_STRING_TO_INT32(&item_p->gTP_TEID, NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].gtp_teid);
/* Set the QOS informations */
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].qos.qci = item_p->e_RABlevelQoSParameters.qCI;
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].qos.allocation_retention_priority.priority_level =
item_p->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel;
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability =
item_p->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability;
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability =
item_p->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability;
} /* for i... */
} else {/* ie != NULL */
return -1;
}
/* id-UESecurityCapabilities */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).security_capabilities.encryption_algorithms =
BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.encryptionAlgorithms);
NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).security_capabilities.integrity_algorithms =
BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.integrityProtectionAlgorithms);
/* id-SecurityKey : Copy the security key */
} else {/* ie != NULL */
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_SecurityKey, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
memcpy(&NGAP_INITIAL_CONTEXT_SETUP_REQ(message_p).security_key,
ie->value.choice.SecurityKey.buf, ie->value.choice.SecurityKey.size);
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
} else {/* ie != NULL */
return -1;
}
return 0;
}
static
int ngap_gNB_handle_ue_context_release_command(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_ue_context_t *ue_desc_p = NULL;
MessageDef *message_p = NULL;
NGAP_MME_UE_NGAP_ID_t mme_ue_ngap_id;
NGAP_GNB_UE_NGAP_ID_t enb_ue_ngap_id;
NGAP_UEContextReleaseCommand_t *container;
NGAP_UEContextReleaseCommand_IEs_t *ie;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.UEContextReleaseCommand;
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received UE context release command for non "
"existing MME context\n", assoc_id);
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_UEContextReleaseCommand_IEs_t, ie, container,
NGAP_ProtocolIE_ID_id_UE_NGAP_IDs, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
switch (ie->value.choice.UE_NGAP_IDs.present) {
case NGAP_UE_NGAP_IDs_PR_uE_NGAP_ID_pair:
enb_ue_ngap_id = ie->value.choice.UE_NGAP_IDs.choice.uE_NGAP_ID_pair.gNB_UE_NGAP_ID;
mme_ue_ngap_id = ie->value.choice.UE_NGAP_IDs.choice.uE_NGAP_ID_pair.mME_UE_NGAP_ID;
MSC_LOG_RX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
NULL,0,
"0 UEContextRelease/%s gNB_ue_ngap_id "NGAP_UE_ID_FMT" mme_ue_ngap_id "NGAP_UE_ID_FMT" len %u",
ngap_direction2String(pdu->present - 1),
enb_ue_ngap_id,
mme_ue_ngap_id);
if ((ue_desc_p = ngap_gNB_get_ue_context(mme_desc_p->ngap_gNB_instance,
enb_ue_ngap_id)) == NULL) {
NGAP_ERROR("[SCTP %d] Received UE context release command for non "
"existing UE context 0x%06lx\n",
assoc_id,
enb_ue_ngap_id);
return -1;
} else {
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_RRC_GNB,
NULL,0,
"0 NGAP_UE_CONTEXT_RELEASE_COMMAND/%d gNB_ue_ngap_id "NGAP_UE_ID_FMT" ",
enb_ue_ngap_id);
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_UE_CONTEXT_RELEASE_COMMAND);
if (ue_desc_p->mme_ue_ngap_id == 0) { // case of Detach Request and switch off from RRC_IDLE mode
ue_desc_p->mme_ue_ngap_id = mme_ue_ngap_id;
}
NGAP_UE_CONTEXT_RELEASE_COMMAND(message_p).gNB_ue_ngap_id = enb_ue_ngap_id;
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
return 0;
}
break;
//#warning "TODO mapping mme_ue_ngap_id enb_ue_ngap_id?"
case NGAP_UE_NGAP_IDs_PR_mME_UE_NGAP_ID:
mme_ue_ngap_id = ie->value.choice.UE_NGAP_IDs.choice.uE_NGAP_ID_pair.mME_UE_NGAP_ID;
NGAP_ERROR("TO DO mapping mme_ue_ngap_id enb_ue_ngap_id");
(void)mme_ue_ngap_id; /* TODO: remove - it's to remove gcc warning about unused var */
case NGAP_UE_NGAP_IDs_PR_NOTHING:
default:
NGAP_ERROR("NGAP_UE_CONTEXT_RELEASE_COMMAND not processed, missing info elements");
return -1;
}
} else {
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_UEContextReleaseCommand_IEs_t, ie, container,
NGAP_ProtocolIE_ID_id_Cause, true);
/* TBD */
}
static
int ngap_gNB_handle_e_rab_setup_request(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
int i;
NGAP_MME_UE_NGAP_ID_t mme_ue_ngap_id;
NGAP_GNB_UE_NGAP_ID_t enb_ue_ngap_id;
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_ue_context_t *ue_desc_p = NULL;
MessageDef *message_p = NULL;
NGAP_E_RABSetupRequest_t *container;
NGAP_E_RABSetupRequestIEs_t *ie;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.E_RABSetupRequest;
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing MME context\n", assoc_id);
return -1;
}
/* id-MME-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
mme_ue_ngap_id = ie->value.choice.MME_UE_NGAP_ID;
} else {
return -1;
}
/* id-gNB-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
enb_ue_ngap_id = ie->value.choice.GNB_UE_NGAP_ID;
} else {
return -1;
}
if ((ue_desc_p = ngap_gNB_get_ue_context(mme_desc_p->ngap_gNB_instance,
enb_ue_ngap_id)) == NULL) {
NGAP_ERROR("[SCTP %d] Received initial context setup request for non "
"existing UE context 0x%06lx\n", assoc_id,
enb_ue_ngap_id);
return -1;
}
/* Initial context request = UE-related procedure -> stream != 0 */
if (stream == 0) {
NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n",
assoc_id, stream);
return -1;
}
ue_desc_p->rx_stream = stream;
if ( ue_desc_p->mme_ue_ngap_id != mme_ue_ngap_id) {
NGAP_WARN("UE context mme_ue_ngap_id is different form that of the message (%d != %ld)",
ue_desc_p->mme_ue_ngap_id, mme_ue_ngap_id);
}
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_E_RAB_SETUP_REQ);
NGAP_E_RAB_SETUP_REQ(message_p).ue_initial_id = ue_desc_p->ue_initial_id;
NGAP_E_RAB_SETUP_REQ(message_p).mme_ue_ngap_id = mme_ue_ngap_id;
NGAP_E_RAB_SETUP_REQ(message_p).gNB_ue_ngap_id = enb_ue_ngap_id;
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABSetupRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_E_RABToBeSetupListBearerSUReq, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
NGAP_E_RAB_SETUP_REQ(message_p).nb_e_rabs_tosetup =
ie->value.choice.E_RABToBeSetupListBearerSUReq.list.count;
for (i = 0; i < ie->value.choice.E_RABToBeSetupListBearerSUReq.list.count; i++) {
NGAP_E_RABToBeSetupItemBearerSUReq_t *item_p;
item_p = &(((NGAP_E_RABToBeSetupItemBearerSUReqIEs_t *)ie->value.choice.E_RABToBeSetupListBearerSUReq.list.array[i])->value.choice.E_RABToBeSetupItemBearerSUReq);
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].e_rab_id = item_p->e_RAB_ID;
// check for the NAS PDU
if (item_p->nAS_PDU.size > 0 ) {
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.length = item_p->nAS_PDU.size;
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.buffer = malloc(sizeof(uint8_t) * item_p->nAS_PDU.size);
memcpy(NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.buffer,
item_p->nAS_PDU.buf, item_p->nAS_PDU.size);
// NGAP_INFO("received a NAS PDU with size %d (%02x.%02x)\n",NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.length, item_p->nAS_PDU.buf[0], item_p->nAS_PDU.buf[1]);
} else {
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.length = 0;
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].nas_pdu.buffer = NULL;
NGAP_WARN("NAS PDU is not provided, generate a E_RAB_SETUP Failure (TBD) back to MME \n");
}
/* Set the transport layer address */
memcpy(NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].sgw_addr.buffer,
item_p->transportLayerAddress.buf, item_p->transportLayerAddress.size);
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].sgw_addr.length =
item_p->transportLayerAddress.size * 8 - item_p->transportLayerAddress.bits_unused;
/* NGAP_INFO("sgw addr %s len: %d (size %d, index %d)\n",
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].sgw_addr.buffer,
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].sgw_addr.length,
item_p->transportLayerAddress.size, i);
*/
/* GTP tunnel endpoint ID */
OCTET_STRING_TO_INT32(&item_p->gTP_TEID, NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].gtp_teid);
/* Set the QOS informations */
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].qos.qci = item_p->e_RABlevelQoSParameters.qCI;
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].qos.allocation_retention_priority.priority_level =
item_p->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel;
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].qos.allocation_retention_priority.pre_emp_capability =
item_p->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability;
NGAP_E_RAB_SETUP_REQ(message_p).e_rab_setup_params[i].qos.allocation_retention_priority.pre_emp_vulnerability =
item_p->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability;
} /* for i... */
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
} else {
return -1;
}
return 0;
}
static
int ngap_gNB_handle_paging(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_instance_t *ngap_gNB_instance = NULL;
MessageDef *message_p = NULL;
NGAP_Paging_t *container;
NGAP_PagingIEs_t *ie;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.Paging;
// received Paging Message from MME
NGAP_DEBUG("[SCTP %d] Received Paging Message From MME\n",assoc_id);
/* Paging procedure -> stream != 0 */
if (stream == 0) {
LOG_W(NGAP,"[SCTP %d] Received Paging procedure on stream (%d)\n",
assoc_id, stream);
return -1;
}
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received Paging for non "
"existing MME context\n", assoc_id);
return -1;
}
ngap_gNB_instance = mme_desc_p->ngap_gNB_instance;
if (ngap_gNB_instance == NULL) {
NGAP_ERROR("[SCTP %d] Received Paging for non existing MME context : ngap_gNB_instance is NULL\n",
assoc_id);
return -1;
}
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_PAGING_IND);
/* convert NGAP_PagingIEs_t to ngap_paging_ind_t */
/* id-UEIdentityIndexValue : convert UE Identity Index value */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_UEIdentityIndexValue, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
NGAP_PAGING_IND(message_p).ue_index_value = BIT_STRING_to_uint32(&ie->value.choice.UEIdentityIndexValue);
NGAP_DEBUG("[SCTP %d] Received Paging ue_index_value (%d)\n",
assoc_id,(uint32_t)NGAP_PAGING_IND(message_p).ue_index_value);
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.mme_code = 0;
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.m_tmsi = 0;
} else {
return -1;
}
/* id-UEPagingID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_UEPagingID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
/* convert UE Paging Identity */
if (ie->value.choice.UEPagingID.present == NGAP_UEPagingID_PR_s_TMSI) {
NGAP_PAGING_IND(message_p).ue_paging_identity.presenceMask = UE_PAGING_IDENTITY_s_tmsi;
OCTET_STRING_TO_INT8(&ie->value.choice.UEPagingID.choice.s_TMSI.mMEC, NGAP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.mme_code);
OCTET_STRING_TO_INT32(&ie->value.choice.UEPagingID.choice.s_TMSI.m_TMSI, NGAP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.m_tmsi);
} else if (ie->value.choice.UEPagingID.present == NGAP_UEPagingID_PR_iMSI) {
NGAP_PAGING_IND(message_p).ue_paging_identity.presenceMask = UE_PAGING_IDENTITY_imsi;
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length = 0;
for (int i = 0; i < ie->value.choice.UEPagingID.choice.iMSI.size; i++) {
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i] = (uint8_t)(ie->value.choice.UEPagingID.choice.iMSI.buf[i] & 0x0F );
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length++;
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i+1] = (uint8_t)((ie->value.choice.UEPagingID.choice.iMSI.buf[i]>>4) & 0x0F);
LOG_D(NGAP,"paging : i %d %d imsi %d %d \n",2*i,2*i+1,NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i], NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i+1]);
if (NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2*i+1] == 0x0F) {
if(i != ie->value.choice.UEPagingID.choice.iMSI.size - 1) {
/* invalid paging_p->uePagingID.choise.iMSI.buffer */
NGAP_ERROR("[SCTP %d] Received Paging : uePagingID.choise.iMSI error(i %d 0x0F)\n", assoc_id,i);
return -1;
}
} else {
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length++;
}
} /* for i... */
if (NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length >= NGAP_IMSI_LENGTH) {
/* invalid paging_p->uePagingID.choise.iMSI.size */
NGAP_ERROR("[SCTP %d] Received Paging : uePagingID.choise.iMSI.size(%d) is over IMSI length(%d)\n", assoc_id, NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length, NGAP_IMSI_LENGTH);
return -1;
}
} else { /* of if (ie->value.choice.UEPagingID.present == NGAP_UEPagingID_PR_iMSI) */
/* invalid paging_p->uePagingID.present */
NGAP_ERROR("[SCTP %d] Received Paging : uePagingID.present(%d) is unknown\n", assoc_id, ie->value.choice.UEPagingID.present);
return -1;
}
} else { /* of ie != NULL */
return -1;
}
NGAP_PAGING_IND(message_p).paging_drx = PAGING_DRX_256;
/* id-pagingDRX */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_pagingDRX, false);
/* optional */
if (ie) {
NGAP_PAGING_IND(message_p).paging_drx = ie->value.choice.PagingDRX;
} else {
NGAP_PAGING_IND(message_p).paging_drx = PAGING_DRX_256;
}
/* */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_CNDomain, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
/* id-CNDomain : convert cnDomain */
if (ie->value.choice.CNDomain == NGAP_CNDomain_ps) {
NGAP_PAGING_IND(message_p).cn_domain = CN_DOMAIN_PS;
} else if (ie->value.choice.CNDomain == NGAP_CNDomain_cs) {
NGAP_PAGING_IND(message_p).cn_domain = CN_DOMAIN_CS;
} else {
/* invalid paging_p->cnDomain */
NGAP_ERROR("[SCTP %d] Received Paging : cnDomain(%ld) is unknown\n", assoc_id, ie->value.choice.CNDomain);
itti_free (ITTI_MSG_ORIGIN_ID(message_p), message_p);
return -1;
}
} else {
return -1;
}
memset (&NGAP_PAGING_IND(message_p).plmn_identity[0], 0, sizeof(plmn_identity_t)*256);
memset (&NGAP_PAGING_IND(message_p).tac[0], 0, sizeof(int16_t)*256);
NGAP_PAGING_IND(message_p).tai_size = 0;
/* id-TAIList */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PagingIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_TAIList, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
NGAP_INFO("[SCTP %d] Received Paging taiList: count %d\n", assoc_id, ie->value.choice.TAIList.list.count);
for (int i = 0; i < ie->value.choice.TAIList.list.count; i++) {
NGAP_TAIItem_t *item_p;
item_p = &(((NGAP_TAIItemIEs_t *)ie->value.choice.TAIList.list.array[i])->value.choice.TAIItem);
TBCD_TO_MCC_MNC(&(item_p->tAI.pLMNidentity), NGAP_PAGING_IND(message_p).plmn_identity[i].mcc,
NGAP_PAGING_IND(message_p).plmn_identity[i].mnc,
NGAP_PAGING_IND(message_p).plmn_identity[i].mnc_digit_length);
OCTET_STRING_TO_INT16(&(item_p->tAI.tAC), NGAP_PAGING_IND(message_p).tac[i]);
NGAP_PAGING_IND(message_p).tai_size++;
NGAP_DEBUG("[SCTP %d] Received Paging: MCC %d, MNC %d, TAC %d\n", assoc_id,
NGAP_PAGING_IND(message_p).plmn_identity[i].mcc,
NGAP_PAGING_IND(message_p).plmn_identity[i].mnc,
NGAP_PAGING_IND(message_p).tac[i]);
}
} else {
return -1;
}
//paging parameter values
NGAP_DEBUG("[SCTP %d] Received Paging parameters: ue_index_value %d cn_domain %d paging_drx %d paging_priority %d\n",assoc_id,
NGAP_PAGING_IND(message_p).ue_index_value, NGAP_PAGING_IND(message_p).cn_domain,
NGAP_PAGING_IND(message_p).paging_drx, NGAP_PAGING_IND(message_p).paging_priority);
NGAP_DEBUG("[SCTP %d] Received Paging parameters(ue): presenceMask %d s_tmsi.m_tmsi %d s_tmsi.mme_code %d IMSI length %d (0-5) %d%d%d%d%d%d\n",assoc_id,
NGAP_PAGING_IND(message_p).ue_paging_identity.presenceMask, NGAP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.m_tmsi,
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.s_tmsi.mme_code, NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.length,
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[0], NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[1],
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[2], NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[3],
NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[4], NGAP_PAGING_IND(message_p).ue_paging_identity.choice.imsi.buffer[5]);
/* send message to RRC */
itti_send_msg_to_task(TASK_RRC_GNB, ngap_gNB_instance->instance, message_p);
return 0;
}
static
int ngap_gNB_handle_e_rab_modify_request(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
int i, nb_of_e_rabs_failed;
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_ue_context_t *ue_desc_p = NULL;
MessageDef *message_p = NULL;
NGAP_E_RABModifyRequest_t *container;
NGAP_E_RABModifyRequestIEs_t *ie;
NGAP_GNB_UE_NGAP_ID_t enb_ue_ngap_id;
NGAP_MME_UE_NGAP_ID_t mme_ue_ngap_id;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.E_RABModifyRequest;
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received E-RAB modify request for non "
"existing MME context\n", assoc_id);
return -1;
}
/* id-MME-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABModifyRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
mme_ue_ngap_id = ie->value.choice.MME_UE_NGAP_ID;
} else {
return -1;
}
/* id-gNB-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABModifyRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
enb_ue_ngap_id = ie->value.choice.GNB_UE_NGAP_ID;
} else {
return -1;
}
if ((ue_desc_p = ngap_gNB_get_ue_context(mme_desc_p->ngap_gNB_instance,
enb_ue_ngap_id)) == NULL) {
NGAP_ERROR("[SCTP %d] Received E-RAB modify request for non "
"existing UE context 0x%06lx\n", assoc_id,
enb_ue_ngap_id);
return -1;
}
/* E-RAB modify request = UE-related procedure -> stream != 0 */
if (stream == 0) {
NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n",
assoc_id, stream);
return -1;
}
ue_desc_p->rx_stream = stream;
if (ue_desc_p->mme_ue_ngap_id != mme_ue_ngap_id) {
NGAP_WARN("UE context mme_ue_ngap_id is different form that of the message (%d != %ld)",
ue_desc_p->mme_ue_ngap_id, mme_ue_ngap_id);
message_p = itti_alloc_new_message (TASK_RRC_GNB, NGAP_E_RAB_MODIFY_RESP);
NGAP_E_RAB_MODIFY_RESP (message_p).gNB_ue_ngap_id = enb_ue_ngap_id;
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABModifyRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_E_RABToBeModifiedListBearerModReq, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
for(nb_of_e_rabs_failed = 0; nb_of_e_rabs_failed < ie->value.choice.E_RABToBeModifiedListBearerModReq.list.count; nb_of_e_rabs_failed++) {
NGAP_E_RABToBeModifiedItemBearerModReq_t *item_p;
item_p = &(((NGAP_E_RABToBeModifiedItemBearerModReqIEs_t *)
ie->value.choice.E_RABToBeModifiedListBearerModReq.list.array[nb_of_e_rabs_failed])->value.choice.E_RABToBeModifiedItemBearerModReq);
NGAP_E_RAB_MODIFY_RESP(message_p).e_rabs_failed[nb_of_e_rabs_failed].e_rab_id = item_p->e_RAB_ID;
NGAP_E_RAB_MODIFY_RESP(message_p).e_rabs_failed[nb_of_e_rabs_failed].cause = NGAP_Cause_PR_radioNetwork;
NGAP_E_RAB_MODIFY_RESP(message_p).e_rabs_failed[nb_of_e_rabs_failed].cause_value = NGAP_CauseRadioNetwork_unknown_mme_ue_ngap_id;
}
} else {
return -1;
}
NGAP_E_RAB_MODIFY_RESP(message_p).nb_of_e_rabs_failed = nb_of_e_rabs_failed;
ngap_gNB_e_rab_modify_resp(mme_desc_p->ngap_gNB_instance->instance,
&NGAP_E_RAB_MODIFY_RESP(message_p));
itti_free(TASK_RRC_GNB,message_p);
message_p = NULL;
return -1;
}
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_E_RAB_MODIFY_REQ);
NGAP_E_RAB_MODIFY_REQ(message_p).ue_initial_id = ue_desc_p->ue_initial_id;
NGAP_E_RAB_MODIFY_REQ(message_p).mme_ue_ngap_id = mme_ue_ngap_id;
NGAP_E_RAB_MODIFY_REQ(message_p).gNB_ue_ngap_id = enb_ue_ngap_id;
/* id-E-RABToBeModifiedListBearerModReq */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABModifyRequestIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_E_RABToBeModifiedListBearerModReq, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
NGAP_E_RAB_MODIFY_REQ(message_p).nb_e_rabs_tomodify =
ie->value.choice.E_RABToBeModifiedListBearerModReq.list.count;
for (i = 0; i < ie->value.choice.E_RABToBeModifiedListBearerModReq.list.count; i++) {
NGAP_E_RABToBeModifiedItemBearerModReq_t *item_p;
item_p = &(((NGAP_E_RABToBeModifiedItemBearerModReqIEs_t *)ie->value.choice.E_RABToBeModifiedListBearerModReq.list.array[i])->value.choice.E_RABToBeModifiedItemBearerModReq);
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].e_rab_id = item_p->e_RAB_ID;
// check for the NAS PDU
if (item_p->nAS_PDU.size > 0 ) {
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.length = item_p->nAS_PDU.size;
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.buffer = malloc(sizeof(uint8_t) * item_p->nAS_PDU.size);
memcpy(NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.buffer,
item_p->nAS_PDU.buf, item_p->nAS_PDU.size);
} else {
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.length = 0;
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].nas_pdu.buffer = NULL;
continue;
}
/* Set the QOS informations */
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.qci = item_p->e_RABLevelQoSParameters.qCI;
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.allocation_retention_priority.priority_level =
item_p->e_RABLevelQoSParameters.allocationRetentionPriority.priorityLevel;
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.allocation_retention_priority.pre_emp_capability =
item_p->e_RABLevelQoSParameters.allocationRetentionPriority.pre_emptionCapability;
NGAP_E_RAB_MODIFY_REQ(message_p).e_rab_modify_params[i].qos.allocation_retention_priority.pre_emp_vulnerability =
item_p->e_RABLevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability;
}
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
} else { /* of if (ie != NULL)*/
return -1;
}
return 0;
}
// handle e-rab release command and send it to rrc_end
static
int ngap_gNB_handle_e_rab_release_command(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
int i;
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_ue_context_t *ue_desc_p = NULL;
MessageDef *message_p = NULL;
NGAP_E_RABReleaseCommand_t *container;
NGAP_E_RABReleaseCommandIEs_t *ie;
NGAP_GNB_UE_NGAP_ID_t enb_ue_ngap_id;
NGAP_MME_UE_NGAP_ID_t mme_ue_ngap_id;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.E_RABReleaseCommand;
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received E-RAB release command for non existing MME context\n", assoc_id);
return -1;
}
/* id-MME-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABReleaseCommandIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
mme_ue_ngap_id = ie->value.choice.MME_UE_NGAP_ID;
} else {
return -1;
}
/* id-gNB-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABReleaseCommandIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
enb_ue_ngap_id = ie->value.choice.GNB_UE_NGAP_ID;
} else {
return -1;
}
if ((ue_desc_p = ngap_gNB_get_ue_context(mme_desc_p->ngap_gNB_instance,
enb_ue_ngap_id)) == NULL) {
NGAP_ERROR("[SCTP %d] Received E-RAB release command for non existing UE context 0x%06lx\n", assoc_id,
ie->value.choice.GNB_UE_NGAP_ID);
return -1;
}
/* Initial context request = UE-related procedure -> stream != 0 */
if (stream == 0) {
NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream (%d)\n",
assoc_id, stream);
return -1;
}
ue_desc_p->rx_stream = stream;
if (ue_desc_p->mme_ue_ngap_id != mme_ue_ngap_id) {
NGAP_WARN("UE context mme_ue_ngap_id is different form that of the message (%d != %ld)",
ue_desc_p->mme_ue_ngap_id, mme_ue_ngap_id);
}
NGAP_DEBUG("[SCTP %d] Received E-RAB release command for gNB_UE_NGAP_ID %ld mme_ue_ngap_id %ld\n",
assoc_id, enb_ue_ngap_id, mme_ue_ngap_id);
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_E_RAB_RELEASE_COMMAND);
NGAP_E_RAB_RELEASE_COMMAND(message_p).gNB_ue_ngap_id = enb_ue_ngap_id;
NGAP_E_RAB_RELEASE_COMMAND(message_p).mme_ue_ngap_id = mme_ue_ngap_id;
/* id-NAS-PDU */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABReleaseCommandIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_NAS_PDU, false);
if(ie && ie->value.choice.NAS_PDU.size > 0) {
NGAP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.length = ie->value.choice.NAS_PDU.size;
NGAP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.buffer =
malloc(sizeof(uint8_t) * ie->value.choice.NAS_PDU.size);
memcpy(NGAP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.buffer,
ie->value.choice.NAS_PDU.buf,
ie->value.choice.NAS_PDU.size);
} else {
NGAP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.length = 0;
NGAP_E_RAB_RELEASE_COMMAND(message_p).nas_pdu.buffer = NULL;
}
/* id-E-RABToBeReleasedList */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_E_RABReleaseCommandIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_E_RABToBeReleasedList, true);
if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */
NGAP_E_RAB_RELEASE_COMMAND(message_p).nb_e_rabs_torelease = ie->value.choice.E_RABList.list.count;
for (i = 0; i < ie->value.choice.E_RABList.list.count; i++) {
NGAP_E_RABItem_t *item_p;
item_p = &(((NGAP_E_RABItemIEs_t *)ie->value.choice.E_RABList.list.array[i])->value.choice.E_RABItem);
NGAP_E_RAB_RELEASE_COMMAND(message_p).e_rab_release_params[i].e_rab_id = item_p->e_RAB_ID;
NGAP_DEBUG("[SCTP] Received E-RAB release command for e-rab id %ld\n", item_p->e_RAB_ID);
}
} else {
return -1;
}
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
return 0;
}
static
int ngap_gNB_handle_s1_path_switch_request_ack(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_ue_context_t *ue_desc_p = NULL;
MessageDef *message_p = NULL;
NGAP_PathSwitchRequestAcknowledge_t *pathSwitchRequestAcknowledge;
NGAP_PathSwitchRequestAcknowledgeIEs_t *ie;
NGAP_E_RABToBeSwitchedULItemIEs_t *ngap_E_RABToBeSwitchedULItemIEs;
NGAP_E_RABToBeSwitchedULItem_t *ngap_E_RABToBeSwitchedULItem;
NGAP_E_RABItemIEs_t *e_RABItemIEs;
NGAP_E_RABItem_t *e_RABItem;
DevAssert(pdu != NULL);
pathSwitchRequestAcknowledge = &pdu->choice.successfulOutcome.value.choice.PathSwitchRequestAcknowledge;
/* Path Switch request == UE-related procedure -> stream !=0 */
if (stream == 0) {
NGAP_ERROR("[SCTP %d] Received s1 path switch request ack on stream (%d)\n",
assoc_id, stream);
//return -1;
}
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received S1 path switch request ack for non existing "
"MME context\n", assoc_id);
return -1;
}
// send a message to RRC
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_PATH_SWITCH_REQ_ACK);
/* mandatory */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, true);
if (ie == NULL) {
NGAP_ERROR("[SCTP %d] Received path switch request ack for non "
"ie context is NULL\n", assoc_id);
return -1;
}
NGAP_PATH_SWITCH_REQ_ACK(message_p).gNB_ue_ngap_id = ie->value.choice.GNB_UE_NGAP_ID;
if ((ue_desc_p = ngap_gNB_get_ue_context(mme_desc_p->ngap_gNB_instance,
ie->value.choice.GNB_UE_NGAP_ID)) == NULL) {
NGAP_ERROR("[SCTP %d] Received path switch request ack for non "
"existing UE context 0x%06lx\n", assoc_id,
ie->value.choice.GNB_UE_NGAP_ID);
itti_free(ITTI_MSG_ORIGIN_ID(message_p), message_p);
return -1;
}
NGAP_PATH_SWITCH_REQ_ACK(message_p).ue_initial_id = ue_desc_p->ue_initial_id;
/* mandatory */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID, true);
if (ie == NULL) {
NGAP_ERROR("[SCTP %d] Received path switch request ack for non "
"ie context is NULL\n", assoc_id);
return -1;
}
NGAP_PATH_SWITCH_REQ_ACK(message_p).mme_ue_ngap_id = ie->value.choice.MME_UE_NGAP_ID;
if ( ue_desc_p->mme_ue_ngap_id != ie->value.choice.MME_UE_NGAP_ID) {
NGAP_WARN("UE context mme_ue_ngap_id is different form that of the message (%d != %ld)",
ue_desc_p->mme_ue_ngap_id, ie->value.choice.MME_UE_NGAP_ID);
}
/* mandatory */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_SecurityContext, true);
if (ie == NULL) {
NGAP_ERROR("[SCTP %d] Received path switch request ack for non "
"ie context is NULL\n", assoc_id);
return -1;
}
NGAP_PATH_SWITCH_REQ_ACK(message_p).next_hop_chain_count =
ie->value.choice.SecurityContext.nextHopChainingCount;
memcpy(&NGAP_PATH_SWITCH_REQ_ACK(message_p).next_security_key,
ie->value.choice.SecurityContext.nextHopParameter.buf,
ie->value.choice.SecurityContext.nextHopParameter.size);
/* optional */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_uEaggregateMaximumBitrate, false);
if (ie) {
OCTET_STRING_TO_INT32 (
&ie->value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateUL,
NGAP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_ul
);
OCTET_STRING_TO_INT32 (
&ie->value.choice.UEAggregateMaximumBitrate.uEaggregateMaximumBitRateDL,
NGAP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_dl
);
} else {
NGAP_WARN("UEAggregateMaximumBitrate not supported\n");
NGAP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_ul = 0;
NGAP_PATH_SWITCH_REQ_ACK(message_p).ue_ambr.br_dl = 0;
}
/* optional */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_E_RABToBeSwitchedULList, false);
if (ie) {
NGAP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobeswitched = ie->value.choice.E_RABToBeSwitchedULList.list.count;
for (int i = 0; i < ie->value.choice.E_RABToBeSwitchedULList.list.count; i++) {
ngap_E_RABToBeSwitchedULItemIEs = (NGAP_E_RABToBeSwitchedULItemIEs_t *)ie->value.choice.E_RABToBeSwitchedULList.list.array[i];
ngap_E_RABToBeSwitchedULItem = &ngap_E_RABToBeSwitchedULItemIEs->value.choice.E_RABToBeSwitchedULItem;
NGAP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].e_rab_id = ngap_E_RABToBeSwitchedULItem->e_RAB_ID;
memcpy(NGAP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].sgw_addr.buffer,
ngap_E_RABToBeSwitchedULItem->transportLayerAddress.buf, ngap_E_RABToBeSwitchedULItem->transportLayerAddress.size);
NGAP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].sgw_addr.length =
ngap_E_RABToBeSwitchedULItem->transportLayerAddress.size * 8 - ngap_E_RABToBeSwitchedULItem->transportLayerAddress.bits_unused;
OCTET_STRING_TO_INT32(&ngap_E_RABToBeSwitchedULItem->gTP_TEID,
NGAP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobeswitched[i].gtp_teid);
}
} else {
NGAP_WARN("E_RABToBeSwitchedULList not supported\n");
NGAP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobeswitched = 0;
}
/* optional */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_E_RABToBeReleasedList, false);
if (ie) {
NGAP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobereleased = ie->value.choice.E_RABList.list.count;
for (int i = 0; i < ie->value.choice.E_RABList.list.count; i++) {
e_RABItemIEs = (NGAP_E_RABItemIEs_t *)ie->value.choice.E_RABList.list.array[i];
e_RABItem = &e_RABItemIEs->value.choice.E_RABItem;
NGAP_PATH_SWITCH_REQ_ACK (message_p).e_rabs_tobereleased[i].e_rab_id = e_RABItem->e_RAB_ID;
}
} else {
NGAP_WARN("E_RABToBeReleasedList not supported\n");
NGAP_PATH_SWITCH_REQ_ACK(message_p).nb_e_rabs_tobereleased = 0;
}
/* optional */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_CriticalityDiagnostics, false);
if(!ie) {
NGAP_WARN("Critical Diagnostic not supported\n");
}
/* optional */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestAcknowledgeIEs_t, ie, pathSwitchRequestAcknowledge,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID_2, false);
if(!ie) {
NGAP_WARN("MME_UE_NGAP_ID_2 flag not supported\n");
}
// TODO continue
itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p);
return 0;
}
static
int ngap_gNB_handle_s1_path_switch_request_failure(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu) {
ngap_gNB_mme_data_t *mme_desc_p = NULL;
NGAP_PathSwitchRequestFailure_t *pathSwitchRequestFailure;
NGAP_PathSwitchRequestFailureIEs_t *ie;
DevAssert(pdu != NULL);
pathSwitchRequestFailure = &pdu->choice.unsuccessfulOutcome.value.choice.PathSwitchRequestFailure;
if (stream != 0) {
NGAP_ERROR("[SCTP %d] Received s1 path switch request failure on stream != 0 (%d)\n",
assoc_id, stream);
return -1;
}
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %d] Received S1 path switch request failure for non existing "
"MME context\n", assoc_id);
return -1;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestFailureIEs_t, ie, pathSwitchRequestFailure,
NGAP_ProtocolIE_ID_id_Cause, true);
if (ie == NULL) {
NGAP_ERROR("[SCTP %d] Received S1 path switch request failure for non existing "
"ie context is NULL\n", assoc_id);
return -1;
}
switch(ie->value.choice.Cause.present) {
case NGAP_Cause_PR_NOTHING:
NGAP_WARN("Received S1 Error indication cause NOTHING\n");
break;
case NGAP_Cause_PR_radioNetwork:
NGAP_WARN("Radio Network Layer Cause Failure\n");
break;
case NGAP_Cause_PR_transport:
NGAP_WARN("Transport Layer Cause Failure\n");
break;
case NGAP_Cause_PR_nas:
NGAP_WARN("NAS Cause Failure\n");
break;
case NGAP_Cause_PR_misc:
NGAP_WARN("Miscelaneous Cause Failure\n");
break;
default:
NGAP_WARN("Received an unknown S1 Error indication cause\n");
break;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PathSwitchRequestFailureIEs_t, ie, pathSwitchRequestFailure,
NGAP_ProtocolIE_ID_id_CriticalityDiagnostics, false);
if(!ie) {
NGAP_WARN("Critical Diagnostic not supported\n");
}
// TODO continue
return 0;
}
static
int ngap_gNB_handle_s1_ENDC_e_rab_modification_confirm(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu){
LOG_W(NGAP, "Implementation of NGAP E-RAB Modification confirm handler is pending...\n");
return 0;
}
/*
* 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 NGAP_GNB_HANDLERS_H_
#define NGAP_GNB_HANDLERS_H_
void ngap_handle_s1_setup_message(ngap_gNB_mme_data_t *mme_desc_p, int sctp_shutdown);
int ngap_gNB_handle_message(uint32_t assoc_id, int32_t stream,
const uint8_t * const data, const uint32_t data_length);
#endif /* NGAP_GNB_HANDLERS_H_ */
/*
* 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 "intertask_interface.h"
#include "ngap_gNB_itti_messaging.h"
void ngap_gNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream)
{
MessageDef *message_p;
sctp_data_req_t *sctp_data_req;
message_p = itti_alloc_new_message(TASK_NGAP, SCTP_DATA_REQ);
sctp_data_req = &message_p->ittiMsg.sctp_data_req;
sctp_data_req->assoc_id = assoc_id;
sctp_data_req->buffer = buffer;
sctp_data_req->buffer_length = buffer_length;
sctp_data_req->stream = stream;
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
}
void ngap_gNB_itti_send_nas_downlink_ind(instance_t instance,
uint16_t ue_initial_id,
uint32_t gNB_ue_ngap_id,
uint8_t *nas_pdu,
uint32_t nas_pdu_length)
{
MessageDef *message_p;
ngap_downlink_nas_t *ngap_downlink_nas;
message_p = itti_alloc_new_message(TASK_NGAP, NGAP_DOWNLINK_NAS);
ngap_downlink_nas = &message_p->ittiMsg.ngap_downlink_nas;
ngap_downlink_nas->ue_initial_id = ue_initial_id;
ngap_downlink_nas->gNB_ue_ngap_id = gNB_ue_ngap_id;
ngap_downlink_nas->nas_pdu.buffer = malloc(sizeof(uint8_t) * nas_pdu_length);
memcpy(ngap_downlink_nas->nas_pdu.buffer, nas_pdu, nas_pdu_length);
ngap_downlink_nas->nas_pdu.length = nas_pdu_length;
itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
}
void ngap_gNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id)
{
MessageDef *message_p = NULL;
sctp_close_association_t *sctp_close_association_p = NULL;
message_p = itti_alloc_new_message(TASK_NGAP, SCTP_CLOSE_ASSOCIATION);
sctp_close_association_p = &message_p->ittiMsg.sctp_close_association;
sctp_close_association_p->assoc_id = assoc_id;
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
}
/*
* 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 NGAP_GNB_ITTI_MESSAGING_H_
#define NGAP_GNB_ITTI_MESSAGING_H_
void ngap_gNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream);
void ngap_gNB_itti_send_nas_downlink_ind(instance_t instance,
uint16_t ue_initial_id,
uint32_t gNB_ue_ngap_id,
uint8_t *nas_pdu,
uint32_t nas_pdu_length);
void ngap_gNB_itti_send_sctp_close_association(instance_t instance,
int32_t assoc_id);
#endif /* NGAP_GNB_ITTI_MESSAGING_H_ */
/*
* 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
*/
/*! \file ngap_gNB_management_procedures.c
* \brief NGAP gNB task
* \author S. Roux and Navid Nikaein
* \date 2010 - 2016
* \email: navid.nikaein@eurecom.fr
* \version 1.0
* @ingroup _ngap
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "intertask_interface.h"
#include "assertions.h"
#include "conversions.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB.h"
ngap_gNB_internal_data_t ngap_gNB_internal_data;
RB_GENERATE(ngap_mme_map, ngap_gNB_mme_data_s, entry, ngap_gNB_compare_assoc_id);
int ngap_gNB_compare_assoc_id(
struct ngap_gNB_mme_data_s *p1, struct ngap_gNB_mme_data_s *p2)
{
if (p1->assoc_id == -1) {
if (p1->cnx_id < p2->cnx_id) {
return -1;
}
if (p1->cnx_id > p2->cnx_id) {
return 1;
}
} else {
if (p1->assoc_id < p2->assoc_id) {
return -1;
}
if (p1->assoc_id > p2->assoc_id) {
return 1;
}
}
/* Matching reference */
return 0;
}
uint16_t ngap_gNB_fetch_add_global_cnx_id(void)
{
return ++ngap_gNB_internal_data.global_cnx_id;
}
void ngap_gNB_prepare_internal_data(void)
{
memset(&ngap_gNB_internal_data, 0, sizeof(ngap_gNB_internal_data));
STAILQ_INIT(&ngap_gNB_internal_data.ngap_gNB_instances_head);
}
void ngap_gNB_insert_new_instance(ngap_gNB_instance_t *new_instance_p)
{
DevAssert(new_instance_p != NULL);
STAILQ_INSERT_TAIL(&ngap_gNB_internal_data.ngap_gNB_instances_head,
new_instance_p, ngap_gNB_entries);
}
struct ngap_gNB_mme_data_s *ngap_gNB_get_MME(
ngap_gNB_instance_t *instance_p,
int32_t assoc_id, uint16_t cnx_id)
{
struct ngap_gNB_mme_data_s temp;
struct ngap_gNB_mme_data_s *found;
memset(&temp, 0, sizeof(struct ngap_gNB_mme_data_s));
temp.assoc_id = assoc_id;
temp.cnx_id = cnx_id;
if (instance_p == NULL) {
STAILQ_FOREACH(instance_p, &ngap_gNB_internal_data.ngap_gNB_instances_head,
ngap_gNB_entries) {
found = RB_FIND(ngap_mme_map, &instance_p->ngap_mme_head, &temp);
if (found != NULL) {
return found;
}
}
} else {
return RB_FIND(ngap_mme_map, &instance_p->ngap_mme_head, &temp);
}
return NULL;
}
struct ngap_gNB_mme_data_s *ngap_gNB_get_MME_from_instance(
ngap_gNB_instance_t *instance_p)
{
struct ngap_gNB_mme_data_s *mme = NULL;
struct ngap_gNB_mme_data_s *mme_next = NULL;
for (mme = RB_MIN(ngap_mme_map, &instance_p->ngap_mme_head); mme!=NULL ; mme = mme_next) {
mme_next = RB_NEXT(ngap_mme_map, &instance_p->ngap_mme_head, mme);
if (mme->ngap_gNB_instance == instance_p) {
return mme;
}
}
return NULL;
}
ngap_gNB_instance_t *ngap_gNB_get_instance(instance_t instance)
{
ngap_gNB_instance_t *temp = NULL;
STAILQ_FOREACH(temp, &ngap_gNB_internal_data.ngap_gNB_instances_head,
ngap_gNB_entries) {
if (temp->instance == instance) {
/* Matching occurence */
return temp;
}
}
return NULL;
}
void ngap_gNB_remove_mme_desc(ngap_gNB_instance_t * instance)
{
struct ngap_gNB_mme_data_s *mme = NULL;
struct ngap_gNB_mme_data_s *mmeNext = NULL;
struct plmn_identity_s* plmnInfo;
struct served_group_id_s* groupInfo;
struct served_gummei_s* gummeiInfo;
struct mme_code_s* mmeCode;
for (mme = RB_MIN(ngap_mme_map, &instance->ngap_mme_head); mme; mme = mmeNext) {
mmeNext = RB_NEXT(ngap_mme_map, &instance->ngap_mme_head, mme);
RB_REMOVE(ngap_mme_map, &instance->ngap_mme_head, mme);
while (!STAILQ_EMPTY(&mme->served_gummei)) {
gummeiInfo = STAILQ_FIRST(&mme->served_gummei);
STAILQ_REMOVE_HEAD(&mme->served_gummei, next);
while (!STAILQ_EMPTY(&gummeiInfo->served_plmns)) {
plmnInfo = STAILQ_FIRST(&gummeiInfo->served_plmns);
STAILQ_REMOVE_HEAD(&gummeiInfo->served_plmns, next);
free(plmnInfo);
}
while (!STAILQ_EMPTY(&gummeiInfo->served_group_ids)) {
groupInfo = STAILQ_FIRST(&gummeiInfo->served_group_ids);
STAILQ_REMOVE_HEAD(&gummeiInfo->served_group_ids, next);
free(groupInfo);
}
while (!STAILQ_EMPTY(&gummeiInfo->mme_codes)) {
mmeCode = STAILQ_FIRST(&gummeiInfo->mme_codes);
STAILQ_REMOVE_HEAD(&gummeiInfo->mme_codes, next);
free(mmeCode);
}
free(gummeiInfo);
}
free(mme);
}
}
/*
* 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 NGAP_GNB_MANAGEMENT_PROCEDURES_H_
#define NGAP_GNB_MANAGEMENT_PROCEDURES_H_
struct ngap_gNB_mme_data_s *ngap_gNB_get_MME(
ngap_gNB_instance_t *instance_p,
int32_t assoc_id, uint16_t cnx_id);
struct ngap_gNB_mme_data_s *ngap_gNB_get_MME_from_instance(ngap_gNB_instance_t *instance_p);
void ngap_gNB_remove_mme_desc(ngap_gNB_instance_t * instance);
void ngap_gNB_insert_new_instance(ngap_gNB_instance_t *new_instance_p);
ngap_gNB_instance_t *ngap_gNB_get_instance(uint8_t mod_id);
uint16_t ngap_gNB_fetch_add_global_cnx_id(void);
void ngap_gNB_prepare_internal_data(void);
#endif /* NGAP_GNB_MANAGEMENT_PROCEDURES_H_ */
/*
* 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
*/
/*! \file ngap_gNB_nas_procedures.c
* \brief NGAP eNb NAS procedure handler
* \author S. Roux and Navid Nikaein
* \date 2010 - 2015
* \email: navid.nikaein@eurecom.fr
* \version 1.0
* @ingroup _ngap
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "assertions.h"
#include "conversions.h"
#include "intertask_interface.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB_itti_messaging.h"
#include "ngap_gNB_encoder.h"
#include "ngap_gNB_nnsf.h"
#include "ngap_gNB_ue_context.h"
#include "ngap_gNB_nas_procedures.h"
#include "ngap_gNB_management_procedures.h"
#include "msc.h"
//------------------------------------------------------------------------------
int ngap_gNB_handle_nas_first_req(
instance_t instance, ngap_nas_first_req_t *ngap_nas_first_req_p)
//------------------------------------------------------------------------------
{
ngap_gNB_instance_t *instance_p = NULL;
struct ngap_gNB_mme_data_s *mme_desc_p = NULL;
struct ngap_gNB_ue_context_s *ue_desc_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_InitialUEMessage_t *out;
NGAP_InitialUEMessage_IEs_t *ie;
uint8_t *buffer = NULL;
uint32_t length = 0;
DevAssert(ngap_nas_first_req_p != NULL);
/* Retrieve the NGAP gNB instance associated with Mod_id */
instance_p = ngap_gNB_get_instance(instance);
DevAssert(instance_p != NULL);
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_initialUEMessage;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_ignore;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_InitialUEMessage;
out = &pdu.choice.initiatingMessage.value.choice.InitialUEMessage;
/* Select the MME corresponding to the provided GUMMEI. */
if (ngap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_gummei) {
mme_desc_p = ngap_gNB_nnsf_select_mme_by_gummei(
instance_p,
ngap_nas_first_req_p->establishment_cause,
ngap_nas_first_req_p->ue_identity.gummei);
if (mme_desc_p) {
NGAP_INFO("[gNB %d] Chose MME '%s' (assoc_id %d) through GUMMEI MCC %d MNC %d MMEGI %d MMEC %d\n",
instance,
mme_desc_p->mme_name,
mme_desc_p->assoc_id,
ngap_nas_first_req_p->ue_identity.gummei.mcc,
ngap_nas_first_req_p->ue_identity.gummei.mnc,
ngap_nas_first_req_p->ue_identity.gummei.mme_group_id,
ngap_nas_first_req_p->ue_identity.gummei.mme_code);
}
}
if (mme_desc_p == NULL) {
/* Select the MME corresponding to the provided s-TMSI. */
if (ngap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_s_tmsi) {
mme_desc_p = ngap_gNB_nnsf_select_mme_by_mme_code(
instance_p,
ngap_nas_first_req_p->establishment_cause,
ngap_nas_first_req_p->selected_plmn_identity,
ngap_nas_first_req_p->ue_identity.s_tmsi.mme_code);
if (mme_desc_p) {
NGAP_INFO("[gNB %d] Chose MME '%s' (assoc_id %d) through S-TMSI MMEC %d and selected PLMN Identity index %d MCC %d MNC %d\n",
instance,
mme_desc_p->mme_name,
mme_desc_p->assoc_id,
ngap_nas_first_req_p->ue_identity.s_tmsi.mme_code,
ngap_nas_first_req_p->selected_plmn_identity,
instance_p->mcc[ngap_nas_first_req_p->selected_plmn_identity],
instance_p->mnc[ngap_nas_first_req_p->selected_plmn_identity]);
}
}
}
if (mme_desc_p == NULL) {
/* Select MME based on the selected PLMN identity, received through RRC
* Connection Setup Complete */
mme_desc_p = ngap_gNB_nnsf_select_mme_by_plmn_id(
instance_p,
ngap_nas_first_req_p->establishment_cause,
ngap_nas_first_req_p->selected_plmn_identity);
if (mme_desc_p) {
NGAP_INFO("[gNB %d] Chose MME '%s' (assoc_id %d) through selected PLMN Identity index %d MCC %d MNC %d\n",
instance,
mme_desc_p->mme_name,
mme_desc_p->assoc_id,
ngap_nas_first_req_p->selected_plmn_identity,
instance_p->mcc[ngap_nas_first_req_p->selected_plmn_identity],
instance_p->mnc[ngap_nas_first_req_p->selected_plmn_identity]);
}
}
if (mme_desc_p == NULL) {
/*
* If no MME corresponds to the GUMMEI, the s-TMSI, or the selected PLMN
* identity, selects the MME with the highest capacity.
*/
mme_desc_p = ngap_gNB_nnsf_select_mme(
instance_p,
ngap_nas_first_req_p->establishment_cause);
if (mme_desc_p) {
NGAP_INFO("[gNB %d] Chose MME '%s' (assoc_id %d) through highest relative capacity\n",
instance,
mme_desc_p->mme_name,
mme_desc_p->assoc_id);
}
}
if (mme_desc_p == NULL) {
/*
* In case gNB has no MME associated, the gNB should inform RRC and discard
* this request.
*/
NGAP_WARN("No MME is associated to the gNB\n");
// TODO: Inform RRC
return -1;
}
/* The gNB should allocate a unique gNB UE NGAP ID for this UE. The value
* will be used for the duration of the connectivity.
*/
ue_desc_p = ngap_gNB_allocate_new_UE_context();
DevAssert(ue_desc_p != NULL);
/* Keep a reference to the selected MME */
ue_desc_p->mme_ref = mme_desc_p;
ue_desc_p->ue_initial_id = ngap_nas_first_req_p->ue_initial_id;
ue_desc_p->gNB_instance = instance_p;
ue_desc_p->selected_plmn_identity = ngap_nas_first_req_p->selected_plmn_identity;
do {
struct ngap_gNB_ue_context_s *collision_p;
/* Peek a random value for the gNB_ue_ngap_id */
ue_desc_p->gNB_ue_ngap_id = (random() + random()) & 0x00ffffff;
if ((collision_p = RB_INSERT(ngap_ue_map, &instance_p->ngap_ue_head, ue_desc_p))
== NULL) {
NGAP_DEBUG("Found usable gNB_ue_ngap_id: 0x%06x %u(10)\n",
ue_desc_p->gNB_ue_ngap_id,
ue_desc_p->gNB_ue_ngap_id);
/* Break the loop as the id is not already used by another UE */
break;
}
} while(1);
/* mandatory */
ie = (NGAP_InitialUEMessage_IEs_t *)calloc(1, sizeof(NGAP_InitialUEMessage_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_InitialUEMessage_IEs_t *)calloc(1, sizeof(NGAP_InitialUEMessage_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_NAS_PDU;
#if 1
ie->value.choice.NAS_PDU.buf = ngap_nas_first_req_p->nas_pdu.buffer;
#else
ie->value.choice.NAS_PDU.buf = malloc(ngap_nas_first_req_p->nas_pdu.length);
memcpy(ie->value.choice.NAS_PDU.buf,
ngap_nas_first_req_p->nas_pdu.buffer,
ngap_nas_first_req_p->nas_pdu.length);
#endif
ie->value.choice.NAS_PDU.size = ngap_nas_first_req_p->nas_pdu.length;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_InitialUEMessage_IEs_t *)calloc(1, sizeof(NGAP_InitialUEMessage_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_TAI;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_TAI;
/* Assuming TAI is the TAI from the cell */
INT16_TO_OCTET_STRING(instance_p->tac, &ie->value.choice.TAI.tAC);
MCC_MNC_TO_PLMNID(instance_p->mcc[ue_desc_p->selected_plmn_identity],
instance_p->mnc[ue_desc_p->selected_plmn_identity],
instance_p->mnc_digit_length[ue_desc_p->selected_plmn_identity],
&ie->value.choice.TAI.pLMNidentity);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_InitialUEMessage_IEs_t *)calloc(1, sizeof(NGAP_InitialUEMessage_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_EUTRAN_CGI;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_EUTRAN_CGI;
/* Set the EUTRAN CGI
* The cell identity is defined on 28 bits but as we use macro enb id,
* we have to pad.
*/
//#warning "TODO get cell id from RRC"
MACRO_GNB_ID_TO_CELL_IDENTITY(instance_p->gNB_id,
0, // Cell ID
&ie->value.choice.EUTRAN_CGI.cell_ID);
MCC_MNC_TO_TBCD(instance_p->mcc[ue_desc_p->selected_plmn_identity],
instance_p->mnc[ue_desc_p->selected_plmn_identity],
instance_p->mnc_digit_length[ue_desc_p->selected_plmn_identity],
&ie->value.choice.EUTRAN_CGI.pLMNidentity);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* Set the establishment cause according to those provided by RRC */
DevCheck(ngap_nas_first_req_p->establishment_cause < RRC_CAUSE_LAST,
ngap_nas_first_req_p->establishment_cause, RRC_CAUSE_LAST, 0);
/* mandatory */
ie = (NGAP_InitialUEMessage_IEs_t *)calloc(1, sizeof(NGAP_InitialUEMessage_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_RRC_Establishment_Cause;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_RRC_Establishment_Cause;
ie->value.choice.RRC_Establishment_Cause = ngap_nas_first_req_p->establishment_cause;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (ngap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_s_tmsi) {
NGAP_DEBUG("S_TMSI_PRESENT\n");
ie = (NGAP_InitialUEMessage_IEs_t *)calloc(1, sizeof(NGAP_InitialUEMessage_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_S_TMSI;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_S_TMSI;
MME_CODE_TO_OCTET_STRING(ngap_nas_first_req_p->ue_identity.s_tmsi.mme_code,
&ie->value.choice.S_TMSI.mMEC);
M_TMSI_TO_OCTET_STRING(ngap_nas_first_req_p->ue_identity.s_tmsi.m_tmsi,
&ie->value.choice.S_TMSI.m_TMSI);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* optional */
if (ngap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_gummei) {
NGAP_DEBUG("GUMMEI_ID_PRESENT\n");
ie = (NGAP_InitialUEMessage_IEs_t *)calloc(1, sizeof(NGAP_InitialUEMessage_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_GUMMEI_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_GUMMEI;
MCC_MNC_TO_PLMNID(
ngap_nas_first_req_p->ue_identity.gummei.mcc,
ngap_nas_first_req_p->ue_identity.gummei.mnc,
ngap_nas_first_req_p->ue_identity.gummei.mnc_len,
&ie->value.choice.GUMMEI.pLMN_Identity);
MME_GID_TO_OCTET_STRING(ngap_nas_first_req_p->ue_identity.gummei.mme_group_id,
&ie->value.choice.GUMMEI.mME_Group_ID);
MME_CODE_TO_OCTET_STRING(ngap_nas_first_req_p->ue_identity.gummei.mme_code,
&ie->value.choice.GUMMEI.mME_Code);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
/* Failed to encode message */
DevMessage("Failed to encode initial UE message\n");
}
/* Update the current NGAP UE state */
ue_desc_p->ue_state = NGAP_UE_WAITING_CSR;
/* Assign a stream for this UE :
* From 3GPP 36.412 7)Transport layers:
* Within the SCTP association established between one MME and gNB pair:
* - a single pair of stream identifiers shall be reserved for the sole use
* of NGAP elementary procedures that utilize non UE-associated signalling.
* - At least one pair of stream identifiers shall be reserved for the sole use
* of NGAP elementary procedures that utilize UE-associated signallings.
* However a few pairs (i.e. more than one) should be reserved.
* - A single UE-associated signalling shall use one SCTP stream and
* the stream should not be changed during the communication of the
* UE-associated signalling.
*/
mme_desc_p->nextstream = (mme_desc_p->nextstream + 1) % mme_desc_p->out_streams;
if ((mme_desc_p->nextstream == 0) && (mme_desc_p->out_streams > 1)) {
mme_desc_p->nextstream += 1;
}
ue_desc_p->tx_stream = mme_desc_p->nextstream;
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)NULL,
0,
MSC_AS_TIME_FMT" initialUEMessage initiatingMessage gNB_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
ue_desc_p->gNB_ue_ngap_id);
/* Send encoded message over sctp */
ngap_gNB_itti_send_sctp_data_req(instance_p->instance, mme_desc_p->assoc_id,
buffer, length, ue_desc_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_handle_nas_downlink(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu)
//------------------------------------------------------------------------------
{
ngap_gNB_mme_data_t *mme_desc_p = NULL;
ngap_gNB_ue_context_t *ue_desc_p = NULL;
ngap_gNB_instance_t *ngap_gNB_instance = NULL;
NGAP_DownlinkNASTransport_t *container;
NGAP_DownlinkNASTransport_IEs_t *ie;
NGAP_GNB_UE_NGAP_ID_t enb_ue_ngap_id;
NGAP_MME_UE_NGAP_ID_t mme_ue_ngap_id;
DevAssert(pdu != NULL);
/* UE-related procedure -> stream != 0 */
if (stream == 0) {
NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream == 0\n",
assoc_id);
return -1;
}
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR(
"[SCTP %d] Received NAS downlink message for non existing MME context\n",
assoc_id);
return -1;
}
ngap_gNB_instance = mme_desc_p->ngap_gNB_instance;
/* Prepare the NGAP message to encode */
container = &pdu->choice.initiatingMessage.value.choice.DownlinkNASTransport;
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkNASTransport_IEs_t, ie, container,
NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID, true);
mme_ue_ngap_id = ie->value.choice.MME_UE_NGAP_ID;
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkNASTransport_IEs_t, ie, container,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, true);
enb_ue_ngap_id = ie->value.choice.GNB_UE_NGAP_ID;
if ((ue_desc_p = ngap_gNB_get_ue_context(ngap_gNB_instance,
enb_ue_ngap_id)) == NULL) {
MSC_LOG_RX_DISCARDED_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
NULL,
0,
MSC_AS_TIME_FMT" downlinkNASTransport gNB_ue_ngap_id %u mme_ue_ngap_id %u",
enb_ue_ngap_id,
mme_ue_ngap_id);
NGAP_ERROR("[SCTP %d] Received NAS downlink message for non existing UE context gNB_UE_NGAP_ID: 0x%lx\n",
assoc_id,
enb_ue_ngap_id);
return -1;
}
if (0 == ue_desc_p->rx_stream) {
ue_desc_p->rx_stream = stream;
} else if (stream != ue_desc_p->rx_stream) {
NGAP_ERROR("[SCTP %d] Received UE-related procedure on stream %u, expecting %u\n",
assoc_id, stream, ue_desc_p->rx_stream);
return -1;
}
/* Is it the first outcome of the MME for this UE ? If so store the mme
* UE ngap id.
*/
if (ue_desc_p->mme_ue_ngap_id == 0) {
ue_desc_p->mme_ue_ngap_id = mme_ue_ngap_id;
} else {
/* We already have a mme ue ngap id check the received is the same */
if (ue_desc_p->mme_ue_ngap_id != mme_ue_ngap_id) {
NGAP_ERROR("[SCTP %d] Mismatch in MME UE NGAP ID (0x%lx != 0x%"PRIx32"\n",
assoc_id,
mme_ue_ngap_id,
ue_desc_p->mme_ue_ngap_id
);
return -1;
}
}
MSC_LOG_RX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
NULL,
0,
MSC_AS_TIME_FMT" downlinkNASTransport gNB_ue_ngap_id %u mme_ue_ngap_id %u",
assoc_id,
mme_ue_ngap_id);
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkNASTransport_IEs_t, ie, container,
NGAP_ProtocolIE_ID_id_NAS_PDU, true);
/* Forward the NAS PDU to RRC */
ngap_gNB_itti_send_nas_downlink_ind(ngap_gNB_instance->instance,
ue_desc_p->ue_initial_id,
ue_desc_p->gNB_ue_ngap_id,
ie->value.choice.NAS_PDU.buf,
ie->value.choice.NAS_PDU.size);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_p)
//------------------------------------------------------------------------------
{
struct ngap_gNB_ue_context_s *ue_context_p;
ngap_gNB_instance_t *ngap_gNB_instance_p;
NGAP_NGAP_PDU_t pdu;
NGAP_UplinkNASTransport_t *out;
NGAP_UplinkNASTransport_IEs_t *ie;
uint8_t *buffer;
uint32_t length;
DevAssert(ngap_uplink_nas_p != NULL);
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p, ngap_uplink_nas_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: %06x\n",
ngap_uplink_nas_p->gNB_ue_ngap_id);
return -1;
}
/* Uplink NAS transport can occur either during an ngap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == NGAP_UE_CONNECTED ||
ue_context_p->ue_state == NGAP_UE_WAITING_CSR)) {
NGAP_WARN("You are attempting to send NAS data over non-connected "
"gNB ue ngap id: %u, current state: %d\n",
ngap_uplink_nas_p->gNB_ue_ngap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_uplinkNASTransport;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_ignore;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_UplinkNASTransport;
out = &pdu.choice.initiatingMessage.value.choice.UplinkNASTransport;
/* mandatory */
ie = (NGAP_UplinkNASTransport_IEs_t *)calloc(1, sizeof(NGAP_UplinkNASTransport_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UplinkNASTransport_IEs_t *)calloc(1, sizeof(NGAP_UplinkNASTransport_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_context_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UplinkNASTransport_IEs_t *)calloc(1, sizeof(NGAP_UplinkNASTransport_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_NAS_PDU;
ie->value.choice.NAS_PDU.buf = ngap_uplink_nas_p->nas_pdu.buffer;
ie->value.choice.NAS_PDU.size = ngap_uplink_nas_p->nas_pdu.length;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UplinkNASTransport_IEs_t *)calloc(1, sizeof(NGAP_UplinkNASTransport_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_EUTRAN_CGI;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_EUTRAN_CGI;
MCC_MNC_TO_PLMNID(
ngap_gNB_instance_p->mcc[ue_context_p->selected_plmn_identity],
ngap_gNB_instance_p->mnc[ue_context_p->selected_plmn_identity],
ngap_gNB_instance_p->mnc_digit_length[ue_context_p->selected_plmn_identity],
&ie->value.choice.EUTRAN_CGI.pLMNidentity);
//#warning "TODO get cell id from RRC"
MACRO_GNB_ID_TO_CELL_IDENTITY(ngap_gNB_instance_p->gNB_id,
0,
&ie->value.choice.EUTRAN_CGI.cell_ID);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UplinkNASTransport_IEs_t *)calloc(1, sizeof(NGAP_UplinkNASTransport_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_TAI;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_UplinkNASTransport_IEs__value_PR_TAI;
MCC_MNC_TO_PLMNID(
ngap_gNB_instance_p->mcc[ue_context_p->selected_plmn_identity],
ngap_gNB_instance_p->mnc[ue_context_p->selected_plmn_identity],
ngap_gNB_instance_p->mnc_digit_length[ue_context_p->selected_plmn_identity],
&ie->value.choice.TAI.pLMNidentity);
TAC_TO_ASN1(ngap_gNB_instance_p->tac, &ie->value.choice.TAI.tAC);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode uplink NAS transport\n");
/* Encode procedure has failed... */
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)NULL,
0,
MSC_AS_TIME_FMT" uplinkNASTransport initiatingMessage gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
ue_context_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_nas_non_delivery_ind(instance_t instance,
ngap_nas_non_delivery_ind_t *ngap_nas_non_delivery_ind)
//------------------------------------------------------------------------------
{
struct ngap_gNB_ue_context_s *ue_context_p;
ngap_gNB_instance_t *ngap_gNB_instance_p;
NGAP_NGAP_PDU_t pdu;
NGAP_NASNonDeliveryIndication_t *out;
NGAP_NASNonDeliveryIndication_IEs_t *ie;
uint8_t *buffer;
uint32_t length;
DevAssert(ngap_nas_non_delivery_ind != NULL);
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p, ngap_nas_non_delivery_ind->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: %06x\n",
ngap_nas_non_delivery_ind->gNB_ue_ngap_id);
MSC_LOG_EVENT(
MSC_NGAP_GNB,
MSC_AS_TIME_FMT" Sent of NAS_NON_DELIVERY_IND to MME failed, no context for gNB_ue_ngap_id %06x",
ngap_nas_non_delivery_ind->gNB_ue_ngap_id);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_NASNonDeliveryIndication;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_ignore;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_NASNonDeliveryIndication;
out = &pdu.choice.initiatingMessage.value.choice.NASNonDeliveryIndication;
/* mandatory */
ie = (NGAP_NASNonDeliveryIndication_IEs_t *)calloc(1, sizeof(NGAP_NASNonDeliveryIndication_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_NASNonDeliveryIndication_IEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_NASNonDeliveryIndication_IEs_t *)calloc(1, sizeof(NGAP_NASNonDeliveryIndication_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_NASNonDeliveryIndication_IEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_context_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_NASNonDeliveryIndication_IEs_t *)calloc(1, sizeof(NGAP_NASNonDeliveryIndication_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_NASNonDeliveryIndication_IEs__value_PR_NAS_PDU;
ie->value.choice.NAS_PDU.buf = ngap_nas_non_delivery_ind->nas_pdu.buffer;
ie->value.choice.NAS_PDU.size = ngap_nas_non_delivery_ind->nas_pdu.length;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_NASNonDeliveryIndication_IEs_t *)calloc(1, sizeof(NGAP_NASNonDeliveryIndication_IEs_t));
ie->id = NGAP_ProtocolIE_ID_id_Cause;
ie->criticality = NGAP_Criticality_ignore;
/* Send a dummy cause */
ie->value.present = NGAP_NASNonDeliveryIndication_IEs__value_PR_Cause;
ie->value.choice.Cause.present = NGAP_Cause_PR_radioNetwork;
ie->value.choice.Cause.choice.radioNetwork = NGAP_CauseRadioNetwork_radio_connection_with_ue_lost;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode NAS NON delivery indication\n");
/* Encode procedure has failed... */
MSC_LOG_EVENT(
MSC_NGAP_GNB,
MSC_AS_TIME_FMT" Sent of NAS_NON_DELIVERY_IND to MME failed (encoding)");
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" NASNonDeliveryIndication initiatingMessage gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
ue_context_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_initial_ctxt_resp(
instance_t instance, ngap_initial_context_setup_resp_t *initial_ctxt_resp_p)
//------------------------------------------------------------------------------
{
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_InitialContextSetupResponse_t *out;
NGAP_InitialContextSetupResponseIEs_t *ie;
uint8_t *buffer = NULL;
uint32_t length;
int i;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(initial_ctxt_resp_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
initial_ctxt_resp_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%06x\n",
initial_ctxt_resp_p->gNB_ue_ngap_id);
return -1;
}
/* Uplink NAS transport can occur either during an ngap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == NGAP_UE_CONNECTED ||
ue_context_p->ue_state == NGAP_UE_WAITING_CSR)) {
NGAP_WARN("You are attempting to send NAS data over non-connected "
"gNB ue ngap id: %06x, current state: %d\n",
initial_ctxt_resp_p->gNB_ue_ngap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome;
pdu.choice.successfulOutcome.procedureCode = NGAP_ProcedureCode_id_InitialContextSetup;
pdu.choice.successfulOutcome.criticality = NGAP_Criticality_reject;
pdu.choice.successfulOutcome.value.present = NGAP_SuccessfulOutcome__value_PR_InitialContextSetupResponse;
out = &pdu.choice.successfulOutcome.value.choice.InitialContextSetupResponse;
/* mandatory */
ie = (NGAP_InitialContextSetupResponseIEs_t *)calloc(1, sizeof(NGAP_InitialContextSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_InitialContextSetupResponseIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_InitialContextSetupResponseIEs_t *)calloc(1, sizeof(NGAP_InitialContextSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_InitialContextSetupResponseIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = initial_ctxt_resp_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_InitialContextSetupResponseIEs_t *)calloc(1, sizeof(NGAP_InitialContextSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABSetupListCtxtSURes;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_InitialContextSetupResponseIEs__value_PR_E_RABSetupListCtxtSURes;
for (i = 0; i < initial_ctxt_resp_p->nb_of_e_rabs; i++) {
NGAP_E_RABSetupItemCtxtSUResIEs_t *item;
/* mandatory */
item = (NGAP_E_RABSetupItemCtxtSUResIEs_t *)calloc(1, sizeof(NGAP_E_RABSetupItemCtxtSUResIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABSetupItemCtxtSURes;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABSetupItemCtxtSUResIEs__value_PR_E_RABSetupItemCtxtSURes;
item->value.choice.E_RABSetupItemCtxtSURes.e_RAB_ID = initial_ctxt_resp_p->e_rabs[i].e_rab_id;
GTP_TEID_TO_ASN1(initial_ctxt_resp_p->e_rabs[i].gtp_teid, &item->value.choice.E_RABSetupItemCtxtSURes.gTP_TEID);
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.buf = malloc(initial_ctxt_resp_p->e_rabs[i].gNB_addr.length);
memcpy(item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.buf,
initial_ctxt_resp_p->e_rabs[i].gNB_addr.buffer,
initial_ctxt_resp_p->e_rabs[i].gNB_addr.length);
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.size = initial_ctxt_resp_p->e_rabs[i].gNB_addr.length;
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.bits_unused = 0;
NGAP_DEBUG("initial_ctxt_resp_p: e_rab ID %ld, enb_addr %d.%d.%d.%d, SIZE %ld \n",
item->value.choice.E_RABSetupItemCtxtSURes.e_RAB_ID,
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.buf[0],
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.buf[1],
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.buf[2],
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.buf[3],
item->value.choice.E_RABSetupItemCtxtSURes.transportLayerAddress.size);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABSetupListCtxtSURes.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (initial_ctxt_resp_p->nb_of_e_rabs_failed) {
ie = (NGAP_InitialContextSetupResponseIEs_t *)calloc(1, sizeof(NGAP_InitialContextSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABFailedToSetupListCtxtSURes;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_InitialContextSetupResponseIEs__value_PR_E_RABList;
for (i = 0; i < initial_ctxt_resp_p->nb_of_e_rabs_failed; i++) {
NGAP_E_RABItemIEs_t *item;
/* mandatory */
item = (NGAP_E_RABItemIEs_t *)calloc(1, sizeof(NGAP_E_RABItemIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABItem;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABItemIEs__value_PR_E_RABItem;
item->value.choice.E_RABItem.e_RAB_ID = initial_ctxt_resp_p->e_rabs_failed[i].e_rab_id;
item->value.choice.E_RABItem.cause.present = initial_ctxt_resp_p->e_rabs_failed[i].cause;
switch(item->value.choice.E_RABItem.cause.present) {
case NGAP_Cause_PR_radioNetwork:
item->value.choice.E_RABItem.cause.choice.radioNetwork = initial_ctxt_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_transport:
item->value.choice.E_RABItem.cause.choice.transport = initial_ctxt_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_nas:
item->value.choice.E_RABItem.cause.choice.nas = initial_ctxt_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_protocol:
item->value.choice.E_RABItem.cause.choice.protocol = initial_ctxt_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_misc:
item->value.choice.E_RABItem.cause.choice.misc = initial_ctxt_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_NOTHING:
default:
break;
}
NGAP_DEBUG("initial context setup response: failed e_rab ID %ld\n", item->value.choice.E_RABItem.e_RAB_ID);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABList.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* optional */
if (0) {
ie = (NGAP_InitialContextSetupResponseIEs_t *)calloc(1, sizeof(NGAP_InitialContextSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_CriticalityDiagnostics;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_InitialContextSetupResponseIEs__value_PR_CriticalityDiagnostics;
// ie->value.choice.CriticalityDiagnostics =;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode uplink NAS transport\n");
/* Encode procedure has failed... */
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" InitialContextSetup successfulOutcome gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
initial_ctxt_resp_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_ue_capabilities(instance_t instance,
ngap_ue_cap_info_ind_t *ue_cap_info_ind_p)
//------------------------------------------------------------------------------
{
ngap_gNB_instance_t *ngap_gNB_instance_p;
struct ngap_gNB_ue_context_s *ue_context_p;
NGAP_NGAP_PDU_t pdu;
NGAP_UECapabilityInfoIndication_t *out;
NGAP_UECapabilityInfoIndicationIEs_t *ie;
uint8_t *buffer;
uint32_t length;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(ue_cap_info_ind_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
ue_cap_info_ind_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: %u\n",
ue_cap_info_ind_p->gNB_ue_ngap_id);
return -1;
}
/* UE capabilities message can occur either during an ngap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == NGAP_UE_CONNECTED ||
ue_context_p->ue_state == NGAP_UE_WAITING_CSR)) {
NGAP_WARN("You are attempting to send NAS data over non-connected "
"gNB ue ngap id: %u, current state: %d\n",
ue_cap_info_ind_p->gNB_ue_ngap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_UECapabilityInfoIndication;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_ignore;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_UECapabilityInfoIndication;
out = &pdu.choice.initiatingMessage.value.choice.UECapabilityInfoIndication;
/* mandatory */
ie = (NGAP_UECapabilityInfoIndicationIEs_t *)calloc(1, sizeof(NGAP_UECapabilityInfoIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UECapabilityInfoIndicationIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UECapabilityInfoIndicationIEs_t *)calloc(1, sizeof(NGAP_UECapabilityInfoIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UECapabilityInfoIndicationIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_cap_info_ind_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_UECapabilityInfoIndicationIEs_t *)calloc(1, sizeof(NGAP_UECapabilityInfoIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_UERadioCapability;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_UECapabilityInfoIndicationIEs__value_PR_UERadioCapability;
ie->value.choice.UERadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer;
ie->value.choice.UERadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
/* Encode procedure has failed... */
NGAP_ERROR("Failed to encode UE capabilities indication\n");
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" UECapabilityInfoIndication initiatingMessage gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
ue_cap_info_ind_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_e_rab_setup_resp(instance_t instance,
ngap_e_rab_setup_resp_t *e_rab_setup_resp_p)
//------------------------------------------------------------------------------
{
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_E_RABSetupResponse_t *out;
NGAP_E_RABSetupResponseIEs_t *ie;
uint8_t *buffer = NULL;
uint32_t length;
int i;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(e_rab_setup_resp_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
e_rab_setup_resp_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%06x\n",
e_rab_setup_resp_p->gNB_ue_ngap_id);
return -1;
}
/* Uplink NAS transport can occur either during an ngap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == NGAP_UE_CONNECTED ||
ue_context_p->ue_state == NGAP_UE_WAITING_CSR)) {
NGAP_WARN("You are attempting to send NAS data over non-connected "
"gNB ue ngap id: %06x, current state: %d\n",
e_rab_setup_resp_p->gNB_ue_ngap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome;
pdu.choice.successfulOutcome.procedureCode = NGAP_ProcedureCode_id_E_RABModify;
pdu.choice.successfulOutcome.criticality = NGAP_Criticality_reject;
pdu.choice.successfulOutcome.value.present = NGAP_SuccessfulOutcome__value_PR_E_RABSetupResponse;
out = &pdu.choice.successfulOutcome.value.choice.E_RABSetupResponse;
/* mandatory */
ie = (NGAP_E_RABSetupResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABSetupResponseIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_E_RABSetupResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABSetupResponseIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = e_rab_setup_resp_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (e_rab_setup_resp_p->nb_of_e_rabs > 0) {
ie = (NGAP_E_RABSetupResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABSetupListBearerSURes;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABSetupResponseIEs__value_PR_E_RABSetupListBearerSURes;
for (i = 0; i < e_rab_setup_resp_p->nb_of_e_rabs; i++) {
NGAP_E_RABSetupItemBearerSUResIEs_t *item;
/* mandatory */
item = (NGAP_E_RABSetupItemBearerSUResIEs_t *)calloc(1, sizeof(NGAP_E_RABSetupItemBearerSUResIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABSetupItemBearerSURes;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABSetupItemBearerSUResIEs__value_PR_E_RABSetupItemBearerSURes;
item->value.choice.E_RABSetupItemBearerSURes.e_RAB_ID = e_rab_setup_resp_p->e_rabs[i].e_rab_id;
GTP_TEID_TO_ASN1(e_rab_setup_resp_p->e_rabs[i].gtp_teid, &item->value.choice.E_RABSetupItemBearerSURes.gTP_TEID);
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.buf = malloc(e_rab_setup_resp_p->e_rabs[i].gNB_addr.length);
memcpy(item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.buf,
e_rab_setup_resp_p->e_rabs[i].gNB_addr.buffer,
e_rab_setup_resp_p->e_rabs[i].gNB_addr.length);
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.size = e_rab_setup_resp_p->e_rabs[i].gNB_addr.length;
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.bits_unused = 0;
NGAP_DEBUG("e_rab_setup_resp: e_rab ID %ld, teid %u, enb_addr %d.%d.%d.%d, SIZE %ld\n",
item->value.choice.E_RABSetupItemBearerSURes.e_RAB_ID,
e_rab_setup_resp_p->e_rabs[i].gtp_teid,
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.buf[0],
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.buf[1],
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.buf[2],
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.buf[3],
item->value.choice.E_RABSetupItemBearerSURes.transportLayerAddress.size);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABSetupListBearerSURes.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* optional */
if (e_rab_setup_resp_p->nb_of_e_rabs_failed > 0) {
ie = (NGAP_E_RABSetupResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABFailedToSetupListBearerSURes;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABSetupResponseIEs__value_PR_E_RABList;
for (i = 0; i < e_rab_setup_resp_p->nb_of_e_rabs_failed; i++) {
NGAP_E_RABItemIEs_t *item;
item = (NGAP_E_RABItemIEs_t *)calloc(1, sizeof(NGAP_E_RABItemIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABItem;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABItemIEs__value_PR_E_RABItem;
item->value.choice.E_RABItem.e_RAB_ID = e_rab_setup_resp_p->e_rabs_failed[i].e_rab_id;
item->value.choice.E_RABItem.cause.present = e_rab_setup_resp_p->e_rabs_failed[i].cause;
switch(item->value.choice.E_RABItem.cause.present) {
case NGAP_Cause_PR_radioNetwork:
item->value.choice.E_RABItem.cause.choice.radioNetwork = e_rab_setup_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_transport:
item->value.choice.E_RABItem.cause.choice.transport = e_rab_setup_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_nas:
item->value.choice.E_RABItem.cause.choice.nas = e_rab_setup_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_protocol:
item->value.choice.E_RABItem.cause.choice.protocol = e_rab_setup_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_misc:
item->value.choice.E_RABItem.cause.choice.misc = e_rab_setup_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_NOTHING:
default:
break;
}
NGAP_DEBUG("e_rab_modify_resp: failed e_rab ID %ld\n", item->value.choice.E_RABItem.e_RAB_ID);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABList.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* optional */
if (0) {
ie = (NGAP_E_RABSetupResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABSetupResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_CriticalityDiagnostics;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABSetupResponseIEs__value_PR_CriticalityDiagnostics;
// ie->value.choice.CriticalityDiagnostics = ;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* NGAP_E_RABSetupListBearerSURes_t e_RABSetupListBearerSURes;
memset(&e_RABSetupListBearerSURes, 0, sizeof(NGAP_E_RABSetupListBearerSURes_t));
if (ngap_encode_ngap_e_rabsetuplistbearersures(&e_RABSetupListBearerSURes, &initial_ies_p->e_RABSetupListBearerSURes.ngap_E_RABSetupItemBearerSURes) < 0 )
return -1;
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_E_RABSetupListBearerSURes, &e_RABSetupListBearerSURes);
*/
fprintf(stderr, "start encode\n");
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode uplink transport\n");
/* Encode procedure has failed... */
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" E_RAN Setup successfulOutcome gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
e_rab_setup_resp_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_e_rab_modify_resp(instance_t instance,
ngap_e_rab_modify_resp_t *e_rab_modify_resp_p)
//------------------------------------------------------------------------------
{
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_E_RABModifyResponse_t *out;
NGAP_E_RABModifyResponseIEs_t *ie;
uint8_t *buffer = NULL;
uint32_t length;
int i;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(e_rab_modify_resp_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
e_rab_modify_resp_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%06x\n",
e_rab_modify_resp_p->gNB_ue_ngap_id);
return -1;
}
/* Uplink NAS transport can occur either during an ngap connected state
* or during initial attach (for example: NAS authentication).
*/
if (!(ue_context_p->ue_state == NGAP_UE_CONNECTED ||
ue_context_p->ue_state == NGAP_UE_WAITING_CSR)) {
NGAP_WARN("You are attempting to send NAS data over non-connected "
"gNB ue ngap id: %06x, current state: %d\n",
e_rab_modify_resp_p->gNB_ue_ngap_id, ue_context_p->ue_state);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome;
pdu.choice.successfulOutcome.procedureCode = NGAP_ProcedureCode_id_E_RABModify;
pdu.choice.successfulOutcome.criticality = NGAP_Criticality_reject;
pdu.choice.successfulOutcome.value.present = NGAP_SuccessfulOutcome__value_PR_E_RABModifyResponse;
out = &pdu.choice.successfulOutcome.value.choice.E_RABModifyResponse;
/* mandatory */
ie = (NGAP_E_RABModifyResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABModifyResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABModifyResponseIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_E_RABModifyResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABModifyResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABModifyResponseIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = e_rab_modify_resp_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (e_rab_modify_resp_p->nb_of_e_rabs > 0) {
ie = (NGAP_E_RABModifyResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABModifyResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABModifyListBearerModRes;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABModifyResponseIEs__value_PR_E_RABModifyListBearerModRes;
for (i = 0; i < e_rab_modify_resp_p->nb_of_e_rabs; i++) {
NGAP_E_RABModifyItemBearerModResIEs_t *item;
item = (NGAP_E_RABModifyItemBearerModResIEs_t *)calloc(1, sizeof(NGAP_E_RABModifyItemBearerModResIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABModifyItemBearerModRes;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABModifyItemBearerModResIEs__value_PR_E_RABModifyItemBearerModRes;
item->value.choice.E_RABModifyItemBearerModRes.e_RAB_ID = e_rab_modify_resp_p->e_rabs[i].e_rab_id;
NGAP_DEBUG("e_rab_modify_resp: modified e_rab ID %ld\n", item->value.choice.E_RABModifyItemBearerModRes.e_RAB_ID);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABModifyListBearerModRes.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* optional */
if (e_rab_modify_resp_p->nb_of_e_rabs_failed > 0) {
ie = (NGAP_E_RABModifyResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABModifyResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABFailedToModifyList;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABModifyResponseIEs__value_PR_E_RABList;
for (i = 0; i < e_rab_modify_resp_p->nb_of_e_rabs_failed; i++) {
NGAP_E_RABItemIEs_t *item;
item = (NGAP_E_RABItemIEs_t *)calloc(1, sizeof(NGAP_E_RABItemIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABItem;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABItemIEs__value_PR_E_RABItem;
item->value.choice.E_RABItem.e_RAB_ID = e_rab_modify_resp_p->e_rabs_failed[i].e_rab_id;
item->value.choice.E_RABItem.cause.present = e_rab_modify_resp_p->e_rabs_failed[i].cause;
switch(item->value.choice.E_RABItem.cause.present) {
case NGAP_Cause_PR_radioNetwork:
item->value.choice.E_RABItem.cause.choice.radioNetwork = e_rab_modify_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_transport:
item->value.choice.E_RABItem.cause.choice.transport = e_rab_modify_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_nas:
item->value.choice.E_RABItem.cause.choice.nas = e_rab_modify_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_protocol:
item->value.choice.E_RABItem.cause.choice.protocol = e_rab_modify_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_misc:
item->value.choice.E_RABItem.cause.choice.misc = e_rab_modify_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_NOTHING:
default:
break;
}
NGAP_DEBUG("e_rab_modify_resp: failed e_rab ID %ld\n", item->value.choice.E_RABItem.e_RAB_ID);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABList.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* optional */
if (0) {
ie = (NGAP_E_RABModifyResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABModifyResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_CriticalityDiagnostics;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABModifyResponseIEs__value_PR_CriticalityDiagnostics;
// ie->value.choice.CriticalityDiagnostics = ;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
fprintf(stderr, "start encode\n");
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode uplink transport\n");
/* Encode procedure has failed... */
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" E_RAN Modify successful Outcome gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
e_rab_modify_resp_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
return 0;
}
//------------------------------------------------------------------------------
int ngap_gNB_e_rab_release_resp(instance_t instance,
ngap_e_rab_release_resp_t *e_rab_release_resp_p)
//------------------------------------------------------------------------------
{
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_E_RABReleaseResponse_t *out;
NGAP_E_RABReleaseResponseIEs_t *ie;
uint8_t *buffer = NULL;
uint32_t length;
int i;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(e_rab_release_resp_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
e_rab_release_resp_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: %u\n",
e_rab_release_resp_p->gNB_ue_ngap_id);
return -1;
}
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome;
pdu.choice.successfulOutcome.procedureCode = NGAP_ProcedureCode_id_E_RABRelease;
pdu.choice.successfulOutcome.criticality = NGAP_Criticality_reject;
pdu.choice.successfulOutcome.value.present = NGAP_SuccessfulOutcome__value_PR_E_RABReleaseResponse;
out = &pdu.choice.successfulOutcome.value.choice.E_RABReleaseResponse;
/* mandatory */
ie = (NGAP_E_RABReleaseResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABReleaseResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABReleaseResponseIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_context_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_E_RABReleaseResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABReleaseResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABReleaseResponseIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = e_rab_release_resp_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* optional */
if (e_rab_release_resp_p->nb_of_e_rabs_released > 0) {
ie = (NGAP_E_RABReleaseResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABReleaseResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABReleaseListBearerRelComp;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABReleaseResponseIEs__value_PR_E_RABReleaseListBearerRelComp;
for (i = 0; i < e_rab_release_resp_p->nb_of_e_rabs_released; i++) {
NGAP_E_RABReleaseItemBearerRelCompIEs_t *item;
item = (NGAP_E_RABReleaseItemBearerRelCompIEs_t *)calloc(1, sizeof(NGAP_E_RABReleaseItemBearerRelCompIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABReleaseItemBearerRelComp;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABReleaseItemBearerRelCompIEs__value_PR_E_RABReleaseItemBearerRelComp;
item->value.choice.E_RABReleaseItemBearerRelComp.e_RAB_ID = e_rab_release_resp_p->e_rab_release[i].e_rab_id;
NGAP_DEBUG("e_rab_release_resp: e_rab ID %ld\n", item->value.choice.E_RABReleaseItemBearerRelComp.e_RAB_ID);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABReleaseListBearerRelComp.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* optional */
if (e_rab_release_resp_p->nb_of_e_rabs_failed > 0) {
ie = (NGAP_E_RABReleaseResponseIEs_t *)calloc(1, sizeof(NGAP_E_RABReleaseResponseIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABFailedToReleaseList;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_E_RABReleaseResponseIEs__value_PR_E_RABList;
for (i = 0; i < e_rab_release_resp_p->nb_of_e_rabs_failed; i++) {
NGAP_E_RABItemIEs_t *item;
item = (NGAP_E_RABItemIEs_t *)calloc(1, sizeof(NGAP_E_RABItemIEs_t));
item->id = NGAP_ProtocolIE_ID_id_E_RABItem;
item->criticality = NGAP_Criticality_ignore;
item->value.present = NGAP_E_RABItemIEs__value_PR_E_RABItem;
item->value.choice.E_RABItem.e_RAB_ID = e_rab_release_resp_p->e_rabs_failed[i].e_rab_id;
item->value.choice.E_RABItem.cause.present = e_rab_release_resp_p->e_rabs_failed[i].cause;
switch(item->value.choice.E_RABItem.cause.present) {
case NGAP_Cause_PR_radioNetwork:
item->value.choice.E_RABItem.cause.choice.radioNetwork = e_rab_release_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_transport:
item->value.choice.E_RABItem.cause.choice.transport = e_rab_release_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_nas:
item->value.choice.E_RABItem.cause.choice.nas = e_rab_release_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_protocol:
item->value.choice.E_RABItem.cause.choice.protocol = e_rab_release_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_misc:
item->value.choice.E_RABItem.cause.choice.misc = e_rab_release_resp_p->e_rabs_failed[i].cause_value;
break;
case NGAP_Cause_PR_NOTHING:
default:
break;
}
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABList.list, item);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode release response\n");
/* Encode procedure has failed... */
return -1;
}
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" E_RAN Release successfulOutcome gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
e_rab_release_resp_p->gNB_ue_ngap_id,
ue_context_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
length, ue_context_p->tx_stream);
NGAP_INFO("e_rab_release_response sended gNB_UE_NGAP_ID %d mme_ue_ngap_id %d nb_of_e_rabs_released %d nb_of_e_rabs_failed %d\n",
e_rab_release_resp_p->gNB_ue_ngap_id, ue_context_p->mme_ue_ngap_id,e_rab_release_resp_p->nb_of_e_rabs_released,e_rab_release_resp_p->nb_of_e_rabs_failed);
return 0;
}
int ngap_gNB_path_switch_req(instance_t instance,
ngap_path_switch_req_t *path_switch_req_p)
//------------------------------------------------------------------------------
{
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
struct ngap_gNB_mme_data_s *mme_desc_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_PathSwitchRequest_t *out;
NGAP_PathSwitchRequestIEs_t *ie;
NGAP_E_RABToBeSwitchedDLItemIEs_t *e_RABToBeSwitchedDLItemIEs;
NGAP_E_RABToBeSwitchedDLItem_t *e_RABToBeSwitchedDLItem;
uint8_t *buffer = NULL;
uint32_t length;
int ret = 0;//-1;
/* Retrieve the NGAP gNB instance associated with Mod_id */
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
DevAssert(path_switch_req_p != NULL);
DevAssert(ngap_gNB_instance_p != NULL);
//if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
// path_switch_req_p->gNB_ue_ngap_id)) == NULL) {
/* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */
//NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%06x\n",
// path_switch_req_p->gNB_ue_ngap_id);
//return -1;
//}
/* Uplink NAS transport can occur either during an ngap connected state
* or during initial attach (for example: NAS authentication).
*/
//if (!(ue_context_p->ue_state == NGAP_UE_CONNECTED ||
// ue_context_p->ue_state == NGAP_UE_WAITING_CSR)) {
//NGAP_WARN("You are attempting to send NAS data over non-connected "
// "gNB ue ngap id: %06x, current state: %d\n",
// path_switch_req_p->gNB_ue_ngap_id, ue_context_p->ue_state);
//return -1;
//}
/* Select the MME corresponding to the provided GUMMEI. */
mme_desc_p = ngap_gNB_nnsf_select_mme_by_gummei_no_cause(ngap_gNB_instance_p, path_switch_req_p->ue_gummei);
if (mme_desc_p == NULL) {
/*
* In case gNB has no MME associated, the gNB should inform RRC and discard
* this request.
*/
NGAP_WARN("No MME is associated to the gNB\n");
// TODO: Inform RRC
return -1;
}
/* The gNB should allocate a unique gNB UE NGAP ID for this UE. The value
* will be used for the duration of the connectivity.
*/
ue_context_p = ngap_gNB_allocate_new_UE_context();
DevAssert(ue_context_p != NULL);
/* Keep a reference to the selected MME */
ue_context_p->mme_ref = mme_desc_p;
ue_context_p->ue_initial_id = path_switch_req_p->ue_initial_id;
ue_context_p->gNB_instance = ngap_gNB_instance_p;
do {
struct ngap_gNB_ue_context_s *collision_p;
/* Peek a random value for the gNB_ue_ngap_id */
ue_context_p->gNB_ue_ngap_id = (random() + random()) & 0x00ffffff;
if ((collision_p = RB_INSERT(ngap_ue_map, &ngap_gNB_instance_p->ngap_ue_head, ue_context_p))
== NULL) {
NGAP_DEBUG("Found usable gNB_ue_ngap_id: 0x%06x %u(10)\n",
ue_context_p->gNB_ue_ngap_id,
ue_context_p->gNB_ue_ngap_id);
/* Break the loop as the id is not already used by another UE */
break;
}
} while(1);
ue_context_p->mme_ue_ngap_id = path_switch_req_p->mme_ue_ngap_id;
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_PathSwitchRequest;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_reject;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_PathSwitchRequest;
out = &pdu.choice.initiatingMessage.value.choice.PathSwitchRequest;
/* mandatory */
ie = (NGAP_PathSwitchRequestIEs_t *)calloc(1, sizeof(NGAP_PathSwitchRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_PathSwitchRequestIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_context_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
if (path_switch_req_p->nb_of_e_rabs > 0) {
ie = (NGAP_PathSwitchRequestIEs_t *)calloc(1, sizeof(NGAP_PathSwitchRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABToBeSwitchedDLList;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_PathSwitchRequestIEs__value_PR_E_RABToBeSwitchedDLList;
for (int i = 0; i < path_switch_req_p->nb_of_e_rabs; i++) {
e_RABToBeSwitchedDLItemIEs = (NGAP_E_RABToBeSwitchedDLItemIEs_t *)calloc(1, sizeof(NGAP_E_RABToBeSwitchedDLItemIEs_t));
e_RABToBeSwitchedDLItemIEs->id = NGAP_ProtocolIE_ID_id_E_RABToBeSwitchedDLItem;
e_RABToBeSwitchedDLItemIEs->criticality = NGAP_Criticality_reject;
e_RABToBeSwitchedDLItemIEs->value.present = NGAP_E_RABToBeSwitchedDLItemIEs__value_PR_E_RABToBeSwitchedDLItem;
e_RABToBeSwitchedDLItem = &e_RABToBeSwitchedDLItemIEs->value.choice.E_RABToBeSwitchedDLItem;
e_RABToBeSwitchedDLItem->e_RAB_ID = path_switch_req_p->e_rabs_tobeswitched[i].e_rab_id;
INT32_TO_OCTET_STRING(path_switch_req_p->e_rabs_tobeswitched[i].gtp_teid, &e_RABToBeSwitchedDLItem->gTP_TEID);
e_RABToBeSwitchedDLItem->transportLayerAddress.size = path_switch_req_p->e_rabs_tobeswitched[i].gNB_addr.length;
e_RABToBeSwitchedDLItem->transportLayerAddress.bits_unused = 0;
e_RABToBeSwitchedDLItem->transportLayerAddress.buf = calloc(1,e_RABToBeSwitchedDLItem->transportLayerAddress.size);
memcpy (e_RABToBeSwitchedDLItem->transportLayerAddress.buf,
path_switch_req_p->e_rabs_tobeswitched[i].gNB_addr.buffer,
path_switch_req_p->e_rabs_tobeswitched[i].gNB_addr.length);
NGAP_DEBUG("path_switch_req: e_rab ID %ld, teid %u, enb_addr %d.%d.%d.%d, SIZE %zu\n",
e_RABToBeSwitchedDLItem->e_RAB_ID,
path_switch_req_p->e_rabs_tobeswitched[i].gtp_teid,
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[0],
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[1],
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[2],
e_RABToBeSwitchedDLItem->transportLayerAddress.buf[3],
e_RABToBeSwitchedDLItem->transportLayerAddress.size);
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABToBeSwitchedDLList.list, e_RABToBeSwitchedDLItemIEs);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
}
/* mandatory */
ie = (NGAP_PathSwitchRequestIEs_t *)calloc(1, sizeof(NGAP_PathSwitchRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_SourceMME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_PathSwitchRequestIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = path_switch_req_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_PathSwitchRequestIEs_t *)calloc(1, sizeof(NGAP_PathSwitchRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_EUTRAN_CGI;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_PathSwitchRequestIEs__value_PR_EUTRAN_CGI;
MACRO_GNB_ID_TO_CELL_IDENTITY(ngap_gNB_instance_p->gNB_id,
0,
&ie->value.choice.EUTRAN_CGI.cell_ID);
MCC_MNC_TO_TBCD(ngap_gNB_instance_p->mcc[0],
ngap_gNB_instance_p->mnc[0],
ngap_gNB_instance_p->mnc_digit_length[0],
&ie->value.choice.EUTRAN_CGI.pLMNidentity);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_PathSwitchRequestIEs_t *)calloc(1, sizeof(NGAP_PathSwitchRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_TAI;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_PathSwitchRequestIEs__value_PR_TAI;
/* Assuming TAI is the TAI from the cell */
INT16_TO_OCTET_STRING(ngap_gNB_instance_p->tac, &ie->value.choice.TAI.tAC);
MCC_MNC_TO_PLMNID(ngap_gNB_instance_p->mcc[0],
ngap_gNB_instance_p->mnc[0],
ngap_gNB_instance_p->mnc_digit_length[0],
&ie->value.choice.TAI.pLMNidentity);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_PathSwitchRequestIEs_t *)calloc(1, sizeof(NGAP_PathSwitchRequestIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_UESecurityCapabilities;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_PathSwitchRequestIEs__value_PR_UESecurityCapabilities;
ENCRALG_TO_BIT_STRING(path_switch_req_p->security_capabilities.encryption_algorithms,
&ie->value.choice.UESecurityCapabilities.encryptionAlgorithms);
INTPROTALG_TO_BIT_STRING(path_switch_req_p->security_capabilities.integrity_algorithms,
&ie->value.choice.UESecurityCapabilities.integrityProtectionAlgorithms);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
NGAP_ERROR("Failed to encode Path Switch Req \n");
/* Encode procedure has failed... */
return -1;
}
/* Update the current NGAP UE state */
ue_context_p->ue_state = NGAP_UE_WAITING_CSR;
/* Assign a stream for this UE :
* From 3GPP 36.412 7)Transport layers:
* Within the SCTP association established between one MME and gNB pair:
* - a single pair of stream identifiers shall be reserved for the sole use
* of NGAP elementary procedures that utilize non UE-associated signalling.
* - At least one pair of stream identifiers shall be reserved for the sole use
* of NGAP elementary procedures that utilize UE-associated signallings.
* However a few pairs (i.e. more than one) should be reserved.
* - A single UE-associated signalling shall use one SCTP stream and
* the stream should not be changed during the communication of the
* UE-associated signalling.
*/
mme_desc_p->nextstream = (mme_desc_p->nextstream + 1) % mme_desc_p->out_streams;
if ((mme_desc_p->nextstream == 0) && (mme_desc_p->out_streams > 1)) {
mme_desc_p->nextstream += 1;
}
ue_context_p->tx_stream = mme_desc_p->nextstream;
MSC_LOG_TX_MESSAGE(
MSC_NGAP_GNB,
MSC_NGAP_MME,
(const char *)buffer,
length,
MSC_AS_TIME_FMT" E_RAN Setup successfulOutcome gNB_ue_ngap_id %u mme_ue_ngap_id %u",
0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
ue_context_p->gNB_ue_ngap_id,
path_switch_req_p->mme_ue_ngap_id);
/* UE associated signalling -> use the allocated stream */
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
mme_desc_p->assoc_id, buffer,
length, ue_context_p->tx_stream);
return ret;
}
//-----------------------------------------------------------------------------
/*
* gNB generate a S1 E_RAB Modification Indication towards MME
*/
/*int ngap_gNB_generate_E_RAB_Modification_Indication(
instance_t instance,
ngap_e_rab_modification_ind_t *e_rab_modification_ind)
//-----------------------------------------------------------------------------
{
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_E_RABModificationIndication_t *out = NULL;
NGAP_E_RABModificationIndicationIEs_t *ie = NULL;
NGAP_E_RABToBeModifiedItemBearerModInd_t *E_RAB_ToBeModifiedItem_BearerModInd = NULL;
NGAP_E_RABToBeModifiedItemBearerModIndIEs_t *E_RAB_ToBeModifiedItem_BearerModInd_IEs = NULL;
NGAP_E_RABNotToBeModifiedItemBearerModInd_t *E_RAB_NotToBeModifiedItem_BearerModInd = NULL;
NGAP_E_RABNotToBeModifiedItemBearerModIndIEs_t *E_RAB_NotToBeModifiedItem_BearerModInd_IEs = NULL;
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
uint8_t *buffer = NULL;
uint32_t len = 0;
int ret = 0;
DevAssert(ngap_gNB_instance_p != NULL);
DevAssert(e_rab_modification_ind != NULL);
int num_e_rabs_tobemodified = e_rab_modification_ind->nb_of_e_rabs_tobemodified;
int num_e_rabs_nottobemodified = e_rab_modification_ind->nb_of_e_rabs_nottobemodified;
uint32_t CSG_id = 0;
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
e_rab_modification_ind->gNB_ue_ngap_id)) == NULL) {
// The context for this gNB ue ngap id doesn't exist in the map of gNB UEs
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%06x\n",
e_rab_modification_ind->gNB_ue_ngap_id);
return -1;
}
// Prepare the NGAP message to encode
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_E_RABModificationIndication;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_reject;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_E_RABModificationIndication;
out = &pdu.choice.initiatingMessage.value.choice.E_RABModificationIndication;
// mandatory
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = e_rab_modification_ind->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = e_rab_modification_ind->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//E-RABs to be modified list
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABToBeModifiedListBearerModInd;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_E_RABToBeModifiedListBearerModInd;
//The following two for-loops here will probably need to change. We should do a different type of search
for(int i=0; i<num_e_rabs_tobemodified; i++){
E_RAB_ToBeModifiedItem_BearerModInd_IEs = (NGAP_E_RABToBeModifiedItemBearerModIndIEs_t *)calloc(1,sizeof(NGAP_E_RABToBeModifiedItemBearerModIndIEs_t));
E_RAB_ToBeModifiedItem_BearerModInd_IEs->id = NGAP_ProtocolIE_ID_id_E_RABToBeModifiedItemBearerModInd;
E_RAB_ToBeModifiedItem_BearerModInd_IEs->criticality = NGAP_Criticality_reject;
E_RAB_ToBeModifiedItem_BearerModInd_IEs->value.present = NGAP_E_RABToBeModifiedItemBearerModIndIEs__value_PR_E_RABToBeModifiedItemBearerModInd;
E_RAB_ToBeModifiedItem_BearerModInd = &E_RAB_ToBeModifiedItem_BearerModInd_IEs->value.choice.E_RABToBeModifiedItemBearerModInd;
{
E_RAB_ToBeModifiedItem_BearerModInd->e_RAB_ID = e_rab_modification_ind->e_rabs_tobemodified[i].e_rab_id;
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.size = e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.length/8;
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.bits_unused = e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.length%8;
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.buf = calloc(1, E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.size);
memcpy (E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.buf, e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.buffer,
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.size);
INT32_TO_OCTET_STRING(e_rab_modification_ind->e_rabs_tobemodified[i].gtp_teid, &E_RAB_ToBeModifiedItem_BearerModInd->dL_GTP_TEID);
}
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABToBeModifiedListBearerModInd.list, E_RAB_ToBeModifiedItem_BearerModInd_IEs);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//E-RABs NOT to be modified list
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABNotToBeModifiedListBearerModInd;
ie->criticality = NGAP_Criticality_reject;
if(num_e_rabs_nottobemodified > 0) {
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_E_RABNotToBeModifiedListBearerModInd;
for(int i=0; i<num_e_rabs_nottobemodified; i++){
E_RAB_NotToBeModifiedItem_BearerModInd_IEs = (NGAP_E_RABNotToBeModifiedItemBearerModIndIEs_t *)calloc(1,sizeof(NGAP_E_RABNotToBeModifiedItemBearerModIndIEs_t));
E_RAB_NotToBeModifiedItem_BearerModInd_IEs->id = NGAP_ProtocolIE_ID_id_E_RABNotToBeModifiedItemBearerModInd;
E_RAB_NotToBeModifiedItem_BearerModInd_IEs->criticality = NGAP_Criticality_reject;
E_RAB_NotToBeModifiedItem_BearerModInd_IEs->value.present = NGAP_E_RABNotToBeModifiedItemBearerModIndIEs__value_PR_E_RABNotToBeModifiedItemBearerModInd;
E_RAB_NotToBeModifiedItem_BearerModInd = &E_RAB_NotToBeModifiedItem_BearerModInd_IEs->value.choice.E_RABNotToBeModifiedItemBearerModInd;
{
E_RAB_NotToBeModifiedItem_BearerModInd->e_RAB_ID = e_rab_modification_ind->e_rabs_nottobemodified[i].e_rab_id;
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.size = e_rab_modification_ind->e_rabs_nottobemodified[i].gNB_addr.length/8;
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.bits_unused = e_rab_modification_ind->e_rabs_nottobemodified[i].gNB_addr.length%8;
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.buf =
calloc(1, E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.size);
memcpy (E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.buf, e_rab_modification_ind->e_rabs_nottobemodified[i].gNB_addr.buffer,
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.size);
INT32_TO_OCTET_STRING(e_rab_modification_ind->e_rabs_nottobemodified[i].gtp_teid, &E_RAB_NotToBeModifiedItem_BearerModInd->dL_GTP_TEID);
}
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABNotToBeModifiedListBearerModInd.list, E_RAB_NotToBeModifiedItem_BearerModInd_IEs);
}
}
else{
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_E_RABNotToBeModifiedListBearerModInd;
ie->value.choice.E_RABNotToBeModifiedListBearerModInd.list.size = 0;
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_CSGMembershipInfo;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_CSGMembershipInfo;
ie->value.choice.CSGMembershipInfo.cSGMembershipStatus = NGAP_CSGMembershipStatus_member;
INT32_TO_BIT_STRING(CSG_id, &ie->value.choice.CSGMembershipInfo.cSG_Id);
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
if (ngap_gNB_encode_pdu(&pdu, &buffer, &len) < 0) {
NGAP_ERROR("Failed to encode S1 E-RAB modification indication \n");
return -1;
}
// Non UE-Associated signalling -> stream = 0
NGAP_INFO("Size of encoded message: %d \n", len);
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
len, ue_context_p->tx_stream);
//ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->mme_ref->assoc_id, buffer, len, 0);
return ret;
}*/
int ngap_gNB_generate_E_RAB_Modification_Indication(
instance_t instance,
ngap_e_rab_modification_ind_t *e_rab_modification_ind)
//-----------------------------------------------------------------------------
{
struct ngap_gNB_ue_context_s *ue_context_p = NULL;
NGAP_NGAP_PDU_t pdu;
NGAP_E_RABModificationIndication_t *out = NULL;
NGAP_E_RABModificationIndicationIEs_t *ie = NULL;
NGAP_E_RABToBeModifiedItemBearerModInd_t *E_RAB_ToBeModifiedItem_BearerModInd = NULL;
NGAP_E_RABToBeModifiedItemBearerModIndIEs_t *E_RAB_ToBeModifiedItem_BearerModInd_IEs = NULL;
//NGAP_E_RABNotToBeModifiedItemBearerModInd_t *E_RAB_NotToBeModifiedItem_BearerModInd = NULL;
//NGAP_E_RABNotToBeModifiedItemBearerModIndIEs_t *E_RAB_NotToBeModifiedItem_BearerModInd_IEs = NULL;
ngap_gNB_instance_t *ngap_gNB_instance_p = NULL;
ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
uint8_t *buffer = NULL;
uint32_t len = 0;
int ret = 0;
DevAssert(ngap_gNB_instance_p != NULL);
DevAssert(e_rab_modification_ind != NULL);
int num_e_rabs_tobemodified = e_rab_modification_ind->nb_of_e_rabs_tobemodified;
//int num_e_rabs_nottobemodified = e_rab_modification_ind->nb_of_e_rabs_nottobemodified;
//uint32_t CSG_id = 0;
//uint32_t pseudo_gtp_teid = 10;
if ((ue_context_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p,
e_rab_modification_ind->gNB_ue_ngap_id)) == NULL) {
// The context for this gNB ue ngap id doesn't exist in the map of gNB UEs
NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%06x\n",
e_rab_modification_ind->gNB_ue_ngap_id);
return -1;
}
// Prepare the NGAP message to encode
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_E_RABModificationIndication;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_reject;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_E_RABModificationIndication;
out = &pdu.choice.initiatingMessage.value.choice.E_RABModificationIndication;
/* mandatory */
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = e_rab_modification_ind->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = e_rab_modification_ind->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//E-RABs to be modified list
ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABToBeModifiedListBearerModInd;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_E_RABToBeModifiedListBearerModInd;
//The following two for-loops here will probably need to change. We should do a different type of search
for(int i=0; i<num_e_rabs_tobemodified; i++){
E_RAB_ToBeModifiedItem_BearerModInd_IEs = (NGAP_E_RABToBeModifiedItemBearerModIndIEs_t *)calloc(1,sizeof(NGAP_E_RABToBeModifiedItemBearerModIndIEs_t));
E_RAB_ToBeModifiedItem_BearerModInd_IEs->id = NGAP_ProtocolIE_ID_id_E_RABToBeModifiedItemBearerModInd;
E_RAB_ToBeModifiedItem_BearerModInd_IEs->criticality = NGAP_Criticality_reject;
E_RAB_ToBeModifiedItem_BearerModInd_IEs->value.present = NGAP_E_RABToBeModifiedItemBearerModIndIEs__value_PR_E_RABToBeModifiedItemBearerModInd;
E_RAB_ToBeModifiedItem_BearerModInd = &E_RAB_ToBeModifiedItem_BearerModInd_IEs->value.choice.E_RABToBeModifiedItemBearerModInd;
{
E_RAB_ToBeModifiedItem_BearerModInd->e_RAB_ID = e_rab_modification_ind->e_rabs_tobemodified[i].e_rab_id;
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.size = e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.length/8;
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.bits_unused = e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.length%8;
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.buf = calloc(1, E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.size);
memcpy (E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.buf, e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.buffer,
E_RAB_ToBeModifiedItem_BearerModInd->transportLayerAddress.size);
INT32_TO_OCTET_STRING(e_rab_modification_ind->e_rabs_tobemodified[i].gtp_teid, &E_RAB_ToBeModifiedItem_BearerModInd->dL_GTP_TEID);
}
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABToBeModifiedListBearerModInd.list, E_RAB_ToBeModifiedItem_BearerModInd_IEs);
}
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
//E-RABs NOT to be modified list
/*ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_RABNotToBeModifiedListBearerModInd;
ie->criticality = NGAP_Criticality_reject;
//if(num_e_rabs_nottobemodified > 0) {
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_E_RABNotToBeModifiedListBearerModInd;
for(int i=0; i<num_e_rabs_tobemodified; i++){
E_RAB_NotToBeModifiedItem_BearerModInd_IEs = (NGAP_E_RABNotToBeModifiedItemBearerModIndIEs_t *)calloc(1,sizeof(NGAP_E_RABNotToBeModifiedItemBearerModIndIEs_t));
E_RAB_NotToBeModifiedItem_BearerModInd_IEs->id = NGAP_ProtocolIE_ID_id_E_RABNotToBeModifiedItemBearerModInd;
E_RAB_NotToBeModifiedItem_BearerModInd_IEs->criticality = NGAP_Criticality_reject;
E_RAB_NotToBeModifiedItem_BearerModInd_IEs->value.present = NGAP_E_RABNotToBeModifiedItemBearerModIndIEs__value_PR_E_RABNotToBeModifiedItemBearerModInd;
E_RAB_NotToBeModifiedItem_BearerModInd = &E_RAB_NotToBeModifiedItem_BearerModInd_IEs->value.choice.E_RABNotToBeModifiedItemBearerModInd;
{
E_RAB_NotToBeModifiedItem_BearerModInd->e_RAB_ID = 10; //e_rab_modification_ind->e_rabs_tobemodified[i].e_rab_id;
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.size = e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.length/8;
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.bits_unused = e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.length%8;
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.buf =
calloc(1, E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.size);
memcpy (E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.buf, e_rab_modification_ind->e_rabs_tobemodified[i].gNB_addr.buffer,
E_RAB_NotToBeModifiedItem_BearerModInd->transportLayerAddress.size);
//INT32_TO_OCTET_STRING(e_rab_modification_ind->e_rabs_tobemodified[i].gtp_teid, &E_RAB_NotToBeModifiedItem_BearerModInd->dL_GTP_TEID);
INT32_TO_OCTET_STRING(pseudo_gtp_teid, &E_RAB_NotToBeModifiedItem_BearerModInd->dL_GTP_TEID);
}
ASN_SEQUENCE_ADD(&ie->value.choice.E_RABNotToBeModifiedListBearerModInd.list, E_RAB_NotToBeModifiedItem_BearerModInd_IEs);
}
// }
//else{
// ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_E_RABNotToBeModifiedListBearerModInd;
// ie->value.choice.E_RABNotToBeModifiedListBearerModInd.list.size = 0;
// } /
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);*/
/*ie = (NGAP_E_RABModificationIndicationIEs_t *)calloc(1, sizeof(NGAP_E_RABModificationIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_CSGMembershipInfo;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_E_RABModificationIndicationIEs__value_PR_CSGMembershipInfo;
ie->value.choice.CSGMembershipInfo.cSGMembershipStatus = NGAP_CSGMembershipStatus_member;
INT32_TO_BIT_STRING(CSG_id, &ie->value.choice.CSGMembershipInfo.cSG_Id);
ie->value.choice.CSGMembershipInfo.cSG_Id.bits_unused=5;
ie->value.choice.CSGMembershipInfo.cellAccessMode = NGAP_CellAccessMode_hybrid;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);*/
if (ngap_gNB_encode_pdu(&pdu, &buffer, &len) < 0) {
NGAP_ERROR("Failed to encode S1 E-RAB modification indication \n");
return -1;
}
// Non UE-Associated signalling -> stream = 0
NGAP_INFO("Size of encoded message: %d \n", len);
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
ue_context_p->mme_ref->assoc_id, buffer,
len, ue_context_p->tx_stream);
//ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->mme_ref->assoc_id, buffer, len, 0);
return ret;
}
/*
* 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 NGAP_GNB_NAS_PROCEDURES_H_
#define NGAP_GNB_NAS_PROCEDURES_H_
int ngap_gNB_handle_nas_downlink(
uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_p);
int ngap_gNB_nas_non_delivery_ind(instance_t instance,
ngap_nas_non_delivery_ind_t *ngap_nas_non_delivery_ind);
int ngap_gNB_handle_nas_first_req(
instance_t instance, ngap_nas_first_req_t *ngap_nas_first_req_p);
int ngap_gNB_initial_ctxt_resp(
instance_t instance, ngap_initial_context_setup_resp_t *initial_ctxt_resp_p);
int ngap_gNB_ue_capabilities(instance_t instance,
ngap_ue_cap_info_ind_t *ue_cap_info_ind_p);
int ngap_gNB_e_rab_setup_resp(instance_t instance,
ngap_e_rab_setup_resp_t *e_rab_setup_resp_p);
int ngap_gNB_e_rab_modify_resp(instance_t instance,
ngap_e_rab_modify_resp_t *e_rab_modify_resp_p);
int ngap_gNB_e_rab_release_resp(instance_t instance,
ngap_e_rab_release_resp_t *e_rab_release_resp_p);
int ngap_gNB_path_switch_req(instance_t instance,
ngap_path_switch_req_t *path_switch_req_p);
int ngap_gNB_generate_E_RAB_Modification_Indication(
instance_t instance, ngap_e_rab_modification_ind_t *e_rab_modification_ind);
#endif /* NGAP_GNB_NAS_PROCEDURES_H_ */
/*
* 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
*/
/*! \file ngap_gNB_nnsf.c
* \brief ngap NAS node selection functions
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
* \date 2012
* \version 0.1
*/
#include <stdio.h>
#include <stdlib.h>
#include "intertask_interface.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB_nnsf.h"
struct ngap_gNB_mme_data_s *
ngap_gNB_nnsf_select_mme(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause)
{
struct ngap_gNB_mme_data_s *mme_data_p = NULL;
struct ngap_gNB_mme_data_s *mme_highest_capacity_p = NULL;
uint8_t current_capacity = 0;
RB_FOREACH(mme_data_p, ngap_mme_map, &instance_p->ngap_mme_head) {
if (mme_data_p->state != NGAP_GNB_STATE_CONNECTED) {
/* The association between MME and gNB is not ready for the moment,
* go to the next known MME.
*/
if (mme_data_p->state == NGAP_GNB_OVERLOAD) {
/* MME is overloaded. We have to check the RRC establishment
* cause and take decision to the select this MME depending on
* the overload state.
*/
if ((cause == RRC_CAUSE_MO_DATA)
&& (mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_MO_DATA)) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_ALL_SIGNALLING)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_ONLY_EMERGENCY_AND_MT)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA)
|| (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) {
continue;
}
/* At this point, the RRC establishment can be handled by the MME
* even if it is in overload state.
*/
} else {
/* The MME is not overloaded, association is simply not ready. */
continue;
}
}
if (current_capacity < mme_data_p->relative_mme_capacity) {
/* We find a better MME, keep a reference to it */
current_capacity = mme_data_p->relative_mme_capacity;
mme_highest_capacity_p = mme_data_p;
}
}
return mme_highest_capacity_p;
}
struct ngap_gNB_mme_data_s *
ngap_gNB_nnsf_select_mme_by_plmn_id(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
int selected_plmn_identity)
{
struct ngap_gNB_mme_data_s *mme_data_p = NULL;
struct ngap_gNB_mme_data_s *mme_highest_capacity_p = NULL;
uint8_t current_capacity = 0;
RB_FOREACH(mme_data_p, ngap_mme_map, &instance_p->ngap_mme_head) {
struct served_gummei_s *gummei_p = NULL;
struct plmn_identity_s *served_plmn_p = NULL;
if (mme_data_p->state != NGAP_GNB_STATE_CONNECTED) {
/* The association between MME and gNB is not ready for the moment,
* go to the next known MME.
*/
if (mme_data_p->state == NGAP_GNB_OVERLOAD) {
/* MME is overloaded. We have to check the RRC establishment
* cause and take decision to the select this MME depending on
* the overload state.
*/
if ((cause == RRC_CAUSE_MO_DATA)
&& (mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_MO_DATA)) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_ALL_SIGNALLING)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_ONLY_EMERGENCY_AND_MT)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA)
|| (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) {
continue;
}
/* At this point, the RRC establishment can be handled by the MME
* even if it is in overload state.
*/
} else {
/* The MME is not overloaded, association is simply not ready. */
continue;
}
}
/* Looking for served GUMMEI PLMN Identity selected matching the one provided by the UE */
STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) {
STAILQ_FOREACH(served_plmn_p, &gummei_p->served_plmns, next) {
if ((served_plmn_p->mcc == instance_p->mcc[selected_plmn_identity]) &&
(served_plmn_p->mnc == instance_p->mnc[selected_plmn_identity])) {
break;
}
}
/* if found, we can stop the outer loop, too */
if (served_plmn_p) break;
}
/* if we didn't find such a served PLMN, go on with the next MME */
if (!served_plmn_p) continue;
if (current_capacity < mme_data_p->relative_mme_capacity) {
/* We find a better MME, keep a reference to it */
current_capacity = mme_data_p->relative_mme_capacity;
mme_highest_capacity_p = mme_data_p;
}
}
return mme_highest_capacity_p;
}
struct ngap_gNB_mme_data_s *
ngap_gNB_nnsf_select_mme_by_mme_code(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
int selected_plmn_identity,
uint8_t mme_code)
{
struct ngap_gNB_mme_data_s *mme_data_p = NULL;
RB_FOREACH(mme_data_p, ngap_mme_map, &instance_p->ngap_mme_head) {
struct served_gummei_s *gummei_p = NULL;
if (mme_data_p->state != NGAP_GNB_STATE_CONNECTED) {
/* The association between MME and gNB is not ready for the moment,
* go to the next known MME.
*/
if (mme_data_p->state == NGAP_GNB_OVERLOAD) {
/* MME is overloaded. We have to check the RRC establishment
* cause and take decision to the select this MME depending on
* the overload state.
*/
if ((cause == RRC_CAUSE_MO_DATA)
&& (mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_MO_DATA)) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_ALL_SIGNALLING)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_ONLY_EMERGENCY_AND_MT)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA)
|| (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) {
continue;
}
/* At this point, the RRC establishment can be handled by the MME
* even if it is in overload state.
*/
} else {
/* The MME is not overloaded, association is simply not ready. */
continue;
}
}
/* Looking for MME code matching the one provided by NAS */
STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) {
struct mme_code_s *mme_code_p = NULL;
struct plmn_identity_s *served_plmn_p = NULL;
STAILQ_FOREACH(served_plmn_p, &gummei_p->served_plmns, next) {
if ((served_plmn_p->mcc == instance_p->mcc[selected_plmn_identity]) &&
(served_plmn_p->mnc == instance_p->mnc[selected_plmn_identity])) {
break;
}
}
STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) {
if (mme_code_p->mme_code == mme_code) {
break;
}
}
/* The MME matches the parameters provided by the NAS layer ->
* the MME is knwown and the association is ready.
* Return the reference to the MME to use it for this UE.
*/
if (mme_code_p && served_plmn_p) {
return mme_data_p;
}
}
}
/* At this point no MME matches the selected PLMN and MME code. In this case,
* return NULL. That way the RRC layer should know about it and reject RRC
* connectivity. */
return NULL;
}
struct ngap_gNB_mme_data_s *
ngap_gNB_nnsf_select_mme_by_gummei(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
ngap_gummei_t gummei)
{
struct ngap_gNB_mme_data_s *mme_data_p = NULL;
RB_FOREACH(mme_data_p, ngap_mme_map, &instance_p->ngap_mme_head) {
struct served_gummei_s *gummei_p = NULL;
if (mme_data_p->state != NGAP_GNB_STATE_CONNECTED) {
/* The association between MME and gNB is not ready for the moment,
* go to the next known MME.
*/
if (mme_data_p->state == NGAP_GNB_OVERLOAD) {
/* MME is overloaded. We have to check the RRC establishment
* cause and take decision to the select this MME depending on
* the overload state.
*/
if ((cause == RRC_CAUSE_MO_DATA)
&& (mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_MO_DATA)) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_REJECT_ALL_SIGNALLING)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) {
continue;
}
if ((mme_data_p->overload_state == NGAP_OVERLOAD_ONLY_EMERGENCY_AND_MT)
&& ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA)
|| (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) {
continue;
}
/* At this point, the RRC establishment can be handled by the MME
* even if it is in overload state.
*/
} else {
/* The MME is not overloaded, association is simply not ready. */
continue;
}
}
/* Looking for MME gummei matching the one provided by NAS */
STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) {
struct served_group_id_s *group_id_p = NULL;
struct mme_code_s *mme_code_p = NULL;
struct plmn_identity_s *served_plmn_p = NULL;
STAILQ_FOREACH(served_plmn_p, &gummei_p->served_plmns, next) {
if ((served_plmn_p->mcc == gummei.mcc) &&
(served_plmn_p->mnc == gummei.mnc)) {
break;
}
}
STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) {
if (mme_code_p->mme_code == gummei.mme_code) {
break;
}
}
STAILQ_FOREACH(group_id_p, &gummei_p->served_group_ids, next) {
if (group_id_p->mme_group_id == gummei.mme_group_id) {
break;
}
}
/* The MME matches the parameters provided by the NAS layer ->
* the MME is knwown and the association is ready.
* Return the reference to the MME to use it for this UE.
*/
if ((group_id_p != NULL) &&
(mme_code_p != NULL) &&
(served_plmn_p != NULL)) {
return mme_data_p;
}
}
}
/* At this point no MME matches the provided GUMMEI. In this case, return
* NULL. That way the RRC layer should know about it and reject RRC
* connectivity. */
return NULL;
}
struct ngap_gNB_mme_data_s *
ngap_gNB_nnsf_select_mme_by_gummei_no_cause(ngap_gNB_instance_t *instance_p,
ngap_gummei_t gummei)
{
struct ngap_gNB_mme_data_s *mme_data_p = NULL;
struct ngap_gNB_mme_data_s *mme_highest_capacity_p = NULL;
uint8_t current_capacity = 0;
RB_FOREACH(mme_data_p, ngap_mme_map, &instance_p->ngap_mme_head) {
struct served_gummei_s *gummei_p = NULL;
if (mme_data_p->state != NGAP_GNB_STATE_CONNECTED) {
/* The association between MME and gNB is not ready for the moment,
* go to the next known MME.
*/
if (mme_data_p->state == NGAP_GNB_OVERLOAD) {
/* MME is overloaded. We have to check the RRC establishment
* cause and take decision to the select this MME depending on
* the overload state.
*/
} else {
/* The MME is not overloaded, association is simply not ready. */
continue;
}
}
if (current_capacity < mme_data_p->relative_mme_capacity) {
/* We find a better MME, keep a reference to it */
current_capacity = mme_data_p->relative_mme_capacity;
mme_highest_capacity_p = mme_data_p;
}
/* Looking for MME gummei matching the one provided by NAS */
STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) {
struct served_group_id_s *group_id_p = NULL;
struct mme_code_s *mme_code_p = NULL;
struct plmn_identity_s *served_plmn_p = NULL;
STAILQ_FOREACH(served_plmn_p, &gummei_p->served_plmns, next) {
if ((served_plmn_p->mcc == gummei.mcc) &&
(served_plmn_p->mnc == gummei.mnc)) {
break;
}
}
STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) {
if (mme_code_p->mme_code == gummei.mme_code) {
break;
}
}
STAILQ_FOREACH(group_id_p, &gummei_p->served_group_ids, next) {
if (group_id_p->mme_group_id == gummei.mme_group_id) {
break;
}
}
/* The MME matches the parameters provided by the NAS layer ->
* the MME is knwown and the association is ready.
* Return the reference to the MME to use it for this UE.
*/
if ((group_id_p != NULL) &&
(mme_code_p != NULL) &&
(served_plmn_p != NULL)) {
return mme_data_p;
}
}
}
/* At this point no MME matches the provided GUMMEI. Select the one with the
* highest relative capacity.
* In case the list of known MME is empty, simply return NULL, that way the RRC
* layer should know about it and reject RRC connectivity.
*/
return mme_highest_capacity_p;
}
/*
* 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 NGAP_GNB_NNSF_H_
#define NGAP_GNB_NNSF_H_
struct ngap_gNB_mme_data_s *
ngap_gNB_nnsf_select_mme(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause);
struct ngap_gNB_mme_data_s *
ngap_gNB_nnsf_select_mme_by_plmn_id(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
int selected_plmn_identity);
struct ngap_gNB_mme_data_s*
ngap_gNB_nnsf_select_mme_by_mme_code(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
int selected_plmn_identity,
uint8_t mme_code);
struct ngap_gNB_mme_data_s*
ngap_gNB_nnsf_select_mme_by_gummei(ngap_gNB_instance_t *instance_p,
rrc_establishment_cause_t cause,
ngap_gummei_t gummei);
struct ngap_gNB_mme_data_s*
ngap_gNB_nnsf_select_mme_by_gummei_no_cause(ngap_gNB_instance_t *instance_p,
ngap_gummei_t gummei);
#endif /* NGAP_GNB_NNSF_H_ */
/*
* 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
*/
/*! \file ngap_gNB_overload.c
* \brief ngap procedures for overload messages within gNB
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
* \date 2012
* \version 0.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "intertask_interface.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB.h"
#include "ngap_gNB_ue_context.h"
#include "ngap_gNB_encoder.h"
#include "ngap_gNB_overload.h"
#include "ngap_gNB_management_procedures.h"
#include "assertions.h"
int ngap_gNB_handle_overload_start(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu)
{
ngap_gNB_mme_data_t *mme_desc_p;
NGAP_OverloadStart_t *container;
NGAP_OverloadStartIEs_t *ie;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.OverloadStart;
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_OverloadStartIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_OverloadResponse, true);
if (ie != NULL) {
DevCheck(ie->value.choice.OverloadResponse.present ==
NGAP_OverloadResponse_PR_overloadAction,
NGAP_OverloadResponse_PR_overloadAction, 0, 0);
}
/* Non UE-associated signalling -> stream 0 */
DevCheck(stream == 0, stream, 0, 0);
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
/* No MME context associated */
return -1;
}
/* Mark the MME as overloaded and set the overload state according to
* the value received.
*/
mme_desc_p->state = NGAP_GNB_OVERLOAD;
mme_desc_p->overload_state =
ie->value.choice.OverloadResponse.choice.overloadAction;
return 0;
}
int ngap_gNB_handle_overload_stop(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu)
{
/* We received Overload stop message, meaning that the MME is no more
* overloaded. This is an empty message, with only message header and no
* Information Element.
*/
DevAssert(pdu != NULL);
ngap_gNB_mme_data_t *mme_desc_p;
/* Non UE-associated signalling -> stream 0 */
DevCheck(stream == 0, stream, 0, 0);
if ((mme_desc_p = ngap_gNB_get_MME(NULL, assoc_id, 0)) == NULL) {
/* No MME context associated */
return -1;
}
mme_desc_p->state = NGAP_GNB_STATE_CONNECTED;
mme_desc_p->overload_state = NGAP_NO_OVERLOAD;
return 0;
}
/*
* 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 NGAP_GNB_OVERLOAD_H_
#define NGAP_GNB_OVERLOAD_H_
/**
* \brief Handle an overload start message
**/
// int ngap_gNB_handle_overload_start(gNB_mme_desc_t *gNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct ngap_message_s *message_p);
int ngap_gNB_handle_overload_start(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
/**
* \brief Handle an overload stop message
**/
// int ngap_gNB_handle_overload_stop(gNB_mme_desc_t *gNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct ngap_message_s *message_p);
int ngap_gNB_handle_overload_stop(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
#endif /* NGAP_GNB_OVERLOAD_H_ */
/*
* 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 <stdint.h>
#include "assertions.h"
#include "intertask_interface.h"
#include "ngap_gNB_default_values.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB.h"
#include "ngap_gNB_ue_context.h"
#include "ngap_gNB_encoder.h"
#include "ngap_gNB_trace.h"
#include "ngap_gNB_itti_messaging.h"
#include "ngap_gNB_management_procedures.h"
static
void ngap_gNB_generate_trace_failure(struct ngap_gNB_ue_context_s *ue_desc_p,
NGAP_E_UTRAN_Trace_ID_t *trace_id,
NGAP_Cause_t *cause_p)
{
NGAP_NGAP_PDU_t pdu;
NGAP_TraceFailureIndication_t *out;
NGAP_TraceFailureIndicationIEs_t *ie;
uint8_t *buffer = NULL;
uint32_t length;
DevAssert(ue_desc_p != NULL);
DevAssert(trace_id != NULL);
DevAssert(cause_p != NULL);
/* Prepare the NGAP message to encode */
memset(&pdu, 0, sizeof(pdu));
pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage;
pdu.choice.initiatingMessage.procedureCode = NGAP_ProcedureCode_id_TraceFailureIndication;
pdu.choice.initiatingMessage.criticality = NGAP_Criticality_ignore;
pdu.choice.initiatingMessage.value.present = NGAP_InitiatingMessage__value_PR_TraceFailureIndication;
out = &pdu.choice.initiatingMessage.value.choice.TraceFailureIndication;
/* mandatory */
ie = (NGAP_TraceFailureIndicationIEs_t *)calloc(1, sizeof(NGAP_TraceFailureIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_MME_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_TraceFailureIndicationIEs__value_PR_MME_UE_NGAP_ID;
ie->value.choice.MME_UE_NGAP_ID = ue_desc_p->mme_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_TraceFailureIndicationIEs_t *)calloc(1, sizeof(NGAP_TraceFailureIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID;
ie->criticality = NGAP_Criticality_reject;
ie->value.present = NGAP_TraceFailureIndicationIEs__value_PR_GNB_UE_NGAP_ID;
ie->value.choice.GNB_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id;
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_TraceFailureIndicationIEs_t *)calloc(1, sizeof(NGAP_TraceFailureIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_E_UTRAN_Trace_ID;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_TraceFailureIndicationIEs__value_PR_E_UTRAN_Trace_ID;
memcpy(&ie->value.choice.E_UTRAN_Trace_ID, trace_id, sizeof(NGAP_E_UTRAN_Trace_ID_t));
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
/* mandatory */
ie = (NGAP_TraceFailureIndicationIEs_t *)calloc(1, sizeof(NGAP_TraceFailureIndicationIEs_t));
ie->id = NGAP_ProtocolIE_ID_id_Cause;
ie->criticality = NGAP_Criticality_ignore;
ie->value.present = NGAP_TraceFailureIndicationIEs__value_PR_Cause;
memcpy(&ie->value.choice.Cause, cause_p, sizeof(NGAP_Cause_t));
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
return;
}
ngap_gNB_itti_send_sctp_data_req(ue_desc_p->mme_ref->ngap_gNB_instance->instance,
ue_desc_p->mme_ref->assoc_id, buffer,
length, ue_desc_p->tx_stream);
}
int ngap_gNB_handle_trace_start(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu)
{
NGAP_TraceStart_t *container;
NGAP_TraceStartIEs_t *ie;
struct ngap_gNB_ue_context_s *ue_desc_p = NULL;
struct ngap_gNB_mme_data_s *mme_ref_p;
DevAssert(pdu != NULL);
container = &pdu->choice.initiatingMessage.value.choice.TraceStart;
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_TraceStartIEs_t, ie, container,
NGAP_ProtocolIE_ID_id_gNB_UE_NGAP_ID, TRUE);
mme_ref_p = ngap_gNB_get_MME(NULL, assoc_id, 0);
DevAssert(mme_ref_p != NULL);
if (ie != NULL) {
ue_desc_p = ngap_gNB_get_ue_context(mme_ref_p->ngap_gNB_instance,
ie->value.choice.GNB_UE_NGAP_ID);
}
if (ue_desc_p == NULL) {
/* Could not find context associated with this gNB_ue_ngap_id -> generate
* trace failure indication.
*/
NGAP_E_UTRAN_Trace_ID_t trace_id;
NGAP_Cause_t cause;
memset(&trace_id, 0, sizeof(NGAP_E_UTRAN_Trace_ID_t));
memset(&cause, 0, sizeof(NGAP_Cause_t));
cause.present = NGAP_Cause_PR_radioNetwork;
cause.choice.radioNetwork = NGAP_CauseRadioNetwork_unknown_pair_ue_ngap_id;
ngap_gNB_generate_trace_failure(NULL, &trace_id, &cause);
}
return 0;
}
int ngap_gNB_handle_deactivate_trace(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *message_p)
{
// NGAP_DeactivateTraceIEs_t *deactivate_trace_p;
//
// deactivate_trace_p = &message_p->msg.deactivateTraceIEs;
return 0;
}
/*
* 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 NGAP_GNB_TRACE_H_
#define NGAP_GNB_TRACE_H_
// int ngap_gNB_generate_trace_failure(sctp_data_t *sctp_data_p,
// int32_t stream,
// uint32_t gNB_ue_ngap_id,
// uint32_t mme_ue_ngap_id,
// E_UTRAN_Trace_ID_t *trace_id,
// Cause_t *cause_p);
// int ngap_gNB_handle_trace_start(gNB_mme_desc_t *gNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct ngap_message_s *message_p);
int ngap_gNB_handle_trace_start(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
// int ngap_gNB_handle_deactivate_trace(gNB_mme_desc_t *gNB_desc_p,
// sctp_queue_item_t *packet_p,
// struct ngap_message_s *message_p);
int ngap_gNB_handle_deactivate_trace(uint32_t assoc_id,
uint32_t stream,
NGAP_NGAP_PDU_t *pdu);
#endif /* NGAP_GNB_TRACE_H_ */
/*
* 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
*/
/*! \file ngap_gNB_ue_context.c
* \brief ngap UE context management within gNB
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
* \date 2012
* \version 0.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "tree.h"
#include "intertask_interface.h"
#include "ngap_common.h"
#include "ngap_gNB_defs.h"
#include "ngap_gNB_ue_context.h"
int ngap_gNB_compare_gNB_ue_ngap_id(
struct ngap_gNB_ue_context_s *p1, struct ngap_gNB_ue_context_s *p2)
{
if (p1->gNB_ue_ngap_id > p2->gNB_ue_ngap_id) {
return 1;
}
if (p1->gNB_ue_ngap_id < p2->gNB_ue_ngap_id) {
return -1;
}
return 0;
}
/* Generate the tree management functions */
RB_GENERATE(ngap_ue_map, ngap_gNB_ue_context_s, entries,
ngap_gNB_compare_gNB_ue_ngap_id);
struct ngap_gNB_ue_context_s *ngap_gNB_allocate_new_UE_context(void)
{
struct ngap_gNB_ue_context_s *new_p;
new_p = malloc(sizeof(struct ngap_gNB_ue_context_s));
if (new_p == NULL) {
NGAP_ERROR("Cannot allocate new ue context\n");
return NULL;
}
memset(new_p, 0, sizeof(struct ngap_gNB_ue_context_s));
return new_p;
}
struct ngap_gNB_ue_context_s *ngap_gNB_get_ue_context(
ngap_gNB_instance_t *instance_p,
uint32_t gNB_ue_ngap_id)
{
ngap_gNB_ue_context_t temp;
memset(&temp, 0, sizeof(struct ngap_gNB_ue_context_s));
/* gNB ue ngap id = 24 bits wide */
temp.gNB_ue_ngap_id = gNB_ue_ngap_id & 0x00FFFFFF;
return RB_FIND(ngap_ue_map, &instance_p->ngap_ue_head, &temp);
}
void ngap_gNB_free_ue_context(struct ngap_gNB_ue_context_s *ue_context_p)
{
if (ue_context_p == NULL) {
NGAP_ERROR("Trying to free a NULL context\n");
return;
}
/* TODO: check that context is currently not in the tree of known
* contexts.
*/
free(ue_context_p);
}
/*
* 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 "tree.h"
#include "queue.h"
#include "ngap_gNB_defs.h"
#ifndef NGAP_GNB_UE_CONTEXT_H_
#define NGAP_GNB_UE_CONTEXT_H_
// Forward declarations
struct ngap_gNB_mme_data_s;
struct ngap_ue_map;
struct gNB_mme_desc_s;
typedef enum {
/* UE has not been registered to a MME or UE association has failed. */
NGAP_UE_DECONNECTED = 0x0,
/* UE ngap state is waiting for initial context setup request message. */
NGAP_UE_WAITING_CSR = 0x1,
/* UE association is ready and bearers are established. */
NGAP_UE_CONNECTED = 0x2,
NGAP_UE_STATE_MAX,
} ngap_ue_state;
typedef struct ngap_gNB_ue_context_s {
/* Tree related data */
RB_ENTRY(ngap_gNB_ue_context_s) entries;
/* Uniquely identifies the UE between MME and gNB within the gNB.
* This id is encoded on 24bits.
*/
unsigned gNB_ue_ngap_id:24;
/* UE id for initial connection to NGAP */
uint16_t ue_initial_id;
/* Uniquely identifies the UE within MME. Encoded on 32 bits. */
uint32_t mme_ue_ngap_id;
/* Stream used for this particular UE */
int32_t tx_stream;
int32_t rx_stream;
/* Current UE state. */
ngap_ue_state ue_state;
/* Reference to MME data this UE is attached to */
struct ngap_gNB_mme_data_s *mme_ref;
/* Signaled by the UE in RRC Connection Setup Complete and used in NAS Uplink
* to route NAS messages correctly. 0-based, not 1-based as in TS 36.331
* 6.2.2 RRC Connection Setup Complete! */
int selected_plmn_identity;
/* Reference to gNB data this UE is attached to */
ngap_gNB_instance_t *gNB_instance;
} ngap_gNB_ue_context_t;
int ngap_gNB_compare_gNB_ue_ngap_id(
struct ngap_gNB_ue_context_s *p1, struct ngap_gNB_ue_context_s *p2);
/* Generate the tree management functions prototypes */
RB_PROTOTYPE(ngap_ue_map, ngap_gNB_ue_context_s, entries,
ngap_gNB_compare_gNB_ue_ngap_id);
struct ngap_gNB_ue_context_s *ngap_gNB_allocate_new_UE_context(void);
struct ngap_gNB_ue_context_s *ngap_gNB_get_ue_context(
ngap_gNB_instance_t *instance_p,
uint32_t gNB_ue_ngap_id);
void ngap_gNB_free_ue_context(struct ngap_gNB_ue_context_s *ue_context_p);
#endif /* NGAP_GNB_UE_CONTEXT_H_ */
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