Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lizhongxiao
OpenXG-RAN
Commits
5268dbf3
Commit
5268dbf3
authored
Mar 31, 2023
by
Robert Schmidt
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/deregistration' into integration_2023_w13
parents
ca6ae2c4
c4a9f0ea
Changes
34
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
563 additions
and
245 deletions
+563
-245
CMakeLists.txt
CMakeLists.txt
+1
-0
ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml
ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml
+1
-1
ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml
ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml
+1
-1
ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml
ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml
+1
-1
ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml
...ripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml
+1
-1
ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml
ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml
+1
-1
ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml
ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml
+1
-1
ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml
...ts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml
+1
-1
common/utils/ocp_itti/intertask_interface.cpp
common/utils/ocp_itti/intertask_interface.cpp
+18
-9
common/utils/ocp_itti/intertask_interface.h
common/utils/ocp_itti/intertask_interface.h
+6
-3
executables/lte-softmodem.c
executables/lte-softmodem.c
+1
-1
executables/lte-uesoftmodem.c
executables/lte-uesoftmodem.c
+1
-1
executables/nr-cuup.c
executables/nr-cuup.c
+1
-1
executables/nr-softmodem.c
executables/nr-softmodem.c
+1
-1
executables/nr-uesoftmodem.c
executables/nr-uesoftmodem.c
+40
-4
openair2/COMMON/as_message.h
openair2/COMMON/as_message.h
+7
-0
openair2/COMMON/rrc_messages_def.h
openair2/COMMON/rrc_messages_def.h
+1
-0
openair2/COMMON/rrc_messages_types.h
openair2/COMMON/rrc_messages_types.h
+2
-0
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+19
-34
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+1
-1
openair2/RRC/NR/rrc_gNB.c
openair2/RRC/NR/rrc_gNB.c
+9
-0
openair2/RRC/NR_UE/rrc_UE.c
openair2/RRC/NR_UE/rrc_UE.c
+4
-5
openair3/NAS/COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.c
...AS/COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.c
+59
-0
openair3/NAS/COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.h
...AS/COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.h
+60
-0
openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.c
openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.c
+17
-0
openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.h
openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.h
+4
-0
openair3/NAS/COMMON/IES/FGSDeregistrationType.h
openair3/NAS/COMMON/IES/FGSDeregistrationType.h
+46
-0
openair3/NAS/COMMON/IES/FGSMobileIdentity.c
openair3/NAS/COMMON/IES/FGSMobileIdentity.c
+4
-2
openair3/NAS/COMMON/NR_NAS_defs.h
openair3/NAS/COMMON/NR_NAS_defs.h
+7
-1
openair3/NAS/COMMON/nr_common.c
openair3/NAS/COMMON/nr_common.c
+1
-1
openair3/NAS/NR_UE/nr_nas_msg_sim.c
openair3/NAS/NR_UE/nr_nas_msg_sim.c
+229
-169
openair3/NAS/NR_UE/nr_nas_msg_sim.h
openair3/NAS/NR_UE/nr_nas_msg_sim.h
+15
-1
openair3/UICC/usim_interface.c
openair3/UICC/usim_interface.c
+1
-2
openair3/UICC/usim_interface.h
openair3/UICC/usim_interface.h
+1
-2
No files found.
CMakeLists.txt
View file @
5268dbf3
...
...
@@ -1895,6 +1895,7 @@ set(libnrnas_emm_msg_OBJS
${
NAS_SRC
}
COMMON/EMM/MSG/FGSUplinkNasTransport.c
${
NAS_SRC
}
COMMON/ESM/MSG/PduSessionEstablishRequest.c
${
NAS_SRC
}
COMMON/ESM/MSG/PduSessionEstablishmentAccept.c
${
NAS_SRC
}
COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.c
)
set
(
libnrnas_ies_OBJS
...
...
ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml
View file @
5268dbf3
...
...
@@ -219,7 +219,7 @@ services:
F1_DU_IP_ADDRESS
:
192.168.71.142
F1_CU_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
:
-
oai-cu
networks
:
...
...
ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml
View file @
5268dbf3
...
...
@@ -180,7 +180,7 @@ services:
GNB_NGA_IP_ADDRESS
:
192.168.71.140
GNB_NGU_IF_NAME
:
eth0
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
:
-
oai-ext-dn
networks
:
...
...
ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml
View file @
5268dbf3
...
...
@@ -181,7 +181,7 @@ services:
GNB_NGU_IF_NAME
:
eth0
GNB_NGU_IP_ADDRESS
:
192.168.71.140
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
:
-
oai-ext-dn
networks
:
...
...
ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml
View file @
5268dbf3
...
...
@@ -169,7 +169,7 @@ services:
environment
:
RFSIMULATOR
:
server
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
:
-
oai-ext-dn
networks
:
...
...
ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml
View file @
5268dbf3
...
...
@@ -169,7 +169,7 @@ services:
environment
:
RFSIMULATOR
:
server
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
:
-
oai-ext-dn
networks
:
...
...
ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml
View file @
5268dbf3
...
...
@@ -216,7 +216,7 @@ services:
environment
:
RFSIMULATOR
:
server
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
:
ran_net
:
ipv4_address
:
192.168.72.142
...
...
ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml
View file @
5268dbf3
...
...
@@ -169,7 +169,7 @@ services:
environment
:
RFSIMULATOR
:
server
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
:
-
oai-ext-dn
networks
:
...
...
common/utils/ocp_itti/intertask_interface.cpp
View file @
5268dbf3
...
...
@@ -24,6 +24,7 @@
#include <vector>
#include <map>
#include <sys/eventfd.h>
#include <semaphore.h>
extern
"C"
{
...
...
@@ -434,24 +435,32 @@ extern "C" {
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
const
char
msg
[]
=
"
\n
** Caught SIGTERM, shutting down
\n
"
;
__attribute__
((
unused
))
int
unused
=
write
(
STDOUT_FILENO
,
msg
,
sizeof
(
msg
)
-
1
);
pthread_mutex_unlock
(
&
signal_mutex
);
itti_wait_tasks_unblock
(
);
}
void
itti_wait_tasks_end
(
void
)
{
pthread_mutex_init
(
&
signal_mutex
,
NULL
);
pthread_mutex_lock
(
&
signal_mutex
);
void
itti_wait_tasks_end
(
void
(
*
handler
)(
int
))
{
int
rc
=
sem_init
(
&
itti_sem_block
,
0
,
0
);
AssertFatal
(
rc
==
0
,
"error in sem_init(): %d %s
\n
"
,
errno
,
strerror
(
errno
)
);
signal
(
SIGTERM
,
catch_sigterm
);
signal
(
SIGINT
,
catch_sigterm
);
if
(
handler
==
NULL
)
/* no handler given: install default */
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
)
{}
...
...
common/utils/ocp_itti/intertask_interface.h
View file @
5268dbf3
...
...
@@ -550,10 +550,13 @@ MessageDef *itti_alloc_new_message_sized(
MessagesIds
message_id
,
MessageHeaderSize
size
);
/** \brief handle signals and wait for all threads to join when the process complete.
This function should be called from the main thread after having created all ITTI tasks.
/** \brief Wait for SIGINT/SIGTERM signals to unblock ITTI.
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
);
/** \brief Send a termination message to all tasks.
...
...
executables/lte-softmodem.c
View file @
5268dbf3
...
...
@@ -614,7 +614,7 @@ int main ( int argc, char **argv )
//getchar();
if
(
IS_SOFTMODEM_DOSCOPE
)
load_softscope
(
"enb"
,
NULL
);
itti_wait_tasks_end
();
itti_wait_tasks_end
(
NULL
);
#if USING_GPROF
// Save the gprof data now (rather than via atexit) in case we crash while shutting down
...
...
executables/lte-uesoftmodem.c
View file @
5268dbf3
...
...
@@ -699,7 +699,7 @@ int main( int argc, char **argv ) {
printf
(
"TYPE <CTRL-C> TO TERMINATE
\n
"
);
//getchar();
printf
(
"Entering ITTI signals handler
\n
"
);
itti_wait_tasks_end
();
itti_wait_tasks_end
(
NULL
);
printf
(
"Returned from ITTI signal handler
\n
"
);
oai_exit
=
1
;
printf
(
"oai_exit=%d
\n
"
,
oai_exit
);
...
...
executables/nr-cuup.c
View file @
5268dbf3
...
...
@@ -153,7 +153,7 @@ int main(int argc, char **argv)
itti_send_msg_to_task
(
TASK_CUUP_E1
,
0
,
msg
);
printf
(
"TYPE <CTRL-C> TO TERMINATE
\n
"
);
itti_wait_tasks_end
();
itti_wait_tasks_end
(
NULL
);
logClean
();
printf
(
"Bye.
\n
"
);
...
...
executables/nr-softmodem.c
View file @
5268dbf3
...
...
@@ -733,7 +733,7 @@ int main( int argc, char **argv ) {
// wait for end of program
printf
(
"Entering ITTI signals handler
\n
"
);
printf
(
"TYPE <CTRL-C> TO TERMINATE
\n
"
);
itti_wait_tasks_end
();
itti_wait_tasks_end
(
NULL
);
printf
(
"Returned from ITTI signal handler
\n
"
);
oai_exit
=
1
;
printf
(
"oai_exit=%d
\n
"
,
oai_exit
);
...
...
executables/nr-uesoftmodem.c
View file @
5268dbf3
...
...
@@ -22,6 +22,8 @@
#define _GNU_SOURCE
/* See feature_test_macros(7) */
#include <sched.h>
#include <stdbool.h>
#include <signal.h>
#include "T.h"
#include "assertions.h"
...
...
@@ -402,6 +404,27 @@ void *rrc_enb_process_msg(void *notUsed) {
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
()
{
paramdef_t
GNBParams
[]
=
GNBPARAMS_DESC
;
config_get
(
GNBParams
,
sizeof
(
GNBParams
)
/
sizeof
(
paramdef_t
),
NULL
);
...
...
@@ -431,7 +454,7 @@ int main( int argc, char **argv ) {
if
(
load_configmodule
(
argc
,
argv
,
CONFIG_ENABLECMDLINEONLY
)
==
NULL
)
{
exit_fun
(
"[SOFTMODEM] Error, configuration module init failed
\n
"
);
}
set_softmodem_sighandler
();
//
set_softmodem_sighandler();
CONFIG_SETRTFLAG
(
CONFIG_NOEXITONHELP
);
memset
(
openair0_cfg
,
0
,
sizeof
(
openair0_config_t
)
*
MAX_CARDS
);
memset
(
tx_max_power
,
0
,
sizeof
(
int
)
*
MAX_NUM_CCs
);
...
...
@@ -555,15 +578,28 @@ int main( int argc, char **argv ) {
// Sleep a while before checking all parameters have been used
// Some are used directly in external threads, asynchronously
sleep
(
2
0
);
sleep
(
2
);
config_check_unknown_cmdlineopt
(
CONFIG_CHECKALLSECTIONS
);
while
(
true
)
sleep
(
3600
);
// wait for end of program
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
)
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
;
}
...
...
openair2/COMMON/as_message.h
View file @
5268dbf3
...
...
@@ -327,6 +327,13 @@ typedef struct nas_establish_req_s {
as_nas_info_t
initialNasMsg
;
/* Initial NAS message to transfer */
}
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 transfers the initial NAS message to the NAS.
...
...
openair2/COMMON/rrc_messages_def.h
View file @
5268dbf3
...
...
@@ -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_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_DEREGISTRATION_REQ
,
MESSAGE_PRIORITY_MED
,
NasDeregistrationReq
,
nas_deregistration_req
)
MESSAGE_DEF
(
NAS_RAB_ESTABLI_RSP
,
MESSAGE_PRIORITY_MED
,
NasRabEstRsp
,
nas_rab_est_rsp
)
...
...
openair2/COMMON/rrc_messages_types.h
View file @
5268dbf3
...
...
@@ -75,6 +75,7 @@
#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_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
...
...
@@ -441,6 +442,7 @@ typedef kenb_refresh_req_t NasKenbRefreshReq;
typedef
cell_info_req_t
NasCellSelectionReq
;
typedef
nas_establish_req_t
NasConnEstabliReq
;
typedef
ul_info_transfer_req_t
NasUlDataReq
;
typedef
nas_deregistration_req_t
NasDeregistrationReq
;
typedef
rab_establish_rsp_t
NasRabEstRsp
;
...
...
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
View file @
5268dbf3
...
...
@@ -3275,41 +3275,26 @@ void nr_ue_process_mac_pdu(nr_downlink_indication_t *dl_info,
// check if LCID is valid at current time.
case
DL_SCH_LCID_DCCH1
:
// 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:
{
if
(
!
get_mac_len
(
pduP
,
pdu_len
,
&
mac_len
,
&
mac_subheader_len
))
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
;
}
LOG_W
(
MAC
,
"unknown lcid %02x
\n
"
,
rx_lcid
);
break
;
}
pduP
+=
(
mac_subheader_len
+
mac_len
);
pdu_len
-=
(
mac_subheader_len
+
mac_len
);
...
...
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
View file @
5268dbf3
...
...
@@ -774,7 +774,7 @@ srb_found:
//printf("\n");
if
((
RC
.
nrrrc
==
NULL
)
||
(
!
NODE_IS_CU
(
node_type
)))
{
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
];
rrc
->
mac_rrc
.
dl_rrc_message_transfer
(
0
,
&
dl_rrc
);
}
else
{
// UE
...
...
openair2/RRC/NR/rrc_gNB.c
View file @
5268dbf3
...
...
@@ -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
);
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
))
{
uint8_t
*
message_buffer
=
itti_malloc
(
TASK_RRC_GNB
,
TASK_CU_F1
,
size
);
...
...
openair2/RRC/NR_UE/rrc_UE.c
View file @
5268dbf3
...
...
@@ -1400,7 +1400,8 @@ static void rrc_ue_generate_RRCSetupComplete(
if
(
get_softmodem_params
()
->
sa
)
{
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_length
=
initialNasMsg
.
length
;
}
else
{
...
...
@@ -2256,11 +2257,9 @@ nr_rrc_ue_establish_srb2(
NR_DL_DCCH_Message_t
*
dl_dcch_msg
=
NULL
;
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
"
,
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
"
);
...
...
@@ -2315,7 +2314,7 @@ nr_rrc_ue_establish_srb2(
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_
NR
UE
,
ctxt_pP
->
instance
,
msg_p
);
break
;
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
);
...
...
openair3/NAS/COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.c
0 → 100644
View file @
5268dbf3
/*
* 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
;
}
openair3/NAS/COMMON/EMM/MSG/FGSDeregistrationRequestUEOriginating.h
0 → 100644
View file @
5268dbf3
/*
* 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_) */
openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.c
View file @
5268dbf3
...
...
@@ -50,6 +50,16 @@ int decode_registration_accept(registration_accept_msg *registration_accept, uin
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
return
decoded
;
}
...
...
@@ -64,6 +74,13 @@ int encode_registration_accept(registration_accept_msg *registration_accept, uin
*
(
buffer
+
encoded
)
=
encode_fgs_registration_result
(
&
registration_accept
->
fgsregistrationresult
);
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
LOG_FUNC_RETURN
(
encoded
);
}
...
...
openair3/NAS/COMMON/EMM/MSG/RegistrationAccept.h
View file @
5268dbf3
...
...
@@ -38,6 +38,7 @@
#include "SpareHalfOctet.h"
#include "MessageType.h"
#include "FGSRegistrationResult.h"
#include "FGSMobileIdentity.h"
#ifndef REGISTRATION_ACCEPT_H_
#define REGISTRATION_ACCEPT_H_
...
...
@@ -56,6 +57,9 @@ typedef struct registration_accept_msg_tag {
SpareHalfOctet
sparehalfoctet
:
4
;
MessageType
messagetype
;
FGSRegistrationResult
fgsregistrationresult
;
/* Optional fields */
FGSMobileIdentity
*
guti
;
}
registration_accept_msg
;
int
decode_registration_accept
(
registration_accept_msg
*
registrationaccept
,
uint8_t
*
buffer
,
uint32_t
len
);
...
...
openair3/NAS/COMMON/IES/FGSDeregistrationType.h
0 → 100644
View file @
5268dbf3
/*
* 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_ */
openair3/NAS/COMMON/IES/FGSMobileIdentity.c
View file @
5268dbf3
...
...
@@ -54,8 +54,8 @@ int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei
decoded
++
;
}
ielen
=
*
(
buffer
+
decoded
);
decoded
++
;
ielen
=
*
(
uint16_t
*
)(
buffer
+
decoded
);
/* length is two bytes */
decoded
+=
2
;
CHECK_LENGTH_DECODER
(
len
-
decoded
,
ielen
);
uint8_t
typeofidentity
=
*
(
buffer
+
decoded
)
&
0x7
;
...
...
@@ -63,6 +63,8 @@ int decode_5gs_mobile_identity(FGSMobileIdentity *fgsmobileidentity, uint8_t iei
if
(
typeofidentity
==
FGS_MOBILE_IDENTITY_5G_GUTI
)
{
decoded_rc
=
decode_guti_5gs_mobile_identity
(
&
fgsmobileidentity
->
guti
,
buffer
+
decoded
);
}
else
{
AssertFatal
(
false
,
"Mobile Identity encoding of type %d not implemented
\n
"
,
typeofidentity
);
}
if
(
decoded_rc
<
0
)
{
...
...
openair3/NAS/COMMON/NR_NAS_defs.h
View file @
5268dbf3
...
...
@@ -364,6 +364,12 @@ typedef struct __attribute__((packed)) {
}
securityModeCommand_t
;
typedef
struct
__attribute__
((
packed
))
{
Extendedprotocoldiscriminator_t
epd
:
8
;
Security_header_t
sh
:
8
;
SGSmobilitymanagementmessages_t
mt
:
8
;
}
deregistrationRequestUEOriginating_t
;
typedef
struct
{
uicc_t
*
uicc
;
}
nr_user_nas_t
;
...
...
@@ -371,7 +377,7 @@ typedef struct {
#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 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
authenticationResponse
(
void
**
msg
,
nr_user_nas_t
*
UE
);
...
...
openair3/NAS/COMMON/nr_common.c
View file @
5268dbf3
...
...
@@ -39,7 +39,7 @@ void servingNetworkName(uint8_t *msg, char * imsiStr, int nmc_size) {
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
//input S to KDF
uint8_t
S
[
128
]
=
{
0
};
...
...
openair3/NAS/NR_UE/nr_nas_msg_sim.c
View file @
5268dbf3
...
...
@@ -42,9 +42,10 @@
#include "kdf.h"
#include "PduSessionEstablishRequest.h"
#include "PduSessionEstablishmentAccept.h"
#include "RegistrationAccept.h"
#include "FGSDeregistrationRequestUEOriginating.h"
#include "intertask_interface.h"
#include "openair2/RRC/NAS/nas_config.h"
#include <openair3/UICC/usim_interface.h>
#include <openair3/NAS/COMMON/NR_NAS_defs.h>
#include <openair1/PHY/phy_extern_nr_ue.h>
#include <openair1/SIMULATION/ETH_TRANSPORT/proto.h>
...
...
@@ -54,7 +55,7 @@ uint8_t *registration_request_buf;
uint32_t
registration_request_len
;
extern
char
*
baseNetAddress
;
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
(
char
*
buffer
,
...
...
@@ -104,6 +105,50 @@ static int _nas_mm_msg_encode_header(const mm_msg_header_t *header,
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
)
{
LOG_FUNC_IN
;
...
...
@@ -140,6 +185,9 @@ int mm_msg_encode(MM_msg *mm_msg, uint8_t *buffer, uint32_t len) {
case
FGS_UPLINK_NAS_TRANSPORT
:
encode_result
=
encode_fgs_uplink_nas_transport
(
&
mm_msg
->
uplink_nas_transport
,
buffer
,
len
);
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:
LOG_TRACE
(
ERROR
,
"EMM-MSG - Unexpected message type: 0x%x"
,
mm_msg
->
header
.
message_type
);
...
...
@@ -303,25 +351,18 @@ void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){
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
sqn
[
6
];
AssertFatal
(
Mod_id
<
NB_UE_INST
,
"Failed, Mod_id %d is over NB_UE_INST!
\n
"
,
Mod_id
);
if
(
ue_security_key
[
Mod_id
]){
// clear old key
memset
(
ue_security_key
[
Mod_id
],
0
,
sizeof
(
ue_sa_security_key_t
));
}
else
{
// Allocate new memory
ue_security_key
[
Mod_id
]
=
(
ue_sa_security_key_t
*
)
calloc
(
1
,
sizeof
(
ue_sa_security_key_t
));
}
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
;
DevAssert
(
nas
!=
NULL
);
uint8_t
*
kausf
=
nas
->
security
.
kausf
;
uint8_t
*
kseaf
=
nas
->
security
.
kseaf
;
uint8_t
*
kamf
=
nas
->
security
.
kamf
;
uint8_t
*
knas_int
=
nas
->
security
.
knas_int
;
uint8_t
*
output
=
nas
->
security
.
res
;
uint8_t
*
rand
=
nas
->
security
.
rand
;
uint8_t
*
kgnb
=
nas
->
security
.
kgnb
;
// get RAND for authentication request
for
(
int
index
=
0
;
index
<
16
;
index
++
){
...
...
@@ -330,17 +371,17 @@ void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) {
uint8_t
resTemp
[
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
++
){
sqn
[
index
]
=
buf
[
26
+
index
];
}
derive_kausf
(
ck
,
ik
,
sqn
,
kausf
,
uicc
);
derive_kseaf
(
kausf
,
kseaf
,
uicc
);
derive_kamf
(
kseaf
,
kamf
,
0x0000
,
uicc
);
derive_kausf
(
ck
,
ik
,
sqn
,
kausf
,
nas
->
uicc
);
derive_kseaf
(
kausf
,
kseaf
,
nas
->
uicc
);
derive_kamf
(
kseaf
,
kamf
,
0x0000
,
nas
->
uicc
);
derive_knas
(
0x02
,
2
,
kamf
,
knas_int
);
derive_kgnb
(
kamf
,
0
,
kgnb
);
...
...
@@ -370,11 +411,17 @@ void derive_ue_keys(int Mod_id, uint8_t *buf, uicc_t *uicc) {
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
);
fgs_nas_message_t
nas_msg
=
{
0
};
MM_msg
*
mm_msg
;
uicc_t
*
uicc
=
checkUicc
(
Mod_id
);
mm_msg
=
&
nas_msg
.
plain
.
mm_msg
;
// set header
...
...
@@ -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
.
naskeysetidentifier
.
naskeysetidentifier
=
1
;
size
+=
1
;
if
(
0
){
mm_msg
->
registration_request
.
fgsmobileidentity
.
guti
.
typeofidentity
=
FGS_MOBILE_IDENTITY_5G_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
;
if
(
nas
->
guti
){
size
+=
fill_guti
(
&
mm_msg
->
registration_request
.
fgsmobileidentity
,
nas
->
guti
);
}
else
{
mm_msg
->
registration_request
.
fgsmobileidentity
.
suci
.
typeofidentity
=
FGS_MOBILE_IDENTITY_SUCI
;
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
);
size
+=
fill_suci
(
&
mm_msg
->
registration_request
.
fgsmobileidentity
,
nas
->
uicc
);
}
mm_msg
->
registration_request
.
presencemask
|=
REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT
;
...
...
@@ -471,18 +491,7 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype
mm_msg
->
fgs_identity_response
.
messagetype
=
FGS_IDENTITY_RESPONSE
;
size
+=
1
;
if
(
identitytype
==
FGS_MOBILE_IDENTITY_SUCI
){
mm_msg
->
fgs_identity_response
.
fgsmobileidentity
.
suci
.
typeofidentity
=
FGS_MOBILE_IDENTITY_SUCI
;
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
);
size
+=
fill_suci
(
&
mm_msg
->
fgs_identity_response
.
fgsmobileidentity
,
uicc
);
}
// encode the message
...
...
@@ -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
){
derive_ue_keys
(
Mod_id
,
buf
,
uicc
);
static
void
generateAuthenticationResp
(
nr_ue_nas_t
*
nas
,
as_nas_info_t
*
initialNasMsg
,
uint8_t
*
buf
)
{
derive_ue_keys
(
buf
,
nas
);
OctetString
res
;
res
.
length
=
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
);
fgs_nas_message_t
nas_msg
;
...
...
@@ -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
);
}
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
;
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
));
return
itti_send_msg_to_task
(
TASK_RRC_NRUE
,
instance
,
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
;
return
itti_send_msg_to_task
(
TASK_RRC_NRUE
,
0
,
message_p
);
}
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
);
fgs_nas_message_t
nas_msg
;
...
...
@@ -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
;
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
.
length
=
registration_request_len
;
...
...
@@ -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
);
stream_cipher
.
key
=
ue_security_key
[
Mod_id
]
->
knas_int
;
stream_cipher
.
key
=
nas
->
security
.
knas_int
;
stream_cipher
.
key_length
=
16
;
stream_cipher
.
count
=
0
;
stream_cipher
.
count
=
nas
->
security
.
mm_counter
++
;
stream_cipher
.
bearer
=
1
;
stream_cipher
.
direction
=
0
;
stream_cipher
.
message
=
(
unsigned
char
*
)(
initialNasMsg
->
data
+
6
);
...
...
@@ -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
sleep
(
1
);
int
length
=
0
;
...
...
@@ -682,9 +692,9 @@ static void generateRegistrationComplete(int Mod_id, as_nas_info_t *initialNasMs
}
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
.
count
=
1
;
stream_cipher
.
count
=
nas
->
security
.
mm_counter
++
;
stream_cipher
.
bearer
=
1
;
stream_cipher
.
direction
=
0
;
stream_cipher
.
message
=
(
unsigned
char
*
)(
initialNasMsg
->
data
+
6
);
...
...
@@ -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
usleep
(
100
*
150
);
int
size
=
0
;
...
...
@@ -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
.
requesttype
=
1
;
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
;
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,
// but pushed in a itti message to another thread
// 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
[
0
]
=
uicc
->
nssai_sst
;
mm_msg
->
uplink_nas_transport
.
snssai
.
value
[
0
]
=
nas
->
uicc
->
nssai_sst
;
if
(
has_nssai_sd
)
{
mm_msg
->
uplink_nas_transport
.
snssai
.
value
[
1
]
=
(
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
[
3
]
=
(
uicc
->
nssai_sd
)
&
0xFF
;
mm_msg
->
uplink_nas_transport
.
snssai
.
value
[
1
]
=
(
nas
->
uicc
->
nssai_sd
>>
16
)
&
0xFF
;
mm_msg
->
uplink_nas_transport
.
snssai
.
value
[
2
]
=
(
nas
->
uicc
->
nssai_sd
>>
8
)
&
0xFF
;
mm_msg
->
uplink_nas_transport
.
snssai
.
value
[
3
]
=
(
nas
->
uicc
->
nssai_sd
)
&
0xFF
;
}
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
.
length
=
dnnSize
+
1
;
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
);
// encode the message
...
...
@@ -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
);
stream_cipher
.
key
=
ue_security_key
[
Mod_id
]
->
knas_int
;
stream_cipher
.
key
=
nas
->
security
.
knas_int
;
stream_cipher
.
key_length
=
16
;
stream_cipher
.
count
=
0
;
stream_cipher
.
count
=
nas
->
security
.
sm_counter
++
;
stream_cipher
.
bearer
=
1
;
stream_cipher
.
direction
=
0
;
stream_cipher
.
message
=
(
unsigned
char
*
)(
initialNasMsg
->
data
+
6
);
...
...
@@ -838,17 +896,27 @@ uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) {
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
)
{
MessageDef
*
msg_p
;
instance_t
instance
;
unsigned
int
Mod_id
;
int
result
;
uint8_t
msg_type
=
0
;
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
);
while
(
1
)
{
...
...
@@ -857,15 +925,7 @@ void *nas_nrue_task(void *args_p)
if
(
msg_p
!=
NULL
)
{
instance
=
msg_p
->
ittiMsgHeader
.
originInstance
;
Mod_id
=
instance
;
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
"
);
}
AssertFatal
(
instance
==
0
,
"cannot handle more than one UE!
\n
"
);
switch
(
ITTI_MSG_ID
(
msg_p
))
{
case
INITIALIZE_MESSAGE
:
...
...
@@ -881,8 +941,8 @@ void *nas_nrue_task(void *args_p)
case
NAS_CELL_SELECTION_CNF
:
LOG_I
(
NAS
,
"[UE %d] Received %s: errCode %u, cellID %u, tac %u
\n
"
,
Mod_id
,
"[UE %
l
d] Received %s: errCode %u, cellID %u, tac %u
\n
"
,
instance
,
ITTI_MSG_NAME
(
msg_p
),
NAS_CELL_SELECTION_CNF
(
msg_p
).
errCode
,
NAS_CELL_SELECTION_CNF
(
msg_p
).
cellID
,
...
...
@@ -895,49 +955,40 @@ void *nas_nrue_task(void *args_p)
break
;
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 */
break
;
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 */
break
;
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
;
msg_type
=
get_msg_type
(
pdu_buffer
,
NAS_CONN_ESTABLI_CNF
(
msg_p
).
nasMsg
.
length
);
if
(
msg_type
==
REGISTRATION_ACCEPT
)
{
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
;
memset
(
&
initialNasMsg
,
0
,
sizeof
(
as_nas_info_t
));
generateRegistrationComplete
(
Mod_id
,
&
initialNasMsg
,
NULL
);
generateRegistrationComplete
(
nas
,
&
initialNasMsg
,
NULL
);
if
(
initialNasMsg
.
length
>
0
)
{
MessageDef
*
message_p
;
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
);
send_nas_uplink_data_req
(
instance
,
&
initialNasMsg
);
LOG_I
(
NAS
,
"Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)
\n
"
);
}
as_nas_info_t
pduEstablishMsg
;
memset
(
&
pduEstablishMsg
,
0
,
sizeof
(
as_nas_info_t
));
generatePduSessionEstablishRequest
(
Mod_id
,
uicc
,
&
pduEstablishMsg
);
generatePduSessionEstablishRequest
(
nas
,
&
pduEstablishMsg
);
if
(
pduEstablishMsg
.
length
>
0
)
{
MessageDef
*
message_p
;
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
);
send_nas_uplink_data_req
(
instance
,
&
pduEstablishMsg
);
LOG_I
(
NAS
,
"Send NAS_UPLINK_DATA_REQ message(PduSessionEstablishRequest)
\n
"
);
}
}
else
if
(
msg_type
==
FGS_PDU_SESSION_ESTABLISHMENT_ACC
)
{
...
...
@@ -948,24 +999,38 @@ void *nas_nrue_task(void *args_p)
}
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
);
itti_wait_tasks_unblock
();
/* will unblock ITTI to stop nr-uesoftmodem */
break
;
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
);
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
:
{
LOG_I
(
NAS
,
"[UE %d] Received %s: UEid %u, length %u , buffer %p
\n
"
,
Mod_id
,
ITTI_MSG_NAME
(
msg_p
),
Mod_id
,
NAS_DOWNLINK_DATA_IND
(
msg_p
).
nasMsg
.
length
,
NAS_DOWNLINK_DATA_IND
(
msg_p
).
nasMsg
.
data
);
LOG_I
(
NAS
,
"[UE %ld] Received %s: length %u , buffer %p
\n
"
,
instance
,
ITTI_MSG_NAME
(
msg_p
),
NAS_DOWNLINK_DATA_IND
(
msg_p
).
nasMsg
.
length
,
NAS_DOWNLINK_DATA_IND
(
msg_p
).
nasMsg
.
data
);
as_nas_info_t
initialNasMsg
=
{
0
};
pdu_buffer
=
NAS_DOWNLINK_DATA_IND
(
msg_p
).
nasMsg
.
data
;
...
...
@@ -974,18 +1039,21 @@ void *nas_nrue_task(void *args_p)
switch
(
msg_type
){
case
FGS_IDENTITY_REQUEST
:
generateIdentityResponse
(
&
initialNasMsg
,
*
(
pdu_buffer
+
3
),
uicc
);
generateIdentityResponse
(
&
initialNasMsg
,
*
(
pdu_buffer
+
3
),
nas
->
uicc
);
break
;
case
FGS_AUTHENTICATION_REQUEST
:
generateAuthenticationResp
(
Mod_id
,
&
initialNasMsg
,
pdu_buffer
,
uicc
);
generateAuthenticationResp
(
nas
,
&
initialNasMsg
,
pdu_buffer
);
break
;
case
FGS_SECURITY_MODE_COMMAND
:
nas_itti_kgnb_refresh_req
(
ue_security_key
[
Mod_id
]
->
kgnb
,
instance
);
generateSecurityModeComplete
(
Mod_id
,
&
initialNasMsg
);
nas_itti_kgnb_refresh_req
(
nas
->
security
.
kgnb
);
generateSecurityModeComplete
(
nas
,
&
initialNasMsg
);
break
;
case
FGS_DOWNLINK_NAS_TRANSPORT
:
decodeDownlinkNASTransport
(
&
initialNasMsg
,
pdu_buffer
);
break
;
case
FGS_DEREGISTRATION_ACCEPT
:
LOG_I
(
NAS
,
"received deregistration accept
\n
"
);
break
;
case
FGS_PDU_SESSION_ESTABLISHMENT_ACC
:
{
uint8_t
offset
=
0
;
...
...
@@ -1017,25 +1085,17 @@ void *nas_nrue_task(void *args_p)
}
break
;
default:
LOG_W
(
NR_RRC
,
"unknow message type %d
\n
"
,
msg_type
);
LOG_W
(
NR_RRC
,
"unknow
n
message type %d
\n
"
,
msg_type
);
break
;
}
if
(
initialNasMsg
.
length
>
0
){
MessageDef
*
message_p
;
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
"
);
if
(
initialNasMsg
.
length
>
0
)
send_nas_uplink_data_req
(
instance
,
&
initialNasMsg
);
}
}
break
;
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
;
}
...
...
openair3/NAS/NR_UE/nr_nas_msg_sim.h
View file @
5268dbf3
...
...
@@ -36,9 +36,11 @@
#include "FGSIdentityResponse.h"
#include "FGSAuthenticationResponse.h"
#include "FGSNASSecurityModeComplete.h"
#include "FGSDeregistrationRequestUEOriginating.h"
#include "RegistrationComplete.h"
#include "as_message.h"
#include "FGSUplinkNasTransport.h"
#include <openair3/UICC/usim_interface.h>
#define PLAIN_5GS_MSG 0b0000
#define INTEGRITY_PROTECTED 0b0001
...
...
@@ -49,6 +51,8 @@
#define REGISTRATION_REQUEST 0b01000001
/* 65 = 0x41 */
#define REGISTRATION_ACCEPT 0b01000010
/* 66 = 0x42 */
#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_RESPONSE 0b01010111
/* 87 = 0x57 */
#define FGS_IDENTITY_REQUEST 0b01011011
/* 91 = 0x5b */
...
...
@@ -78,8 +82,16 @@ typedef struct {
uint8_t
res
[
16
];
uint8_t
rand
[
16
];
uint8_t
kgnb
[
32
];
uint32_t
mm_counter
;
uint32_t
sm_counter
;
}
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
{
/* Protocol discriminator identifier for 5GS Mobility Management */
FGS_MOBILITY_MANAGEMENT_MESSAGE
=
0x7E
,
...
...
@@ -108,6 +120,7 @@ typedef union {
registration_request_msg
registration_request
;
fgs_identiy_response_msg
fgs_identity_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
;
registration_complete_msg
registration_complete
;
fgs_uplink_nas_transport_msg
uplink_nas_transport
;
...
...
@@ -158,7 +171,8 @@ typedef struct {
fgs_sm_nas_msg_header_t
sm_nas_msg_header
;
}
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
);
#endif
/* __NR_NAS_MSG_SIM_H__*/
...
...
openair3/UICC/usim_interface.c
View file @
5268dbf3
...
...
@@ -116,9 +116,8 @@ uicc_t * checkUicc(int 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
l
=
strlen
(
uicc
->
imeisvStr
);
if
(
l
>
IMEISV_STR_MAX_LENGTH
)
{
...
...
openair3/UICC/usim_interface.h
View file @
5268dbf3
...
...
@@ -73,6 +73,5 @@ typedef struct {
uicc_t
*
checkUicc
(
int
Mod_id
);
uicc_t
*
init_uicc
(
char
*
sectionName
);
void
uicc_milenage_generate
(
uint8_t
*
autn
,
uicc_t
*
uicc
);
uicc_t
*
checkUicc
(
int
Mod_id
);
uint8_t
getImeisvDigit
(
int
Mod_id
,
uint8_t
i
);
uint8_t
getImeisvDigit
(
const
uicc_t
*
uicc
,
uint8_t
i
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment