Compare commits

...

2 Commits

Author SHA1 Message Date
Sakthivel Velumani
07dfa659c8 Add documentation
Instructions on the usage of AT command inteface and supported commands.
2024-10-23 13:48:23 -04:00
Sakthivel Velumani
9ef178f478 Enable AT command interface and link to NAS layer
1. Add AT command handlers to set and activate PDP context.
2. Changes to NAS for sending multiple PDU session request.
3. Function to create PTY pair to get AT commands.
4. Trigger deregistration with at+cfun=0.
5. Optional command line parameter to user device from user.
2024-10-23 13:47:13 -04:00
24 changed files with 616 additions and 77 deletions

View File

@@ -162,6 +162,44 @@ e.g.
sudo ./nr-uesoftmodem --sa -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 2 --ue-nb-ant-rx 2 --uecap_file /opt/oai-nr-ue/etc/uecap.xml
```
## AT Command Interface in NR-UE
NR UE features an interactive AT command interface. Users can use this interface to issue commands and to get specific information from the softmodem in the same manner as in Quectel or Sierra modems. At the moment, the UE supports only the following commands
- `at+cgdcont`
- `at+cfun`
### Example Usage
1. By default, the UE creates a pair of serial device and opens one interface to receive AT commands. The other interface is printed in the logs so that the user can open using tools like minicom to send AT commands. A sample log from UE looks like
```
[NAS] Serial device for AT command: /dev/pts/66
```
2. Open the interface using minicom
```
sudo minicom -D /dev/pts/66
```
**Optional**: Alternatively, the user can create their own pair of virtual serail port using `socat`.
```
socat -d -d pty,raw,echo=1 pty,raw,echo=1
```
The output should be something like this
```
2024/06/05 13:14:57 socat[893875] N PTY is /dev/pts/12
2024/06/05 13:14:57 socat[893875] N PTY is /dev/pts/13
2024/06/05 13:14:57 socat[893875] N starting data transfer loop with FDs [5,5] and [7,7]
```
Provide one interface to the UE with `--at-interface "/dev/pts/12"` and open the other with minicom.
### Example Commands
1. Read back the configured PDP contexts
```
at+cgdcont?
```
2. Trigger deregistration from network
```
at+cfun=0
```
## How to run a NTN configuration
### NTN channel

View File

@@ -153,6 +153,8 @@ int create_tasks_nrue(uint32_t ue_nb) {
if (itti_create_task(TASK_NAS_NRUE, nas_nrue_task, &parmsNAS) < 0) {
LOG_E(NR_RRC, "Create task for NAS UE failed\n");
return -1;
} else {
nas_nrue_user((void *)&parmsNAS);
}
}

View File

@@ -17,6 +17,11 @@
#define CONFIG_HLP_AUTONOMOUS_TA "Autonomously update TA based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite)\n"
#define CONFIG_HLP_AGC "Rx Gain control used for UE\n"
#define CONFIG_HLP_AT_IF \
"Name of the serial interface to be used by uesoftmodem to receive AT commands. Usually a pair of interface is created with " \
"socat and one interface is specified here. By default, the uesoftmodem creates a pair and prints the device name to send AT " \
"commands."
/***************************************************************************************************************************************/
/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument
when calling config_get or config_getlist functions */
@@ -71,6 +76,8 @@
{"ntn-ta-commondrift", CONFIG_HLP_NTN_TA_COMMONDRIFT, 0, .dblptr=&(nrUE_params.ntn_ta_commondrift), .defdblval=0.0, TYPE_DOUBLE, 0}, \
{"autonomous-ta", CONFIG_HLP_AUTONOMOUS_TA, PARAMFLAG_BOOL, .iptr=&(nrUE_params.autonomous_ta), .defintval=0, TYPE_INT, 0}, \
{"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \
{"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \
{"at-interface", CONFIG_HLP_AT_IF, 0, .strptr=&(nrUE_params.at_interface_name), .defstrval="psudoterm", TYPE_STRING, 0}, \
}
// clang-format on
@@ -109,6 +116,7 @@ typedef struct {
double rx_gain_off;
int vcdflag;
int tx_max_power;
char *at_interface_name;
} nrUE_params_t;
extern uint64_t get_nrUE_optmask(void);
extern uint64_t set_nrUE_optmask(uint64_t bitmask);

View File

@@ -463,13 +463,6 @@ typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t;
*/
typedef ul_info_transfer_ind_t dl_info_transfer_ind_t;
typedef struct nas_pdu_session_req_s {
int pdusession_id;
int pdusession_type;
int sst;
int sd;
} nas_pdu_session_req_t;
/*
* --------------------------------------------------------------------------
* Radio Access Bearer establishment
@@ -547,6 +540,18 @@ typedef struct rab_release_ind_s {
as_rab_id_t rabID; /* Radio access bearer identity */
} rab_release_ind_t;
/* PDP context stored in UE */
typedef struct nr_nas_pdp_context_s {
int pdu_session_id;
int pdu_session_type;
char dnn[64];
char nssaiStr[64];
int nssai_sst;
int nssai_sd;
bool is_active;
bool is_defined;
} nr_nas_pdp_context_t;
/*
* --------------------------------------------------------------------------
* Structure of the AS messages handled by the network sublayer

View File

@@ -84,4 +84,4 @@ MESSAGE_DEF(NRRRC_FRAME_PROCESS, MESSAGE_PRIORITY_MED, NRRrcFramePr
// eNB: RLC -> RRC messages
MESSAGE_DEF(RLC_SDU_INDICATION, MESSAGE_PRIORITY_MED, RlcSduIndication, rlc_sdu_indication)
MESSAGE_DEF(NAS_PDU_SESSION_REQ, MESSAGE_PRIORITY_MED, nas_pdu_session_req_t, nas_pdu_session_req)
MESSAGE_DEF(NAS_PDU_SESSION_REQ, MESSAGE_PRIORITY_MED, nr_nas_pdp_context_t, nas_pdu_session_req)

View File

@@ -25,7 +25,7 @@
#include "common/utils/tun_if.h"
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
static uint16_t getShort(uint8_t *input)
static uint16_t getShort(const uint8_t *input)
{
uint16_t tmp16;
memcpy(&tmp16, input, sizeof(tmp16));
@@ -40,7 +40,7 @@ static int capture_ipv4_addr(const uint8_t *addr, char *ip, size_t len)
static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len)
{
// 24.501 Sec 9.11.4.10: "an interface identifier for the IPv6 link local
// address": link local starts with fe80::, and only the last 64bits are
// address": link local starts with fe80::, and only the last 64bits> are
// given (middle is zero)
return snprintf(ip,
len,
@@ -55,12 +55,12 @@ static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len)
addr[7]);
}
void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_length)
void capture_pdu_session_establishment_accept_msg(const uint8_t *buffer, uint32_t msg_length, int *pdu_id)
{
security_protected_nas_5gs_msg_t sec_nas_hdr;
security_protected_plain_nas_5gs_msg_t sec_nas_msg;
pdu_session_establishment_accept_msg_t psea_msg;
uint8_t *curPtr = buffer;
const uint8_t *curPtr = buffer;
sec_nas_hdr.epd = *curPtr++;
sec_nas_hdr.sht = *curPtr++;
uint32_t tmp;
@@ -77,6 +77,7 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
/* Mandatory Presence IEs */
psea_msg.epd = *curPtr++;
psea_msg.pdu_id = *curPtr++;
*pdu_id = psea_msg.pdu_id;
psea_msg.pti = *curPtr++;
psea_msg.msg_type = *curPtr++;
psea_msg.pdu_type = *curPtr & 0x0f;

View File

@@ -163,6 +163,6 @@ typedef struct security_protected_nas_5gs_msg_s {
uint8_t sqn; /* Sequence Number */
} security_protected_nas_5gs_msg_t; /* 24.501 Figure 9.1.1.2 */
void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_length);
void capture_pdu_session_establishment_accept_msg(const uint8_t *buffer, uint32_t msg_length, int *pdu_id);
#endif

View File

@@ -43,6 +43,8 @@ Description Implements Linux/UNIX I/O device handlers
#include <stdlib.h> // malloc, free
#include <string.h> // strncpy
#include <unistd.h> // read, write, close
#include <pty.h> // openpty
#include <termios.h>
#include <sys/stat.h>
#include <fcntl.h> // open
@@ -75,6 +77,64 @@ struct device_id_s {
/****************** E X P O R T E D F U N C T I O N S ******************/
/****************************************************************************/
/****************************************************************************
** **
** Name: device_open_psudoterm() **
** **
** Description: Create a PTY device pair to perform read **
** and write I/O operations **
** **
** Inputs: None **
** **
** Outputs: None **
** Return: A pointer to the device identifier alloca- **
** ted for I/O operations. NULL if the device **
** has not been successfully opened. **
** Others: None **
** **
***************************************************************************/
void* device_open_psudoterm(int type, const char* devpath, const char* params)
{
if (type != DEVICE) {
return NULL;
}
int master_fd, slave_fd;
char slave_name[DEVICE_PATHNAME_SIZE];
/* Create a PTY pair */
if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) == -1) {
perror("failed during openpty()");
return NULL;
}
/* Set echo mode to dispay characters */
struct termios slave_settings;
if (tcsetattr(slave_fd, TCSANOW, &slave_settings) == -1) {
perror("failed during tcsetattr()");
return NULL;
}
slave_settings.c_lflag |= ECHO;
if (tcsetattr(slave_fd, TCSANOW, &slave_settings) == -1) {
perror("failed during tcsetattr()");
return NULL;
}
/* The device has been successfully created */
device_id_t* devid = (device_id_t*)malloc(sizeof(struct device_id_s));
if (devid != NULL) {
strncpy(devid->pathname, slave_name, DEVICE_PATHNAME_SIZE);
devid->fd = master_fd;
}
printf("Serial interface for AT command: %s\n", slave_name);
return devid;
}
/****************************************************************************
** **
** Name: device_open() **
@@ -247,6 +307,29 @@ int device_get_fd(const void* id)
return RETURNerror;
}
/****************************************************************************
** **
** Name: device_get_name() **
** **
** Description: Get the value of the file descriptor created to handle **
** the device with the given identifier **
** **
** Inputs: id: The identifier of the device **
** Others: None **
** **
** Outputs: None **
** Return: The path and name of the device **
** Others: None **
** **
***************************************************************************/
char* device_get_name(const void* id)
{
if (id) {
return ((device_id_t*)id)->pathname;
}
return NULL;
}
/****************************************************************************/
/********************* L O C A L F U N C T I O N S *********************/
/****************************************************************************/

View File

@@ -62,8 +62,10 @@ typedef struct device_id_s device_id_t;
/****************** E X P O R T E D F U N C T I O N S ******************/
/****************************************************************************/
void* device_open_psudoterm(int type, const char* devpath, const char* params);
void* device_open(int type, const char* devname, const char* params);
int device_get_fd(const void* id);
char* device_get_name(const void* id);
ssize_t device_read(void* id, char* buffer, size_t length);
ssize_t device_write(const void* id, const char* buffer, size_t length);

View File

@@ -50,12 +50,15 @@
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "openair3/SECU/nas_stream_eia2.h"
#include "openair3/UTILS/conversions.h"
#include "openair3/NAS/UE/nas_user.h"
#include "openair3/NAS/UE/API/USER/user_api.h"
#include "openair3/NAS/UE/user_defs.h"
#include "executables/nr-uesoftmodem.h"
#define MAX_NAS_UE 4
extern uint16_t NB_UE_INST;
static nr_ue_nas_t nr_ue_nas[MAX_NAS_UE] = {0};
static nr_nas_msg_snssai_t nas_allowed_nssai[8];
typedef enum {
NAS_SECURITY_NO_SECURITY_CONTEXT,
@@ -928,7 +931,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi
}
}
static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, nas_pdu_session_req_t *pdu_req)
static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, nr_nas_pdp_context_t *pdu_req)
{
int size = 0;
fgs_nas_message_t nas_msg = {0};
@@ -938,11 +941,11 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
uint8_t *req_buffer = malloc(req_length);
pdu_session_establishment_request_msg pdu_session_establish;
pdu_session_establish.protocoldiscriminator = FGS_SESSION_MANAGEMENT_MESSAGE;
pdu_session_establish.pdusessionid = pdu_req->pdusession_id;
pdu_session_establish.pdusessionid = pdu_req->pdu_session_id;
pdu_session_establish.pti = 1;
pdu_session_establish.pdusessionestblishmsgtype = FGS_PDU_SESSION_ESTABLISHMENT_REQ;
pdu_session_establish.maxdatarate = 0xffff;
pdu_session_establish.pdusessiontype = pdu_req->pdusession_type;
pdu_session_establish.pdusessiontype = pdu_req->pdu_session_type;
encode_pdu_session_establishment_request(&pdu_session_establish, req_buffer);
MM_msg *mm_msg;
@@ -975,25 +978,25 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
mm_msg->uplink_nas_transport.fgspayloadcontainer.payloadcontainercontents.length = req_length;
mm_msg->uplink_nas_transport.fgspayloadcontainer.payloadcontainercontents.value = req_buffer;
size += (2 + req_length);
mm_msg->uplink_nas_transport.pdusessionid = pdu_req->pdusession_id;
mm_msg->uplink_nas_transport.pdusessionid = pdu_req->pdu_session_id;
mm_msg->uplink_nas_transport.requesttype = 1;
size += 3;
const bool has_nssai_sd = pdu_req->sd != 0xffffff; // 0xffffff means "no SD", TS 23.003
const bool has_nssai_sd = pdu_req->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] = pdu_req->sst;
mm_msg->uplink_nas_transport.snssai.value[0] = pdu_req->nssai_sst;
if (has_nssai_sd)
INT24_TO_BUFFER(pdu_req->sd, &mm_msg->uplink_nas_transport.snssai.value[1]);
INT24_TO_BUFFER(pdu_req->nssai_sd, &mm_msg->uplink_nas_transport.snssai.value[1]);
size += 1 + 1 + nssai_len;
int dnnSize = strlen(nas->uicc->dnnStr);
mm_msg->uplink_nas_transport.dnn.value = calloc(1, dnnSize + 1);
int dnnSize = strlen(pdu_req->dnn);
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, nas->uicc->dnnStr, dnnSize);
memcpy(mm_msg->uplink_nas_transport.dnn.value + 1, pdu_req->dnn, dnnSize);
size += (1 + 1 + dnnSize + 1);
// encode the message
@@ -1189,24 +1192,157 @@ static void get_allowed_nssai(nr_nas_msg_snssai_t nssai[8], const uint8_t *pdu_b
}
}
static void request_default_pdusession(nr_ue_nas_t *nas, int nssai_idx)
int nas_request_deregistration(nas_user_t *nas_user)
{
MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_PDU_SESSION_REQ);
NAS_PDU_SESSION_REQ(message_p).pdusession_id = 10; /* first or default pdu session */
NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6
NAS_PDU_SESSION_REQ(message_p).sst = nas_allowed_nssai[nssai_idx].sst;
NAS_PDU_SESSION_REQ(message_p).sd = nas_allowed_nssai[nssai_idx].sd;
itti_send_msg_to_task(TASK_NAS_NRUE, nas->UE_id, message_p);
const int UE_id = nas_user->ueid;
MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, UE_id, NAS_DEREGISTRATION_REQ);
NAS_DEREGISTRATION_REQ(message_p).cause = AS_DETACH;
itti_send_msg_to_task(TASK_NAS_NRUE, UE_id, message_p);
return RETURNok;
}
static int get_user_nssai_idx(const nr_nas_msg_snssai_t allowed_nssai[8], const nr_ue_nas_t *nas)
static void request_pdusession(const nr_nas_pdp_context_t *pdp_cxt, int UE_id)
{
MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, UE_id, NAS_PDU_SESSION_REQ);
NAS_PDU_SESSION_REQ(message_p) = *pdp_cxt;
itti_send_msg_to_task(TASK_NAS_NRUE, UE_id, message_p);
}
int nas_request_pdu_release(nas_user_t *user, int cid)
{
LOG_E(NAS, "PDU release not implemented yet\n");
return RETURNerror;
}
int nas_request_pdusession(nas_user_t *nas_user, int cid)
{
LOG_E(NAS, "Additional PDU session not supported yet\n");
return RETURNerror;
}
/* @brief Set active flag for PDP context */
static void set_pdp_active_flag(nr_ue_nas_t *nas, int pdu_session_id, bool flag)
{
for (int i = 0; i < MAX_PDP_CONTEXTS; i++) {
nr_nas_pdp_context_t *p = &nas->nas_user->pdp_context[i];
if (p->pdu_session_id == pdu_session_id) {
AssertFatal(p->is_defined, "Trying to de/activate a PDP context (%d) thats not defined by user. Something went wrong!\n", i);
p->is_active = true;
break;
}
}
}
/* @brief Check if user entered NSSAI fields match with
the list received from the network */
static bool valid_user_nssai(const nr_nas_msg_snssai_t allowed_nssai[8], const nr_nas_pdp_context_t *pdp_cxt)
{
for (int i = 0; i < 8; i++) {
const nr_nas_msg_snssai_t *nssai = allowed_nssai + i;
if ((nas->uicc->nssai_sst == nssai->sst) && (nas->uicc->nssai_sd == nssai->sd))
return i;
if ((pdp_cxt->nssai_sst == nssai->sst) && (pdp_cxt->nssai_sd == nssai->sd))
return true;
}
return -1;
return false;
}
static void parse_nssai_string(const char *nssaiStr, int *sst, int *sd)
{
if (nssaiStr[0] == '\0')
return;
const char *del = ".";
char *tmp = (char *)nssaiStr;
char *token = strtok(tmp, del);
*sst = atoi(token);
token = strtok(NULL, del);
*sd = atoi(token);
token = strtok(NULL, del);
DevAssert(token == NULL);
}
int nas_reset_pdp_context(nas_user_t *user, int index)
{
if ((user == NULL) || (index >= MAX_PDP_CONTEXTS)) {
LOG_E(NAS, "Can't reset PDP context\n");
return RETURNerror;
}
memset(&user->pdp_context[index], 0, sizeof(user->pdp_context[index]));
return RETURNok;
}
/* @brief Sets additional PDP context from user */
int nas_set_pdp_context(nas_user_t *user,
int index,
int pdu_session_type,
const char *dnn,
int ipv4_addr,
int emergency,
int p_cscf,
int im_cn_signal,
const char *nssai)
{
if (!((index > 0) && (index < MAX_PDP_CONTEXTS))) {
LOG_E(NAS, "Invalid index.\n"); // index 0 for default PDP
return RETURNerror;
}
if (!dnn || !nssai) {
LOG_E(NAS, "No DNN or NSSAI config.\n");
return RETURNerror;
}
nr_nas_pdp_context_t *pdp_cxt = &user->pdp_context[index];
pdp_cxt->pdu_session_id = user->pdp_context[0].pdu_session_id + index;
pdp_cxt->pdu_session_type = 0x90 | (pdu_session_type & 0xf);
strcpy(pdp_cxt->nssaiStr, nssai);
parse_nssai_string(nssai, &pdp_cxt->nssai_sst, &pdp_cxt->nssai_sd);
pdp_cxt->is_defined = true;
memcpy(&pdp_cxt->dnn, dnn, strlen(dnn));
return RETURNok;
}
/* @brief Sets the first and default PDP context in NAS.
This is requested after registration. */
static void set_default_pdp_context(nr_ue_nas_t *nas)
{
nr_nas_pdp_context_t *pdp_cxt = &nas->nas_user->pdp_context[0];
pdp_cxt->pdu_session_id = 10; /* first or default pdu session */
pdp_cxt->pdu_session_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6
pdp_cxt->nssai_sd = nas->uicc->nssai_sd;
pdp_cxt->nssai_sst = nas->uicc->nssai_sst;
sprintf(pdp_cxt->nssaiStr, "%02d.%06d", pdp_cxt->nssai_sst, pdp_cxt->nssai_sd); /* used by AT get command */
pdp_cxt->is_defined = true;
memcpy(&pdp_cxt->dnn, nas->uicc->dnnStr, strlen(nas->uicc->dnnStr));
}
int nas_get_pdp_status(nas_user_t *user, int *index, int *status, int n_pdn_max)
{
int n_pdn = 0;
for (int i = 0; ((i < MAX_PDP_CONTEXTS) && (n_pdn < n_pdn_max)); i++) {
if (!user->pdp_context[i].is_defined)
continue;
*(index++) = i;
*(status++) = user->pdp_context[i].is_active;
n_pdn++;
}
return n_pdn;
}
int nas_get_pdp_contexts(nas_user_t *user, int *index, int *types, const char **apns, const char **nssai, int n_pdn_max)
{
int n_pdn = 0;
for (int i = 0; ((i < MAX_PDP_CONTEXTS) && (n_pdn < n_pdn_max)); i++) {
if (!user->pdp_context[i].is_defined)
continue;
*(index++) = i;
*(types++) = user->pdp_context[i].pdu_session_type;
*(apns++) = user->pdp_context[i].dnn;
*(nssai++) = user->pdp_context[i].nssaiStr;
n_pdn++;
}
return n_pdn;
}
int nas_get_pdp_range(nas_user_t *user)
{
return MAX_PDP_CONTEXTS;
}
void *nas_nrue_task(void *args_p)
@@ -1214,7 +1350,7 @@ void *nas_nrue_task(void *args_p)
for (int UE_id = 0; UE_id < NB_UE_INST; UE_id++) {
// This sets UE uicc from command line. Needs to be called 2 seconds into nr-ue runtime, otherwise the unused command line
// arguments will be reported as unused and the modem asserts.
(void)get_ue_nas_info(UE_id);
get_ue_nas_info(UE_id);
}
while (1) {
nas_nrue(NULL);
@@ -1225,7 +1361,7 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff
{
LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n");
decodeRegistrationAccept(pdu_buffer, msg_length, nas);
get_allowed_nssai(nas_allowed_nssai, pdu_buffer, msg_length);
get_allowed_nssai(nas->nas_allowed_nssai, pdu_buffer, msg_length);
as_nas_info_t initialNasMsg = {0};
generateRegistrationComplete(nas, &initialNasMsg, NULL);
@@ -1233,11 +1369,11 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff
send_nas_uplink_data_req(nas, &initialNasMsg);
LOG_I(NAS, "Send NAS_UPLINK_DATA_REQ message(RegistrationComplete)\n");
}
const int nssai_idx = get_user_nssai_idx(nas_allowed_nssai, nas);
if (nssai_idx < 0) {
if (!valid_user_nssai(nas->nas_allowed_nssai, &nas->nas_user->pdp_context[0])) {
LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n");
} else {
request_default_pdusession(nas, nssai_idx);
/* Default PDU session */
request_pdusession(&nas->nas_user->pdp_context[0], nas->UE_id);
}
}
@@ -1296,7 +1432,8 @@ void *nas_nrue(void *args_p)
case NAS_PDU_SESSION_REQ: {
as_nas_info_t pduEstablishMsg = {0};
nas_pdu_session_req_t *pduReq = &NAS_PDU_SESSION_REQ(msg_p);
nr_nas_pdp_context_t *pduReq = &NAS_PDU_SESSION_REQ(msg_p);
nr_ue_nas_t *nas = get_ue_nas_info(0);
generatePduSessionEstablishRequest(nas, &pduEstablishMsg, pduReq);
if (pduEstablishMsg.length > 0) {
send_nas_uplink_data_req(nas, &pduEstablishMsg);
@@ -1327,10 +1464,14 @@ void *nas_nrue(void *args_p)
if (msg_type == REGISTRATION_ACCEPT) {
handle_registration_accept(nas, pdu_buffer, pdu_length);
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length);
int pdu_session_id = -1;
capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length, &pdu_session_id);
set_pdp_active_flag(nas, pdu_session_id, true);
}
// Free NAS buffer memory after use (coming from RRC)
const void *nas_user_id = nas->nas_user->user_api_id->endpoint;
LOG_A(NAS, "Serial device for AT command: %s\n", nas->nas_user->user_api_id->getname(nas_user_id));
free(pdu_buffer);
break;
}
@@ -1473,3 +1614,67 @@ void *nas_nrue(void *args_p)
}
return NULL;
}
static void init_nas_user(nr_ue_nas_t *nas)
{
if (nas->nas_user)
return;
nas->nas_user = calloc(1, sizeof(*nas->nas_user));
set_default_pdp_context(nas);
}
static void *nas_user_mngr(void *args)
{
const int ue_id = 0; // create user manager for only one UE instance
user_api_id_t user_api = {0};
at_response_t atr = {0};
user_at_commands_t atc = {0};
if (user_api_initialize(&user_api, NULL, NULL, get_nrUE_params()->at_interface_name, "9600") != RETURNok) {
LOG_E(NAS, "Unable to initialize NAS user interface\n");
}
nr_ue_nas_t *nas = get_ue_nas_info(ue_id);
init_nas_user(nas);
nas_user_t *nas_user = nas->nas_user;
nas_user->ueid = nas->UE_id;
nas_user->nas_ue_type = UE_NR;
nas_user->nas_reset_pdn = nas_reset_pdp_context;
nas_user->nas_get_pdn = nas_get_pdp_contexts;
nas_user->nas_set_pdn = nas_set_pdp_context;
nas_user->nas_get_pdn_range = nas_get_pdp_range;
nas_user->nas_deactivate_pdn = nas_request_pdu_release;
nas_user->nas_activate_pdn = nas_request_pdusession;
nas_user->nas_get_pdn_status = nas_get_pdp_status;
nas_user->nas_deregister = nas_request_deregistration;
nas_user->user_api_id = &user_api;
nas_user->at_response = &atr;
nas_user->user_at_commands = &atc;
nas_user_context_t user_ctxt = {0};
const char *version = "v1.0";
nas_user_context_initialize(&user_ctxt, version);
user_ctxt.sim_status = NAS_USER_READY; /* set SIM ready by default */
nas_user->nas_user_context = &user_ctxt;
bool exit_loop = false;
int fd = user_api_get_fd(&user_api);
LOG_I(NAS, "User interface manager started with fd %d\n", fd);
while (!exit_loop) {
exit_loop = nas_user_receive_and_process(nas_user, NULL);
}
user_api_close(nas_user->user_api_id);
LOG_I(NAS, "User interface manager ended\n");
free_and_zero(nas->nas_user);
return NULL;
}
void nas_nrue_user(void *args_p)
{
pthread_t user_mngr;
threadCreate(&user_mngr, nas_user_mngr, NULL, "UE-nas", -1, OAI_PRIORITY_RT_LOW);
}

View File

@@ -42,6 +42,9 @@
#include "FGSUplinkNasTransport.h"
#include <openair3/UICC/usim_interface.h>
#include "secu_defs.h"
#include <openair3/NAS/UE/API/USER/user_api_defs.h>
#include "openair3/NAS/UE/API/USER/at_response.h"
#include "openair3/NAS/UE/user_defs.h"
#define PLAIN_5GS_MSG 0b0000
#define INTEGRITY_PROTECTED 0b0001
@@ -106,6 +109,8 @@ typedef struct {
uint8_t *registration_request_buf;
uint32_t registration_request_len;
instance_t UE_id;
nr_nas_msg_snssai_t nas_allowed_nssai[8];
nas_user_t *nas_user;
} nr_ue_nas_t;
typedef enum fgs_protocol_discriminator_e {
@@ -191,6 +196,8 @@ 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(void *args_p);
void nr_ue_create_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id);
void nas_nrue_user(void *args_p);
#endif /* __NR_NAS_MSG_SIM_H__*/

View File

@@ -55,8 +55,8 @@ Description Defines the ATtention (AT) command set supported by the NAS
/****************************************************************************/
// FIXME Put this in .h
extern int at_response_format_v1;
extern int at_error_code_suppression_q1;
extern bool at_response_format_v1;
extern bool at_error_code_suppression_q1;
extern at_error_format_t at_error_format;
/****************************************************************************/
@@ -1512,7 +1512,11 @@ static int parse_cereg_test(const char* string, int position, at_command_t* at_c
static int parse_cgdcont_set(const char* string, int position, at_command_t* at_command)
{
/* CGDCONT parameter command - Parameters [<cid>[,<PDP_type>[,<APN>[,<PDP_addr>[,<d_comp>[,<h_comp>[,<IPv4AddrAlloc>[,<emergency indication>[,<P-CSCF_discovery>[,<IM_CN_Signalling_Flag_Ind>]]]]]]]]]] */
/* CGDCONT parameter command - Parameters [<cid>[,<PDP_type>[,<APN>[,<PDP_addr>[,<d_comp>[,<h_comp>
[,<IPv4AddrAlloc>[,<request_type>[,<P-CSCF_discovery>[,<IM_CN_Signalling_Flag_Ind>[,<NSLPI>[,<securePCO>
[,<IPv4_MTU_discovery>[,<Local_Addr_Ind>[,<Non-IP_MTU_discovery>[,<Reliable_Data_Service>[,<SSC_mode>
[,<S-NSSAI>[,<Pref_access_type>]]]]]]]]]]]]]]]]]]]
*/
at_command->id = AT_CGDCONT;
unsigned char* parameter_start_index = (unsigned char*) string + position;
@@ -1752,6 +1756,80 @@ static int parse_cgdcont_set(const char* string, int position, at_command_t* at_
AT_CGDCONT_EMERGECY_INDICATION_MASK | AT_CGDCONT_P_CSCF_DISCOVERY_MASK | AT_CGDCONT_IM_CN_SIGNALLING_FLAG_IND_MASK;
break;
case 19: /* <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>
,<IPv4AddrAlloc>,<request_type>,<P-CSCF_discovery>,<IM_CN_Signalling_Flag_Ind>,<NSLPI>,<securePCO>
,<IPv4_MTU_discovery>,<Local_Addr_Ind>,<Non-IP_MTU_discovery>,<Reliable_Data_Service>,<SSC_mode>
,<S-NSSAI>,<Pref_access_type> are present */
if (ParseCommand(parameter_start_index,
"@i,@r,@r,@r,@I,@I,@I,@I,@I,@I,@I,@I,@I,@I,@I,@I,@I,@r,@I",
&at_command->command.cgdcont.cid,
&at_command->command.cgdcont.PDP_type,
AT_CGDCONT_PDP_SIZE,
&at_command->command.cgdcont.APN,
AT_CGDCONT_APN_SIZE,
&at_command->command.cgdcont.PDP_addr,
AT_CGDCONT_ADDR_SIZE,
&at_command->command.cgdcont.d_comp,
&at_command->command.cgdcont.h_comp,
&at_command->command.cgdcont.IPv4AddrAlloc,
&at_command->command.cgdcont.emergency_indication,
&at_command->command.cgdcont.P_CSCF_discovery,
&at_command->command.cgdcont.IM_CN_Signalling_Flag_Ind,
&at_command->command.cgdcont.nspli,
&at_command->command.cgdcont.secure_PCO,
&at_command->command.cgdcont.IPv4_MTU_discovery,
&at_command->command.cgdcont.Local_Addr_Ind,
&at_command->command.cgdcont.Non_IP_MTU_discovery,
&at_command->command.cgdcont.Reliable_Data_Service,
&at_command->command.cgdcont.SSC_mode,
&at_command->command.cgdcont.nssaiStr,
AT_CGDCONT_NSSAI_SIZE,
&at_command->command.cgdcont.Pref_access_type)
!= RETURNok) {
LOG_TRACE(ERROR,
"USR-API - Parsing of "
"AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<request_type>,<P-CSCF_discovery>,<"
"IM_CN_Signalling_Flag_Ind>,<NSLPI>,<securePCO>,<IPv4_MTU_discovery>,<Local_Addr_Ind>,<Non-IP_MTU_discovery>,<"
"Reliable_Data_Service>,<SSC_mode>,<S-NSSAI>,<Pref_access_type> failed\n");
return RETURNerror;
}
LOG_TRACE(INFO,
"USR-API - Parsing of "
"AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<request_type>,<P-CSCF_discovery>,<"
"IM_CN_Signalling_Flag_Ind>,<NSLPI>,<securePCO>,<IPv4_MTU_discovery>,<Local_Addr_Ind>,<Non-IP_MTU_discovery>,<"
"Reliable_Data_Service>,<SSC_mode>,<S-NSSAI>,<Pref_access_type> succeeded (cid:%d, PDP_type:%s ,APN:%s, PDP_addr:%s, "
"d_comp:%d, h_comp:%d, IPv4AddrAlloc:%d, request_type:%d, P-CSCF_discovery:%d, IM_CN_Signalling_Flag_Ind:%d, "
"NSLPI:%d, securePCO:%d, IPv4_MTU_discovery:%d, Local_Addr_Ind:%d, Non-IP_MTU_discovery:%d, "
"Reliable_Data_Service:%d, SSC_mode:%d, S-NSSAI:%s, Pref_access_type:%d)",
at_command->command.cgdcont.cid,
at_command->command.cgdcont.PDP_type,
at_command->command.cgdcont.APN,
at_command->command.cgdcont.PDP_addr,
at_command->command.cgdcont.d_comp,
at_command->command.cgdcont.h_comp,
at_command->command.cgdcont.IPv4AddrAlloc,
at_command->command.cgdcont.emergency_indication,
at_command->command.cgdcont.P_CSCF_discovery,
at_command->command.cgdcont.IM_CN_Signalling_Flag_Ind,
at_command->command.cgdcont.nspli,
at_command->command.cgdcont.secure_PCO,
at_command->command.cgdcont.IPv4_MTU_discovery,
at_command->command.cgdcont.Local_Addr_Ind,
at_command->command.cgdcont.Non_IP_MTU_discovery,
at_command->command.cgdcont.Reliable_Data_Service,
at_command->command.cgdcont.SSC_mode,
at_command->command.cgdcont.nssaiStr,
at_command->command.cgdcont.Pref_access_type);
at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK
| AT_CGDCONT_D_COMP_MASK | AT_CGDCONT_H_COMP_MASK | AT_CGDCONT_IPV4ADDRALLOC_MASK
| AT_CGDCONT_EMERGECY_INDICATION_MASK | AT_CGDCONT_P_CSCF_DISCOVERY_MASK
| AT_CGDCONT_IM_CN_SIGNALLING_FLAG_IND_MASK | AT_CGDCONT_NSPLI | AT_CGDCONT_SECURE_PCO
| AT_CGDCONT_IPV4_MTU_DIS | AT_CGDCONT_LOCAL_ADDR_IND | AT_CGDCONT_NON_IP_MTU_DIS
| AT_CGDCONT_REL_DATA_SERVICE | AT_CGDCONT_SSC_MODE | AT_CGDCONT_NSSAI | AT_CGDCONT_PREF_ACCESS_TYPE;
break;
default:
LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters);
return RETURNerror;

View File

@@ -65,6 +65,9 @@ Description Defines the ATtention (AT) command set supported by the NAS
#define AT_COMMAND_PARAM14 0x2000 /* 14th parameter is present */
#define AT_COMMAND_PARAM15 0x4000 /* 15th parameter is present */
#define AT_COMMAND_PARAM16 0x8000 /* 16th parameter is present */
#define AT_COMMAND_PARAM17 0x10000 /* 17th parameter is present */
#define AT_COMMAND_PARAM18 0x20000 /* 18th parameter is present */
#define AT_COMMAND_PARAM19 0x40000 /* 19th parameter is present */
/* Value of the mask parameter for AT commands without any parameters */
#define AT_COMMAND_NO_PARAM AT_COMMAND_PARAM0
@@ -737,6 +740,15 @@ typedef struct {
#define AT_CGDCONT_EMERGECY_INDICATION_MASK AT_COMMAND_PARAM8
#define AT_CGDCONT_P_CSCF_DISCOVERY_MASK AT_COMMAND_PARAM9
#define AT_CGDCONT_IM_CN_SIGNALLING_FLAG_IND_MASK AT_COMMAND_PARAM10
#define AT_CGDCONT_NSPLI AT_COMMAND_PARAM11
#define AT_CGDCONT_SECURE_PCO AT_COMMAND_PARAM12
#define AT_CGDCONT_IPV4_MTU_DIS AT_COMMAND_PARAM13
#define AT_CGDCONT_LOCAL_ADDR_IND AT_COMMAND_PARAM14
#define AT_CGDCONT_NON_IP_MTU_DIS AT_COMMAND_PARAM15
#define AT_CGDCONT_REL_DATA_SERVICE AT_COMMAND_PARAM16
#define AT_CGDCONT_SSC_MODE AT_COMMAND_PARAM17
#define AT_CGDCONT_NSSAI AT_COMMAND_PARAM18
#define AT_CGDCONT_PREF_ACCESS_TYPE AT_COMMAND_PARAM19
/* CGDCONT AT command type */
typedef struct {
@@ -754,6 +766,16 @@ typedef struct {
int emergency_indication;
int P_CSCF_discovery;
int IM_CN_Signalling_Flag_Ind;
int nspli;
int secure_PCO;
int IPv4_MTU_discovery;
int Local_Addr_Ind;
int Non_IP_MTU_discovery;
int Reliable_Data_Service;
int SSC_mode;
#define AT_CGDCONT_NSSAI_SIZE 16
char nssaiStr[AT_CGDCONT_NSSAI_SIZE];
int Pref_access_type;
} at_cgdcont_t;
/* CGACT: PDP context activate or deactivate

View File

@@ -50,7 +50,7 @@ Description Defines error codes returned when execution of AT command
/****************************************************************************/
// FIXME put this in .h
extern int at_response_format_v1;
extern bool at_response_format_v1;
/*
* Result code suppression indicator (set by ATQ0 and ATQ1)

View File

@@ -951,8 +951,13 @@ static int _at_response_encode_cgdcont(char* buffer, const at_response_t* data)
offset += sprintf(buffer+offset, ",%s", cgdcont->APN[i]);
/* No data/header compression */
offset += sprintf(buffer+offset, ",%u,%u\r\n",
(unsigned int)(AT_CGDCONT_D_COMP_OFF), (unsigned int)(AT_CGDCONT_H_COMP_OFF));
offset +=
sprintf(buffer + offset, ",%u,%u", (unsigned int)(AT_CGDCONT_D_COMP_OFF), (unsigned int)(AT_CGDCONT_H_COMP_OFF));
offset += sprintf(buffer + offset, ",,,,,,,,,,,"); /* Currently unused parameters */
/* NSSAI */
offset += sprintf(buffer + offset, ",%s", cgdcont->nssaiStr[i]);
/* Preferred access type */
offset += sprintf(buffer + offset, ",\r\n");
}
} else if (data->type == AT_COMMAND_TST) {
const at_cgdcont_tst_t * cgdcont = &(data->response.cgdcont.tst);

View File

@@ -641,6 +641,19 @@ typedef struct {
const char* APN[AT_CGDCONT_RESP_SIZE];
int d_comp[AT_CGDCONT_RESP_SIZE];
int h_comp[AT_CGDCONT_RESP_SIZE];
int IPv4AddrAlloc[AT_CGDCONT_RESP_SIZE];
int emergency_indication[AT_CGDCONT_RESP_SIZE];
int P_CSCF_discovery[AT_CGDCONT_RESP_SIZE];
int IM_CN_Signalling_Flag_Ind[AT_CGDCONT_RESP_SIZE];
int nspli[AT_CGDCONT_RESP_SIZE];
int secure_PCO[AT_CGDCONT_RESP_SIZE];
int IPv4_MTU_discovery[AT_CGDCONT_RESP_SIZE];
int Local_Addr_Ind[AT_CGDCONT_RESP_SIZE];
int Non_IP_MTU_discovery[AT_CGDCONT_RESP_SIZE];
int Reliable_Data_Service[AT_CGDCONT_RESP_SIZE];
int SSC_mode[AT_CGDCONT_RESP_SIZE];
const char* nssaiStr[AT_CGDCONT_RESP_SIZE];
int Pref_access_type[AT_CGDCONT_RESP_SIZE];
} at_cgdcont_get_t;
/* Structure of CGDCONT AT read parameter command */

View File

@@ -105,8 +105,13 @@ int user_api_initialize(user_api_id_t *user_api_id, const char* host, const char
if (devname != NULL) {
/* Initialize device handlers */
user_api_id->open = device_open;
if (strcmp(devname, "psudoterm") == 0) {
user_api_id->open = device_open_psudoterm;
} else {
user_api_id->open = device_open;
}
user_api_id->getfd = device_get_fd;
user_api_id->getname = device_get_name;
user_api_id->recv = device_read;
user_api_id->send = device_write;
user_api_id->close = device_close;

View File

@@ -39,6 +39,7 @@ typedef struct {
/* Connection endpoint handlers */
void* (*open) (int, const char*, const char*);
int (*getfd)(const void*);
char* (*getname)(const void*);
ssize_t (*recv) (void*, char*, size_t);
ssize_t (*send) (const void*, const char*, size_t);
void (*close)(void*);

View File

@@ -106,6 +106,15 @@ void nas_proc_initialize(nas_user_t *user, emm_indication_callback_t emm_cb,
/* Initialize the ESM procedure manager */
esm_main_initialize(user, esm_cb);
AssertFatal(user->nas_ue_type != UE_NR, "Wrong UE type\n");
user->nas_reset_pdn = nas_proc_reset_pdn;
user->nas_set_pdn = nas_proc_set_pdn;
user->nas_get_pdn = nas_proc_get_pdn_param;
user->nas_get_pdn_range = nas_proc_get_pdn_range;
user->nas_deactivate_pdn = nas_proc_deactivate_pdn;
user->nas_activate_pdn = nas_proc_activate_pdn;
user->nas_get_pdn_status = nas_proc_get_pdn_status;
LOG_FUNC_OUT;
}
@@ -652,11 +661,11 @@ bool nas_proc_get_attach_status(nas_user_t *user)
** Others: None **
** **
***************************************************************************/
int nas_proc_get_pdn_range(esm_data_t *esm_data)
int nas_proc_get_pdn_range(nas_user_t *user)
{
LOG_FUNC_IN;
int max_pdn_id = esm_main_get_nb_pdns_max(esm_data);
int max_pdn_id = esm_main_get_nb_pdns_max(user->esm_data);
LOG_FUNC_RETURN (max_pdn_id);
}
@@ -721,13 +730,13 @@ int nas_proc_get_pdn_status(nas_user_t *user, int *cids, int *states, int n_pdn_
** Others: None **
** **
***************************************************************************/
int nas_proc_get_pdn_param(esm_data_t *esm_data, int *cids, int *types, const char **apns,
int n_pdn_max)
int nas_proc_get_pdn_param(nas_user_t *user, int *cids, int *types, const char **apns, const char **nssai, int n_pdn_max)
{
LOG_FUNC_IN;
int cid;
int n_defined_pdn = 0;
esm_data_t *esm_data = user->esm_data;
/* Get the maximum number of supported PDN contexts */
int n_pdn = esm_main_get_nb_pdns_max(esm_data);
@@ -836,9 +845,20 @@ int nas_proc_get_pdn_addr(nas_user_t *user, int cid, int *cids, const char **add
** Others: None **
** **
***************************************************************************/
int nas_proc_set_pdn(nas_user_t *user, int cid, int type, const char *apn, int ipv4_addr,
int emergency, int p_cscf, int im_cn_signal)
int nas_proc_set_pdn(nas_user_t *user,
int cid,
int type,
const char *apn,
int ipv4_addr,
int emergency,
int p_cscf,
int im_cn_signal,
const char *nssai)
{
if (user->nas_ue_type != UE_LTE || nssai != NULL) {
LOG_TRACE(ERROR, "NSSAI is an unvalid parameter for LTE\n");
return RETURNerror;
}
LOG_FUNC_IN;
int rc;

View File

@@ -95,12 +95,18 @@ int nas_proc_attach(nas_user_t *user);
bool nas_proc_get_attach_status(nas_user_t *user);
int nas_proc_reset_pdn(nas_user_t *user, int cid);
int nas_proc_set_pdn(nas_user_t *user, int cid, int type, const char *apn, int ipv4_addr,
int emergency, int p_cscf, int im_cn_signal);
int nas_proc_get_pdn_range(esm_data_t *esm_data);
int nas_proc_set_pdn(nas_user_t *user,
int cid,
int type,
const char *apn,
int ipv4_addr,
int emergency,
int p_cscf,
int im_cn_signal,
const char *nssai);
int nas_proc_get_pdn_range(nas_user_t *user);
int nas_proc_get_pdn_status(nas_user_t *user, int *cids, int *states, int n_pdn_max);
int nas_proc_get_pdn_param(esm_data_t *esm_data, int *cids, int *types, const char **apns,
int n_pdn_max);
int nas_proc_get_pdn_param(nas_user_t *user, int *cids, int *types, const char **apns, const char **nssai, int n_pdn_max);
int nas_proc_get_pdn_addr(nas_user_t *user, int cid, int *cids, const char **addr1,
const char **addr2, int n_addr_max);
int nas_proc_deactivate_pdn(nas_user_t *user, int cid);

View File

@@ -135,6 +135,7 @@ void *nas_ue_task(void *args_p)
user->at_response = calloc_or_fail(1, sizeof(at_response_t));
user->lowerlayer_data = calloc_or_fail(1, sizeof(lowerlayer_data_t));
/* Initialize NAS user */
user->nas_ue_type = UE_LTE;
nas_user_initialize(user, &user_api_emm_callback, &user_api_esm_callback, OAI_FIRMWARE_VERSION);
}
}
@@ -175,6 +176,7 @@ void *nas_ue_task(void *args_p)
user->at_response = calloc_or_fail(1, sizeof(at_response_t));
user->lowerlayer_data = calloc_or_fail(1, sizeof(lowerlayer_data_t));
/* Initialize NAS user */
user->nas_ue_type = UE_LTE;
nas_user_initialize(user, &user_api_emm_callback, &user_api_esm_callback, OAI_FIRMWARE_VERSION);
user->ueid = 0;
}

View File

@@ -53,6 +53,8 @@ Description NAS procedure functions triggered by the user
#include <string.h> // memset, strncpy, strncmp
#include <stdlib.h> // free
#include "openair3/NAS/NR_UE/nr_nas_msg_sim.h"
/****************************************************************************/
/**************** E X T E R N A L D E F I N I T I O N S ****************/
/****************************************************************************/
@@ -128,7 +130,8 @@ static const char *const _nas_user_sim_status_str[] = {"READY", "SIM PIN", "SIM
/****************** E X P O R T E D F U N C T I O N S ******************/
/****************************************************************************/
void _nas_user_context_initialize(nas_user_context_t *nas_user_context, const char *version) {
void nas_user_context_initialize(nas_user_context_t *nas_user_context, const char *version)
{
nas_user_context->version = version;
nas_user_context->sim_status = NAS_USER_SIM_PIN;
nas_user_context->fun = AT_CFUN_FUN_DEFAULT;
@@ -164,7 +167,7 @@ void nas_user_initialize(nas_user_t *user, emm_indication_callback_t emm_cb,
}
user->nas_user_context = calloc_or_fail(1, sizeof(nas_user_context_t));
_nas_user_context_initialize(user->nas_user_context, version);
nas_user_context_initialize(user->nas_user_context, version);
/* Initialize the internal NAS processing data */
nas_proc_initialize(user, emm_cb, esm_cb, user->nas_user_nvdata->IMEI);
@@ -201,6 +204,7 @@ bool nas_user_receive_and_process(nas_user_t *user, char *message)
} else {
/* Read the user data message */
bytes = user_api_read_data (user_api_id);
LOG_TRACE(INFO, "%d bytes read\n", bytes);
if (bytes == RETURNerror) {
/* Failed to read data from the user application layer;
@@ -696,7 +700,8 @@ static int _nas_user_proc_cfun(nas_user_t *user, const at_command_t *data)
switch (fun) {
case AT_CFUN_MIN:
/* TODO: Shutdown ??? */
/* deregistration */
ret_code = user->nas_deregister(user);
break;
case AT_CFUN_FULL:
@@ -1816,6 +1821,7 @@ static int _nas_user_proc_cgdcont(nas_user_t *user, const at_command_t *data)
int emergency = AT_CGDCONT_EBS_DEFAULT;
int p_cscf = AT_CGDCONT_PCSCF_DEFAULT;
int im_cn_signalling = AT_CGDCONT_IM_CM_DEFAULT;
const char *nssai = NULL;
bool reset_pdn = true;
at_response->id = data->id;
@@ -1967,18 +1973,20 @@ static int _nas_user_proc_cgdcont(nas_user_t *user, const at_command_t *data)
im_cn_signalling = data->command.cgdcont.IM_CN_Signalling_Flag_Ind;
}
if (data->mask & AT_CGDCONT_NSSAI) {
nssai = data->command.cgdcont.nssaiStr;
}
/*
* Setup PDN context
*/
if (reset_pdn) {
/* A special form of the set command, +CGDCONT=<cid> causes
* the values for context number <cid> to become undefined */
ret_code = nas_proc_reset_pdn(user, cid);
ret_code = user->nas_reset_pdn(user, cid);
} else {
/* Define a new PDN connection */
ret_code = nas_proc_set_pdn(user, cid, pdn_type, apn,
ipv4_addr_allocation, emergency,
p_cscf, im_cn_signalling);
ret_code = user->nas_set_pdn(user, cid, pdn_type, apn, ipv4_addr_allocation, emergency, p_cscf, im_cn_signalling, nssai);
}
if (ret_code != RETURNok) {
@@ -1994,10 +2002,8 @@ static int _nas_user_proc_cgdcont(nas_user_t *user, const at_command_t *data)
* Read command returns the current settings for each
* defined PDN connection/default EPS bearer context
*/
cgdcont->n_pdns = nas_proc_get_pdn_param(user->esm_data, cgdcont->cid,
cgdcont->PDP_type,
cgdcont->APN,
AT_CGDCONT_RESP_SIZE);
cgdcont->n_pdns =
user->nas_get_pdn(user, cgdcont->cid, cgdcont->PDP_type, cgdcont->APN, cgdcont->nssaiStr, AT_CGDCONT_RESP_SIZE);
if (cgdcont->n_pdns == 0) {
LOG_TRACE(ERROR, "USR-MAIN - No any PDN context is defined");
@@ -2012,7 +2018,7 @@ static int _nas_user_proc_cgdcont(nas_user_t *user, const at_command_t *data)
*/
{
/* Get the maximum value of a PDN context identifier */
int cid_max = nas_proc_get_pdn_range(user->esm_data);
int cid_max = user->nas_get_pdn_range(user);
if (cid_max > AT_CGDCONT_RESP_SIZE) {
/* The range is defined by the user interface */
@@ -2115,9 +2121,9 @@ static int _nas_user_proc_cgact(nas_user_t *user, const at_command_t *data)
ret_code = RETURNerror;
if (state == AT_CGACT_DEACTIVATED) {
ret_code = nas_proc_deactivate_pdn(user, cid);
ret_code = user->nas_deactivate_pdn(user, cid);
} else if (state == AT_CGACT_ACTIVATED) {
ret_code = nas_proc_activate_pdn(user, cid);
ret_code = user->nas_activate_pdn(user, cid);
}
if (ret_code != RETURNok) {
@@ -2135,8 +2141,7 @@ static int _nas_user_proc_cgact(nas_user_t *user, const at_command_t *data)
* The read command returns the current activation states for
* all the defined PDN/EPS bearer contexts
*/
cgact->n_pdns = nas_proc_get_pdn_status(user, cgact->cid, cgact->state,
AT_CGACT_RESP_SIZE);
cgact->n_pdns = user->nas_get_pdn_status(user, cgact->cid, cgact->state, AT_CGACT_RESP_SIZE);
if (cgact->n_pdns == 0) {
LOG_TRACE(ERROR, "USR-MAIN - No any PDN context is defined");

View File

@@ -43,6 +43,7 @@ Description NAS procedure functions triggered by the user
#include "emm_main.h"
#include "esm_ebr.h"
#include "user_defs.h"
#include "openair3/NAS/NR_UE/nr_nas_msg_sim.h"
/****************************************************************************/
/********************* G L O B A L C O N S T A N T S *******************/
@@ -69,4 +70,6 @@ int nas_user_process_data(nas_user_t *user, const void *data);
const void *nas_user_get_data(nas_user_t *nas_user);
void nas_user_context_initialize(nas_user_context_t *nas_user_context, const char *version);
#endif /* __NAS_USER_H__*/

View File

@@ -51,8 +51,18 @@ Description NAS type definition to manage a user equipment
#include "SecurityModeControl.h"
#include "userDef.h"
#include "at_response.h"
#include "as_message.h"
typedef struct {
enum ue_type {
UE_LTE,
UE_NR,
};
#define MAX_PDP_CONTEXTS 8
struct nas_user_s;
typedef struct nas_user_s {
int ueid; /* UE lower layer identifier */
proc_data_t proc;
// Eps Session Management
@@ -79,6 +89,24 @@ typedef struct {
user_at_commands_t *user_at_commands; //decoded data received from the user application layer
user_api_id_t *user_api_id;
lowerlayer_data_t *lowerlayer_data;
enum ue_type nas_ue_type;
nr_nas_pdp_context_t pdp_context[MAX_PDP_CONTEXTS];
int (*nas_reset_pdn)(struct nas_user_s *user, int cid);
int (*nas_set_pdn)(struct nas_user_s *user,
int cid,
int type,
const char *apn,
int ipv4_addr,
int emergency,
int p_cscf,
int im_cn_signal,
const char *nssai);
int (*nas_get_pdn)(struct nas_user_s *user, int *cids, int *types, const char **apns, const char **nssai, int n_pdn_max);
int (*nas_get_pdn_range)(struct nas_user_s *user);
int (*nas_deactivate_pdn)(struct nas_user_s *user, int cid);
int (*nas_activate_pdn)(struct nas_user_s *user, int cid);
int (*nas_get_pdn_status)(struct nas_user_s *user, int *cid, int *status, int n_pdn_max);
int (*nas_deregister)(struct nas_user_s *user);
} nas_user_t;
#endif