Commit 5268dbf3 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/deregistration' into integration_2023_w13

parents ca6ae2c4 c4a9f0ea
...@@ -1895,6 +1895,7 @@ set(libnrnas_emm_msg_OBJS ...@@ -1895,6 +1895,7 @@ set(libnrnas_emm_msg_OBJS
${NAS_SRC}COMMON/EMM/MSG/FGSUplinkNasTransport.c ${NAS_SRC}COMMON/EMM/MSG/FGSUplinkNasTransport.c
${NAS_SRC}COMMON/ESM/MSG/PduSessionEstablishRequest.c ${NAS_SRC}COMMON/ESM/MSG/PduSessionEstablishRequest.c
${NAS_SRC}COMMON/ESM/MSG/PduSessionEstablishmentAccept.c ${NAS_SRC}COMMON/ESM/MSG/PduSessionEstablishmentAccept.c
${NAS_SRC}COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.c
) )
set(libnrnas_ies_OBJS set(libnrnas_ies_OBJS
......
...@@ -219,7 +219,7 @@ services: ...@@ -219,7 +219,7 @@ services:
F1_DU_IP_ADDRESS: 192.168.71.142 F1_DU_IP_ADDRESS: 192.168.71.142
F1_CU_D_PORT: 2153 F1_CU_D_PORT: 2153
F1_DU_D_PORT: 2153 F1_DU_D_PORT: 2153
USE_ADDITIONAL_OPTIONS: --sa --rfsim --rfsimulator.wait_timeout 20 --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --sa --rfsim --log_config.global_log_options level,nocolor,time
depends_on: depends_on:
- oai-cu - oai-cu
networks: networks:
......
...@@ -180,7 +180,7 @@ services: ...@@ -180,7 +180,7 @@ services:
GNB_NGA_IP_ADDRESS: 192.168.71.140 GNB_NGA_IP_ADDRESS: 192.168.71.140
GNB_NGU_IF_NAME: eth0 GNB_NGU_IF_NAME: eth0
GNB_NGU_IP_ADDRESS: 192.168.71.140 GNB_NGU_IP_ADDRESS: 192.168.71.140
USE_ADDITIONAL_OPTIONS: --sa -E --rfsim --rfsimulator.wait_timeout 20 --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --sa -E --rfsim --log_config.global_log_options level,nocolor,time
depends_on: depends_on:
- oai-ext-dn - oai-ext-dn
networks: networks:
......
...@@ -181,7 +181,7 @@ services: ...@@ -181,7 +181,7 @@ services:
GNB_NGU_IF_NAME: eth0 GNB_NGU_IF_NAME: eth0
GNB_NGU_IP_ADDRESS: 192.168.71.140 GNB_NGU_IP_ADDRESS: 192.168.71.140
SDR_ADDRS: serial=XXXXXXX SDR_ADDRS: serial=XXXXXXX
USE_ADDITIONAL_OPTIONS: --sa -E --rfsim --rfsimulator.wait_timeout 20 --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --sa -E --rfsim --log_config.global_log_options level,nocolor,time
depends_on: depends_on:
- oai-ext-dn - oai-ext-dn
networks: networks:
......
...@@ -169,7 +169,7 @@ services: ...@@ -169,7 +169,7 @@ services:
environment: environment:
RFSIMULATOR: server RFSIMULATOR: server
USE_VOLUMED_CONF: 'yes' USE_VOLUMED_CONF: 'yes'
USE_ADDITIONAL_OPTIONS: --sa --rfsim --rfsimulator.wait_timeout 20 --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --sa --rfsim --log_config.global_log_options level,nocolor,time
depends_on: depends_on:
- oai-ext-dn - oai-ext-dn
networks: networks:
......
...@@ -169,7 +169,7 @@ services: ...@@ -169,7 +169,7 @@ services:
environment: environment:
RFSIMULATOR: server RFSIMULATOR: server
USE_VOLUMED_CONF: 'yes' USE_VOLUMED_CONF: 'yes'
USE_ADDITIONAL_OPTIONS: --sa --rfsim --rfsimulator.wait_timeout 20 --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --sa --rfsim --log_config.global_log_options level,nocolor,time
depends_on: depends_on:
- oai-ext-dn - oai-ext-dn
networks: networks:
......
...@@ -216,7 +216,7 @@ services: ...@@ -216,7 +216,7 @@ services:
environment: environment:
RFSIMULATOR: server RFSIMULATOR: server
USE_VOLUMED_CONF: 'yes' USE_VOLUMED_CONF: 'yes'
USE_ADDITIONAL_OPTIONS: --sa --rfsim --rfsimulator.wait_timeout 20 --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --sa --rfsim --log_config.global_log_options level,nocolor,time
networks: networks:
ran_net: ran_net:
ipv4_address: 192.168.72.142 ipv4_address: 192.168.72.142
......
...@@ -169,7 +169,7 @@ services: ...@@ -169,7 +169,7 @@ services:
environment: environment:
RFSIMULATOR: server RFSIMULATOR: server
USE_VOLUMED_CONF: 'yes' USE_VOLUMED_CONF: 'yes'
USE_ADDITIONAL_OPTIONS: --sa --rfsim --rfsimulator.wait_timeout 20 --log_config.global_log_options level,nocolor,time USE_ADDITIONAL_OPTIONS: --sa --rfsim --log_config.global_log_options level,nocolor,time
depends_on: depends_on:
- oai-ext-dn - oai-ext-dn
networks: networks:
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <semaphore.h>
extern "C" { extern "C" {
...@@ -434,24 +435,32 @@ extern "C" { ...@@ -434,24 +435,32 @@ extern "C" {
void itti_send_terminate_message(task_id_t task_id) { void itti_send_terminate_message(task_id_t task_id) {
} }
pthread_mutex_t signal_mutex; sem_t itti_sem_block;
void itti_wait_tasks_unblock()
{
int rc = sem_post(&itti_sem_block);
AssertFatal(rc == 0, "error in sem_post(): %d %s\n", errno, strerror(errno));
}
static void catch_sigterm(int) { static void catch_sigterm(int) {
static const char msg[] = "\n** Caught SIGTERM, shutting down\n"; static const char msg[] = "\n** Caught SIGTERM, shutting down\n";
__attribute__((unused)) __attribute__((unused))
int unused = write(STDOUT_FILENO, msg, sizeof(msg) - 1); int unused = write(STDOUT_FILENO, msg, sizeof(msg) - 1);
pthread_mutex_unlock(&signal_mutex); itti_wait_tasks_unblock();
} }
void itti_wait_tasks_end(void) { void itti_wait_tasks_end(void (*handler)(int))
{
pthread_mutex_init(&signal_mutex, NULL); int rc = sem_init(&itti_sem_block, 0, 0);
pthread_mutex_lock(&signal_mutex); AssertFatal(rc == 0, "error in sem_init(): %d %s\n", errno, strerror(errno));
signal(SIGTERM, catch_sigterm); if (handler == NULL) /* no handler given: install default */
signal(SIGINT, catch_sigterm); handler = catch_sigterm;
signal(SIGTERM, handler);
signal(SIGINT, handler);
pthread_mutex_lock(&signal_mutex); rc = sem_wait(&itti_sem_block);
AssertFatal(rc == 0, "error in sem_wait(): %d %s\n", errno, strerror(errno));
} }
void itti_update_lte_time(uint32_t frame, uint8_t slot) {} void itti_update_lte_time(uint32_t frame, uint8_t slot) {}
......
...@@ -550,10 +550,13 @@ MessageDef *itti_alloc_new_message_sized( ...@@ -550,10 +550,13 @@ MessageDef *itti_alloc_new_message_sized(
MessagesIds message_id, MessagesIds message_id,
MessageHeaderSize size); MessageHeaderSize size);
/** \brief handle signals and wait for all threads to join when the process complete. /** \brief Wait for SIGINT/SIGTERM signals to unblock ITTI.
This function should be called from the main thread after having created all ITTI tasks. This function should be called from the main thread after having created all ITTI tasks. If handler is NULL, a default handler is installed.
\param handler a custom signal handler. To unblock, it should call itti_wait_tasks_unblock()
**/ **/
void itti_wait_tasks_end(void); void itti_wait_tasks_end(void (*handler)(int));
/** \brif unblocks ITTI waiting in itti_wait_tasks_end(). **/
void itti_wait_tasks_unblock(void);
void itti_set_task_real_time(task_id_t task_id); void itti_set_task_real_time(task_id_t task_id);
/** \brief Send a termination message to all tasks. /** \brief Send a termination message to all tasks.
......
...@@ -614,7 +614,7 @@ int main ( int argc, char **argv ) ...@@ -614,7 +614,7 @@ int main ( int argc, char **argv )
//getchar(); //getchar();
if(IS_SOFTMODEM_DOSCOPE) if(IS_SOFTMODEM_DOSCOPE)
load_softscope("enb",NULL); load_softscope("enb",NULL);
itti_wait_tasks_end(); itti_wait_tasks_end(NULL);
#if USING_GPROF #if USING_GPROF
// Save the gprof data now (rather than via atexit) in case we crash while shutting down // Save the gprof data now (rather than via atexit) in case we crash while shutting down
......
...@@ -699,7 +699,7 @@ int main( int argc, char **argv ) { ...@@ -699,7 +699,7 @@ int main( int argc, char **argv ) {
printf("TYPE <CTRL-C> TO TERMINATE\n"); printf("TYPE <CTRL-C> TO TERMINATE\n");
//getchar(); //getchar();
printf("Entering ITTI signals handler\n"); printf("Entering ITTI signals handler\n");
itti_wait_tasks_end(); itti_wait_tasks_end(NULL);
printf("Returned from ITTI signal handler\n"); printf("Returned from ITTI signal handler\n");
oai_exit=1; oai_exit=1;
printf("oai_exit=%d\n",oai_exit); printf("oai_exit=%d\n",oai_exit);
......
...@@ -153,7 +153,7 @@ int main(int argc, char **argv) ...@@ -153,7 +153,7 @@ int main(int argc, char **argv)
itti_send_msg_to_task(TASK_CUUP_E1, 0, msg); itti_send_msg_to_task(TASK_CUUP_E1, 0, msg);
printf("TYPE <CTRL-C> TO TERMINATE\n"); printf("TYPE <CTRL-C> TO TERMINATE\n");
itti_wait_tasks_end(); itti_wait_tasks_end(NULL);
logClean(); logClean();
printf("Bye.\n"); printf("Bye.\n");
......
...@@ -733,7 +733,7 @@ int main( int argc, char **argv ) { ...@@ -733,7 +733,7 @@ int main( int argc, char **argv ) {
// wait for end of program // wait for end of program
printf("Entering ITTI signals handler\n"); printf("Entering ITTI signals handler\n");
printf("TYPE <CTRL-C> TO TERMINATE\n"); printf("TYPE <CTRL-C> TO TERMINATE\n");
itti_wait_tasks_end(); itti_wait_tasks_end(NULL);
printf("Returned from ITTI signal handler\n"); printf("Returned from ITTI signal handler\n");
oai_exit=1; oai_exit=1;
printf("oai_exit=%d\n",oai_exit); printf("oai_exit=%d\n",oai_exit);
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */ #define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h> #include <sched.h>
#include <stdbool.h>
#include <signal.h>
#include "T.h" #include "T.h"
#include "assertions.h" #include "assertions.h"
...@@ -402,6 +404,27 @@ void *rrc_enb_process_msg(void *notUsed) { ...@@ -402,6 +404,27 @@ void *rrc_enb_process_msg(void *notUsed) {
return NULL; return NULL;
} }
static bool stop_immediately = false;
static void trigger_stop(int sig)
{
if (!oai_exit)
itti_wait_tasks_unblock();
}
static void trigger_deregistration(int sig)
{
if (!stop_immediately) {
MessageDef *msg = itti_alloc_new_message(TASK_RRC_UE_SIM, 0, NAS_DEREGISTRATION_REQ);
itti_send_msg_to_task(TASK_NAS_NRUE, 0, msg);
stop_immediately = true;
static const char m[] = "Press ^C again to trigger immediate shutdown\n";
__attribute__((unused)) int unused = write(STDOUT_FILENO, m, sizeof(m) - 1);
signal(SIGALRM, trigger_stop);
alarm(5);
} else {
itti_wait_tasks_unblock();
}
}
static void get_channel_model_mode() { static void get_channel_model_mode() {
paramdef_t GNBParams[] = GNBPARAMS_DESC; paramdef_t GNBParams[] = GNBPARAMS_DESC;
config_get(GNBParams, sizeof(GNBParams)/sizeof(paramdef_t), NULL); config_get(GNBParams, sizeof(GNBParams)/sizeof(paramdef_t), NULL);
...@@ -431,7 +454,7 @@ int main( int argc, char **argv ) { ...@@ -431,7 +454,7 @@ int main( int argc, char **argv ) {
if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == NULL) { if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == NULL) {
exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
} }
set_softmodem_sighandler(); //set_softmodem_sighandler();
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
memset(openair0_cfg,0,sizeof(openair0_config_t)*MAX_CARDS); memset(openair0_cfg,0,sizeof(openair0_config_t)*MAX_CARDS);
memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs); memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
...@@ -555,15 +578,28 @@ int main( int argc, char **argv ) { ...@@ -555,15 +578,28 @@ int main( int argc, char **argv ) {
// Sleep a while before checking all parameters have been used // Sleep a while before checking all parameters have been used
// Some are used directly in external threads, asynchronously // Some are used directly in external threads, asynchronously
sleep(20); sleep(2);
config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS); config_check_unknown_cmdlineopt(CONFIG_CHECKALLSECTIONS);
while(true) // wait for end of program
sleep(3600); printf("Entering ITTI signals handler\n");
printf("TYPE <CTRL-C> TO TERMINATE\n");
itti_wait_tasks_end(trigger_deregistration);
printf("Returned from ITTI signal handler\n");
oai_exit=1;
printf("oai_exit=%d\n",oai_exit);
if (ouput_vcd) if (ouput_vcd)
vcd_signal_dumper_close(); vcd_signal_dumper_close();
if (PHY_vars_UE_g && PHY_vars_UE_g[0]) {
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
PHY_VARS_NR_UE *phy_vars = PHY_vars_UE_g[0][CC_id];
if (phy_vars && phy_vars->rfdevice.trx_end_func)
phy_vars->rfdevice.trx_end_func(&phy_vars->rfdevice);
}
}
return 0; return 0;
} }
......
...@@ -327,6 +327,13 @@ typedef struct nas_establish_req_s { ...@@ -327,6 +327,13 @@ typedef struct nas_establish_req_s {
as_nas_info_t initialNasMsg; /* Initial NAS message to transfer */ as_nas_info_t initialNasMsg; /* Initial NAS message to transfer */
} nas_establish_req_t; } nas_establish_req_t;
/*
* fill me
*/
typedef struct nas_deregistration_req_s {
// fill me
} nas_deregistration_req_t;
/* /*
* AS->NAS - NAS signalling connection establishment indication * AS->NAS - NAS signalling connection establishment indication
* AS transfers the initial NAS message to the NAS. * AS transfers the initial NAS message to the NAS.
......
...@@ -62,6 +62,7 @@ MESSAGE_DEF(NAS_KENB_REFRESH_REQ, MESSAGE_PRIORITY_MED, NasKenbRefre ...@@ -62,6 +62,7 @@ MESSAGE_DEF(NAS_KENB_REFRESH_REQ, MESSAGE_PRIORITY_MED, NasKenbRefre
MESSAGE_DEF(NAS_CELL_SELECTION_REQ, MESSAGE_PRIORITY_MED, NasCellSelectionReq, nas_cell_selection_req) MESSAGE_DEF(NAS_CELL_SELECTION_REQ, MESSAGE_PRIORITY_MED, NasCellSelectionReq, nas_cell_selection_req)
MESSAGE_DEF(NAS_CONN_ESTABLI_REQ, MESSAGE_PRIORITY_MED, NasConnEstabliReq, nas_conn_establi_req) MESSAGE_DEF(NAS_CONN_ESTABLI_REQ, MESSAGE_PRIORITY_MED, NasConnEstabliReq, nas_conn_establi_req)
MESSAGE_DEF(NAS_UPLINK_DATA_REQ, MESSAGE_PRIORITY_MED, NasUlDataReq, nas_ul_data_req) MESSAGE_DEF(NAS_UPLINK_DATA_REQ, MESSAGE_PRIORITY_MED, NasUlDataReq, nas_ul_data_req)
MESSAGE_DEF(NAS_DEREGISTRATION_REQ, MESSAGE_PRIORITY_MED, NasDeregistrationReq, nas_deregistration_req)
MESSAGE_DEF(NAS_RAB_ESTABLI_RSP, MESSAGE_PRIORITY_MED, NasRabEstRsp, nas_rab_est_rsp) MESSAGE_DEF(NAS_RAB_ESTABLI_RSP, MESSAGE_PRIORITY_MED, NasRabEstRsp, nas_rab_est_rsp)
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
#define NAS_CELL_SELECTION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_cell_selection_req #define NAS_CELL_SELECTION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_cell_selection_req
#define NAS_CONN_ESTABLI_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_conn_establi_req #define NAS_CONN_ESTABLI_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_conn_establi_req
#define NAS_UPLINK_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_ul_data_req #define NAS_UPLINK_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_ul_data_req
#define NAS_DEREGISTRATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_deregistration_req
#define NAS_RAB_ESTABLI_RSP(mSGpTR) (mSGpTR)->ittiMsg.nas_rab_est_rsp #define NAS_RAB_ESTABLI_RSP(mSGpTR) (mSGpTR)->ittiMsg.nas_rab_est_rsp
...@@ -441,6 +442,7 @@ typedef kenb_refresh_req_t NasKenbRefreshReq; ...@@ -441,6 +442,7 @@ typedef kenb_refresh_req_t NasKenbRefreshReq;
typedef cell_info_req_t NasCellSelectionReq; typedef cell_info_req_t NasCellSelectionReq;
typedef nas_establish_req_t NasConnEstabliReq; typedef nas_establish_req_t NasConnEstabliReq;
typedef ul_info_transfer_req_t NasUlDataReq; typedef ul_info_transfer_req_t NasUlDataReq;
typedef nas_deregistration_req_t NasDeregistrationReq;
typedef rab_establish_rsp_t NasRabEstRsp; typedef rab_establish_rsp_t NasRabEstRsp;
......
...@@ -3275,41 +3275,26 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info, ...@@ -3275,41 +3275,26 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info,
// check if LCID is valid at current time. // check if LCID is valid at current time.
case DL_SCH_LCID_DCCH1: case DL_SCH_LCID_DCCH1:
// check if LCID is valid at current time. // check if LCID is valid at current time.
case DL_SCH_LCID_DTCH ... (DL_SCH_LCID_DTCH + 28):
if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len))
return;
LOG_D(NR_MAC, "%4d.%2d : DLSCH -> LCID %d %d bytes\n", frameP, slot, rx_lcid, mac_len);
mac_rlc_data_ind(module_idP,
mac->crnti,
gNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
rx_lcid,
(char *)(pduP + mac_subheader_len),
mac_len,
1,
NULL);
break;
default: default:
{ LOG_W(MAC, "unknown lcid %02x\n", rx_lcid);
if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) break;
return;
LOG_D(NR_MAC, "[UE %d] %4d.%2d : DLSCH -> DL-DTCH %d (gNB %d, %d bytes)\n", module_idP, frameP, slot, rx_lcid, gNB_index, mac_len);
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
LOG_T(MAC, "[UE %d] First 32 bytes of DLSCH : \n", module_idP);
for (i = 0; i < 32; i++)
LOG_T(MAC, "%x.", (pduP + mac_subheader_len)[i]);
LOG_T(MAC, "\n");
#endif
if (rx_lcid < NB_RB_MAX && rx_lcid >= DL_SCH_LCID_DCCH) {
mac_rlc_data_ind(module_idP,
mac->crnti,
gNB_index,
frameP,
ENB_FLAG_NO,
MBMS_FLAG_NO,
rx_lcid,
(char *) (pduP + mac_subheader_len),
mac_len,
1,
NULL);
} else {
LOG_E(MAC, "[UE %d] Frame %d : unknown LCID %d (gNB %d)\n", module_idP, frameP, rx_lcid, gNB_index);
}
break;
}
} }
pduP += ( mac_subheader_len + mac_len ); pduP += ( mac_subheader_len + mac_len );
pdu_len -= ( mac_subheader_len + mac_len ); pdu_len -= ( mac_subheader_len + mac_len );
......
...@@ -774,7 +774,7 @@ srb_found: ...@@ -774,7 +774,7 @@ srb_found:
//printf("\n"); //printf("\n");
if ((RC.nrrrc == NULL) || (!NODE_IS_CU(node_type))) { if ((RC.nrrrc == NULL) || (!NODE_IS_CU(node_type))) {
if (entity->is_gnb) { if (entity->is_gnb) {
f1ap_dl_rrc_message_t dl_rrc = {.old_gNB_DU_ue_id = 0xFFFFFF, .rrc_container = (uint8_t *)buf, .rrc_container_length = size, .rnti = ue->rntiMaybeUEid, .srb_id = DCCH}; f1ap_dl_rrc_message_t dl_rrc = {.old_gNB_DU_ue_id = 0xFFFFFF, .rrc_container = (uint8_t *)buf, .rrc_container_length = size, .rnti = ue->rntiMaybeUEid, .srb_id = srb_id};
gNB_RRC_INST *rrc = RC.nrrrc[0]; gNB_RRC_INST *rrc = RC.nrrrc[0];
rrc->mac_rrc.dl_rrc_message_transfer(0, &dl_rrc); rrc->mac_rrc.dl_rrc_message_transfer(0, &dl_rrc);
} else { // UE } else { // UE
......
...@@ -3687,6 +3687,15 @@ rrc_gNB_generate_RRCRelease( ...@@ -3687,6 +3687,15 @@ rrc_gNB_generate_RRCRelease(
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(ctxt_pP->instance, ue_context_pP->ue_context.gNB_ue_ngap_id); rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(ctxt_pP->instance, ue_context_pP->ue_context.gNB_ue_ngap_id);
ue_context_pP->ue_context.ue_release_timer_rrc = 1; ue_context_pP->ue_context.ue_release_timer_rrc = 1;
/* TODO: 38.331 says for RRC Release that the UE should release everything
* after 60ms or if lower layers acked receipt of release. Hence, from the
* gNB POV, we can free the UE's RRC context as soon as we sent the msg.
* Currently, without the F1 interface, the ue_release timer expiration also
* triggers MAC, so we give it some time. If we send an F1 UE Context release
* message, we can free it immediately. The MAC should release it after these
* 60ms, or the ack of the DLSCH transmission. */
ue_context_pP->ue_context.ue_release_timer_thres_rrc = 5;
LOG_I(RRC, "delaying UE %ld context removal by 5ms\n", ctxt_pP->rntiMaybeUEid);
if (NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)) { if (NODE_IS_CU(RC.nrrrc[ctxt_pP->module_id]->node_type)) {
uint8_t *message_buffer = itti_malloc (TASK_RRC_GNB, TASK_CU_F1, size); uint8_t *message_buffer = itti_malloc (TASK_RRC_GNB, TASK_CU_F1, size);
......
...@@ -1400,7 +1400,8 @@ static void rrc_ue_generate_RRCSetupComplete( ...@@ -1400,7 +1400,8 @@ static void rrc_ue_generate_RRCSetupComplete(
if (get_softmodem_params()->sa) { if (get_softmodem_params()->sa) {
as_nas_info_t initialNasMsg; as_nas_info_t initialNasMsg;
generateRegistrationRequest(&initialNasMsg, ctxt_pP->module_id); nr_ue_nas_t *nas = get_ue_nas_info(ctxt_pP->module_id);
generateRegistrationRequest(&initialNasMsg, nas);
nas_msg = (char*)initialNasMsg.data; nas_msg = (char*)initialNasMsg.data;
nas_msg_length = initialNasMsg.length; nas_msg_length = initialNasMsg.length;
} else { } else {
...@@ -2256,11 +2257,9 @@ nr_rrc_ue_establish_srb2( ...@@ -2256,11 +2257,9 @@ nr_rrc_ue_establish_srb2(
NR_DL_DCCH_Message_t *dl_dcch_msg = NULL; NR_DL_DCCH_Message_t *dl_dcch_msg = NULL;
MessageDef *msg_p; MessageDef *msg_p;
if (Srb_id != 1) { if (Srb_id != 1 && Srb_id != 2) {
LOG_E(NR_RRC,"[UE %d] Frame %d: Received message on DL-DCCH (SRB%ld), should not have ...\n", LOG_E(NR_RRC,"[UE %d] Frame %d: Received message on DL-DCCH (SRB%ld), should not have ...\n",
ctxt_pP->module_id, ctxt_pP->frame, Srb_id); ctxt_pP->module_id, ctxt_pP->frame, Srb_id);
} else {
LOG_D(NR_RRC, "Received message on SRB%ld\n", Srb_id);
} }
LOG_D(NR_RRC, "Decoding DL-DCCH Message\n"); LOG_D(NR_RRC, "Decoding DL-DCCH Message\n");
...@@ -2315,7 +2314,7 @@ nr_rrc_ue_establish_srb2( ...@@ -2315,7 +2314,7 @@ nr_rrc_ue_establish_srb2(
NR_RRCRelease_IEs__deprioritisationReq__deprioritisationType_frequency; NR_RRCRelease_IEs__deprioritisationReq__deprioritisationType_frequency;
} }
itti_send_msg_to_task(TASK_NAS_UE, ctxt_pP->instance, msg_p); itti_send_msg_to_task(TASK_NAS_NRUE, ctxt_pP->instance, msg_p);
break; break;
case NR_DL_DCCH_MessageType__c1_PR_ueCapabilityEnquiry: case NR_DL_DCCH_MessageType__c1_PR_ueCapabilityEnquiry:
LOG_I(NR_RRC, "[UE %d] Received Capability Enquiry (gNB %d)\n", ctxt_pP->module_id,gNB_indexP); LOG_I(NR_RRC, "[UE %d] Received Capability Enquiry (gNB %d)\n", ctxt_pP->module_id,gNB_indexP);
......
/*
* 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 RegistrationRequest.c
* \brief registration request procedures for gNB
* \author Yoshio INOUE, Masayuki HARADA
* \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com
* \date 2020
* \version 0.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "FGSDeregistrationRequestUEOriginating.h"
int encode_fgs_deregistration_request_ue_originating(fgs_deregistration_request_ue_originating_msg *drr,
uint8_t *buffer,
uint32_t len)
{
int encoded = 0;
FGSDeregistrationType *dt = &drr->deregistrationtype;
*(buffer + encoded) = ((dt->switchoff & 0x1) << 7)
| ((dt->reregistration_required & 0x1) << 6)
| ((dt->access_type & 0x3) << 4);
int encode_result;
if ((encode_result = encode_nas_key_set_identifier(&drr->naskeysetidentifier, 0, buffer + encoded, len - encoded)) < 0)
return encode_result;
encoded++;
if ((encode_result = encode_5gs_mobile_identity(&drr->fgsmobileidentity, 0, buffer + encoded, len - encoded)) < 0)
return encode_result;
else
encoded += encode_result;
return encoded;
}
/*
* 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 FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING_H_
#define FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING_H_
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "ExtendedProtocolDiscriminator.h"
#include "SecurityHeaderType.h"
#include "SpareHalfOctet.h"
#include "MessageType.h"
#include "FGSDeregistrationType.h"
#include "NasKeySetIdentifier.h"
#include "FGSMobileIdentity.h"
/*
* Message name: De-registration request (UE originating de-registration)
* Description: This message is sent by the UE to the AMF. See TS24.501 table 8.2.12.1.1.
* Significance: dual
* Direction: UE to network
*/
typedef struct fgs_deregistration_request_ue_originating_msg_tag {
/* Mandatory fields */
ExtendedProtocolDiscriminator protocoldiscriminator;
SecurityHeaderType securityheadertype: 4;
SpareHalfOctet sparehalfoctet: 4;
MessageType messagetype;
FGSDeregistrationType deregistrationtype;
NasKeySetIdentifier naskeysetidentifier;
FGSMobileIdentity fgsmobileidentity;
} fgs_deregistration_request_ue_originating_msg;
int encode_fgs_deregistration_request_ue_originating(fgs_deregistration_request_ue_originating_msg *registrationrequest,
uint8_t *buffer,
uint32_t len);
#endif /* ! defined(REGISTRATION_REQUEST_H_) */
...@@ -50,6 +50,16 @@ int decode_registration_accept(registration_accept_msg *registration_accept, uin ...@@ -50,6 +50,16 @@ int decode_registration_accept(registration_accept_msg *registration_accept, uin
decoded += decoded_result; decoded += decoded_result;
if (decoded < len && buffer[decoded] == 0x77) {
registration_accept->guti = calloc(1, sizeof(*registration_accept->guti));
if (!registration_accept->guti)
return -1;
int mi_dec = decode_5gs_mobile_identity(registration_accept->guti, 0x77, buffer + decoded, len - decoded);
if (mi_dec < 0)
return -1;
decoded += mi_dec;
}
// todo ,Decoding optional fields // todo ,Decoding optional fields
return decoded; return decoded;
} }
...@@ -64,6 +74,13 @@ int encode_registration_accept(registration_accept_msg *registration_accept, uin ...@@ -64,6 +74,13 @@ int encode_registration_accept(registration_accept_msg *registration_accept, uin
*(buffer + encoded) = encode_fgs_registration_result(&registration_accept->fgsregistrationresult); *(buffer + encoded) = encode_fgs_registration_result(&registration_accept->fgsregistrationresult);
encoded = encoded + 2; encoded = encoded + 2;
if (registration_accept->guti) {
int mi_enc = encode_5gs_mobile_identity(registration_accept->guti, 0x77, buffer + encoded, len - encoded);
if (mi_enc < 0)
return mi_enc;
encoded += mi_enc;
}
// todo ,Encoding optional fields // todo ,Encoding optional fields
LOG_FUNC_RETURN(encoded); LOG_FUNC_RETURN(encoded);
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "SpareHalfOctet.h" #include "SpareHalfOctet.h"
#include "MessageType.h" #include "MessageType.h"
#include "FGSRegistrationResult.h" #include "FGSRegistrationResult.h"
#include "FGSMobileIdentity.h"
#ifndef REGISTRATION_ACCEPT_H_ #ifndef REGISTRATION_ACCEPT_H_
#define REGISTRATION_ACCEPT_H_ #define REGISTRATION_ACCEPT_H_
...@@ -56,6 +57,9 @@ typedef struct registration_accept_msg_tag { ...@@ -56,6 +57,9 @@ typedef struct registration_accept_msg_tag {
SpareHalfOctet sparehalfoctet:4; SpareHalfOctet sparehalfoctet:4;
MessageType messagetype; MessageType messagetype;
FGSRegistrationResult fgsregistrationresult; FGSRegistrationResult fgsregistrationresult;
/* Optional fields */
FGSMobileIdentity *guti;
} registration_accept_msg; } registration_accept_msg;
int decode_registration_accept(registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); int decode_registration_accept(registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len);
......
/*
* 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 FGS_DEREGISTRATION_TYPE_H_
#define FGS_DEREGISTRATION_TYPE_H_
#include <stdint.h>
#include "OctetString.h"
#define FGS_DEREGISTRATION_TYPE_MINIMUM_LENGTH 1
#define FGS_DEREGISTRATION_TYPE_MAXIMUM_LENGTH 1
typedef struct FGSDeregistrationType_tag {
#define NORMAL_DEREGISTRATION 0
#define SWITCH_OFF 1
uint8_t switchoff: 1;
#define REREGISTRATION_NOT_REQUIRED 0
#define REREGISTRATION_REQUIRED 1
uint8_t reregistration_required: 1;
#define TGPP_ACCESS 1
#define NON_TGPP_ACCESS 2
#define TGPP_AND_NON_TGPP_ACCESS 3
uint8_t access_type: 2;
} FGSDeregistrationType;
int encode_fgs_deregistration_type(FGSDeregistrationType *dt, uint8_t iei, uint8_t *buffer, uint32_t len);
#endif /* FGS_DEREGISTRATION_TYPE_H_ */
...@@ -54,8 +54,8 @@ int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei ...@@ -54,8 +54,8 @@ int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei
decoded++; decoded++;
} }
ielen = *(buffer + decoded); ielen = *(uint16_t*)(buffer + decoded); /* length is two bytes */
decoded++; decoded += 2;
CHECK_LENGTH_DECODER(len - decoded, ielen); CHECK_LENGTH_DECODER(len - decoded, ielen);
uint8_t typeofidentity = *(buffer + decoded) & 0x7; uint8_t typeofidentity = *(buffer + decoded) & 0x7;
...@@ -63,6 +63,8 @@ int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei ...@@ -63,6 +63,8 @@ int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei
if (typeofidentity == FGS_MOBILE_IDENTITY_5G_GUTI) { if (typeofidentity == FGS_MOBILE_IDENTITY_5G_GUTI) {
decoded_rc = decode_guti_5gs_mobile_identity(&fgsmobileidentity->guti, decoded_rc = decode_guti_5gs_mobile_identity(&fgsmobileidentity->guti,
buffer + decoded); buffer + decoded);
} else {
AssertFatal(false, "Mobile Identity encoding of type %d not implemented\n", typeofidentity);
} }
if (decoded_rc < 0) { if (decoded_rc < 0) {
......
...@@ -364,6 +364,12 @@ typedef struct __attribute__((packed)) { ...@@ -364,6 +364,12 @@ typedef struct __attribute__((packed)) {
} securityModeCommand_t; } securityModeCommand_t;
typedef struct __attribute__((packed)) {
Extendedprotocoldiscriminator_t epd: 8;
Security_header_t sh: 8;
SGSmobilitymanagementmessages_t mt: 8;
} deregistrationRequestUEOriginating_t;
typedef struct { typedef struct {
uicc_t *uicc; uicc_t *uicc;
} nr_user_nas_t; } nr_user_nas_t;
...@@ -371,7 +377,7 @@ typedef struct { ...@@ -371,7 +377,7 @@ typedef struct {
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed") #define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
#define myCalloc(var, type) type * var=(type*)calloc(sizeof(type),1); #define myCalloc(var, type) type * var=(type*)calloc(sizeof(type),1);
#define arrayCpy(tO, FroM) STATIC_ASSERT(sizeof(tO) == sizeof(FroM)) ; memcpy(tO, FroM, sizeof(tO)) #define arrayCpy(tO, FroM) STATIC_ASSERT(sizeof(tO) == sizeof(FroM)) ; memcpy(tO, FroM, sizeof(tO))
int resToresStar(uint8_t *msg, uicc_t* uicc); int resToresStar(uint8_t *msg, const uicc_t* uicc);
int identityResponse(void **msg, nr_user_nas_t *UE); int identityResponse(void **msg, nr_user_nas_t *UE);
int authenticationResponse(void **msg, nr_user_nas_t *UE); int authenticationResponse(void **msg, nr_user_nas_t *UE);
......
...@@ -39,7 +39,7 @@ void servingNetworkName(uint8_t *msg, char * imsiStr, int nmc_size) { ...@@ -39,7 +39,7 @@ void servingNetworkName(uint8_t *msg, char * imsiStr, int nmc_size) {
memcpy(msg+13, imsiStr, 3); memcpy(msg+13, imsiStr, 3);
} }
int resToresStar(uint8_t *msg, uicc_t* uicc) { int resToresStar(uint8_t *msg, const uicc_t* uicc) {
// TS 33.220 annex B.2 => FC=0x6B in TS 33.501 annex A.4 // TS 33.220 annex B.2 => FC=0x6B in TS 33.501 annex A.4
//input S to KDF //input S to KDF
uint8_t S[128]= {0}; uint8_t S[128]= {0};
......
...@@ -42,9 +42,10 @@ ...@@ -42,9 +42,10 @@
#include "kdf.h" #include "kdf.h"
#include "PduSessionEstablishRequest.h" #include "PduSessionEstablishRequest.h"
#include "PduSessionEstablishmentAccept.h" #include "PduSessionEstablishmentAccept.h"
#include "RegistrationAccept.h"
#include "FGSDeregistrationRequestUEOriginating.h"
#include "intertask_interface.h" #include "intertask_interface.h"
#include "openair2/RRC/NAS/nas_config.h" #include "openair2/RRC/NAS/nas_config.h"
#include <openair3/UICC/usim_interface.h>
#include <openair3/NAS/COMMON/NR_NAS_defs.h> #include <openair3/NAS/COMMON/NR_NAS_defs.h>
#include <openair1/PHY/phy_extern_nr_ue.h> #include <openair1/PHY/phy_extern_nr_ue.h>
#include <openair1/SIMULATION/ETH_TRANSPORT/proto.h> #include <openair1/SIMULATION/ETH_TRANSPORT/proto.h>
...@@ -54,7 +55,7 @@ uint8_t *registration_request_buf; ...@@ -54,7 +55,7 @@ uint8_t *registration_request_buf;
uint32_t registration_request_len; uint32_t registration_request_len;
extern char *baseNetAddress; extern char *baseNetAddress;
extern uint16_t NB_UE_INST; extern uint16_t NB_UE_INST;
static ue_sa_security_key_t ** ue_security_key; static nr_ue_nas_t nr_ue_nas;
static int nas_protected_security_header_encode( static int nas_protected_security_header_encode(
char *buffer, char *buffer,
...@@ -104,6 +105,50 @@ static int _nas_mm_msg_encode_header(const mm_msg_header_t *header, ...@@ -104,6 +105,50 @@ static int _nas_mm_msg_encode_header(const mm_msg_header_t *header,
return (size); return (size);
} }
static int fill_suci(FGSMobileIdentity *mi, const uicc_t *uicc)
{
mi->suci.typeofidentity = FGS_MOBILE_IDENTITY_SUCI;
mi->suci.mncdigit1 = uicc->nmc_size == 2 ? uicc->imsiStr[3] - '0' : uicc->imsiStr[4] - '0';
mi->suci.mncdigit2 = uicc->nmc_size == 2 ? uicc->imsiStr[4] - '0' : uicc->imsiStr[5] - '0';
mi->suci.mncdigit3 = uicc->nmc_size == 2 ? 0xF : uicc->imsiStr[3] - '0';
mi->suci.mccdigit1 = uicc->imsiStr[0] - '0';
mi->suci.mccdigit2 = uicc->imsiStr[1] - '0';
mi->suci.mccdigit3 = uicc->imsiStr[2] - '0';
memcpy(mi->suci.schemeoutput, uicc->imsiStr + 3 + uicc->nmc_size, strlen(uicc->imsiStr) - (3 + uicc->nmc_size));
return sizeof(Suci5GSMobileIdentity_t);
}
static int fill_guti(FGSMobileIdentity *mi, const Guti5GSMobileIdentity_t *guti)
{
AssertFatal(guti != NULL, "UE has no GUTI\n");
mi->guti = *guti;
return 13;
}
static int fill_imeisv(FGSMobileIdentity *mi, const uicc_t *uicc)
{
int i=0;
mi->imeisv.typeofidentity = FGS_MOBILE_IDENTITY_IMEISV;
mi->imeisv.digittac01 = getImeisvDigit(uicc, i++);
mi->imeisv.digittac02 = getImeisvDigit(uicc, i++);
mi->imeisv.digittac03 = getImeisvDigit(uicc, i++);
mi->imeisv.digittac04 = getImeisvDigit(uicc, i++);
mi->imeisv.digittac05 = getImeisvDigit(uicc, i++);
mi->imeisv.digittac06 = getImeisvDigit(uicc, i++);
mi->imeisv.digittac07 = getImeisvDigit(uicc, i++);
mi->imeisv.digittac08 = getImeisvDigit(uicc, i++);
mi->imeisv.digit09 = getImeisvDigit(uicc, i++);
mi->imeisv.digit10 = getImeisvDigit(uicc, i++);
mi->imeisv.digit11 = getImeisvDigit(uicc, i++);
mi->imeisv.digit12 = getImeisvDigit(uicc, i++);
mi->imeisv.digit13 = getImeisvDigit(uicc, i++);
mi->imeisv.digit14 = getImeisvDigit(uicc, i++);
mi->imeisv.digitsv1 = getImeisvDigit(uicc, i++);
mi->imeisv.digitsv2 = getImeisvDigit(uicc, i++);
mi->imeisv.spare = 0x0f;
mi->imeisv.oddeven = 1;
return 19;
}
int mm_msg_encode(MM_msg *mm_msg, uint8_t *buffer, uint32_t len) { int mm_msg_encode(MM_msg *mm_msg, uint8_t *buffer, uint32_t len) {
LOG_FUNC_IN; LOG_FUNC_IN;
...@@ -140,6 +185,9 @@ int mm_msg_encode(MM_msg *mm_msg, uint8_t *buffer, uint32_t len) { ...@@ -140,6 +185,9 @@ int mm_msg_encode(MM_msg *mm_msg, uint8_t *buffer, uint32_t len) {
case FGS_UPLINK_NAS_TRANSPORT: case FGS_UPLINK_NAS_TRANSPORT:
encode_result = encode_fgs_uplink_nas_transport(&mm_msg->uplink_nas_transport, buffer, len); encode_result = encode_fgs_uplink_nas_transport(&mm_msg->uplink_nas_transport, buffer, len);
break; break;
case FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING:
encode_result = encode_fgs_deregistration_request_ue_originating(&mm_msg->fgs_deregistration_request_ue_originating, buffer, len);
break;
default: default:
LOG_TRACE(ERROR, "EMM-MSG - Unexpected message type: 0x%x", LOG_TRACE(ERROR, "EMM-MSG - Unexpected message type: 0x%x",
mm_msg->header.message_type); mm_msg->header.message_type);
...@@ -303,25 +351,18 @@ void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){ ...@@ -303,25 +351,18 @@ void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){
printf("\n"); printf("\n");
} }
void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) { void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) {
uint8_t ak[6]; uint8_t ak[6];
uint8_t sqn[6]; uint8_t sqn[6];
AssertFatal (Mod_id < NB_UE_INST, "Failed, Mod_id %d is over NB_UE_INST!\n", Mod_id); DevAssert(nas != NULL);
if(ue_security_key[Mod_id]){ uint8_t *kausf = nas->security.kausf;
// clear old key uint8_t *kseaf = nas->security.kseaf;
memset(ue_security_key[Mod_id],0,sizeof(ue_sa_security_key_t)); uint8_t *kamf = nas->security.kamf;
}else{ uint8_t *knas_int = nas->security.knas_int;
// Allocate new memory uint8_t *output = nas->security.res;
ue_security_key[Mod_id]=(ue_sa_security_key_t *)calloc(1,sizeof(ue_sa_security_key_t)); uint8_t *rand = nas->security.rand;
} uint8_t *kgnb = nas->security.kgnb;
uint8_t *kausf = ue_security_key[Mod_id]->kausf;
uint8_t *kseaf = ue_security_key[Mod_id]->kseaf;
uint8_t *kamf = ue_security_key[Mod_id]->kamf;
uint8_t *knas_int = ue_security_key[Mod_id]->knas_int;
uint8_t *output = ue_security_key[Mod_id]->res;
uint8_t *rand = ue_security_key[Mod_id]->rand;
uint8_t *kgnb = ue_security_key[Mod_id]->kgnb;
// get RAND for authentication request // get RAND for authentication request
for(int index = 0; index < 16;index++){ for(int index = 0; index < 16;index++){
...@@ -330,17 +371,17 @@ void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) { ...@@ -330,17 +371,17 @@ void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) {
uint8_t resTemp[16]; uint8_t resTemp[16];
uint8_t ck[16], ik[16]; uint8_t ck[16], ik[16];
f2345(uicc->key, rand, resTemp, ck, ik, ak, uicc->opc); f2345(nas->uicc->key, rand, resTemp, ck, ik, ak, nas->uicc->opc);
transferRES(ck, ik, resTemp, rand, output, uicc); transferRES(ck, ik, resTemp, rand, output, nas->uicc);
for(int index = 0; index < 6; index++){ for(int index = 0; index < 6; index++){
sqn[index] = buf[26+index]; sqn[index] = buf[26+index];
} }
derive_kausf(ck, ik, sqn, kausf, uicc); derive_kausf(ck, ik, sqn, kausf, nas->uicc);
derive_kseaf(kausf, kseaf, uicc); derive_kseaf(kausf, kseaf, nas->uicc);
derive_kamf(kseaf, kamf, 0x0000, uicc); derive_kamf(kseaf, kamf, 0x0000, nas->uicc);
derive_knas(0x02, 2, kamf, knas_int); derive_knas(0x02, 2, kamf, knas_int);
derive_kgnb(kamf,0,kgnb); derive_kgnb(kamf,0,kgnb);
...@@ -370,11 +411,17 @@ void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) { ...@@ -370,11 +411,17 @@ void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) {
printf("\n"); printf("\n");
} }
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, int Mod_id) { nr_ue_nas_t *get_ue_nas_info(module_id_t module_id)
{
DevAssert(module_id == 0);
return &nr_ue_nas;
}
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
{
int size = sizeof(mm_msg_header_t); int size = sizeof(mm_msg_header_t);
fgs_nas_message_t nas_msg={0}; fgs_nas_message_t nas_msg={0};
MM_msg *mm_msg; MM_msg *mm_msg;
uicc_t * uicc=checkUicc(Mod_id);
mm_msg = &nas_msg.plain.mm_msg; mm_msg = &nas_msg.plain.mm_msg;
// set header // set header
...@@ -393,37 +440,10 @@ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, int Mod_id) { ...@@ -393,37 +440,10 @@ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, int Mod_id) {
mm_msg->registration_request.fgsregistrationtype = INITIAL_REGISTRATION; mm_msg->registration_request.fgsregistrationtype = INITIAL_REGISTRATION;
mm_msg->registration_request.naskeysetidentifier.naskeysetidentifier = 1; mm_msg->registration_request.naskeysetidentifier.naskeysetidentifier = 1;
size += 1; size += 1;
if(0){ if(nas->guti){
mm_msg->registration_request.fgsmobileidentity.guti.typeofidentity = FGS_MOBILE_IDENTITY_5G_GUTI; size += fill_guti(&mm_msg->registration_request.fgsmobileidentity, nas->guti);
mm_msg->registration_request.fgsmobileidentity.guti.amfregionid = 0xca;
mm_msg->registration_request.fgsmobileidentity.guti.amfpointer = 0;
mm_msg->registration_request.fgsmobileidentity.guti.amfsetid = 1016;
mm_msg->registration_request.fgsmobileidentity.guti.tmsi = 10;
mm_msg->registration_request.fgsmobileidentity.guti.mncdigit1 =
uicc->nmc_size==2 ? uicc->imsiStr[3]-'0' : uicc->imsiStr[4]-'0';
mm_msg->registration_request.fgsmobileidentity.guti.mncdigit2 =
uicc->nmc_size==2 ? uicc->imsiStr[4]-'0' : uicc->imsiStr[5]-'0';
mm_msg->registration_request.fgsmobileidentity.guti.mncdigit3 =
uicc->nmc_size==2 ? 0xf : uicc->imsiStr[3]-'0';
mm_msg->registration_request.fgsmobileidentity.guti.mccdigit1 = uicc->imsiStr[0]-'0';
mm_msg->registration_request.fgsmobileidentity.guti.mccdigit2 = uicc->imsiStr[1]-'0';
mm_msg->registration_request.fgsmobileidentity.guti.mccdigit3 = uicc->imsiStr[2]-'0';
size += 13;
} else { } else {
mm_msg->registration_request.fgsmobileidentity.suci.typeofidentity = FGS_MOBILE_IDENTITY_SUCI; size += fill_suci(&mm_msg->registration_request.fgsmobileidentity, nas->uicc);
mm_msg->registration_request.fgsmobileidentity.suci.mncdigit1 =
uicc->nmc_size==2 ? uicc->imsiStr[3]-'0' : uicc->imsiStr[4]-'0';
mm_msg->registration_request.fgsmobileidentity.suci.mncdigit2 =
uicc->nmc_size==2 ? uicc->imsiStr[4]-'0' : uicc->imsiStr[5]-'0';
mm_msg->registration_request.fgsmobileidentity.suci.mncdigit3 =
uicc->nmc_size==2 ? 0xf : uicc->imsiStr[3]-'0';
mm_msg->registration_request.fgsmobileidentity.suci.mccdigit1 = uicc->imsiStr[0]-'0';
mm_msg->registration_request.fgsmobileidentity.suci.mccdigit2 = uicc->imsiStr[1]-'0';
mm_msg->registration_request.fgsmobileidentity.suci.mccdigit3 = uicc->imsiStr[2]-'0';
memcpy(mm_msg->registration_request.fgsmobileidentity.suci.schemeoutput, uicc->imsiStr+3+uicc->nmc_size, strlen(uicc->imsiStr) - (3+uicc->nmc_size));
size += sizeof(Suci5GSMobileIdentity_t);
} }
mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT; mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT;
...@@ -471,18 +491,7 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype ...@@ -471,18 +491,7 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype
mm_msg->fgs_identity_response.messagetype = FGS_IDENTITY_RESPONSE; mm_msg->fgs_identity_response.messagetype = FGS_IDENTITY_RESPONSE;
size += 1; size += 1;
if(identitytype == FGS_MOBILE_IDENTITY_SUCI){ if(identitytype == FGS_MOBILE_IDENTITY_SUCI){
mm_msg->fgs_identity_response.fgsmobileidentity.suci.typeofidentity = FGS_MOBILE_IDENTITY_SUCI; size += fill_suci(&mm_msg->fgs_identity_response.fgsmobileidentity, uicc);
mm_msg->fgs_identity_response.fgsmobileidentity.suci.mncdigit1 =
uicc->nmc_size==2 ? uicc->imsiStr[3]-'0' : uicc->imsiStr[4]-'0';
mm_msg->fgs_identity_response.fgsmobileidentity.suci.mncdigit2 =
uicc->nmc_size==2 ? uicc->imsiStr[4]-'0' : uicc->imsiStr[5]-'0';
mm_msg->fgs_identity_response.fgsmobileidentity.suci.mncdigit3 =
uicc->nmc_size==2? 0xF : uicc->imsiStr[3]-'0';
mm_msg->fgs_identity_response.fgsmobileidentity.suci.mccdigit1 = uicc->imsiStr[0]-'0';
mm_msg->fgs_identity_response.fgsmobileidentity.suci.mccdigit2 = uicc->imsiStr[1]-'0';
mm_msg->fgs_identity_response.fgsmobileidentity.suci.mccdigit3 = uicc->imsiStr[2]-'0';
memcpy(mm_msg->registration_request.fgsmobileidentity.suci.schemeoutput, uicc->imsiStr+3+uicc->nmc_size, strlen(uicc->imsiStr) - (3+uicc->nmc_size));
size += sizeof(Suci5GSMobileIdentity_t);
} }
// encode the message // encode the message
...@@ -492,13 +501,13 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype ...@@ -492,13 +501,13 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype
} }
static void generateAuthenticationResp(int Mod_id,as_nas_info_t *initialNasMsg, uint8_t *buf, uicc_t *uicc){ static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *buf)
{
derive_ue_keys(Mod_id,buf,uicc); derive_ue_keys(buf, nas);
OctetString res; OctetString res;
res.length = 16; res.length = 16;
res.value = calloc(1,16); res.value = calloc(1,16);
memcpy(res.value,ue_security_key[Mod_id]->res,16); memcpy(res.value, nas->security.res, 16);
int size = sizeof(mm_msg_header_t); int size = sizeof(mm_msg_header_t);
fgs_nas_message_t nas_msg; fgs_nas_message_t nas_msg;
...@@ -528,39 +537,15 @@ static void generateAuthenticationResp(int Mod_id,as_nas_info_t *initialNasMsg, ...@@ -528,39 +537,15 @@ static void generateAuthenticationResp(int Mod_id,as_nas_info_t *initialNasMsg,
initialNasMsg->length = mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data), size); initialNasMsg->length = mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data), size);
} }
int nas_itti_kgnb_refresh_req(const uint8_t kgnb[32], int instance) { int nas_itti_kgnb_refresh_req(const uint8_t kgnb[32])
{
MessageDef *message_p; MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_KENB_REFRESH_REQ); message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_KENB_REFRESH_REQ);
memcpy(NAS_KENB_REFRESH_REQ(message_p).kenb, kgnb, sizeof(NAS_KENB_REFRESH_REQ(message_p).kenb)); memcpy(NAS_KENB_REFRESH_REQ(message_p).kenb, kgnb, sizeof(NAS_KENB_REFRESH_REQ(message_p).kenb));
return itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p); return itti_send_msg_to_task(TASK_RRC_NRUE, 0, message_p);
}
static int addImeisv(int Mod_id,MM_msg *mm_msg)
{
int i=0;
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.typeofidentity = FGS_MOBILE_IDENTITY_IMEISV;
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac01 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac02 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac03 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac04 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac05 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac06 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac07 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digittac08 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digit09 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digit10 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digit11 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digit12 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digit13 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digit14 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digitsv1 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.digitsv2 = getImeisvDigit(Mod_id,i++);
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.spare = 0x0f;
mm_msg->fgs_security_mode_complete.fgsmobileidentity.imeisv.oddeven = 1;
return 19;
} }
static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg) static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg)
{ {
int size = sizeof(mm_msg_header_t); int size = sizeof(mm_msg_header_t);
fgs_nas_message_t nas_msg; fgs_nas_message_t nas_msg;
...@@ -589,7 +574,7 @@ static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg ...@@ -589,7 +574,7 @@ static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg
mm_msg->fgs_security_mode_complete.messagetype = FGS_SECURITY_MODE_COMPLETE; mm_msg->fgs_security_mode_complete.messagetype = FGS_SECURITY_MODE_COMPLETE;
size += 1; size += 1;
size += addImeisv(Mod_id, mm_msg); size += fill_imeisv(&mm_msg->fgs_security_mode_complete.fgsmobileidentity, nas->uicc);
mm_msg->fgs_security_mode_complete.fgsnasmessagecontainer.nasmessagecontainercontents.value = registration_request_buf; mm_msg->fgs_security_mode_complete.fgsnasmessagecontainer.nasmessagecontainercontents.value = registration_request_buf;
mm_msg->fgs_security_mode_complete.fgsnasmessagecontainer.nasmessagecontainercontents.length = registration_request_len; mm_msg->fgs_security_mode_complete.fgsnasmessagecontainer.nasmessagecontainercontents.length = registration_request_len;
...@@ -602,9 +587,9 @@ static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg ...@@ -602,9 +587,9 @@ static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg
initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len);
stream_cipher.key = ue_security_key[Mod_id]->knas_int; stream_cipher.key = nas->security.knas_int;
stream_cipher.key_length = 16; stream_cipher.key_length = 16;
stream_cipher.count = 0; stream_cipher.count = nas->security.mm_counter++;
stream_cipher.bearer = 1; stream_cipher.bearer = 1;
stream_cipher.direction = 0; stream_cipher.direction = 0;
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6);
...@@ -622,7 +607,32 @@ static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg ...@@ -622,7 +607,32 @@ static void generateSecurityModeComplete(int Mod_id,as_nas_info_t *initialNasMsg
} }
} }
static void generateRegistrationComplete(int Mod_id, as_nas_info_t *initialNasMsg, SORTransparentContainer *sortransparentcontainer) { static void decodeRegistrationAccept(uint8_t *buf, int len, nr_ue_nas_t *nas)
{
registration_accept_msg reg_acc = {0};
/* it seems there is no 5G corresponding emm_msg_decode() function, so here
* we just jump to the right decision */
buf += 7; /* skip security header */
buf += 2; /* skip prot discriminator, security header, half octet */
AssertFatal(*buf == 0x42, "this is not a NAS Registration Accept\n");
buf++;
int decoded = decode_registration_accept(&reg_acc, buf, len);
AssertFatal(decoded > 0, "could not decode registration accept\n");
if (reg_acc.guti) {
AssertFatal(reg_acc.guti->guti.typeofidentity == FGS_MOBILE_IDENTITY_5G_GUTI,
"registration accept 5GS Mobile Identity is not GUTI, but %d\n",
reg_acc.guti->guti.typeofidentity);
nas->guti = malloc(sizeof(nas->guti));
AssertFatal(nas->guti, "out of memory\n");
*nas->guti = reg_acc.guti->guti;
free(reg_acc.guti); /* no proper memory management for NAS decoded messages */
} else {
LOG_W(NAS, "no GUTI in registration accept\n");
}
}
static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, SORTransparentContainer *sortransparentcontainer)
{
//wait send RRCReconfigurationComplete and InitialContextSetupResponse //wait send RRCReconfigurationComplete and InitialContextSetupResponse
sleep(1); sleep(1);
int length = 0; int length = 0;
...@@ -682,9 +692,9 @@ static void generateRegistrationComplete(int Mod_id, as_nas_info_t *initialNasMs ...@@ -682,9 +692,9 @@ static void generateRegistrationComplete(int Mod_id, as_nas_info_t *initialNasMs
} }
initialNasMsg->length = length; initialNasMsg->length = length;
stream_cipher.key = ue_security_key[Mod_id]->knas_int; stream_cipher.key = nas->security.knas_int;
stream_cipher.key_length = 16; stream_cipher.key_length = 16;
stream_cipher.count = 1; stream_cipher.count = nas->security.mm_counter++;
stream_cipher.bearer = 1; stream_cipher.bearer = 1;
stream_cipher.direction = 0; stream_cipher.direction = 0;
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6);
...@@ -715,7 +725,55 @@ void decodeDownlinkNASTransport(as_nas_info_t *initialNasMsg, uint8_t * pdu_buff ...@@ -715,7 +725,55 @@ void decodeDownlinkNASTransport(as_nas_info_t *initialNasMsg, uint8_t * pdu_buff
} }
} }
static void generatePduSessionEstablishRequest(int Mod_id, uicc_t * uicc, as_nas_info_t *initialNasMsg){ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, const nas_deregistration_req_t *req)
{
fgs_nas_message_t nas_msg = {0};
fgs_nas_message_security_protected_t *sp_msg;
sp_msg = &nas_msg.security_protected;
sp_msg->header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
sp_msg->header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
sp_msg->header.message_authentication_code = 0;
sp_msg->header.sequence_number = 2;
int size = sizeof(fgs_nas_message_security_header_t);
fgs_deregistration_request_ue_originating_msg *dereg_req = &sp_msg->plain.mm_msg.fgs_deregistration_request_ue_originating;
dereg_req->protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
size += 1;
dereg_req->securityheadertype = INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX;
size += 1;
dereg_req->messagetype = FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING;
size += 1;
dereg_req->deregistrationtype.switchoff = NORMAL_DEREGISTRATION;
dereg_req->deregistrationtype.reregistration_required = REREGISTRATION_NOT_REQUIRED;
dereg_req->deregistrationtype.access_type = TGPP_ACCESS;
dereg_req->naskeysetidentifier.naskeysetidentifier = 1;
size += 1;
size += fill_guti(&dereg_req->fgsmobileidentity, nas->guti);
// encode the message
initialNasMsg->data = calloc(size, sizeof(Byte_t));
int security_header_len = nas_protected_security_header_encode((char *)(initialNasMsg->data), &nas_msg.header, size);
initialNasMsg->length = security_header_len + mm_msg_encode(&sp_msg->plain.mm_msg, (uint8_t *)(initialNasMsg->data + security_header_len), size - security_header_len);
nas_stream_cipher_t stream_cipher = {
.key = nas->security.knas_int,
.key_length = 16,
.count = nas->security.mm_counter++,
.bearer = 1,
.direction = 0,
.message = (unsigned char *)(initialNasMsg->data + 6),
.blength = (initialNasMsg->length - 6) << 3, /* length in bits */
};
uint8_t mac[4];
nas_stream_encrypt_eia2(&stream_cipher, mac);
for(int i = 0; i < 4; i++)
initialNasMsg->data[2 + i] = mac[i];
}
static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg)
{
//wait send RegistrationComplete //wait send RegistrationComplete
usleep(100*150); usleep(100*150);
int size = 0; int size = 0;
...@@ -766,25 +824,25 @@ static void generatePduSessionEstablishRequest(int Mod_id, uicc_t * uicc, as_nas ...@@ -766,25 +824,25 @@ static void generatePduSessionEstablishRequest(int Mod_id, uicc_t * uicc, as_nas
mm_msg->uplink_nas_transport.pdusessionid = 10; mm_msg->uplink_nas_transport.pdusessionid = 10;
mm_msg->uplink_nas_transport.requesttype = 1; mm_msg->uplink_nas_transport.requesttype = 1;
size += 3; size += 3;
const bool has_nssai_sd = uicc->nssai_sd != 0xffffff; // 0xffffff means "no SD", TS 23.003 const bool has_nssai_sd = nas->uicc->nssai_sd != 0xffffff; // 0xffffff means "no SD", TS 23.003
const size_t nssai_len = has_nssai_sd ? 4 : 1; const size_t nssai_len = has_nssai_sd ? 4 : 1;
mm_msg->uplink_nas_transport.snssai.length = nssai_len; mm_msg->uplink_nas_transport.snssai.length = nssai_len;
//Fixme: it seems there are a lot of memory errors in this: this value was on the stack, //Fixme: it seems there are a lot of memory errors in this: this value was on the stack,
// but pushed in a itti message to another thread // but pushed in a itti message to another thread
// this kind of error seems in many places in 5G NAS // this kind of error seems in many places in 5G NAS
mm_msg->uplink_nas_transport.snssai.value = calloc(1, nssai_len); mm_msg->uplink_nas_transport.snssai.value = calloc(1, nssai_len);
mm_msg->uplink_nas_transport.snssai.value[0] = uicc->nssai_sst; mm_msg->uplink_nas_transport.snssai.value[0] = nas->uicc->nssai_sst;
if (has_nssai_sd) { if (has_nssai_sd) {
mm_msg->uplink_nas_transport.snssai.value[1] = (uicc->nssai_sd >> 16) & 0xFF; mm_msg->uplink_nas_transport.snssai.value[1] = (nas->uicc->nssai_sd >> 16) & 0xFF;
mm_msg->uplink_nas_transport.snssai.value[2] = (uicc->nssai_sd >> 8) & 0xFF; mm_msg->uplink_nas_transport.snssai.value[2] = (nas->uicc->nssai_sd >> 8) & 0xFF;
mm_msg->uplink_nas_transport.snssai.value[3] = (uicc->nssai_sd) & 0xFF; mm_msg->uplink_nas_transport.snssai.value[3] = (nas->uicc->nssai_sd) & 0xFF;
} }
size += 1 + 1 + nssai_len; size += 1 + 1 + nssai_len;
int dnnSize=strlen(uicc->dnnStr); int dnnSize=strlen(nas->uicc->dnnStr);
mm_msg->uplink_nas_transport.dnn.value=calloc(1,dnnSize+1); mm_msg->uplink_nas_transport.dnn.value=calloc(1,dnnSize+1);
mm_msg->uplink_nas_transport.dnn.length = dnnSize + 1; mm_msg->uplink_nas_transport.dnn.length = dnnSize + 1;
mm_msg->uplink_nas_transport.dnn.value[0] = dnnSize; mm_msg->uplink_nas_transport.dnn.value[0] = dnnSize;
memcpy(mm_msg->uplink_nas_transport.dnn.value+1,uicc->dnnStr, dnnSize); memcpy(mm_msg->uplink_nas_transport.dnn.value + 1, nas->uicc->dnnStr, dnnSize);
size += (1+1+dnnSize+1); size += (1+1+dnnSize+1);
// encode the message // encode the message
...@@ -793,9 +851,9 @@ static void generatePduSessionEstablishRequest(int Mod_id, uicc_t * uicc, as_nas ...@@ -793,9 +851,9 @@ static void generatePduSessionEstablishRequest(int Mod_id, uicc_t * uicc, as_nas
initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len);
stream_cipher.key = ue_security_key[Mod_id]->knas_int; stream_cipher.key = nas->security.knas_int;
stream_cipher.key_length = 16; stream_cipher.key_length = 16;
stream_cipher.count = 0; stream_cipher.count = nas->security.sm_counter++;
stream_cipher.bearer = 1; stream_cipher.bearer = 1;
stream_cipher.direction = 0; stream_cipher.direction = 0;
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6); stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6);
...@@ -838,17 +896,27 @@ uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) { ...@@ -838,17 +896,27 @@ uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) {
return msg_type; return msg_type;
} }
static void send_nas_uplink_data_req(instance_t instance, const as_nas_info_t *initial_nas_msg)
{
MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ);
ul_info_transfer_req_t *req = &NAS_UPLINK_DATA_REQ(msg);
req->UEid = instance;
req->nasMsg.data = (uint8_t *) initial_nas_msg->data;
req->nasMsg.length = initial_nas_msg->length;
itti_send_msg_to_task(TASK_RRC_NRUE, instance, msg);
}
void *nas_nrue_task(void *args_p) void *nas_nrue_task(void *args_p)
{ {
MessageDef *msg_p; MessageDef *msg_p;
instance_t instance; instance_t instance;
unsigned int Mod_id;
int result; int result;
uint8_t msg_type = 0; uint8_t msg_type = 0;
uint8_t *pdu_buffer = NULL; uint8_t *pdu_buffer = NULL;
ue_security_key=(ue_sa_security_key_t **)calloc(1,sizeof(ue_sa_security_key_t*)*NB_UE_INST); nr_ue_nas.uicc = checkUicc(0);
nr_ue_nas_t *nas = get_ue_nas_info(0);
itti_mark_task_ready (TASK_NAS_NRUE); itti_mark_task_ready (TASK_NAS_NRUE);
while(1) { while(1) {
...@@ -857,15 +925,7 @@ void *nas_nrue_task(void *args_p) ...@@ -857,15 +925,7 @@ void *nas_nrue_task(void *args_p)
if (msg_p != NULL) { if (msg_p != NULL) {
instance = msg_p->ittiMsgHeader.originInstance; instance = msg_p->ittiMsgHeader.originInstance;
Mod_id = instance ; AssertFatal(instance == 0, "cannot handle more than one UE!\n");
uicc_t *uicc=checkUicc(Mod_id);
LOG_I(NAS, "[UE %d] Received %s\n", Mod_id, ITTI_MSG_NAME(msg_p));
if (instance == INSTANCE_DEFAULT) {
printf("%s:%d: FATAL: instance is INSTANCE_DEFAULT, should not happen.\n",
__FILE__, __LINE__);
exit_fun("exit... \n");
}
switch (ITTI_MSG_ID(msg_p)) { switch (ITTI_MSG_ID(msg_p)) {
case INITIALIZE_MESSAGE: case INITIALIZE_MESSAGE:
...@@ -881,8 +941,8 @@ void *nas_nrue_task(void *args_p) ...@@ -881,8 +941,8 @@ void *nas_nrue_task(void *args_p)
case NAS_CELL_SELECTION_CNF: case NAS_CELL_SELECTION_CNF:
LOG_I(NAS, LOG_I(NAS,
"[UE %d] Received %s: errCode %u, cellID %u, tac %u\n", "[UE %ld] Received %s: errCode %u, cellID %u, tac %u\n",
Mod_id, instance,
ITTI_MSG_NAME(msg_p), ITTI_MSG_NAME(msg_p),
NAS_CELL_SELECTION_CNF(msg_p).errCode, NAS_CELL_SELECTION_CNF(msg_p).errCode,
NAS_CELL_SELECTION_CNF(msg_p).cellID, NAS_CELL_SELECTION_CNF(msg_p).cellID,
...@@ -895,49 +955,40 @@ void *nas_nrue_task(void *args_p) ...@@ -895,49 +955,40 @@ void *nas_nrue_task(void *args_p)
break; break;
case NAS_CELL_SELECTION_IND: case NAS_CELL_SELECTION_IND:
LOG_I(NAS, "[UE %d] Received %s: cellID %u, tac %u\n", Mod_id, ITTI_MSG_NAME(msg_p), NAS_CELL_SELECTION_IND(msg_p).cellID, NAS_CELL_SELECTION_IND(msg_p).tac); LOG_I(NAS, "[UE %ld] Received %s: cellID %u, tac %u\n", instance, ITTI_MSG_NAME(msg_p), NAS_CELL_SELECTION_IND(msg_p).cellID, NAS_CELL_SELECTION_IND(msg_p).tac);
/* TODO not processed by NAS currently */ /* TODO not processed by NAS currently */
break; break;
case NAS_PAGING_IND: case NAS_PAGING_IND:
LOG_I(NAS, "[UE %d] Received %s: cause %u\n", Mod_id, ITTI_MSG_NAME(msg_p), NAS_PAGING_IND(msg_p).cause); LOG_I(NAS, "[UE %ld] Received %s: cause %u\n", instance, ITTI_MSG_NAME(msg_p), NAS_PAGING_IND(msg_p).cause);
/* TODO not processed by NAS currently */ /* TODO not processed by NAS currently */
break; break;
case NAS_CONN_ESTABLI_CNF: { case NAS_CONN_ESTABLI_CNF: {
LOG_I(NAS, "[UE %d] Received %s: errCode %u, length %u\n", Mod_id, ITTI_MSG_NAME(msg_p), NAS_CONN_ESTABLI_CNF(msg_p).errCode, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); LOG_I(NAS, "[UE %ld] Received %s: errCode %u, length %u\n", instance, ITTI_MSG_NAME(msg_p), NAS_CONN_ESTABLI_CNF(msg_p).errCode, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
pdu_buffer = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.data; pdu_buffer = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.data;
msg_type = get_msg_type(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); msg_type = get_msg_type(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
if (msg_type == REGISTRATION_ACCEPT) { if (msg_type == REGISTRATION_ACCEPT) {
LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n"); LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n");
decodeRegistrationAccept(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length, nas);
as_nas_info_t initialNasMsg; as_nas_info_t initialNasMsg;
memset(&initialNasMsg, 0, sizeof(as_nas_info_t)); memset(&initialNasMsg, 0, sizeof(as_nas_info_t));
generateRegistrationComplete(Mod_id, &initialNasMsg, NULL); generateRegistrationComplete(nas, &initialNasMsg, NULL);
if (initialNasMsg.length > 0) { if (initialNasMsg.length > 0) {
MessageDef *message_p; send_nas_uplink_data_req(instance, &initialNasMsg);
message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ);
NAS_UPLINK_DATA_REQ(message_p).UEid = Mod_id;
NAS_UPLINK_DATA_REQ(message_p).nasMsg.data = (uint8_t *)initialNasMsg.data;
NAS_UPLINK_DATA_REQ(message_p).nasMsg.length = initialNasMsg.length;
itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p);
LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n"); LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n");
} }
as_nas_info_t pduEstablishMsg; as_nas_info_t pduEstablishMsg;
memset(&pduEstablishMsg, 0, sizeof(as_nas_info_t)); memset(&pduEstablishMsg, 0, sizeof(as_nas_info_t));
generatePduSessionEstablishRequest(Mod_id, uicc, &pduEstablishMsg); generatePduSessionEstablishRequest(nas, &pduEstablishMsg);
if (pduEstablishMsg.length > 0) { if (pduEstablishMsg.length > 0) {
MessageDef *message_p; send_nas_uplink_data_req(instance, &pduEstablishMsg);
message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ);
NAS_UPLINK_DATA_REQ(message_p).UEid = Mod_id;
NAS_UPLINK_DATA_REQ(message_p).nasMsg.data = (uint8_t *)pduEstablishMsg.data;
NAS_UPLINK_DATA_REQ(message_p).nasMsg.length = pduEstablishMsg.length;
itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p);
LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(PduSessionEstablishRequest)\n"); LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(PduSessionEstablishRequest)\n");
} }
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
...@@ -948,24 +999,38 @@ void *nas_nrue_task(void *args_p) ...@@ -948,24 +999,38 @@ void *nas_nrue_task(void *args_p)
} }
case NAS_CONN_RELEASE_IND: case NAS_CONN_RELEASE_IND:
LOG_I(NAS, "[UE %d] Received %s: cause %u\n", Mod_id, ITTI_MSG_NAME (msg_p), LOG_I(NAS, "[UE %ld] Received %s: cause %u\n", instance, ITTI_MSG_NAME (msg_p),
NAS_CONN_RELEASE_IND (msg_p).cause); NAS_CONN_RELEASE_IND (msg_p).cause);
itti_wait_tasks_unblock(); /* will unblock ITTI to stop nr-uesoftmodem */
break; break;
case NAS_UPLINK_DATA_CNF: case NAS_UPLINK_DATA_CNF:
LOG_I(NAS, "[UE %d] Received %s: UEid %u, errCode %u\n", Mod_id, ITTI_MSG_NAME (msg_p), LOG_I(NAS, "[UE %ld] Received %s: UEid %u, errCode %u\n", instance, ITTI_MSG_NAME (msg_p),
NAS_UPLINK_DATA_CNF (msg_p).UEid, NAS_UPLINK_DATA_CNF (msg_p).errCode); NAS_UPLINK_DATA_CNF (msg_p).UEid, NAS_UPLINK_DATA_CNF (msg_p).errCode);
break; break;
case NAS_DEREGISTRATION_REQ: {
LOG_I(NAS, "[UE %ld] Received %s\n", instance, ITTI_MSG_NAME(msg_p));
if (nas->guti) {
nas_deregistration_req_t *req = &NAS_DEREGISTRATION_REQ(msg_p);
as_nas_info_t initialNasMsg = {0};
generateDeregistrationRequest(nas, &initialNasMsg, req);
send_nas_uplink_data_req(instance, &initialNasMsg);
} else {
LOG_E(NAS, "no GUTI, cannot trigger deregistration request\n");
}
}
break;
case NAS_DOWNLINK_DATA_IND: case NAS_DOWNLINK_DATA_IND:
{ {
LOG_I(NAS, "[UE %d] Received %s: UEid %u, length %u , buffer %p\n", Mod_id, LOG_I(NAS,
ITTI_MSG_NAME (msg_p), "[UE %ld] Received %s: length %u , buffer %p\n",
Mod_id, instance,
NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length, ITTI_MSG_NAME(msg_p),
NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data); NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length,
NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data);
as_nas_info_t initialNasMsg={0}; as_nas_info_t initialNasMsg={0};
pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data; pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data;
...@@ -974,18 +1039,21 @@ void *nas_nrue_task(void *args_p) ...@@ -974,18 +1039,21 @@ void *nas_nrue_task(void *args_p)
switch(msg_type){ switch(msg_type){
case FGS_IDENTITY_REQUEST: case FGS_IDENTITY_REQUEST:
generateIdentityResponse(&initialNasMsg,*(pdu_buffer+3), uicc); generateIdentityResponse(&initialNasMsg, *(pdu_buffer + 3), nas->uicc);
break; break;
case FGS_AUTHENTICATION_REQUEST: case FGS_AUTHENTICATION_REQUEST:
generateAuthenticationResp(Mod_id,&initialNasMsg, pdu_buffer, uicc); generateAuthenticationResp(nas, &initialNasMsg, pdu_buffer);
break; break;
case FGS_SECURITY_MODE_COMMAND: case FGS_SECURITY_MODE_COMMAND:
nas_itti_kgnb_refresh_req(ue_security_key[Mod_id]->kgnb, instance); nas_itti_kgnb_refresh_req(nas->security.kgnb);
generateSecurityModeComplete(Mod_id,&initialNasMsg); generateSecurityModeComplete(nas, &initialNasMsg);
break; break;
case FGS_DOWNLINK_NAS_TRANSPORT: case FGS_DOWNLINK_NAS_TRANSPORT:
decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer); decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer);
break; break;
case FGS_DEREGISTRATION_ACCEPT:
LOG_I(NAS, "received deregistration accept\n");
break;
case FGS_PDU_SESSION_ESTABLISHMENT_ACC: case FGS_PDU_SESSION_ESTABLISHMENT_ACC:
{ {
uint8_t offset = 0; uint8_t offset = 0;
...@@ -1017,25 +1085,17 @@ void *nas_nrue_task(void *args_p) ...@@ -1017,25 +1085,17 @@ void *nas_nrue_task(void *args_p)
} }
break; break;
default: default:
LOG_W(NR_RRC,"unknow message type %d\n",msg_type); LOG_W(NR_RRC,"unknown message type %d\n",msg_type);
break; break;
} }
if(initialNasMsg.length > 0){ if (initialNasMsg.length > 0)
MessageDef *message_p; send_nas_uplink_data_req(instance, &initialNasMsg);
message_p = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_UPLINK_DATA_REQ);
NAS_UPLINK_DATA_REQ(message_p).UEid = Mod_id;
NAS_UPLINK_DATA_REQ(message_p).nasMsg.data = (uint8_t *)initialNasMsg.data;
NAS_UPLINK_DATA_REQ(message_p).nasMsg.length = initialNasMsg.length;
itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p);
LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message\n");
} }
}
break; break;
default: default:
LOG_E(NAS, "[UE %d] Received unexpected message %s\n", Mod_id, ITTI_MSG_NAME (msg_p)); LOG_E(NAS, "[UE %ld] Received unexpected message %s\n", instance, ITTI_MSG_NAME (msg_p));
break; break;
} }
......
...@@ -36,9 +36,11 @@ ...@@ -36,9 +36,11 @@
#include "FGSIdentityResponse.h" #include "FGSIdentityResponse.h"
#include "FGSAuthenticationResponse.h" #include "FGSAuthenticationResponse.h"
#include "FGSNASSecurityModeComplete.h" #include "FGSNASSecurityModeComplete.h"
#include "FGSDeregistrationRequestUEOriginating.h"
#include "RegistrationComplete.h" #include "RegistrationComplete.h"
#include "as_message.h" #include "as_message.h"
#include "FGSUplinkNasTransport.h" #include "FGSUplinkNasTransport.h"
#include <openair3/UICC/usim_interface.h>
#define PLAIN_5GS_MSG 0b0000 #define PLAIN_5GS_MSG 0b0000
#define INTEGRITY_PROTECTED 0b0001 #define INTEGRITY_PROTECTED 0b0001
...@@ -49,6 +51,8 @@ ...@@ -49,6 +51,8 @@
#define REGISTRATION_REQUEST 0b01000001 /* 65 = 0x41 */ #define REGISTRATION_REQUEST 0b01000001 /* 65 = 0x41 */
#define REGISTRATION_ACCEPT 0b01000010 /* 66 = 0x42 */ #define REGISTRATION_ACCEPT 0b01000010 /* 66 = 0x42 */
#define REGISTRATION_COMPLETE 0b01000011 /* 67 = 0x43 */ #define REGISTRATION_COMPLETE 0b01000011 /* 67 = 0x43 */
#define FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING 0b01000101
#define FGS_DEREGISTRATION_ACCEPT 0b01000110
#define FGS_AUTHENTICATION_REQUEST 0b01010110 /* 86 = 0x56 */ #define FGS_AUTHENTICATION_REQUEST 0b01010110 /* 86 = 0x56 */
#define FGS_AUTHENTICATION_RESPONSE 0b01010111 /* 87 = 0x57 */ #define FGS_AUTHENTICATION_RESPONSE 0b01010111 /* 87 = 0x57 */
#define FGS_IDENTITY_REQUEST 0b01011011 /* 91 = 0x5b */ #define FGS_IDENTITY_REQUEST 0b01011011 /* 91 = 0x5b */
...@@ -78,8 +82,16 @@ typedef struct { ...@@ -78,8 +82,16 @@ typedef struct {
uint8_t res[16]; uint8_t res[16];
uint8_t rand[16]; uint8_t rand[16];
uint8_t kgnb[32]; uint8_t kgnb[32];
uint32_t mm_counter;
uint32_t sm_counter;
} ue_sa_security_key_t; } ue_sa_security_key_t;
typedef struct {
uicc_t *uicc;
ue_sa_security_key_t security;
Guti5GSMobileIdentity_t *guti;
} nr_ue_nas_t;
typedef enum fgs_protocol_discriminator_e { typedef enum fgs_protocol_discriminator_e {
/* Protocol discriminator identifier for 5GS Mobility Management */ /* Protocol discriminator identifier for 5GS Mobility Management */
FGS_MOBILITY_MANAGEMENT_MESSAGE = 0x7E, FGS_MOBILITY_MANAGEMENT_MESSAGE = 0x7E,
...@@ -108,6 +120,7 @@ typedef union { ...@@ -108,6 +120,7 @@ typedef union {
registration_request_msg registration_request; registration_request_msg registration_request;
fgs_identiy_response_msg fgs_identity_response; fgs_identiy_response_msg fgs_identity_response;
fgs_authentication_response_msg fgs_auth_response; fgs_authentication_response_msg fgs_auth_response;
fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating;
fgs_security_mode_complete_msg fgs_security_mode_complete; fgs_security_mode_complete_msg fgs_security_mode_complete;
registration_complete_msg registration_complete; registration_complete_msg registration_complete;
fgs_uplink_nas_transport_msg uplink_nas_transport; fgs_uplink_nas_transport_msg uplink_nas_transport;
...@@ -158,7 +171,8 @@ typedef struct { ...@@ -158,7 +171,8 @@ typedef struct {
fgs_sm_nas_msg_header_t sm_nas_msg_header; fgs_sm_nas_msg_header_t sm_nas_msg_header;
} dl_nas_transport_t; } dl_nas_transport_t;
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, int Mod_id); nr_ue_nas_t *get_ue_nas_info(module_id_t module_id);
void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas);
void *nas_nrue_task(void *args_p); void *nas_nrue_task(void *args_p);
#endif /* __NR_NAS_MSG_SIM_H__*/ #endif /* __NR_NAS_MSG_SIM_H__*/
......
...@@ -116,9 +116,8 @@ uicc_t * checkUicc(int Mod_id) { ...@@ -116,9 +116,8 @@ uicc_t * checkUicc(int Mod_id) {
return (uicc_t*) uiccArray[Mod_id]; return (uicc_t*) uiccArray[Mod_id];
} }
uint8_t getImeisvDigit(int Mod_id,uint8_t i) uint8_t getImeisvDigit(const uicc_t *uicc, uint8_t i)
{ {
uicc_t * uicc=checkUicc(Mod_id);
uint8_t r = 0; uint8_t r = 0;
uint8_t l = strlen(uicc->imeisvStr); uint8_t l = strlen(uicc->imeisvStr);
if (l > IMEISV_STR_MAX_LENGTH) { if (l > IMEISV_STR_MAX_LENGTH) {
......
...@@ -73,6 +73,5 @@ typedef struct { ...@@ -73,6 +73,5 @@ typedef struct {
uicc_t *checkUicc(int Mod_id); uicc_t *checkUicc(int Mod_id);
uicc_t *init_uicc(char *sectionName); uicc_t *init_uicc(char *sectionName);
void uicc_milenage_generate(uint8_t * autn, uicc_t *uicc); void uicc_milenage_generate(uint8_t * autn, uicc_t *uicc);
uicc_t * checkUicc(int Mod_id); uint8_t getImeisvDigit(const uicc_t *uicc, uint8_t i);
uint8_t getImeisvDigit(int Mod_id,uint8_t i);
#endif #endif
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