NGSetup is added

This commit is contained in:
Sukchan Lee 2020-05-25 12:15:22 -04:00
parent c534d47a78
commit 6ef5a746e5
142 changed files with 12739 additions and 885 deletions

85
configs/5gc.yaml.in Normal file
View File

@ -0,0 +1,85 @@
db_uri: mongodb://localhost/open5gs
logger:
parameter:
nrf:
sbi:
- addr:
- 127.0.0.1
- ::1
port: 7777
amf:
sbi:
- addr: 127.0.0.2
port: 7777
ngap:
guami:
- plmn_id:
mcc: 208
mnc: 93
amf_id:
region: 202
set: 1016
tai:
- plmn_id:
mcc: 901
mnc: 70
tac: 1
plmn:
- plmn_id:
mcc: 901
mnc: 70
s_nssai:
- sst: 1
security:
integrity_order : [ EIA1, EIA2, EIA0 ]
ciphering_order : [ EEA0, EEA1, EEA2 ]
network_name:
full: Open5GS
amf_name: amf.open5gs.org
smf:
sbi:
- addr: 127.0.0.3
port: 7777
gtpc:
- addr: 127.0.0.3
- addr: ::1
pfcp:
- addr: 127.0.0.3
pdn:
- addr: 10.45.0.1/16
- addr: cafe::1/64
dns:
- 8.8.8.8
- 8.8.4.4
- 2001:4860:4860::8888
- 2001:4860:4860::8844
mtu: 1400
freeDiameter:
identity: pgw.open-ims.test
realm: open-ims.test
listen_on: 127.0.0.3
load_extension:
- module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx
conf: 0x8888
- module: @freediameter_extensions_builddir@/dict_rfc5777.fdx
- module: @freediameter_extensions_builddir@/dict_mip6i.fdx
- module: @freediameter_extensions_builddir@/dict_nasreq.fdx
- module: @freediameter_extensions_builddir@/dict_nas_mipv6.fdx
- module: @freediameter_extensions_builddir@/dict_dcca.fdx
- module: @freediameter_extensions_builddir@/dict_dcca_3gpp.fdx
connect:
- identity: pcrf.open-ims.test
addr: 127.0.0.5
upf:
pfcp:
addr: 127.0.0.4
gtpu:
- addr:
- 127.0.0.4
- ::1
pdn:

View File

@ -34,9 +34,11 @@ else
endif
example_conf = '''
simple.yaml
installed.yaml
split.yaml
5gc.yaml
minimal.yaml
epc.yaml
epc-fdconf.yaml
epc-custom.yaml
mnc3.yaml
csfb.yaml
volte.yaml

89
configs/minimal.yaml.in Normal file
View File

@ -0,0 +1,89 @@
db_uri: mongodb://localhost/open5gs
logger:
parameter:
nrf:
sbi:
- addr:
- 127.0.0.1
- ::1
port: 7777
amf:
sbi:
- addr: 127.0.0.2
port: 7777
ngap:
- addr: 127.0.0.1
guami:
- plmn_id:
mcc: 208
mnc: 93
amf_id:
region: 202
set: 1016
tai:
- plmn_id:
mcc: 208
mnc: 93
tac: 1
plmn:
- plmn_id:
mcc: 208
mnc: 93
s_nssai:
- sst: 1
sd: 010203
- sst: 1
sd: 112233
security:
integrity_order : [ EIA1, EIA2, EIA0 ]
ciphering_order : [ EEA0, EEA1, EEA2 ]
network_name:
full: Open5GS
amf_name: amf.open5gs.org
smf:
sbi:
- addr: 127.0.0.3
port: 7777
gtpc:
- addr: 127.0.0.3
- addr: ::1
pfcp:
- addr: 127.0.0.3
pdn:
- addr: 10.45.0.1/16
- addr: cafe::1/64
dns:
- 8.8.8.8
- 8.8.4.4
- 2001:4860:4860::8888
- 2001:4860:4860::8844
mtu: 1400
freeDiameter:
identity: pgw.open-ims.test
realm: open-ims.test
listen_on: 127.0.0.3
load_extension:
- module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx
conf: 0x8888
- module: @freediameter_extensions_builddir@/dict_rfc5777.fdx
- module: @freediameter_extensions_builddir@/dict_mip6i.fdx
- module: @freediameter_extensions_builddir@/dict_nasreq.fdx
- module: @freediameter_extensions_builddir@/dict_nas_mipv6.fdx
- module: @freediameter_extensions_builddir@/dict_dcca.fdx
- module: @freediameter_extensions_builddir@/dict_dcca_3gpp.fdx
connect:
- identity: pcrf.open-ims.test
addr: 127.0.0.5
upf:
pfcp:
- addr: 127.0.0.4
gtpu:
- addr:
- 127.0.0.4
- ::1
pdn:

202
configs/open5gs/amf.yaml.in Normal file
View File

@ -0,0 +1,202 @@
#
# logger:
#
# o Set OGS_LOG_INFO to all domain level
# - If `level` is omitted, the default level is OGS_LOG_INFO)
# - If `domain` is omitted, the all domain level is set from 'level'
# (Nothing is needed)
#
# o Set OGS_LOG_ERROR to all domain level
# - `level` can be set with none, fatal, error, warn, info, debug, trace
# level: error
#
# o Set OGS_LOG_DEBUG to mme/emm domain level
# level: debug
# domain: mme,emm
#
# o Set OGS_LOG_TRACE to all domain level
# level: trace
# domain: core,pfcp,fd,gtp,amf,event,tlv,mem,sock
#
logger:
file: @localstatedir@/log/open5gs/amf.log
#
# amf:
#
# <SBI Server>
#
# o SBI Server(http://<all address available>:80)
# sbi:
#
# o SBI Server(http://<any address>:80)
# sbi:
# - addr:
# - 0.0.0.0
# - ::0
# port: 7777
#
# o SBI Server(https://<all address avaiable>:443)
# sbi:
# tls:
# key: amf.key
# pem: amf.pem
#
# o SBI Server(https://127.0.0.2:443, http://[::1]:80)
# sbi:
# - addr: 127.0.0.2
# tls:
# key: amf.key
# pem: amf.pem
# - addr: ::1
#
# o SBI Server(http://amf.open5gs.org:80)
# sbi:
# name: amf.open5gs.org
#
# o SBI Server(http://127.0.0.2:7777)
# sbi:
# - addr: 127.0.0.2
# port: 7777
#
# o SBI Server(http://<eth0 IP address>:80)
# sbi:
# dev: eth0
#
amf:
sbi:
- addr: 127.0.0.2
port: 7777
ngap:
guami:
- plmn_id:
mcc: 901
mnc: 70
amf_id:
region: 2
set: 1
tai:
- plmn_id:
mcc: 901
mnc: 70
tac: 1
plmn:
- plmn_id:
mcc: 901
mnc: 70
s_nssai:
- sst: 1
security:
integrity_order : [ EIA1, EIA2, EIA0 ]
ciphering_order : [ EEA0, EEA1, EEA2 ]
network_name:
full: Open5GS
amf_name: amf.open5gs.org
#
# nrf:
#
# <SBI Client>>
#
# o SBI Client(http://127.0.0.1:7777)
# sbi:
# addr: 127.0.0.1
# port: 7777
#
# o SBI Client(https://127.0.0.1:443, http://nrf.open5gs.org:80)
# sbi:
# - addr: 127.0.0.1
# tls:
# key: nrf.key
# pem: nrf.pem
# - name: nrf.open5gs.org
#
# o SBI Client(http://[fe80::1%@loopback_devname@]:80)
# If prefer_ipv4 is true, http://127.0.0.1:80 is selected.
#
# sbi:
# addr:
# - 127.0.0.1
# - fe80::1%@loopback_devname@
#
nrf:
sbi:
- addr:
- 127.0.0.1
- ::1
port: 7777
#
# parameter:
#
# o Number of output streams per SCTP associations.
# sctp_streams: 30
#
# o Disable use of IPv4 addresses (only IPv6)
# no_ipv4: true
#
# o Disable use of IPv6 addresses (only IPv4)
# no_ipv6: true
#
# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections.
# prefer_ipv4: true
#
# o Enable Multicast traffic to the UE
# multicast: true
#
# o Disable Stateless Address Autoconfiguration for IPv6
# no_slaac: true
#
parameter:
#
# max:
#
# o Maximum Number of gNB per AMF
# gnb: 32
# o Maximum Number of UE per gNB
# ue: 128
#
max:
#
# pool:
#
# o The Number of Default Memory Pool Size
#
# - Pool-size 128 => 8192 Number
# - Pool-size 256 => 4096 Number
# - Pool-size 512 => 2048 Number
# - Pool-size 1024 => 1024 Number
# - Pool-size 2048 => 512 Number
# - Pool-size 8192 => 128 Number
# - Pool-size 1024*1024 => 8 Number
#
# 128: 8192
# 256: 4096
# 512: 2048
# 1024: 1024
# 2048: 512
# 8192: 128
# big: 8
#
# o Memory of Packet Buffering in SGW
# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW
# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes
#
# packet: 65536
#
pool:
#
# time:
#
# o NF Instance Heartbeat (Default : 3 seconds)
#
# o NF Instance Heartbeat (Disabled)
# nf_instance:
# heartbeat: 0
#
# o NF Instance Heartbeat (5 seconds)
# nf_instance:
# heartbeat: 5
time:

View File

@ -27,8 +27,9 @@ open5gs_conf = '''
pcrf.yaml
nrf.yaml
smf.yaml
upf.yaml
smf.yaml
amf.yaml
'''.split()
foreach file : open5gs_conf

View File

@ -98,15 +98,9 @@ parameter:
#
# max:
#
# o Maximum Number of SGW per MME
# sgw: 32
# o Maximum Number of PGW per MME
# pgw: 32
# o Maximum Number of VLR per MME
# vlr: 32
# o Maximum Number of eNodeB per MME
# enb: 32
# o Maximum Number of UE per eNodeB
# o Maximum Number of gNB per MME
# gnb: 32
# o Maximum Number of UE per gNB
# ue: 128
#
max:

View File

@ -228,10 +228,10 @@ smf:
#
nrf:
sbi:
addr:
- 127.0.0.1
- ::1
port: 7777
- addr:
- 127.0.0.1
- ::1
port: 7777
#
# upf:
@ -245,7 +245,7 @@ nrf:
#
upf:
pfcp:
addr: 127.0.0.4
- addr: 127.0.0.4
#
# parameter:
@ -273,15 +273,9 @@ parameter:
#
# max:
#
# o Maximum Number of SGW per MME
# sgw: 32
# o Maximum Number of PGW per MME
# pgw: 32
# o Maximum Number of VLR per MME
# vlr: 32
# o Maximum Number of eNodeB per MME
# enb: 32
# o Maximum Number of UE per eNodeB
# o Maximum Number of gNB per AMF
# gnb: 32
# o Maximum Number of UE per gNB
# ue: 128
#
max:

View File

@ -59,7 +59,7 @@ logger:
#
upf:
pfcp:
addr: 127.0.0.4
- addr: 127.0.0.4
gtpu:
- addr:
- 127.0.0.4
@ -78,7 +78,7 @@ upf:
#
smf:
pfcp:
addr: 127.0.0.3
- addr: 127.0.0.3
#
# parameter:
@ -107,15 +107,9 @@ parameter:
#
# max:
#
# o Maximum Number of SGW per MME
# sgw: 32
# o Maximum Number of PGW per MME
# pgw: 32
# o Maximum Number of VLR per MME
# vlr: 32
# o Maximum Number of eNodeB per MME
# enb: 32
# o Maximum Number of UE per eNodeB
# o Maximum Number of gNB per AMF
# gnb: 32
# o Maximum Number of UE per gNB
# ue: 128
#
max:

View File

@ -11,10 +11,10 @@ Sometimes you may get a message like the one below due to a problem with the fre
$ meson test
...
5/8 open5gs:system / simple OK 7.69 s
5/8 open5gs:epc / simple OK 7.69 s
--- command ---
08:06:23 /home/parallels/open5gs/build/tests/simple/simple
08:06:23 /home/parallels/open5gs/build/tests/epc-simple/simple
--- stdout ---
s1setup-test : SUCCESS
attach-test : SUCCESS
@ -123,10 +123,10 @@ ninja: no work to do.
2/8 open5gs:unit / crypt OK 0.08 s
3/8 open5gs:system / sctp OK 1.09 s
4/8 open5gs:unit / unit OK 0.04 s
5/8 open5gs:system / simple OK 5.07 s
6/8 open5gs:system / mnc3 OK 1.18 s
7/8 open5gs:system / volte OK 2.99 s
8/8 open5gs:system / csfb OK 6.53 s
5/8 open5gs:epc / simple OK 5.07 s
6/8 open5gs:epc / mnc3 OK 1.18 s
7/8 open5gs:epc / volte OK 2.99 s
8/8 open5gs:epc / csfb OK 6.53 s
Ok: 8
Expected Fail: 0
@ -385,17 +385,17 @@ You can start MongoDB using systemctl.
$ sudo systemctl start mongodb
```
#### I have some error when running `./build/test/simple/simple`
#### I have some error when running `./build/test/epc-simple/simple`
Did you see the following error after executing `./build/test/simple/simple`?
Did you see the following error after executing `./build/test/epc-simple/simple`?
```bash
$ ./build/test/simple/simple
$ ./build/test/epc-simple/simple
s1setup_test : SUCCESS
attach_test : -Line 134: Condition is false, but expected true
\04/09 15:49:09.285: [esm] FATAL: esm_handle_pdn_connectivity_request: Assertion `SECURITY_CONTEXT_IS_VALID(mme_ue)' failed. (esm_handler.c:29)
/home/acetcom/Documents/git/open5gs/open5gs/lib/ogslib/src/core/.libs/libogscore-1.0.so.0(ogs_abort+0x2b)[0x7f608518271b]
/home/acetcom/Documents/git/open5gs/open5gs/test/.libs/testcomplex(+0x92121)[0x55dc9e274121]
/home/acetcom/Documents/git/open5gs/open5gs/test/.libs/testcomplex(+0x4f5b9)[0x55dc9e2315b9]
/home/acetcom/Documents/git/open5gs/open5gs/test/.libs/simple(+0x92121)[0x55dc9e274121]
/home/acetcom/Documents/git/open5gs/open5gs/test/.libs/simple(+0x4f5b9)[0x55dc9e2315b9]
```
@ -415,9 +415,9 @@ $ sudo pkill -9 simple
$ sudo pkill -9 open5gs-mmed ...
```
Execute `./build/test/simple/simple`
Execute `./build/test/epc-simple/simple`
```bash
$ ./build/test/simple/simple
$ ./build/test/epc-simple/simple
```
#### My eNB does not support IPv6.

View File

@ -60,11 +60,14 @@ void pcrf_terminate(void);
int nrf_initialize(void);
void nrf_terminate(void);
int upf_initialize(void);
void upf_terminate(void);
int smf_initialize(void);
void smf_terminate(void);
int upf_initialize(void);
void upf_terminate(void);
int amf_initialize(void);
void amf_terminate(void);
#ifdef __cplusplus
}

View File

@ -138,7 +138,7 @@ static void recalculate_pool_size(void)
#define MAX_NUM_OF_TUNNEL 3 /* Num of Tunnel per Bearer */
#define MAX_NUM_OF_PF 16 /* Num of PacketFilter per Bearer */
self.pool.ue = self.max.ue * self.max.enb;
self.pool.ue = self.max.ue * self.max.gnb;
self.pool.pfcp = ogs_max(self.max.smf, self.max.upf);
self.pool.sbi = self.pool.pfcp;
self.pool.sess = self.pool.ue * OGS_MAX_NUM_OF_SESS;
@ -156,15 +156,17 @@ static int config_prepare(void)
#define MAX_NUM_OF_PGW 32 /* Num of PGW per MME */
#define MAX_NUM_OF_VLR 32 /* Num of VLR per MME */
#define MAX_NUM_OF_CSMAP 128 /* Num of TAI-LAI MAP per MME */
#define MAX_NUM_OF_ENB 32 /* Num of eNodeB per MME */
#define MAX_NUM_OF_UE 128 /* Num of UE per eNodeB */
#define MAX_NUM_OF_UE 128 /* Num of UE per gNB */
#define MAX_NUM_OF_SMF 32 /* Num of SMF per AMF */
#define MAX_NUM_OF_UPF 32 /* Num of PGW per AMF */
#define MAX_NUM_OF_GNB 32 /* Num of gNB per AMF */
self.max.sgw = MAX_NUM_OF_SGW;
self.max.pgw = MAX_NUM_OF_PGW;
self.max.vlr = MAX_NUM_OF_VLR;
self.max.csmap = MAX_NUM_OF_CSMAP;
self.max.enb = MAX_NUM_OF_ENB;
self.max.gnb = MAX_NUM_OF_GNB;
self.max.ue = MAX_NUM_OF_UE;
self.max.smf = MAX_NUM_OF_SMF;
self.max.upf = MAX_NUM_OF_UPF;
@ -323,9 +325,10 @@ int ogs_config_parse()
if (!strcmp(max_key, "ue")) {
const char *v = ogs_yaml_iter_value(&max_iter);
if (v) self.max.ue = atoi(v);
} else if (!strcmp(max_key, "enb")) {
} else if (!strcmp(max_key, "gnb") ||
!strcmp(max_key, "enb")) {
const char *v = ogs_yaml_iter_value(&max_iter);
if (v) self.max.enb = atoi(v);
if (v) self.max.gnb = atoi(v);
} else
ogs_warn("unknown key `%s`", max_key);
}

View File

@ -48,6 +48,11 @@ typedef struct ogs_config_s {
int no_pgw;
int no_pcrf;
int no_amf;
int no_smf;
int no_upf;
int no_nrf;
/* Network */
int no_ipv4;
int no_ipv6;
@ -66,10 +71,11 @@ typedef struct ogs_config_s {
int pgw;
int vlr;
int csmap;
int enb;
int ue;
int smf;
int upf;
int gnb;
} max;
struct {

View File

@ -38,6 +38,17 @@ void ogs_asn_uint16_to_OCTET_STRING(
octet_string->buf[1] = uint16;
}
void ogs_asn_uint24_to_OCTET_STRING(
ogs_uint24_t uint24, OCTET_STRING_t *octet_string)
{
octet_string->size = 3;
octet_string->buf = CALLOC(octet_string->size, sizeof(uint8_t));
octet_string->buf[0] = uint24.v >> 16;
octet_string->buf[1] = uint24.v >> 8;
octet_string->buf[2] = uint24.v;
}
void ogs_asn_uint32_to_OCTET_STRING(
uint32_t uint32, OCTET_STRING_t *octet_string)
{
@ -50,6 +61,15 @@ void ogs_asn_uint32_to_OCTET_STRING(
octet_string->buf[3] = uint32;
}
void ogs_asn_buffer_to_OCTET_STRING(
void *buf, int size, OCTET_STRING_t *octet_string)
{
octet_string->size = size;
octet_string->buf = CALLOC(octet_string->size, sizeof(uint8_t));
memcpy(octet_string->buf, buf, size);
}
int ogs_asn_BIT_STRING_to_ip(BIT_STRING_t *bit_string, ogs_ip_t *ip)
{
char buf[OGS_ADDRSTRLEN], buf2[OGS_ADDRSTRLEN];

View File

@ -30,12 +30,36 @@
extern "C" {
#endif
#define OGS_ASN_CLEAR_DATA(__dATA) \
do { \
ogs_assert((__dATA)); \
if ((__dATA)->buf) { \
FREEMEM((__dATA)->buf); \
(__dATA)->buf = NULL; \
(__dATA)->size = 0; \
} \
} while(0)
#define OGS_ASN_STORE_DATA(__dST, __sRC) \
do { \
ogs_assert((__sRC)); \
ogs_assert((__sRC)->buf); \
ogs_assert((__dST)); \
OGS_ASN_CLEAR_DATA(__dST); \
(__dST)->size = (__sRC)->size; \
(__dST)->buf = CALLOC((__dST)->size, sizeof(uint8_t)); \
memcpy((__dST)->buf, (__sRC)->buf, (__dST)->size); \
} while(0)
void ogs_asn_uint8_to_OCTET_STRING(
uint8_t uint8, OCTET_STRING_t *octet_string);
void ogs_asn_uint16_to_OCTET_STRING(
uint16_t uint16, OCTET_STRING_t *octet_string);
void ogs_asn_uint24_to_OCTET_STRING(
ogs_uint24_t uint24, OCTET_STRING_t *octet_string);
void ogs_asn_uint32_to_OCTET_STRING(
uint32_t uint32, OCTET_STRING_t *octet_string);
void ogs_asn_buffer_to_OCTET_STRING(
void *buf, int size, OCTET_STRING_t *octet_string);
int ogs_asn_BIT_STRING_to_ip(
BIT_STRING_t *bit_string, ogs_ip_t *ip);

View File

@ -64,6 +64,82 @@ void *ogs_plmn_id_build(ogs_plmn_id_t *plmn_id,
return plmn_id;
}
uint32_t ogs_amf_id_hexdump(ogs_amf_id_t *amf_id)
{
uint32_t hex;
ogs_assert(amf_id);
memcpy(&hex, amf_id, sizeof(ogs_amf_id_t));
hex = be32toh(hex) >> 8;
return hex;
}
ogs_amf_id_t *ogs_amf_id_from_string(ogs_amf_id_t *amf_id, const char *hex)
{
char hexbuf[sizeof(ogs_amf_id_t)];
ogs_assert(amf_id);
ogs_assert(hex);
OGS_HEX(hex, strlen(hex), hexbuf);
amf_id->region = hexbuf[0];
amf_id->set1 = hexbuf[1];
amf_id->set2 = (hexbuf[2] & 0xc0) >> 6;
amf_id->pointer = hexbuf[2] & 0x3f;
return amf_id;
}
char *ogs_amf_id_to_string(ogs_amf_id_t *amf_id, char *buf)
{
int i;
ogs_assert(amf_id);
ogs_assert(buf);
ogs_hex_to_ascii(amf_id, sizeof(ogs_amf_id_t), buf, OGS_AMFIDSTRLEN);
/* I'd just like to use lower character */
for (i = 0; buf[i]; i++)
if (buf[i] >= 'A' && buf[i] <= 'Z')
buf[i] = buf[i] + 'a' - 'A';
return buf;
}
uint8_t ogs_amf_region_id(ogs_amf_id_t *amf_id)
{
ogs_assert(amf_id);
return amf_id->region;
}
uint16_t ogs_amf_set_id(ogs_amf_id_t *amf_id)
{
ogs_assert(amf_id);
return (amf_id->set1 << 2) + amf_id->set2;
}
uint8_t ogs_amf_pointer(ogs_amf_id_t *amf_id)
{
ogs_assert(amf_id);
return amf_id->pointer;
}
ogs_amf_id_t *ogs_amf_id_build(ogs_amf_id_t *amf_id,
uint8_t region, uint16_t set, uint8_t pointer)
{
ogs_assert(amf_id);
ogs_assert(region);
ogs_assert(set);
amf_id->region = region;
amf_id->set1 = set >> 2;
amf_id->set2 = set & 0x3;
amf_id->pointer = pointer;
return amf_id;
}
int ogs_fqdn_build(char *dst, char *src, int length)
{
int i = 0, j = 0;

View File

@ -28,8 +28,6 @@
extern "C" {
#endif /* __cplusplus */
#define OGS_MAX_FILEPATH_LEN 256
#define OGS_MAX_NUM_OF_SESS 4 /* Num of APN(Session) per UE */
#define OGS_MAX_NUM_OF_RULE 4 /* Num of Rule per Session */
@ -50,7 +48,11 @@ extern "C" {
#define OGS_MAX_DNN_LEN 100
#define OGS_MAX_PCO_LEN 251
#define OGS_MAX_FQDN_LEN 256
#define OGS_MAX_IFNAME_LEN 32
#define OGS_MAX_NUM_OF_SERVED_TAI 16
#define OGS_MAX_NUM_OF_ALGORITHM 8
#define OGS_MAX_NUM_OF_BPLMN 6
#define OGS_NEXT_ID(__id, __min, __max) \
((__id) = ((__id) == (__max) ? (__min) : ((__id) + 1)))
@ -63,8 +65,49 @@ extern "C" {
#define OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED 0
/**********************************
* PLMN_ID Structure */
typedef struct ogs_uint24_s {
uint32_t v:24;
} __attribute__ ((packed)) ogs_uint24_t;
static ogs_inline ogs_uint24_t ogs_be24toh(ogs_uint24_t x)
{
uint32_t tmp = x.v;
tmp = be32toh(tmp);
x.v = tmp >> 8;
return x;
}
static ogs_inline ogs_uint24_t ogs_htobe24(ogs_uint24_t x)
{
uint32_t tmp = x.v;
tmp = htobe32(tmp);
x.v = tmp >> 8;
return x;
}
static ogs_inline ogs_uint24_t ogs_uint24_from_string(char *str)
{
ogs_uint24_t x;
ogs_assert(str);
OGS_HEX(str, strlen(str), &x);
return ogs_be24toh(x);
}
#define OGS_24BITSTRLEN (sizeof(ogs_uint24_t)*2+1)
static ogs_inline char *ogs_uint24_to_string(ogs_uint24_t x, char *str)
{
ogs_assert(str);
x = ogs_htobe24(x);
ogs_hex_to_ascii(&x, sizeof(x), str, OGS_24BITSTRLEN);
return str;
}
/************************************
* PLMN_ID Structure */
#define OGS_MAX_NUM_OF_PLMN 6
typedef struct ogs_plmn_id_s {
ED2(uint8_t mcc2:4;,
uint8_t mcc1:4;)
@ -83,18 +126,55 @@ uint16_t ogs_plmn_id_mnc_len(ogs_plmn_id_t *plmn_id);
void *ogs_plmn_id_build(ogs_plmn_id_t *plmn_id,
uint16_t mcc, uint16_t mnc, uint16_t mnc_len);
#define OGS_MAX_NUM_OF_TAI 16
/************************************
* AMF_ID Structure */
typedef struct ogs_amf_id_s {
uint8_t region;
uint8_t set1;
ED2(uint8_t set2:2;,
uint8_t pointer:6;)
} __attribute__ ((packed)) ogs_amf_id_t;
typedef struct ogs_tai_s {
uint32_t ogs_amf_id_hexdump(ogs_amf_id_t *amf_id);
#define OGS_AMFIDSTRLEN (sizeof(ogs_amf_id_t)*2+1)
ogs_amf_id_t *ogs_amf_id_from_string(ogs_amf_id_t *amf_id, const char *hex);
char *ogs_amf_id_to_string(ogs_amf_id_t *amf_id, char *buf);
uint8_t ogs_amf_region_id(ogs_amf_id_t *amf_id);
uint16_t ogs_amf_set_id(ogs_amf_id_t *amf_id);
uint8_t ogs_amf_pointer(ogs_amf_id_t *amf_id);
ogs_amf_id_t *ogs_amf_id_build(ogs_amf_id_t *amf_id,
uint8_t region, uint16_t set, uint8_t pointer);
/************************************
* TAI Structure */
#define OGS_MAX_NUM_OF_TAI 16
typedef struct ogs_eps_tai_s {
ogs_plmn_id_t plmn_id;
uint16_t tac;
} __attribute__ ((packed)) ogs_tai_t;
} __attribute__ ((packed)) ogs_eps_tai_t;
typedef struct ogs_5gs_tai_s {
ogs_plmn_id_t plmn_id;
ogs_uint24_t tac;
} __attribute__ ((packed)) ogs_5gs_tai_t;
typedef struct ogs_e_cgi_s {
ogs_plmn_id_t plmn_id;
uint32_t cell_id; /* 28 bit */
} __attribute__ ((packed)) ogs_e_cgi_t;
/************************************
* S-NSSAI Structure */
#define OGS_MAX_NUM_OF_S_NSSAI 8
#define OGS_S_NSSAI_NO_SD_VALUE 0xffffff
typedef struct ogs_s_nssai_s {
uint8_t sst;
ogs_uint24_t sd;
} __attribute__ ((packed)) ogs_s_nssai_t;
/**************************************************
* Common Structure
* S1AP : 9.2.2.1 Transport Layer Address, See 36.414

View File

@ -177,6 +177,10 @@ extern "C" {
#define END }}}
#endif
#define OGS_ARG_MAX 256
#define OGS_MAX_FILEPATH_LEN 256
#define OGS_MAX_IFNAME_LEN 32
#ifdef __cplusplus
}
#endif

View File

@ -344,7 +344,7 @@ typedef struct ogs_gtp_uli_s {
ogs_gtp_uli_cgi_t cgi;
ogs_gtp_uli_sai_t sai;
ogs_gtp_uli_rai_t rai;
ogs_tai_t tai;
ogs_eps_tai_t tai;
ogs_e_cgi_t e_cgi;
ogs_gtp_uli_lai_t lai;
} ogs_gtp_uli_t;

View File

@ -28,7 +28,7 @@
/*******************************************************************************
* This file had been created by nas-message.py script v0.2.0
* Please do not modify this file but regenerate it via script.
* Created on: 2020-05-22 16:56:22.013388 by acetcom
* Created on: 2020-05-24 17:29:31.606634 by acetcom
* from 24501-g41.docx
******************************************************************************/

View File

@ -28,7 +28,7 @@
/*******************************************************************************
* This file had been created by nas-message.py script v0.2.0
* Please do not modify this file but regenerate it via script.
* Created on: 2020-05-22 16:56:22.024260 by acetcom
* Created on: 2020-05-24 17:29:31.617845 by acetcom
* from 24501-g41.docx
******************************************************************************/

View File

@ -28,7 +28,7 @@
/*******************************************************************************
* This file had been created by nas-message.py script v0.2.0
* Please do not modify this file but regenerate it via script.
* Created on: 2020-05-22 16:56:21.995840 by acetcom
* Created on: 2020-05-24 17:29:31.588956 by acetcom
* from 24501-g41.docx
******************************************************************************/
@ -2713,7 +2713,7 @@ int ogs_nas_5gs_decode_5gs_tracking_area_identity(ogs_nas_5gs_tracking_area_iden
ogs_assert(ogs_pkbuf_pull(pkbuf, size));
memcpy(tracking_area_identity, pkbuf->data - size, size);
tracking_area_identity->tac = be16toh(tracking_area_identity->tac);
tracking_area_identity->tac = ogs_be24toh(tracking_area_identity->tac);
ogs_trace(" 5GS_TRACKING_AREA_IDENTITY - ");
ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);
@ -2727,7 +2727,7 @@ int ogs_nas_5gs_encode_5gs_tracking_area_identity(ogs_pkbuf_t *pkbuf, ogs_nas_5g
ogs_nas_5gs_tracking_area_identity_t target;
memcpy(&target, tracking_area_identity, size);
target.tac = htobe16(tracking_area_identity->tac);
target.tac = ogs_htobe24(tracking_area_identity->tac);
ogs_assert(ogs_pkbuf_pull(pkbuf, size));
memcpy(pkbuf->data - size, &target, size);

View File

@ -28,7 +28,7 @@
/*******************************************************************************
* This file had been created by nas-message.py script v0.2.0
* Please do not modify this file but regenerate it via script.
* Created on: 2020-05-22 16:56:21.993076 by acetcom
* Created on: 2020-05-24 17:29:31.586197 by acetcom
* from 24501-g41.docx
******************************************************************************/

View File

@ -16,6 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
libnas_5gs_sources = files('''
types.c
ies.c
decoder.c
encoder.c

View File

@ -28,7 +28,7 @@
/*******************************************************************************
* This file had been created by nas-message.py script v0.2.0
* Please do not modify this file but regenerate it via script.
* Created on: 2020-05-22 16:56:22.005526 by acetcom
* Created on: 2020-05-24 17:29:31.598549 by acetcom
* from 24501-g41.docx
******************************************************************************/

View File

@ -17,9 +17,9 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
type_list["5GS tracking area identity"]["decode"] = \
" tracking_area_identity->tac = be16toh(tracking_area_identity->tac);\n\n"
" tracking_area_identity->tac = ogs_be24toh(tracking_area_identity->tac);\n\n"
type_list["5GS tracking area identity"]["encode"] = \
" target.tac = htobe16(tracking_area_identity->tac);\n\n"
" target.tac = ogs_htobe24(tracking_area_identity->tac);\n\n"
type_list["5GS mobile identity"]["decode"] = \
" if (mobile_identity->guti.type == OGS_NAS_5GS_MOBILE_IDENTITY_GUTI) {\n" \

92
lib/nas/5gs/types.c Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-nas-5gs.h"
void ogs_nas_5gs_tai_list_build(
ogs_nas_5gs_tracking_area_identity_list_t *target,
ogs_5gs_tai0_list_t *source0, ogs_5gs_tai2_list_t *source2)
{
int i = 0, j = 0, size = 0;
ogs_5gs_tai0_list_t target0;
ogs_5gs_tai2_list_t target2;
ogs_nas_plmn_id_t ogs_nas_plmn_id;
ogs_assert(target);
ogs_assert(source0);
ogs_assert(source2);
memset(target, 0, sizeof(ogs_nas_5gs_tracking_area_identity_list_t));
memset(&target0, 0, sizeof(ogs_5gs_tai0_list_t));
memset(&target2, 0, sizeof(ogs_5gs_tai2_list_t));
for (i = 0; source0->tai[i].num; i++) {
ogs_assert(source0->tai[i].type == OGS_TAI0_TYPE);
target0.tai[i].type = source0->tai[i].type;
/* <Spec> target->num = source->num - 1 */
ogs_assert(source0->tai[i].num < OGS_MAX_NUM_OF_TAI);
target0.tai[i].num = source0->tai[i].num - 1;
memcpy(&target0.tai[i].plmn_id,
ogs_nas_from_plmn_id(&ogs_nas_plmn_id, &source0->tai[i].plmn_id),
OGS_PLMN_ID_LEN);
for (j = 0; j < source0->tai[i].num; j++) {
target0.tai[i].tac[j] = ogs_htobe24(source0->tai[i].tac[j]);
}
size = (1 + 3 + 2 * source0->tai[i].num);
if ((target->length + size) > OGS_NAS_5GS_MAX_TAI_LIST_LEN) {
ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)",
target->length, size);
return;
}
memcpy(target->buffer + target->length, &target0.tai[i], size);
target->length += size;
}
if (source2->num) {
memset(&target2, 0, sizeof(target2));
ogs_assert(source2->type == OGS_TAI1_TYPE ||
source2->type == OGS_TAI2_TYPE);
target2.type = source2->type;
/* <Spec> target->num = source->num - 1 */
ogs_assert(source2->num < OGS_MAX_NUM_OF_TAI);
target2.num = source2->num - 1;
size = (1 + (3 + 2) * source2->num);
if ((target->length + size) > OGS_NAS_5GS_MAX_TAI_LIST_LEN) {
ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)",
target->length, size);
return;
}
for (i = 0; i < source2->num; i++) {
memcpy(&target2.tai[i].plmn_id,
ogs_nas_from_plmn_id(&ogs_nas_plmn_id,
&source2->tai[i].plmn_id),
OGS_PLMN_ID_LEN);
target2.tai[i].tac = ogs_htobe24(source2->tai[i].tac);
}
memcpy(target->buffer + target->length, &target2, size);
target->length += size;
}
}

View File

@ -28,6 +28,14 @@
extern "C" {
#endif
/**********************
* NAS GUTI Structure */
typedef struct ogs_nas_5gs_guti_s {
ogs_nas_plmn_id_t nas_plmn_id;
ogs_amf_id_t amf_id;
uint32_t m_tmsi;
} __attribute__ ((packed)) ogs_nas_5gs_guti_t;
/* 9.11.2.1A DNN
* O TLV 3-102 */
typedef struct ogs_nas_dnn_s {
@ -48,11 +56,10 @@ typedef struct ogs_nas_eap_message_s {
#define OGS_NAS_S_NSSAI_SST_AND_MAPPED_HPLMN_SST_LEN 2
#define OGS_NAS_S_NSSAI_SST_AND_SD 4
#define OGS_NAS_S_NSSAI_SST_SD_AND_MAPPED_HPLMN_SST_LEN 5
#define OGS_NAS_MAX_S_NSSAI_LEN 8
typedef struct ogs_nas_s_nssai_s {
uint8_t length;
uint32_t sst_sd;
uint32_t mapped_sst_sd;
ogs_s_nssai_t s_nssai;
ogs_s_nssai_t mapped_s_nssai;
} __attribute__ ((packed)) ogs_nas_s_nssai_t;
/* 9.11.3.1 5GMM capability
@ -133,20 +140,12 @@ ED3(uint8_t type:4;,
/* 9.11.3.4 5GS mobile identity
* M LV-E 6-n */
#define OGS_NAS_GET_AMF_SET_ID(_iDentity) \
((_iDentity)->amf_set_id2 + ((_iDentity)->amf_set_id1 << 2))
#define OGS_NAS_SET_AMF_SET_ID(_iDentity, _aMFSetId) \
do { \
ogs_assert((_iDentity)); \
(_iDentity)->amf_set_id1 = (_aMFSetId >> 2) & 0x000f; \
(_iDentity)->amf_set_id2 = _aMFSetId & 0x0003; \
} while(0)
typedef struct ogs_nas_5gs_mobile_identity_guti_s {
ED3(uint8_t _0xf:4;,
uint8_t spare:1;,
uint8_t type:3;)
ogs_nas_plmn_id_t nas_plmn_id;
uint16_t amf_region_id;
uint8_t amf_region_id;
uint8_t amf_set_id1;
ED2(uint8_t amf_set_id2:2;,
uint8_t amf_pointer:6;)
@ -156,7 +155,7 @@ typedef struct ogs_nas_5gs_mobile_identity_s_tmsi_s {
ED3(uint8_t _0xf:4;,
uint8_t spare:1;,
uint8_t type:3;)
uint16_t amf_region_id;
uint8_t amf_region_id;
uint8_t amf_set_id1;
ED2(uint8_t amf_set_id2:2;,
uint8_t amf_pointer:6;)
@ -214,11 +213,54 @@ ED3(uint8_t type:4;,
/* 9.11.3.8 5GS tracking area identity
* O TV 6 */
typedef ogs_nas_tracking_area_identity_t ogs_nas_5gs_tracking_area_identity_t;
typedef struct ogs_nas_5gs_tracking_area_identity_s {
ogs_nas_plmn_id_t nas_plmn_id;
ogs_uint24_t tac;
} __attribute__ ((packed)) ogs_nas_5gs_tracking_area_identity_t;
typedef ogs_nas_5gs_tracking_area_identity_t ogs_nas_5gs_tai_t;
/* 9.11.3.9 5GS tracking area identity list
* O TLV 9-114 */
typedef ogs_nas_tracking_area_identity_list_t ogs_nas_5gs_tracking_area_identity_list_t;
#define OGS_NAS_5GS_MAX_TAI_LIST_LEN 114
typedef struct ogs_5gs_tai0_list_s {
struct {
ED3(uint8_t spare:1;,
uint8_t type:2;,
uint8_t num:5;)
/*
* Do not change 'ogs_plmn_id_t' to 'ogs_nas_plmn_id_t'.
* Use 'ogs_plmn_id_t' for easy implementation.
* ogs_nas_tai_list_build() changes to NAS format(ogs_nas_plmn_id_t)
* and is sent to the UE.
*/
ogs_plmn_id_t plmn_id;
ogs_uint24_t tac[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) tai[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) ogs_5gs_tai0_list_t;
typedef struct ogs_5gs_tai2_list_s {
ED3(uint8_t spare:1;,
uint8_t type:2;,
uint8_t num:5;)
/*
* Do not change 'ogs_5gs_tai_t' to 'ogs_nas_tracking_area_identity_t'.
* Use 'ogs_5gs_tai_t' for easy implementation.
* ogs_nas_tai_list_build() changes to NAS
* format(ogs_nas_tracking_area_identity_t)
* and is sent to the UE.
*/
ogs_5gs_tai_t tai[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) ogs_5gs_tai2_list_t;
typedef struct ogs_nas_5gs_tracking_area_identity_list_s {
uint8_t length;
uint8_t buffer[OGS_NAS_5GS_MAX_TAI_LIST_LEN];
} __attribute__ ((packed)) ogs_nas_5gs_tracking_area_identity_list_t;
void ogs_nas_5gs_tai_list_build(
ogs_nas_5gs_tracking_area_identity_list_t *target,
ogs_5gs_tai0_list_t *source0, ogs_5gs_tai2_list_t *source2);
/* 9.11.3.9A 5GS update type
* O TLV 3 */
@ -381,10 +423,10 @@ ED2(uint8_t type:4;,
/* 9.11.3.31B Mapped NSSAI
* O TLV 3-42 */
#define OGS_NAS_MAX_MAPPED_NSSAI_LEN 40
#define OGS_NAX_MAX_NUM_OF_MAPPED_S_NSSAI 10
typedef struct ogs_nas_mapped_nssai_s {
uint8_t length;
uint8_t buffer[OGS_NAS_MAX_MAPPED_NSSAI_LEN];
ogs_s_nssai_t s_nssai[OGS_NAX_MAX_NUM_OF_MAPPED_S_NSSAI];
} ogs_nas_mapped_nssai_t;
/* 9.11.3.33 message container
@ -405,10 +447,10 @@ ED4(uint8_t type:4;,
/* 9.11.3.37 NSSAI
* O TLV 4-72 */
#define MAX_NAS_NSSAI_LEN 72
#define OGS_NAS_MAX_NUM_OF_S_NSSAI 18
typedef struct ogs_nas_nssai_s {
uint8_t length;
uint8_t buffer[MAX_NAS_NSSAI_LEN];
ogs_s_nssai_t s_nssai[OGS_NAS_MAX_NUM_OF_S_NSSAI];
} __attribute__ ((packed)) ogs_nas_nssai_t;
/* 9.11.3.37A NSSAI inclusion mode
@ -468,10 +510,13 @@ typedef ogs_nas_allowed_pdu_session_status_t ogs_nas_pdu_session_status_t;
/* 9.11.3.46 Rejected NSSAI
* O TLV 4-42 */
#define OGS_MAX_NAS_REJECTED_NSSAI_LEN 40
typedef struct ogs_nas_rejected_nssai_s {
uint8_t length;
uint8_t buffer[OGS_MAX_NAS_REJECTED_NSSAI_LEN];
struct {
ED2(uint8_t len:4;,
uint8_t value:4;)
ogs_s_nssai_t s_nssai;
} rejected[OGS_MAX_NUM_OF_S_NSSAI];
} ogs_nas_rejected_nssai_t;
/* 9.11.3.49 Service area list

View File

@ -427,73 +427,3 @@ void eps_qos_build(ogs_nas_eps_quality_of_service_t *eps_qos, uint8_t qci,
eps_qos->length = length*4+1;
}
void ogs_nas_tai_list_build(
ogs_nas_tracking_area_identity_list_t *target,
tai0_list_t *source0, tai2_list_t *source2)
{
int i = 0, j = 0, size = 0;
tai0_list_t target0;
tai2_list_t target2;
ogs_nas_plmn_id_t ogs_nas_plmn_id;
ogs_assert(target);
ogs_assert(source0);
ogs_assert(source2);
memset(target, 0, sizeof(ogs_nas_tracking_area_identity_list_t));
memset(&target0, 0, sizeof(tai0_list_t));
memset(&target2, 0, sizeof(tai2_list_t));
for (i = 0; source0->tai[i].num; i++) {
ogs_assert(source0->tai[i].type == TAI0_TYPE);
target0.tai[i].type = source0->tai[i].type;
/* <Spec> target->num = source->num - 1 */
ogs_assert(source0->tai[i].num < OGS_MAX_NUM_OF_TAI);
target0.tai[i].num = source0->tai[i].num - 1;
memcpy(&target0.tai[i].plmn_id,
ogs_nas_from_plmn_id(&ogs_nas_plmn_id, &source0->tai[i].plmn_id),
OGS_PLMN_ID_LEN);
for (j = 0; j < source0->tai[i].num; j++) {
target0.tai[i].tac[j] = htobe16(source0->tai[i].tac[j]);
}
size = (1 + 3 + 2 * source0->tai[i].num);
if ((target->length + size) > OGS_NAS_MAX_TAI_LIST_LEN) {
ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)",
target->length, size);
return;
}
memcpy(target->buffer + target->length, &target0.tai[i], size);
target->length += size;
}
if (source2->num) {
memset(&target2, 0, sizeof(target2));
ogs_assert(source2->type == TAI1_TYPE || source2->type == TAI2_TYPE);
target2.type = source2->type;
/* <Spec> target->num = source->num - 1 */
ogs_assert(source2->num < OGS_MAX_NUM_OF_TAI);
target2.num = source2->num - 1;
size = (1 + (3 + 2) * source2->num);
if ((target->length + size) > OGS_NAS_MAX_TAI_LIST_LEN) {
ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)",
target->length, size);
return;
}
for (i = 0; i < source2->num; i++) {
memcpy(&target2.tai[i].plmn_id,
ogs_nas_from_plmn_id(&ogs_nas_plmn_id, &source2->tai[i].plmn_id),
OGS_PLMN_ID_LEN);
target2.tai[i].tac = htobe16(source2->tai[i].tac);
}
memcpy(target->buffer + target->length, &target2, size);
target->length += size;
}
}

View File

@ -97,13 +97,6 @@ void *ogs_nas_from_plmn_id(
void *ogs_nas_to_plmn_id(
ogs_plmn_id_t *plmn_id, ogs_nas_plmn_id_t *ogs_nas_plmn_id);
typedef struct ogs_nas_guti_s {
ogs_nas_plmn_id_t nas_plmn_id;
uint16_t mme_gid;
uint8_t mme_code;
uint32_t m_tmsi;
} __attribute__ ((packed)) ogs_nas_guti_t;
/* 9.9.2.0 Additional information
* O TLV 3-n */
#define NAX_MAX_ADDITIONAL_INFORMATION_LEN 255
@ -466,59 +459,13 @@ typedef struct ogs_nas_time_zone_and_time_s {
uint8_t timezone;
} ogs_nas_time_zone_and_time_t;
/* 9.9.3.32 Tracking area identity
* O TV 6 */
typedef struct ogs_nas_tracking_area_identity_s {
ogs_nas_plmn_id_t nas_plmn_id;
uint16_t tac;
} __attribute__ ((packed)) ogs_nas_tracking_area_identity_t;
typedef ogs_nas_tracking_area_identity_t ogs_nas_tai_t;
/* 9.9.3.33 Tracking area identity list
* M LV 7-97 */
#define OGS_NAS_MAX_TAI_LIST_LEN 96
#define TAI0_TYPE 0
#define TAI1_TYPE 1
#define TAI2_TYPE 2
typedef struct tai0_list_s {
struct {
ED3(uint8_t spare:1;,
uint8_t type:2;,
uint8_t num:5;)
/*
* Do not change 'ogs_plmn_id_t' to 'ogs_nas_plmn_id_t'.
* Use 'ogs_plmn_id_t' for easy implementation.
* ogs_nas_tai_list_build() changes to NAS format(ogs_nas_plmn_id_t)
* and is sent to the UE.
*/
ogs_plmn_id_t plmn_id;
uint16_t tac[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) tai[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) tai0_list_t;
typedef struct tai2_list_s {
ED3(uint8_t spare:1;,
uint8_t type:2;,
uint8_t num:5;)
/*
* Do not change 'ogs_tai_t' to 'ogs_nas_tracking_area_identity_t'.
* Use 'ogs_tai_t' for easy implementation.
* ogs_nas_tai_list_build() changes to NAS
* format(ogs_nas_tracking_area_identity_t)
* and is sent to the UE.
*/
ogs_tai_t tai[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) tai2_list_t;
typedef struct ogs_nas_tracking_area_identity_list_s {
uint8_t length;
uint8_t buffer[OGS_NAS_MAX_TAI_LIST_LEN];
} __attribute__ ((packed)) ogs_nas_tracking_area_identity_list_t;
void ogs_nas_tai_list_build(
ogs_nas_tracking_area_identity_list_t *target,
tai0_list_t *source0, tai2_list_t *source2);
* M LV 7-97
* 9.11.3.9 5GS tracking area identity list
* O TLV 9-114 */
#define OGS_TAI0_TYPE 0
#define OGS_TAI1_TYPE 1
#define OGS_TAI2_TYPE 2
/* 9.9.3.34 UE network capability
* M LV 3-14

View File

@ -16,6 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
libnas_eps_sources = files('''
types.c
ies.c
decoder.c
encoder.c

91
lib/nas/eps/types.c Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-nas-eps.h"
void ogs_nas_tai_list_build(ogs_nas_tracking_area_identity_list_t *target,
ogs_eps_tai0_list_t *source0, ogs_eps_tai2_list_t *source2)
{
int i = 0, j = 0, size = 0;
ogs_eps_tai0_list_t target0;
ogs_eps_tai2_list_t target2;
ogs_nas_plmn_id_t ogs_nas_plmn_id;
ogs_assert(target);
ogs_assert(source0);
ogs_assert(source2);
memset(target, 0, sizeof(ogs_nas_tracking_area_identity_list_t));
memset(&target0, 0, sizeof(ogs_eps_tai0_list_t));
memset(&target2, 0, sizeof(ogs_eps_tai2_list_t));
for (i = 0; source0->tai[i].num; i++) {
ogs_assert(source0->tai[i].type == OGS_TAI0_TYPE);
target0.tai[i].type = source0->tai[i].type;
/* <Spec> target->num = source->num - 1 */
ogs_assert(source0->tai[i].num < OGS_MAX_NUM_OF_TAI);
target0.tai[i].num = source0->tai[i].num - 1;
memcpy(&target0.tai[i].plmn_id,
ogs_nas_from_plmn_id(&ogs_nas_plmn_id, &source0->tai[i].plmn_id),
OGS_PLMN_ID_LEN);
for (j = 0; j < source0->tai[i].num; j++) {
target0.tai[i].tac[j] = htobe16(source0->tai[i].tac[j]);
}
size = (1 + 3 + 2 * source0->tai[i].num);
if ((target->length + size) > OGS_NAS_EPS_MAX_TAI_LIST_LEN) {
ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)",
target->length, size);
return;
}
memcpy(target->buffer + target->length, &target0.tai[i], size);
target->length += size;
}
if (source2->num) {
memset(&target2, 0, sizeof(target2));
ogs_assert(source2->type == OGS_TAI1_TYPE ||
source2->type == OGS_TAI2_TYPE);
target2.type = source2->type;
/* <Spec> target->num = source->num - 1 */
ogs_assert(source2->num < OGS_MAX_NUM_OF_TAI);
target2.num = source2->num - 1;
size = (1 + (3 + 2) * source2->num);
if ((target->length + size) > OGS_NAS_EPS_MAX_TAI_LIST_LEN) {
ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)",
target->length, size);
return;
}
for (i = 0; i < source2->num; i++) {
memcpy(&target2.tai[i].plmn_id,
ogs_nas_from_plmn_id(&ogs_nas_plmn_id,
&source2->tai[i].plmn_id),
OGS_PLMN_ID_LEN);
target2.tai[i].tac = htobe16(source2->tai[i].tac);
}
memcpy(target->buffer + target->length, &target2, size);
target->length += size;
}
}

View File

@ -28,6 +28,15 @@
extern "C" {
#endif
/**********************
* NAS GUTI Structure */
typedef struct ogs_nas_eps_guti_s {
ogs_nas_plmn_id_t nas_plmn_id;
uint16_t mme_gid;
uint8_t mme_code;
uint32_t m_tmsi;
} __attribute__ ((packed)) ogs_nas_eps_guti_t;
/* 9.9.2.0A Device properties
* See subclause 10.5.7.8 in 3GPP TS 24.008 [13].
* O TV 1 */
@ -418,6 +427,57 @@ ED3(uint8_t type:4;,
uint8_t tmsi_flag:1;)
} __attribute__ ((packed)) ogs_nas_tmsi_status_t;
/* 9.9.3.32 Tracking area identity
* O TV 6 */
typedef struct ogs_nas_tracking_area_identity_s {
ogs_nas_plmn_id_t nas_plmn_id;
uint16_t tac;
} __attribute__ ((packed)) ogs_nas_tracking_area_identity_t;
typedef ogs_nas_tracking_area_identity_t ogs_nas_eps_tai_t;
/* 9.9.3.33 Tracking area identity list
* M LV 7-97 */
#define OGS_NAS_EPS_MAX_TAI_LIST_LEN 96
typedef struct ogs_eps_tai0_list_s {
struct {
ED3(uint8_t spare:1;,
uint8_t type:2;,
uint8_t num:5;)
/*
* Do not change 'ogs_plmn_id_t' to 'ogs_nas_plmn_id_t'.
* Use 'ogs_plmn_id_t' for easy implementation.
* ogs_nas_tai_list_build() changes to NAS format(ogs_nas_plmn_id_t)
* and is sent to the UE.
*/
ogs_plmn_id_t plmn_id;
uint16_t tac[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) tai[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) ogs_eps_tai0_list_t;
typedef struct ogs_eps_tai2_list_s {
ED3(uint8_t spare:1;,
uint8_t type:2;,
uint8_t num:5;)
/*
* Do not change 'ogs_eps_tai_t' to 'ogs_nas_tracking_area_identity_t'.
* Use 'ogs_eps_tai_t' for easy implementation.
* ogs_nas_tai_list_build() changes to NAS
* format(ogs_nas_tracking_area_identity_t)
* and is sent to the UE.
*/
ogs_eps_tai_t tai[OGS_MAX_NUM_OF_TAI];
} __attribute__ ((packed)) ogs_eps_tai2_list_t;
typedef struct ogs_nas_tracking_area_identity_list_s {
uint8_t length;
uint8_t buffer[OGS_NAS_EPS_MAX_TAI_LIST_LEN];
} __attribute__ ((packed)) ogs_nas_tracking_area_identity_list_t;
void ogs_nas_tai_list_build(ogs_nas_tracking_area_identity_list_t *target,
ogs_eps_tai0_list_t *source0, ogs_eps_tai2_list_t *source2);
/* 9.9.3.35 UE radio capability information update needed
* O TV 1 */
typedef struct ogs_nas_ue_radio_capability_information_update_needed_s {

85
lib/ngap/conv.c Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-ngap.h"
void ogs_ngap_uint32_to_GNB_ID(uint32_t gnb_id, NGAP_GNB_ID_t *gNB_ID)
{
BIT_STRING_t *bit_string = NULL;
ogs_assert(gNB_ID);
bit_string = &gNB_ID->choice.gNB_ID;
ogs_assert(bit_string);
gNB_ID->present = NGAP_GNB_ID_PR_gNB_ID;
bit_string->size = 3;
bit_string->buf = CALLOC(bit_string->size, sizeof(uint8_t));
bit_string->buf[0] = gnb_id >> 16;
bit_string->buf[1] = gnb_id >> 8;
bit_string->buf[2] = (gnb_id & 0xff);
}
void ogs_ngap_GNB_ID_to_uint32(NGAP_GNB_ID_t *gNB_ID, uint32_t *gnb_id)
{
uint8_t *buf = NULL;
ogs_assert(gnb_id);
ogs_assert(gNB_ID);
buf = gNB_ID->choice.gNB_ID.buf;
ogs_assert(buf);
*gnb_id = (buf[0] << 16) + (buf[1] << 8) + buf[2];
}
void ogs_ngap_uint8_to_AMFRegionID(
uint8_t region, NGAP_AMFRegionID_t *aMFRegionID)
{
ogs_assert(aMFRegionID);
aMFRegionID->size = 1;
aMFRegionID->buf = CALLOC(aMFRegionID->size, sizeof(uint8_t));
aMFRegionID->buf[0] = region;
}
void ogs_ngap_uint16_to_NGAP_AMFSetID(
uint16_t set, NGAP_AMFSetID_t *aMFSetID)
{
ogs_assert(aMFSetID);
aMFSetID->size = 2;
aMFSetID->buf = CALLOC(aMFSetID->size, sizeof(uint8_t));
aMFSetID->bits_unused = 6;
aMFSetID->buf[0] = (set >> 2);
aMFSetID->buf[1] = ((set & 0x03) << 6);
}
void ogs_ngap_uint8_to_NGAP_NGAP_AMFPointer(
uint8_t pointer, NGAP_AMFPointer_t *aMFPointer)
{
ogs_assert(aMFPointer);
aMFPointer->size = 1;
aMFPointer->buf = CALLOC(aMFPointer->size, sizeof(uint8_t));
aMFPointer->bits_unused = 2;
aMFPointer->buf[0] = (pointer << 2);
}

46
lib/ngap/conv.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if !defined(OGS_NGAP_INSIDE) && !defined(OGS_NGAP_COMPILATION)
#error "This header cannot be included directly."
#endif
#ifndef OGS_NGAP_CONV_H
#define OGS_NGAP_CONV_H
#ifdef __cplusplus
extern "C" {
#endif
void ogs_ngap_uint32_to_GNB_ID(uint32_t gnb_id, NGAP_GNB_ID_t *gNB_ID);
void ogs_ngap_GNB_ID_to_uint32(NGAP_GNB_ID_t *gNB_ID, uint32_t *gnb_id);
void ogs_ngap_uint8_to_AMFRegionID(
uint8_t region, NGAP_AMFRegionID_t *aMFRegionID);
void ogs_ngap_uint16_to_NGAP_AMFSetID(
uint16_t set, NGAP_AMFSetID_t *aMFSetID);
void ogs_ngap_uint8_to_NGAP_NGAP_AMFPointer(
uint8_t pointer, NGAP_AMFPointer_t *aMFPointer);
#ifdef __cplusplus
}
#endif
#endif /* OGS_NGAP_CONV_H */

View File

@ -1,4 +1,4 @@
# Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
# Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
# This file is part of Open5GS.
@ -16,6 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
libngap_sources = files('''
conv.c
message.c
'''.split())

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -28,27 +28,6 @@
extern "C" {
#endif
/* Octets */
#define OGS_NGAP_CLEAR_DATA(__dATA) \
do { \
ogs_assert((__dATA)); \
if ((__dATA)->buf) { \
FREEMEM((__dATA)->buf); \
(__dATA)->buf = NULL; \
(__dATA)->size = 0; \
} \
} while(0)
#define OGS_NGAP_STORE_DATA(__dST, __sRC) \
do { \
ogs_assert((__sRC)); \
ogs_assert((__sRC)->buf); \
ogs_assert((__dST)); \
OGS_NGAP_CLEAR_DATA(__dST); \
(__dST)->size = (__sRC)->size; \
(__dST)->buf = CALLOC((__dST)->size, sizeof(uint8_t)); \
memcpy((__dST)->buf, (__sRC)->buf, (__dST)->size); \
} while(0)
typedef struct NGAP_NGAP_PDU ogs_ngap_message_t;
int ogs_ngap_decode(ogs_ngap_message_t *message, ogs_pkbuf_t *pkbuf);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -633,6 +633,7 @@
#define OGS_NGAP_INSIDE
#include "ngap/conv.h"
#include "ngap/message.h"
#undef OGS_NGAP_INSIDE

View File

@ -28,27 +28,6 @@
extern "C" {
#endif
/* Octets */
#define OGS_S1AP_CLEAR_DATA(__dATA) \
do { \
ogs_assert((__dATA)); \
if ((__dATA)->buf) { \
FREEMEM((__dATA)->buf); \
(__dATA)->buf = NULL; \
(__dATA)->size = 0; \
} \
} while(0)
#define OGS_S1AP_STORE_DATA(__dST, __sRC) \
do { \
ogs_assert((__sRC)); \
ogs_assert((__sRC)->buf); \
ogs_assert((__dST)); \
OGS_S1AP_CLEAR_DATA(__dST); \
(__dST)->size = (__sRC)->size; \
(__dST)->buf = CALLOC((__dST)->size, sizeof(uint8_t)); \
memcpy((__dST)->buf, (__sRC)->buf, (__dST)->size); \
} while(0)
typedef struct S1AP_S1AP_PDU ogs_s1ap_message_t;
int ogs_s1ap_decode(ogs_s1ap_message_t *message, ogs_pkbuf_t *pkbuf);

View File

@ -41,10 +41,12 @@ extern int __ogs_sctp_domain;
#define OGS_S1AP_SCTP_PORT 36412
#define OGS_SGSAP_SCTP_PORT 29118
#define OGS_NGAP_SCTP_PORT 38412
#define OGS_SCTP_S1AP_PPID 18
#define OGS_SCTP_X2AP_PPID 27
#define OGS_SCTP_SGSAP_PPID 0
#define OGS_SCTP_NGAP_PPID 60
#if HAVE_USRSCTP

415
src/amf/amf-sm.c Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "sbi-path.h"
#include "nnrf-handler.h"
#include "ngap-path.h"
void amf_state_initial(ogs_fsm_t *s, amf_event_t *e)
{
amf_sm_debug(e);
ogs_assert(s);
OGS_FSM_TRAN(s, &amf_state_operational);
}
void amf_state_final(ogs_fsm_t *s, amf_event_t *e)
{
amf_sm_debug(e);
ogs_assert(s);
}
void amf_state_operational(ogs_fsm_t *s, amf_event_t *e)
{
int rv;
#if 0
ogs_pkbuf_t *recvbuf = NULL;
#endif
char buf[OGS_ADDRSTRLEN];
ogs_sock_t *sock = NULL;
ogs_sockaddr_t *addr = NULL;
amf_gnb_t *gnb = NULL;
uint16_t max_num_of_ostreams = 0;
ogs_ngap_message_t ngap_message;
ogs_pkbuf_t *pkbuf = NULL;
int rc;
#if 0
ogs_nas_5gs_message_t nas_message;
#endif
ogs_sbi_server_t *server = NULL;
ogs_sbi_session_t *session = NULL;
ogs_sbi_request_t *sbi_request = NULL;
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_subscription_t *subscription = NULL;
ogs_sbi_response_t *sbi_response = NULL;
ogs_sbi_message_t sbi_message;
amf_sm_debug(e);
ogs_assert(s);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
rv = amf_sbi_open();
if (rv != OGS_OK) {
ogs_fatal("Can't establish SBI path");
}
rv = ngap_open();
if (rv != OGS_OK) {
ogs_error("Can't establish NGAP path");
break;
}
break;
case OGS_FSM_EXIT_SIG:
ngap_close();
amf_sbi_close();
break;
case AMF_EVT_SBI_SERVER:
sbi_request = e->sbi.request;
ogs_assert(sbi_request);
session = e->sbi.session;
ogs_assert(session);
server = e->sbi.server;
ogs_assert(server);
rv = ogs_sbi_parse_request(&sbi_message, sbi_request);
if (rv != OGS_OK) {
/* 'sbi_message' buffer is released in ogs_sbi_parse_request() */
ogs_error("cannot parse HTTP sbi_message");
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
NULL, "cannot parse HTTP sbi_message", NULL);
break;
}
if (strcmp(sbi_message.h.api.version, OGS_SBI_API_VERSION) != 0) {
ogs_error("Not supported version [%s]", sbi_message.h.api.version);
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
&sbi_message, "Not supported version", NULL);
ogs_sbi_message_free(&sbi_message);
break;
}
SWITCH(sbi_message.h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NRF_NFM)
SWITCH(sbi_message.h.resource.name)
CASE(OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY)
SWITCH(sbi_message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
amf_nnrf_handle_nf_status_notify(
server, session, &sbi_message);
break;
DEFAULT
ogs_error("Invalid HTTP method [%s]",
sbi_message.h.method);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED,
&sbi_message,
"Invalid HTTP method", sbi_message.h.method);
END
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
sbi_message.h.resource.name);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, &sbi_message,
"Unknown resource name", sbi_message.h.resource.name);
END
break;
DEFAULT
ogs_error("Invalid API name [%s]", sbi_message.h.service.name);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, &sbi_message,
"Invalid API name", sbi_message.h.resource.name);
END
/* In lib/sbi/server.c, notify_completed() releases 'request' buffer. */
ogs_sbi_message_free(&sbi_message);
break;
case AMF_EVT_SBI_CLIENT:
ogs_assert(e);
sbi_response = e->sbi.response;
ogs_assert(sbi_response);
rv = ogs_sbi_parse_response(&sbi_message, sbi_response);
if (rv != OGS_OK) {
ogs_error("cannot parse HTTP response");
ogs_sbi_message_free(&sbi_message);
ogs_sbi_response_free(sbi_response);
break;
}
if (strcmp(sbi_message.h.api.version, OGS_SBI_API_VERSION) != 0) {
ogs_error("Not supported version [%s]", sbi_message.h.api.version);
ogs_sbi_message_free(&sbi_message);
ogs_sbi_response_free(sbi_response);
break;
}
SWITCH(sbi_message.h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NRF_NFM)
SWITCH(sbi_message.h.resource.name)
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
ogs_assert(OGS_FSM_STATE(&nf_instance->sm));
e->sbi.message = &sbi_message;
ogs_fsm_dispatch(&nf_instance->sm, e);
if (OGS_FSM_CHECK(&nf_instance->sm, amf_nf_state_exception)) {
ogs_error("State machine exception");
}
break;
CASE(OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS)
subscription = e->sbi.data;
ogs_assert(subscription);
SWITCH(sbi_message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
if (sbi_message.res_status == OGS_SBI_HTTP_STATUS_CREATED ||
sbi_message.res_status == OGS_SBI_HTTP_STATUS_OK) {
amf_nnrf_handle_nf_status_subscribe(
subscription, &sbi_message);
} else {
ogs_error("HTTP response error : %d",
sbi_message.res_status);
}
break;
CASE(OGS_SBI_HTTP_METHOD_DELETE)
if (sbi_message.res_status ==
OGS_SBI_HTTP_STATUS_NO_CONTENT) {
ogs_sbi_subscription_remove(subscription);
} else {
ogs_error("HTTP response error : %d",
sbi_message.res_status);
}
break;
DEFAULT
ogs_error("Invalid HTTP method [%s]", sbi_message.h.method);
END
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
sbi_message.h.resource.name);
END
break;
CASE(OGS_SBI_SERVICE_NAME_NRF_DISC)
SWITCH(sbi_message.h.resource.name)
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
if (sbi_message.res_status == OGS_SBI_HTTP_STATUS_OK) {
amf_nnrf_handle_nf_discover(&sbi_message);
} else {
ogs_error("HTTP response error : %d",
sbi_message.res_status);
}
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
sbi_message.h.resource.name);
END
break;
DEFAULT
ogs_error("Invalid API name [%s]", sbi_message.h.service.name);
END
ogs_sbi_message_free(&sbi_message);
ogs_sbi_response_free(sbi_response);
break;
case AMF_EVT_SBI_TIMER:
ogs_assert(e);
switch(e->timer_id) {
case AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL:
case AMF_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL:
case AMF_TIMER_NF_INSTANCE_HEARTBEAT:
case AMF_TIMER_NF_INSTANCE_VALIDITY:
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
ogs_assert(OGS_FSM_STATE(&nf_instance->sm));
ogs_fsm_dispatch(&nf_instance->sm, e);
if (OGS_FSM_CHECK(&nf_instance->sm, amf_nf_state_de_registered)) {
amf_nf_fsm_fini(nf_instance);
ogs_sbi_nf_instance_remove(nf_instance);
} else if (OGS_FSM_CHECK(&nf_instance->sm,
amf_nf_state_exception)) {
ogs_error("State machine exception");
}
break;
case AMF_TIMER_SUBSCRIPTION_VALIDITY:
subscription = e->sbi.data;
ogs_assert(subscription);
ogs_info("Subscription validity expired [%s]", subscription->id);
ogs_sbi_subscription_remove(subscription);
amf_sbi_send_nf_status_subscribe(subscription->client,
amf_self()->nf_type, subscription->nf_instance_id);
break;
default:
ogs_error("Unknown timer[%s:%d]",
amf_timer_get_name(e->timer_id), e->timer_id);
}
break;
case AMF_EVT_NGAP_LO_ACCEPT:
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
ogs_info("gNB-N1 accepted[%s] in master_sm module",
OGS_ADDR(addr, buf));
gnb = amf_gnb_find_by_addr(addr);
if (!gnb) {
gnb = amf_gnb_add(sock, addr);
ogs_assert(gnb);
} else {
ogs_warn("gNB context duplicated with IP-address [%s]!!!",
OGS_ADDR(addr, buf));
ogs_sock_destroy(sock);
ogs_warn("N1 Socket Closed");
}
break;
case AMF_EVT_NGAP_LO_SCTP_COMM_UP:
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
max_num_of_ostreams = e->ngap.max_num_of_ostreams;
gnb = amf_gnb_find_by_addr(addr);
if (!gnb) {
gnb = amf_gnb_add(sock, addr);
ogs_assert(gnb);
} else {
ogs_free(addr);
}
gnb->max_num_of_ostreams =
ogs_min(max_num_of_ostreams, gnb->max_num_of_ostreams);
ogs_debug("gNB-N1 SCTP_COMM_UP[%s] Max Num of Outbound Streams[%d]",
OGS_ADDR(addr, buf), gnb->max_num_of_ostreams);
break;
case AMF_EVT_NGAP_LO_CONNREFUSED:
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
gnb = amf_gnb_find_by_addr(addr);
ogs_free(addr);
if (gnb) {
ogs_info("gNB-N1[%s] connection refused!!!",
OGS_ADDR(addr, buf));
amf_gnb_remove(gnb);
} else {
ogs_warn("gNB-N1[%s] connection refused, Already Removed!",
OGS_ADDR(addr, buf));
}
break;
case AMF_EVT_NGAP_MESSAGE:
sock = e->ngap.sock;
ogs_assert(sock);
addr = e->ngap.addr;
ogs_assert(addr);
pkbuf = e->pkbuf;
ogs_assert(pkbuf);
gnb = amf_gnb_find_by_addr(addr);
ogs_free(addr);
ogs_assert(gnb);
ogs_assert(OGS_FSM_STATE(&gnb->sm));
rc = ogs_ngap_decode(&ngap_message, pkbuf);
if (rc == OGS_OK) {
e->gnb = gnb;
e->ngap.message = &ngap_message;
ogs_fsm_dispatch(&gnb->sm, e);
} else {
ogs_error("Cannot decode NGAP message");
#if 0
ngap_send_error_indication(
gnb, NULL, NULL, NGAP_Cause_PR_protocol,
NGAP_CauseProtocol_abstract_syntax_error_falsely_constructed_message);
#endif
}
ogs_ngap_free(&ngap_message);
ogs_pkbuf_free(pkbuf);
break;
case AMF_EVT_NGAP_TIMER:
#if 0
gnb_ue = e->gnb_ue;
ogs_assert(gnb_ue);
gnb = e->gnb;
ogs_assert(gnb);
ogs_assert(OGS_FSM_STATE(&gnb->sm));
ogs_fsm_dispatch(&gnb->sm, e);
#else
ogs_fatal("Not implemeted");
#endif
break;
default:
ogs_error("No handler for event %s", amf_event_get_name(e));
break;
}
}

55
src/amf/amf-sm.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AMF_SM_H
#define AMF_SM_H
#include "event.h"
#ifdef __cplusplus
extern "C" {
#endif
void amf_state_initial(ogs_fsm_t *s, amf_event_t *e);
void amf_state_final(ogs_fsm_t *s, amf_event_t *e);
void amf_state_operational(ogs_fsm_t *s, amf_event_t *e);
void amf_nf_fsm_init(ogs_sbi_nf_instance_t *nf_instance);
void amf_nf_fsm_fini(ogs_sbi_nf_instance_t *nf_instance);
void amf_nf_state_initial(ogs_fsm_t *s, amf_event_t *e);
void amf_nf_state_final(ogs_fsm_t *s, amf_event_t *e);
void amf_nf_state_will_register(ogs_fsm_t *s, amf_event_t *e);
void amf_nf_state_registered(ogs_fsm_t *s, amf_event_t *e);
void amf_nf_state_de_registered(ogs_fsm_t *s, amf_event_t *e);
void amf_nf_state_exception(ogs_fsm_t *s, amf_event_t *e);
void ngap_state_initial(ogs_fsm_t *s, amf_event_t *e);
void ngap_state_final(ogs_fsm_t *s, amf_event_t *e);
void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e);
void ngap_state_exception(ogs_fsm_t *s, amf_event_t *e);
#define amf_sm_debug(__pe) \
ogs_debug("%s(): %s", __func__, amf_event_get_name(__pe))
#ifdef __cplusplus
}
#endif
#endif /* AMF_SM_H */

40
src/amf/app.c Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-app.h"
int app_initialize(const char *const argv[])
{
int rv;
rv = amf_initialize();
if (rv != OGS_OK) {
ogs_error("Failed to intialize AMF");
return rv;
}
ogs_info("AMF initialize...done");
return OGS_OK;
}
void app_terminate(void)
{
amf_terminate();
ogs_info("AMF terminate...done");
}

1044
src/amf/context.c Normal file

File diff suppressed because it is too large Load Diff

165
src/amf/context.h Normal file
View File

@ -0,0 +1,165 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AMF_CONTEXT_H
#define AMF_CONTEXT_H
#include "ogs-app.h"
#include "ogs-sbi.h"
#include "ogs-sctp.h"
#include "ogs-ngap.h"
#include "ogs-nas-5gs.h"
#include "amf-sm.h"
#include "timer.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_NUM_OF_SERVED_GUAMI 8
extern int __amf_log_domain;
#undef OGS_LOG_DOMAIN
#define OGS_LOG_DOMAIN __amf_log_domain
typedef uint32_t amf_m_tmsi_t;
typedef struct amf_context_s {
ogs_queue_t *queue; /* Queue for processing UPF control */
ogs_timer_mgr_t *timer_mgr; /* Timer Manager */
ogs_pollset_t *pollset; /* Poll Set for I/O Multiplexing */
OpenAPI_nf_type_e nf_type;
const char *amf_name;
/* Served GUMME */
uint8_t num_of_served_guami;
struct {
ogs_plmn_id_t plmn_id;
ogs_amf_id_t amf_id;
} served_guami[MAX_NUM_OF_SERVED_GUAMI];
/* Served TAI */
uint8_t num_of_served_tai;
struct {
ogs_5gs_tai0_list_t list0;
ogs_5gs_tai2_list_t list2;
} served_tai[OGS_MAX_NUM_OF_SERVED_TAI];
/* PLMN Support */
uint8_t num_of_plmn_support;
struct {
ogs_plmn_id_t plmn_id;
int num_of_s_nssai;
ogs_s_nssai_t s_nssai[OGS_MAX_NUM_OF_S_NSSAI];
} plmn_support[OGS_MAX_NUM_OF_PLMN];
/* defined in 'nas_ies.h'
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
* #define NAS_SECURITY_ALGORITHMS_128_EEA1 1
* #define NAS_SECURITY_ALGORITHMS_128_EEA2 2
* #define NAS_SECURITY_ALGORITHMS_128_EEA3 3 */
uint8_t num_of_ciphering_order;
uint8_t ciphering_order[OGS_MAX_NUM_OF_ALGORITHM];
/* defined in 'nas_ies.h'
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
* #define NAS_SECURITY_ALGORITHMS_128_EIA1 1
* #define NAS_SECURITY_ALGORITHMS_128_EIA1 2
* #define NAS_SECURITY_ALGORITHMS_128_EIA3 3 */
uint8_t num_of_integrity_order;
uint8_t integrity_order[OGS_MAX_NUM_OF_ALGORITHM];
/* Network Name */
ogs_nas_network_name_t short_name; /* Network short name */
ogs_nas_network_name_t full_name; /* Network Full Name */
/* M-TMSI Pool */
OGS_POOL(m_tmsi, amf_m_tmsi_t);
/* NGSetupResponse */
uint8_t relative_capacity;
uint16_t ngap_port; /* Default NGAP Port */
ogs_list_t ngap_list; /* AMF NGAP IPv4 Server List */
ogs_list_t ngap_list6; /* AMF NGAP IPv6 Server List */
ogs_list_t gnb_list; /* ENB S1AP Client List */
ogs_hash_t *gnb_addr_hash; /* hash table for GNB Address */
ogs_hash_t *gnb_id_hash; /* hash table for GNB-ID */
} amf_context_t;
typedef struct amf_gnb_s {
ogs_lnode_t lnode;
ogs_fsm_t sm; /* A state machine */
uint32_t gnb_id; /* eNB_ID received from eNB */
int sock_type; /* SOCK_STREAM or SOCK_SEQPACKET */
ogs_sock_t *sock; /* eNB S1AP Socket */
ogs_sockaddr_t *addr; /* eNB S1AP Address */
ogs_poll_t *poll; /* eNB S1AP Poll */
struct {
bool ng_setup_success; /* eNB S1AP Setup complete successfuly */
} state;
uint16_t max_num_of_ostreams;/* SCTP Max num of outbound streams */
uint16_t ostream_id; /* gnb_ostream_id generator */
uint8_t num_of_supported_ta_list;
ogs_5gs_tai_t supported_ta_list[OGS_MAX_NUM_OF_TAI*OGS_MAX_NUM_OF_BPLMN];
ogs_list_t gnb_ue_list;
} amf_gnb_t;
void amf_context_init(void);
void amf_context_final(void);
amf_context_t *amf_self(void);
int amf_context_parse_config(void);
amf_gnb_t *amf_gnb_add(ogs_sock_t *sock, ogs_sockaddr_t *addr);
int amf_gnb_remove(amf_gnb_t *gnb);
int amf_gnb_remove_all(void);
amf_gnb_t *amf_gnb_find_by_addr(ogs_sockaddr_t *addr);
amf_gnb_t *amf_gnb_find_by_gnb_id(uint32_t gnb_id);
int amf_gnb_set_gnb_id(amf_gnb_t *gnb, uint32_t gnb_id);
int amf_gnb_sock_type(ogs_sock_t *sock);
int amf_find_served_tai(ogs_5gs_tai_t *tai);
int amf_m_tmsi_pool_generate(void);
amf_m_tmsi_t *amf_m_tmsi_alloc(void);
int amf_m_tmsi_free(amf_m_tmsi_t *tmsi);
#if 0
uint8_t amf_selected_int_algorithm(amf_ue_t *amf_ue);
uint8_t amf_selected_enc_algorithm(amf_ue_t *amf_ue);
#endif
#ifdef __cplusplus
}
#endif
#endif /* AMF_CONTEXT_H */

139
src/amf/event.c Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "event.h"
#include "context.h"
#define EVENT_POOL 32 /* FIXME : 32 */
static OGS_POOL(pool, amf_event_t);
void amf_event_init(void)
{
ogs_pool_init(&pool, EVENT_POOL);
amf_self()->queue = ogs_queue_create(EVENT_POOL);
ogs_assert(amf_self()->queue);
amf_self()->timer_mgr = ogs_timer_mgr_create();
ogs_assert(amf_self()->timer_mgr);
amf_self()->pollset = ogs_pollset_create();
ogs_assert(amf_self()->pollset);
}
void amf_event_final(void)
{
if (amf_self()->pollset)
ogs_pollset_destroy(amf_self()->pollset);
if (amf_self()->timer_mgr)
ogs_timer_mgr_destroy(amf_self()->timer_mgr);
if (amf_self()->queue)
ogs_queue_destroy(amf_self()->queue);
ogs_pool_final(&pool);
}
amf_event_t *amf_event_new(amf_event_e id)
{
amf_event_t *e = NULL;
ogs_pool_alloc(&pool, &e);
ogs_assert(e);
memset(e, 0, sizeof(*e));
e->id = id;
return e;
}
void amf_event_free(amf_event_t *e)
{
ogs_assert(e);
ogs_pool_free(&pool, e);
}
const char *amf_event_get_name(amf_event_t *e)
{
if (e == NULL)
return OGS_FSM_NAME_INIT_SIG;
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
return OGS_FSM_NAME_ENTRY_SIG;
case OGS_FSM_EXIT_SIG:
return OGS_FSM_NAME_EXIT_SIG;
case AMF_EVT_SBI_SERVER:
return "AMF_EVT_SBI_SERVER";
case AMF_EVT_SBI_CLIENT:
return "AMF_EVT_SBI_CLIENT";
case AMF_EVT_SBI_TIMER:
return "AMF_EVT_SBI_TIMER";
case AMF_EVT_NGAP_MESSAGE:
return "AMF_EVT_NGAP_MESSAGE";
case AMF_EVT_NGAP_TIMER:
return "AMF_EVT_NGAP_TIMER";
case AMF_EVT_NGAP_LO_ACCEPT:
return "AMF_EVT_NGAP_LO_ACCEPT";
case AMF_EVT_NGAP_LO_SCTP_COMM_UP:
return "AMF_EVT_NGAP_LO_SCTP_COMM_UP";
case AMF_EVT_NGAP_LO_CONNREFUSED:
return "AMF_EVT_NGAP_LO_CONNREFUSED";
default:
break;
}
return "UNKNOWN_EVENT";
}
void amf_sctp_event_push(amf_event_e id,
void *sock, ogs_sockaddr_t *addr, ogs_pkbuf_t *pkbuf,
uint16_t max_num_of_istreams, uint16_t max_num_of_ostreams)
{
amf_event_t *e = NULL;
int rv;
ogs_assert(id);
ogs_assert(sock);
ogs_assert(addr);
e = amf_event_new(id);
ogs_assert(e);
e->pkbuf = pkbuf;
e->ngap.sock = sock;
e->ngap.addr = addr;
e->ngap.max_num_of_istreams = max_num_of_istreams;
e->ngap.max_num_of_ostreams = max_num_of_ostreams;
rv = ogs_queue_push(amf_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
ogs_free(e->ngap.addr);
if (e->pkbuf)
ogs_pkbuf_free(e->pkbuf);
amf_event_free(e);
}
#if HAVE_USRSCTP
else {
ogs_pollset_notify(amf_self()->pollset);
}
#endif
}

106
src/amf/event.h Normal file
View File

@ -0,0 +1,106 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AMF_EVENT_H
#define AMF_EVENT_H
#include "ogs-core.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ogs_sbi_server_s ogs_sbi_server_t;
typedef struct ogs_sbi_session_s ogs_sbi_session_t;
typedef struct ogs_sbi_request_s ogs_sbi_request_t;
typedef struct ogs_sbi_response_s ogs_sbi_response_t;
typedef struct ogs_sbi_message_s ogs_sbi_message_t;
typedef struct ogs_sbi_nf_instance_s ogs_sbi_nf_instance_t;
typedef struct ogs_sbi_subscription_s ogs_sbi_subscription_t;
typedef enum {
AMF_EVT_BASE = OGS_FSM_USER_SIG,
AMF_EVT_SBI_SERVER,
AMF_EVT_SBI_CLIENT,
AMF_EVT_SBI_TIMER,
AMF_EVT_NGAP_MESSAGE,
AMF_EVT_NGAP_TIMER,
AMF_EVT_NGAP_LO_ACCEPT,
AMF_EVT_NGAP_LO_SCTP_COMM_UP,
AMF_EVT_NGAP_LO_CONNREFUSED,
AMF_EVT_TOP,
} amf_event_e;
typedef struct amf_gnb_s amf_gnb_t;
typedef struct ogs_nas_5gs_message_s ogs_nas_5gs_message_t;
typedef struct NGAP_NGAP_PDU ogs_ngap_message_t;
typedef long NGAP_ProcedureCode_t;
typedef struct amf_event_s {
int id;
ogs_pkbuf_t *pkbuf;
int timer_id;
struct {
ogs_sock_t *sock;
ogs_sockaddr_t *addr;
uint16_t max_num_of_istreams;
uint16_t max_num_of_ostreams;
NGAP_ProcedureCode_t code;
ogs_ngap_message_t *message;
} ngap;
struct {
/* OGS_EVT_SBI_SERVER */
ogs_sbi_request_t *request;
ogs_sbi_session_t *session;
ogs_sbi_server_t *server;
/* OGS_EVT_SBI_CLIENT */
ogs_sbi_response_t *response;
void *data;
ogs_sbi_message_t *message;
} sbi;
amf_gnb_t *gnb;
} amf_event_t;
void amf_event_init(void);
void amf_event_final(void);
amf_event_t *amf_event_new(amf_event_e id);
void amf_event_free(amf_event_t *e);
const char *amf_event_get_name(amf_event_t *e);
void amf_sctp_event_push(amf_event_e id,
void *sock, ogs_sockaddr_t *addr, ogs_pkbuf_t *pkbuf,
uint16_t max_num_of_istreams, uint16_t max_num_of_ostreams);
#ifdef __cplusplus
}
#endif
#endif /* AMF_EVENT_H */

134
src/amf/init.c Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "context.h"
static ogs_thread_t *thread;
static void amf_main(void *data);
static int initialized = 0;
int amf_initialize()
{
int rv;
amf_context_init();
amf_event_init(); /* Create event with poll, timer */
ogs_sbi_context_init(amf_self()->pollset, amf_self()->timer_mgr);
rv = ogs_sbi_context_parse_config("amf", "nrf");
if (rv != OGS_OK) return rv;
rv = amf_context_parse_config();
if (rv != OGS_OK) return rv;
rv = ogs_log_config_domain(
ogs_config()->logger.domain, ogs_config()->logger.level);
if (rv != OGS_OK) return rv;
thread = ogs_thread_create(amf_main, NULL);
if (!thread) return OGS_ERROR;
initialized = 1;
return OGS_OK;
}
static ogs_timer_t *t_termination_holding = NULL;
static void event_termination(void)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
/* Sending NF Instance De-registeration to NRF */
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
amf_nf_fsm_fini(nf_instance);
/* Starting holding timer */
t_termination_holding = ogs_timer_add(amf_self()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);
#define TERMINATION_HOLDING_TIME ogs_time_from_msec(300)
ogs_timer_start(t_termination_holding, TERMINATION_HOLDING_TIME);
/* Sending termination event to the queue */
ogs_queue_term(amf_self()->queue);
ogs_pollset_notify(amf_self()->pollset);
}
void amf_terminate(void)
{
if (!initialized) return;
/* Daemon terminating */
event_termination();
ogs_thread_destroy(thread);
ogs_timer_delete(t_termination_holding);
amf_context_final();
ogs_sbi_context_final();
amf_event_final(); /* Destroy event */
}
static void amf_main(void *data)
{
ogs_fsm_t amf_sm;
int rv;
ogs_fsm_create(&amf_sm, amf_state_initial, amf_state_final);
ogs_fsm_init(&amf_sm, 0);
for ( ;; ) {
ogs_pollset_poll(amf_self()->pollset,
ogs_timer_mgr_next(amf_self()->timer_mgr));
/*
* After ogs_pollset_poll(), ogs_timer_mgr_expire() must be called.
*
* The reason is why ogs_timer_mgr_next() can get the corrent value
* when ogs_timer_stop() is called internally in ogs_timer_mgr_expire().
*
* You should not use event-queue before ogs_timer_mgr_expire().
* In this case, ogs_timer_mgr_expire() does not work
* because 'if rv == OGS_DONE' statement is exiting and
* not calling ogs_timer_mgr_expire().
*/
ogs_timer_mgr_expire(amf_self()->timer_mgr);
for ( ;; ) {
amf_event_t *e = NULL;
rv = ogs_queue_trypop(amf_self()->queue, (void**)&e);
ogs_assert(rv != OGS_ERROR);
if (rv == OGS_DONE)
goto done;
if (rv == OGS_RETRY)
break;
ogs_assert(e);
ogs_fsm_dispatch(&amf_sm, e);
amf_event_free(e);
}
}
done:
ogs_fsm_fini(&amf_sm, 0);
ogs_fsm_delete(&amf_sm);
}

68
src/amf/meson.build Normal file
View File

@ -0,0 +1,68 @@
# Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
# This file is part of Open5GS.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
libamf_sources = files('''
context.c
event.c
timer.c
nnrf-handler.c
nnrf-build.c
sbi-path.c
nf-sm.c
ngap-sctp.c
ngap-build.c
ngap-handler.c
ngap-path.c
ngap-sm.c
amf-sm.c
init.c
'''.split())
libamf = static_library('amf',
sources : libamf_sources,
link_with : libipfw,
dependencies : [libapp_dep,
libsctp_dep,
libngap_dep,
libnas_5gs_dep,
libsbi_dep],
install : false)
libamf_dep = declare_dependency(
link_with : libamf,
dependencies : [libapp_dep,
libsctp_dep,
libngap_dep,
libnas_5gs_dep,
libsbi_dep])
amf_sources = files('''
app.c
../main.c
'''.split())
executable('open5gs-amfd',
sources : amf_sources,
c_args : '-DDEFAULT_CONFIG_FILENAME="@0@/amf.yaml"'.format(open5gs_sysconfdir),
include_directories : srcinc,
dependencies : libamf_dep,
install_rpath : libdir,
install : true)

384
src/amf/nf-sm.c Normal file
View File

@ -0,0 +1,384 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "context.h"
#include "sbi-path.h"
#include "nnrf-handler.h"
void amf_nf_fsm_init(ogs_sbi_nf_instance_t *nf_instance)
{
amf_event_t e;
ogs_assert(nf_instance);
e.sbi.data = nf_instance;
ogs_fsm_create(&nf_instance->sm,
amf_nf_state_initial, amf_nf_state_final);
ogs_fsm_init(&nf_instance->sm, &e);
}
void amf_nf_fsm_fini(ogs_sbi_nf_instance_t *nf_instance)
{
amf_event_t e;
ogs_assert(nf_instance);
e.sbi.data = nf_instance;
ogs_fsm_fini(&nf_instance->sm, &e);
ogs_fsm_delete(&nf_instance->sm);
}
void amf_nf_state_initial(ogs_fsm_t *s, amf_event_t *e)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
ogs_assert(nf_instance->id);
nf_instance->t_registration_interval = ogs_timer_add(amf_self()->timer_mgr,
amf_timer_nf_instance_registration_interval, nf_instance);
ogs_assert(nf_instance->t_registration_interval);
nf_instance->t_heartbeat_interval = ogs_timer_add(amf_self()->timer_mgr,
amf_timer_nf_instance_heartbeat_interval, nf_instance);
ogs_assert(nf_instance->t_heartbeat_interval);
nf_instance->t_heartbeat = ogs_timer_add(amf_self()->timer_mgr,
amf_timer_nf_instance_heartbeat, nf_instance);
ogs_assert(nf_instance->t_heartbeat);
nf_instance->t_validity = ogs_timer_add(amf_self()->timer_mgr,
amf_timer_nf_instance_validity, nf_instance);
ogs_assert(nf_instance->t_validity);
if (NF_INSTANCE_IS_SELF(nf_instance->id)) {
OGS_FSM_TRAN(s, &amf_nf_state_will_register);
} else {
OGS_FSM_TRAN(s, &amf_nf_state_registered);
}
}
void amf_nf_state_final(ogs_fsm_t *s, amf_event_t *e)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
ogs_timer_delete(nf_instance->t_registration_interval);
ogs_timer_delete(nf_instance->t_heartbeat_interval);
ogs_timer_delete(nf_instance->t_heartbeat);
ogs_timer_delete(nf_instance->t_validity);
}
void amf_nf_state_will_register(ogs_fsm_t *s, amf_event_t *e)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_client_t *client = NULL;
ogs_sbi_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
ogs_timer_start(nf_instance->t_registration_interval,
amf_timer_cfg(AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL)->
duration);
amf_sbi_send_nf_register(nf_instance);
break;
case OGS_FSM_EXIT_SIG:
ogs_timer_stop(nf_instance->t_registration_interval);
break;
case AMF_EVT_SBI_CLIENT:
message = e->sbi.message;
ogs_assert(message);
SWITCH(message->h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NRF_NFM)
SWITCH(message->h.resource.name)
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
if (message->res_status == OGS_SBI_HTTP_STATUS_OK ||
message->res_status == OGS_SBI_HTTP_STATUS_CREATED) {
amf_nnrf_handle_nf_register(nf_instance, message);
OGS_FSM_TRAN(s, &amf_nf_state_registered);
} else {
ogs_error("HTTP Response Status Code [%d]",
message->res_status);
OGS_FSM_TRAN(s, &amf_nf_state_exception);
}
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
message->h.resource.name);
END
break;
DEFAULT
ogs_error("Invalid API name [%s]", message->h.service.name);
END
break;
case AMF_EVT_SBI_TIMER:
switch(e->timer_id) {
case AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL:
client = nf_instance->client;
ogs_assert(client);
addr = client->addr;
ogs_assert(addr);
ogs_warn("Retry to registration with NRF [%s]", nf_instance->id);
ogs_timer_start(nf_instance->t_registration_interval,
amf_timer_cfg(AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL)->
duration);
amf_sbi_send_nf_register(nf_instance);
break;
default:
ogs_error("Unknown timer[%s:%d]",
amf_timer_get_name(e->timer_id), e->timer_id);
}
break;
default:
ogs_error("Unknown event %s", amf_event_get_name(e));
break;
}
}
void amf_nf_state_registered(ogs_fsm_t *s, amf_event_t *e)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_client_t *client = NULL;
ogs_sbi_message_t *message = NULL;
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
if (NF_INSTANCE_IS_SELF(nf_instance->id)) {
ogs_info("NF registered [%s]", nf_instance->id);
client = nf_instance->client;
ogs_assert(client);
if (nf_instance->time.heartbeat) {
ogs_timer_start(nf_instance->t_heartbeat_interval,
ogs_time_from_sec(nf_instance->time.heartbeat));
ogs_timer_start(nf_instance->t_heartbeat,
ogs_time_from_sec(nf_instance->time.heartbeat *
OGS_SBI_HEARTBEAT_RETRYCOUNT));
}
amf_sbi_send_nf_status_subscribe(client,
amf_self()->nf_type, nf_instance->id);
}
break;
case OGS_FSM_EXIT_SIG:
if (NF_INSTANCE_IS_SELF(nf_instance->id)) {
ogs_info("NF de-registered [%s]", nf_instance->id);
if (nf_instance->time.heartbeat) {
ogs_timer_stop(nf_instance->t_heartbeat_interval);
ogs_timer_stop(nf_instance->t_heartbeat);
}
amf_sbi_send_nf_de_register(nf_instance);
}
break;
case AMF_EVT_SBI_CLIENT:
message = e->sbi.message;
ogs_assert(message);
SWITCH(message->h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NRF_NFM)
SWITCH(message->h.resource.name)
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
if (message->res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT ||
message->res_status == OGS_SBI_HTTP_STATUS_OK) {
if (nf_instance->time.heartbeat)
ogs_timer_start(nf_instance->t_heartbeat,
ogs_time_from_sec(nf_instance->time.heartbeat *
OGS_SBI_HEARTBEAT_RETRYCOUNT));
} else {
ogs_error("HTTP response error : %d", message->res_status);
}
break;
DEFAULT
ogs_error("Invalid resource name [%s]",
message->h.resource.name);
END
break;
DEFAULT
ogs_error("Invalid API name [%s]", message->h.service.name);
END
break;
case AMF_EVT_SBI_TIMER:
switch(e->timer_id) {
case AMF_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL:
if (nf_instance->time.heartbeat) {
ogs_timer_start(nf_instance->t_heartbeat_interval,
ogs_time_from_sec(nf_instance->time.heartbeat));
}
amf_sbi_send_nf_update(nf_instance);
break;
case AMF_TIMER_NF_INSTANCE_HEARTBEAT:
OGS_FSM_TRAN(s, &amf_nf_state_will_register);
break;
case AMF_TIMER_NF_INSTANCE_VALIDITY:
if (NF_INSTANCE_IS_OTHERS(nf_instance->id)) {
ogs_info("NF expired [%s]", nf_instance->id);
OGS_FSM_TRAN(s, &amf_nf_state_de_registered);
}
break;
default:
ogs_error("Unknown timer[%s:%d]",
amf_timer_get_name(e->timer_id), e->timer_id);
break;
}
break;
default:
ogs_error("Unknown event %s", amf_event_get_name(e));
break;
}
}
void amf_nf_state_de_registered(ogs_fsm_t *s, amf_event_t *e)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
if (NF_INSTANCE_IS_SELF(nf_instance->id)) {
ogs_info("NF de-registered [%s]", nf_instance->id);
}
break;
case OGS_FSM_EXIT_SIG:
break;
default:
ogs_error("Unknown event %s", amf_event_get_name(e));
break;
}
}
void amf_nf_state_exception(ogs_fsm_t *s, amf_event_t *e)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_client_t *client = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
nf_instance = e->sbi.data;
ogs_assert(nf_instance);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
if (NF_INSTANCE_IS_SELF(nf_instance->id)) {
ogs_timer_start(nf_instance->t_registration_interval,
amf_timer_cfg(AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL)->
duration);
}
break;
case OGS_FSM_EXIT_SIG:
if (NF_INSTANCE_IS_SELF(nf_instance->id)) {
ogs_timer_stop(nf_instance->t_registration_interval);
}
break;
case AMF_EVT_SBI_TIMER:
switch(e->timer_id) {
case AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL:
client = nf_instance->client;
ogs_assert(client);
addr = client->addr;
ogs_assert(addr);
ogs_warn("Retry to registration with NRF [%s]", nf_instance->id);
OGS_FSM_TRAN(s, &amf_nf_state_will_register);
break;
default:
ogs_error("Unknown timer[%s:%d]",
amf_timer_get_name(e->timer_id), e->timer_id);
break;
}
break;
default:
ogs_error("Unknown event %s", amf_event_get_name(e));
break;
}
}

2606
src/amf/ngap-build.c Normal file

File diff suppressed because it is too large Load Diff

109
src/amf/ngap-build.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef NGAP_BUILD_H
#define NGAP_BUILD_H
#include "context.h"
#ifdef __cplusplus
extern "C" {
#endif
ogs_pkbuf_t *ngap_build_setup_rsp(void);
ogs_pkbuf_t *ngap_build_setup_failure(
NGAP_Cause_PR group, long cause, long time_to_wait);
#if 0
ogs_pkbuf_t *ngap_build_downlink_nas_transport(
gnb_ue_t *gnb_ue, ogs_pkbuf_t *emmbuf);
ogs_pkbuf_t *ngap_build_initial_context_setup_request(
amf_ue_t *amf_ue, ogs_pkbuf_t *emmbuf);
ogs_pkbuf_t *ngap_build_ue_context_modification_request(amf_ue_t *amf_ue);
ogs_pkbuf_t *ngap_build_ue_context_release_command(
gnb_ue_t *gnb_ue, NGAP_Cause_PR group, long cause);
ogs_pkbuf_t *ngap_build_e_rab_setup_request(
amf_bearer_t *bearer, ogs_pkbuf_t *esmbuf);
ogs_pkbuf_t *ngap_build_e_rab_modify_request(
amf_bearer_t *bearer, ogs_pkbuf_t *esmbuf);
ogs_pkbuf_t *ngap_build_e_rab_release_command(
amf_bearer_t *bearer, ogs_pkbuf_t *esmbuf, NGAP_Cause_PR group, long cause);
ogs_pkbuf_t *ngap_build_paging(
amf_ue_t *amf_ue, NGAP_CNDomain_t cn_domain);
ogs_pkbuf_t *ngap_build_amf_configuration_transfer(
NGAP_SONConfigurationTransfer_t *son_configuration_transfer);
ogs_pkbuf_t *ngap_build_path_switch_ack(amf_ue_t *amf_ue);
ogs_pkbuf_t *ngap_build_path_switch_failure(
uint32_t gnb_ue_ngap_id, uint32_t amf_ue_ngap_id,
NGAP_Cause_PR group, long cause);
ogs_pkbuf_t *ngap_build_handover_command(gnb_ue_t *source_ue);
ogs_pkbuf_t *ngap_build_handover_preparation_failure(
gnb_ue_t *source_ue, NGAP_Cause_t *cause);
ogs_pkbuf_t *ngap_build_handover_request(
amf_ue_t *amf_ue, gnb_ue_t *target_ue,
NGAP_ENB_UE_NGAP_ID_t *gnb_ue_ngap_id,
NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id,
NGAP_HandoverType_t *handovertype,
NGAP_Cause_t *cause,
NGAP_Source_ToTarget_TransparentContainer_t
*source_totarget_transparentContainer);
ogs_pkbuf_t *ngap_build_handover_cancel_ack(
gnb_ue_t *source_ue);
ogs_pkbuf_t *ngap_build_amf_status_transfer(
gnb_ue_t *target_ue,
NGAP_ENB_StatusTransfer_TransparentContainer_t
*gnb_statustransfer_transparentContainer);
ogs_pkbuf_t *ngap_build_error_indication(
NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id,
NGAP_ENB_UE_NGAP_ID_t *gnb_ue_ngap_id,
NGAP_Cause_PR group, long cause);
ogs_pkbuf_t *ngap_build_s1_reset(
NGAP_Cause_PR group, long cause,
NGAP_UE_associatedLogicalS1_ConnectionListRes_t *partOfS1_Interface);
ogs_pkbuf_t *ngap_build_s1_reset_partial(
NGAP_Cause_PR group, long cause,
NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id,
NGAP_ENB_UE_NGAP_ID_t *gnb_ue_ngap_id);
ogs_pkbuf_t *ngap_build_s1_reset_ack(
NGAP_UE_associatedLogicalS1_ConnectionListRes_t *partOfS1_Interface);
ogs_pkbuf_t *ngap_build_write_replace_warning_request(
sbc_pws_data_t *sbc_pws);
ogs_pkbuf_t *ngap_build_kill_request(sbc_pws_data_t *sbc_pws);
#endif
#ifdef __cplusplus
}
#endif
#endif /* NGAP_BUILD_H */

2063
src/amf/ngap-handler.c Normal file

File diff suppressed because it is too large Load Diff

88
src/amf/ngap-handler.h Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef NGAP_HANDLER_H
#define NGAP_HANDLER_H
#include "context.h"
#ifdef __cplusplus
extern "C" {
#endif
void ngap_handle_ng_setup_request(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
#if 0
void ngap_handle_initial_ue_message(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_uplink_nas_transport(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_ue_capability_info_indication(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_initial_context_setup_response(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_initial_context_setup_failure(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_ue_context_modification_response(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_ue_context_modification_failure(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_ue_context_release_request(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_ue_context_release_complete(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_e_rab_setup_response(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_path_switch_request(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_handover_required(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_handover_request_ack(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_handover_failure(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_handover_cancel(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_gnb_status_transfer(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_gnb_configuration_transfer(
amf_gnb_t *gnb, ogs_ngap_message_t *message, ogs_pkbuf_t *pkbuf);
void ngap_handle_handover_notification(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_s1_reset(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_write_replace_warning_response(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
void ngap_handle_kill_response(
amf_gnb_t *gnb, ogs_ngap_message_t *message);
#endif
#ifdef __cplusplus
}
#endif
#endif /* NGAP_HANDLER_H */

546
src/amf/ngap-path.c Normal file
View File

@ -0,0 +1,546 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-sctp.h"
#include "context.h"
#include "ngap-build.h"
#include "ngap-path.h"
int ngap_open(void)
{
ogs_socknode_t *node = NULL;
ogs_list_for_each(&amf_self()->ngap_list, node)
ngap_server(node);
ogs_list_for_each(&amf_self()->ngap_list6, node)
ngap_server(node);
return OGS_OK;
}
void ngap_close()
{
ogs_socknode_remove_all(&amf_self()->ngap_list);
ogs_socknode_remove_all(&amf_self()->ngap_list6);
}
int ngap_send(ogs_sock_t *sock, ogs_pkbuf_t *pkbuf,
ogs_sockaddr_t *addr, uint16_t stream_no)
{
int sent;
ogs_assert(sock);
ogs_assert(pkbuf);
sent = ogs_sctp_sendmsg(sock, pkbuf->data, pkbuf->len,
addr, OGS_SCTP_NGAP_PPID, stream_no);
if (sent < 0 || sent != pkbuf->len) {
ogs_error("ogs_sctp_sendmsg error (%d:%s)", errno, strerror(errno));
return OGS_ERROR;
}
ogs_pkbuf_free(pkbuf);
return OGS_OK;
}
int ngap_send_to_gnb(amf_gnb_t *gnb, ogs_pkbuf_t *pkbuf, uint16_t stream_no)
{
char buf[OGS_ADDRSTRLEN];
int rv;
ogs_assert(gnb);
ogs_assert(pkbuf);
ogs_assert(gnb->sock);
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(gnb->addr, buf), gnb->gnb_id);
rv = ngap_send(gnb->sock, pkbuf,
gnb->sock_type == SOCK_STREAM ? NULL : gnb->addr,
stream_no);
if (rv != OGS_OK) {
ogs_error("ngap_send() failed");
ogs_pkbuf_free(pkbuf);
ngap_event_push(AMF_EVT_NGAP_LO_CONNREFUSED,
gnb->sock, gnb->addr, NULL, 0, 0);
}
return rv;
}
#if 0
int ngap_send_to_gnb_ue(gnb_ue_t *gnb_ue, ogs_pkbuf_t *pkbuf)
{
amf_gnb_t *gnb = NULL;
ogs_assert(gnb_ue);
gnb = gnb_ue->gnb;
ogs_assert(gnb);
return ngap_send_to_gnb(gnb, pkbuf, gnb_ue->gnb_ostream_id);
}
int ngap_delayed_send_to_gnb_ue(
gnb_ue_t *gnb_ue, ogs_pkbuf_t *pkbuf, ogs_time_t duration)
{
ogs_assert(gnb_ue);
ogs_assert(pkbuf);
if (duration) {
amf_event_t *e = NULL;
e = amf_event_new(AMF_EVT_NGAP_TIMER);
ogs_assert(e);
e->timer = ogs_timer_add(
amf_self()->timer_mgr, amf_timer_ng_delayed_send, e);
ogs_assert(e->timer);
e->pkbuf = pkbuf;
e->gnb_ue = gnb_ue;
e->gnb = gnb_ue->gnb;
ogs_timer_start(e->timer, duration);
return OGS_OK;
} else {
amf_gnb_t *gnb = NULL;
gnb = gnb_ue->gnb;
ogs_assert(gnb);
return ngap_send_to_gnb_ue(gnb_ue, pkbuf);
}
}
int ngap_send_to_esm(amf_ue_t *amf_ue, ogs_pkbuf_t *esmbuf)
{
int rv;
amf_event_t *e = NULL;
ogs_assert(amf_ue);
ogs_assert(esmbuf);
e = amf_event_new(AMF_EVT_ESM_MESSAGE);
ogs_assert(e);
e->amf_ue = amf_ue;
e->pkbuf = esmbuf;
rv = ogs_queue_push(amf_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
ogs_pkbuf_free(e->pkbuf);
amf_event_free(e);
}
return rv;
}
int ngap_send_to_nas(gnb_ue_t *gnb_ue,
NGAP_ProcedureCode_t procedureCode, NGAP_NAS_PDU_t *nasPdu)
{
ogs_nas_eps_security_header_t *sh = NULL;
ogs_nas_security_header_type_t security_header_type;
ogs_nas_emm_header_t *h = NULL;
ogs_pkbuf_t *nasbuf = NULL;
amf_event_t *e = NULL;
ogs_assert(gnb_ue);
ogs_assert(nasPdu);
/* The Packet Buffer(pkbuf_t) for NAS message MUST make a HEADROOM.
* When calculating AES_CMAC, we need to use the headroom of the packet. */
nasbuf = ogs_pkbuf_alloc(NULL, OGS_NAS_HEADROOM+nasPdu->size);
ogs_pkbuf_reserve(nasbuf, OGS_NAS_HEADROOM);
ogs_pkbuf_put_data(nasbuf, nasPdu->buf, nasPdu->size);
sh = (ogs_nas_eps_security_header_t *)nasbuf->data;
ogs_assert(sh);
memset(&security_header_type, 0, sizeof(ogs_nas_security_header_type_t));
switch(sh->security_header_type) {
case OGS_NAS_SECURITY_HEADER_PLAIN_NAS_MESSAGE:
break;
case OGS_NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE:
security_header_type.service_request = 1;
break;
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED:
security_header_type.integrity_protected = 1;
ogs_pkbuf_pull(nasbuf, 6);
break;
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED:
security_header_type.integrity_protected = 1;
security_header_type.ciphered = 1;
ogs_pkbuf_pull(nasbuf, 6);
break;
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_NEW_SECURITY_CONTEXT:
security_header_type.integrity_protected = 1;
security_header_type.new_security_context = 1;
ogs_pkbuf_pull(nasbuf, 6);
break;
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHTERD_WITH_NEW_INTEGRITY_CONTEXT:
security_header_type.integrity_protected = 1;
security_header_type.ciphered = 1;
security_header_type.new_security_context = 1;
ogs_pkbuf_pull(nasbuf, 6);
break;
default:
ogs_error("Not implemented(security header type:0x%x)",
sh->security_header_type);
return OGS_ERROR;
}
if (gnb_ue->amf_ue) {
if (nas_eps_security_decode(gnb_ue->amf_ue,
security_header_type, nasbuf) != OGS_OK) {
ogs_error("nas_eps_security_decode failed()");
return OGS_ERROR;
}
}
h = (ogs_nas_emm_header_t *)nasbuf->data;
ogs_assert(h);
if (h->protocol_discriminator == OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM) {
int rv;
e = amf_event_new(AMF_EVT_EMM_MESSAGE);
ogs_assert(e);
e->gnb_ue = gnb_ue;
e->ngap_code = procedureCode;
e->nas_type = security_header_type.type;
e->pkbuf = nasbuf;
rv = ogs_queue_push(amf_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
ogs_pkbuf_free(e->pkbuf);
amf_event_free(e);
}
return rv;
} else if (h->protocol_discriminator == OGS_NAS_PROTOCOL_DISCRIMINATOR_ESM) {
amf_ue_t *amf_ue = gnb_ue->amf_ue;
ogs_assert(amf_ue);
return ngap_send_to_esm(amf_ue, nasbuf);
} else {
ogs_error("Unknown/Unimplemented NAS Protocol discriminator 0x%02x",
h->protocol_discriminator);
return OGS_ERROR;
}
}
#endif
void ngap_send_ng_setup_response(amf_gnb_t *gnb)
{
ogs_pkbuf_t *ngap_buffer;
ogs_debug("[AMF] NG-Setup response");
ngap_buffer = ngap_build_setup_rsp();
ogs_expect_or_return(ngap_buffer);
ogs_expect(OGS_OK ==
ngap_send_to_gnb(gnb, ngap_buffer, NGAP_NON_UE_SIGNALLING));
}
void ngap_send_ng_setup_failure(
amf_gnb_t *gnb, NGAP_Cause_PR group, long cause)
{
ogs_pkbuf_t *ngap_buffer;
ogs_debug("[AMF] NG-Setup failure");
ngap_buffer = ngap_build_setup_failure(group, cause, NGAP_TimeToWait_v10s);
ogs_expect_or_return(ngap_buffer);
ogs_expect(OGS_OK ==
ngap_send_to_gnb(gnb, ngap_buffer, NGAP_NON_UE_SIGNALLING));
}
#if 0
void ngap_send_initial_context_setup_request(amf_ue_t *amf_ue)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(amf_ue);
ngapbuf = ngap_build_initial_context_setup_request(amf_ue, NULL);
ogs_expect_or_return(ngapbuf);
rv = nas_eps_send_to_gnb(amf_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_ue_context_modification_request(amf_ue_t *amf_ue)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(amf_ue);
ngapbuf = ngap_build_ue_context_modification_request(amf_ue);
ogs_expect_or_return(ngapbuf);
rv = nas_eps_send_to_gnb(amf_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_ue_context_release_command(
gnb_ue_t *gnb_ue, NGAP_Cause_PR group, long cause,
uint8_t action, uint32_t delay)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(gnb_ue);
ogs_debug("[AMF] UE Context release command");
ogs_debug(" ENB_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%d]",
gnb_ue->gnb_ue_ngap_id, gnb_ue->amf_ue_ngap_id);
if (delay) {
ogs_assert(action != NGAP_UE_CTX_REL_INVALID_ACTION);
gnb_ue->ue_ctx_rel_action = action;
ogs_debug(" Group[%d] Cause[%d] Action[%d] Delay[%d]",
group, (int)cause, action, delay);
ngapbuf = ngap_build_ue_context_release_command(gnb_ue, group, cause);
ogs_expect_or_return(ngapbuf);
rv = ngap_delayed_send_to_gnb_ue(gnb_ue, ngapbuf, delay);
ogs_expect(rv == OGS_OK);
} else {
ogs_assert(action != NGAP_UE_CTX_REL_INVALID_ACTION);
gnb_ue->ue_ctx_rel_action = action;
ogs_debug(" Group[%d] Cause[%d] Action[%d] Delay[%d]",
group, (int)cause, action, delay);
ngapbuf = ngap_build_ue_context_release_command(gnb_ue, group, cause);
ogs_expect_or_return(ngapbuf);
rv = ngap_delayed_send_to_gnb_ue(gnb_ue, ngapbuf, 0);
ogs_expect(rv == OGS_OK);
}
}
void ngap_send_paging(amf_ue_t *amf_ue, NGAP_CNDomain_t cn_domain)
{
ogs_pkbuf_t *ngapbuf = NULL;
amf_gnb_t *gnb = NULL;
int i;
int rv;
/* Find enB with matched TAI */
ogs_list_for_each(&amf_self()->gnb_list, gnb) {
for (i = 0; i < gnb->num_of_supported_ta_list; i++) {
if (memcmp(&gnb->supported_ta_list[i], &amf_ue->tai,
sizeof(ogs_5gs_tai_t)) == 0) {
if (amf_ue->t3413.pkbuf) {
ngapbuf = amf_ue->t3413.pkbuf;
} else {
ngapbuf = ngap_build_paging(amf_ue, cn_domain);
ogs_expect_or_return(ngapbuf);
}
amf_ue->t3413.pkbuf = ogs_pkbuf_copy(ngapbuf);
rv = ngap_send_to_gnb(gnb, ngapbuf, NGAP_NON_UE_SIGNALLING);
ogs_expect(rv == OGS_OK);
}
}
}
/* Start T3413 */
ogs_timer_start(amf_ue->t3413.timer,
amf_timer_cfg(AMF_TIMER_T3413)->duration);
}
void ngap_send_amf_configuration_transfer(
amf_gnb_t *target_gnb,
NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(target_gnb);
ogs_assert(SONConfigurationTransfer);
ngapbuf = ngap_build_amf_configuration_transfer(SONConfigurationTransfer);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb(target_gnb, ngapbuf, NGAP_NON_UE_SIGNALLING);
ogs_expect(rv == OGS_OK);
}
void ngap_send_path_switch_ack(amf_ue_t *amf_ue)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(amf_ue);
ngapbuf = ngap_build_path_switch_ack(amf_ue);
ogs_expect_or_return(ngapbuf);
rv = nas_eps_send_to_gnb(amf_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_handover_command(gnb_ue_t *source_ue)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(source_ue);
ngapbuf = ngap_build_handover_command(source_ue);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb_ue(source_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_handover_preparation_failure(
gnb_ue_t *source_ue, NGAP_Cause_t *cause)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(source_ue);
ogs_assert(cause);
ngapbuf = ngap_build_handover_preparation_failure(source_ue, cause);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb_ue(source_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_handover_cancel_ack(gnb_ue_t *source_ue)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(source_ue);
ngapbuf = ngap_build_handover_cancel_ack(source_ue);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb_ue(source_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_handover_request(
amf_ue_t *amf_ue,
amf_gnb_t *target_gnb,
NGAP_ENB_UE_NGAP_ID_t *gnb_ue_ngap_id,
NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id,
NGAP_HandoverType_t *handovertype,
NGAP_Cause_t *cause,
NGAP_Source_ToTarget_TransparentContainer_t
*source_totarget_transparentContainer)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
gnb_ue_t *source_ue = NULL, *target_ue = NULL;
ogs_debug("[AMF] Handover request");
ogs_assert(target_gnb);
ogs_assert(amf_ue);
source_ue = amf_ue->gnb_ue;
ogs_assert(source_ue);
ogs_assert(source_ue->target_ue == NULL);
target_ue = gnb_ue_add(target_gnb, INVALID_UE_NGAP_ID);
ogs_assert(target_ue);
ogs_debug(" Source : ENB_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%d]",
source_ue->gnb_ue_ngap_id, source_ue->amf_ue_ngap_id);
ogs_debug(" Target : ENB_UE_NGAP_ID[Unknown] AMF_UE_NGAP_ID[%d]",
target_ue->amf_ue_ngap_id);
source_ue_associate_target_ue(source_ue, target_ue);
ngapbuf = ngap_build_handover_request(amf_ue, target_ue,
gnb_ue_ngap_id, amf_ue_ngap_id,
handovertype, cause,
source_totarget_transparentContainer);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb_ue(target_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_amf_status_transfer(
gnb_ue_t *target_ue,
NGAP_ENB_StatusTransfer_TransparentContainer_t
*gnb_statustransfer_transparentContainer)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(target_ue);
ngapbuf = ngap_build_amf_status_transfer(target_ue,
gnb_statustransfer_transparentContainer);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb_ue(target_ue, ngapbuf);
ogs_expect(rv == OGS_OK);
}
void ngap_send_error_indication(
amf_gnb_t *gnb,
NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id,
NGAP_ENB_UE_NGAP_ID_t *gnb_ue_ngap_id,
NGAP_Cause_PR group, long cause)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(gnb);
ngapbuf = ngap_build_error_indication(
amf_ue_ngap_id, gnb_ue_ngap_id, group, cause);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb(gnb, ngapbuf, NGAP_NON_UE_SIGNALLING);
ogs_expect(rv == OGS_OK);
}
void ngap_send_ng_reset_ack(
amf_gnb_t *gnb,
NGAP_UE_associatedLogicalNG_ConnectionListRes_t *partOfNG_Interface)
{
int rv;
ogs_pkbuf_t *ngapbuf = NULL;
ogs_assert(gnb);
ngapbuf = ngap_build_ng_reset_ack(partOfNG_Interface);
ogs_expect_or_return(ngapbuf);
rv = ngap_send_to_gnb(gnb, ngapbuf, NGAP_NON_UE_SIGNALLING);
ogs_expect(rv == OGS_OK);
}
#endif

105
src/amf/ngap-path.h Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef NGAP_PATH_H
#define NGAP_PATH_H
#include "context.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NGAP_NON_UE_SIGNALLING 0
#define ngap_event_push amf_sctp_event_push
int ngap_open(void);
void ngap_close(void);
ogs_sock_t *ngap_server(ogs_socknode_t *node);
void ngap_recv_upcall(short when, ogs_socket_t fd, void *data);
int ngap_send(ogs_sock_t *sock,
ogs_pkbuf_t *pkbuf, ogs_sockaddr_t *addr, uint16_t stream_no);
int ngap_send_to_gnb(
amf_gnb_t *gnb, ogs_pkbuf_t *pkb, uint16_t stream_no);
#if 0
int ngap_send_to_gnb_ue(gnb_ue_t *gnb_ue, ogs_pkbuf_t *pkbuf);
int ngap_delayed_send_to_gnb_ue(gnb_ue_t *gnb_ue,
ogs_pkbuf_t *pkbuf, ogs_time_t duration);
int ngap_send_to_nas(gnb_ue_t *gnb_ue,
NGAP_ProcedureCode_t procedureCode, NGAP_NAS_PDU_t *nasPdu);
int ngap_send_to_esm(amf_ue_t *amf_ue, ogs_pkbuf_t *esmbuf);
#endif
void ngap_send_ng_setup_response(amf_gnb_t *gnb);
void ngap_send_ng_setup_failure(
amf_gnb_t *gnb, NGAP_Cause_PR group, long cause);
#if 0
void ngap_send_initial_context_setup_request(amf_ue_t *amf_ue);
void ngap_send_ue_context_modification_request(amf_ue_t *amf_ue);
void ngap_send_ue_context_release_command(
gnb_ue_t *gnb_ue, NGAP_Cause_PR group, long cause,
uint8_t action, uint32_t delay);
void ngap_send_paging(amf_ue_t *amf_ue, NGAP_CNDomain_t cn_domain);
void ngap_send_amf_configuration_transfer(
amf_gnb_t *target_gnb,
NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer);
void ngap_send_path_switch_ack(amf_ue_t *amf_ue);
void ngap_send_handover_command(gnb_ue_t *source_ue);
void ngap_send_handover_preparation_failure(
gnb_ue_t *source_ue, NGAP_Cause_t *cause);
void ngap_send_handover_request(
amf_ue_t *amf_ue,
amf_gnb_t *target_gnb,
NGAP_ENB_UE_NGAP_ID_t *gnb_ue_ngap_id,
NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id,
NGAP_HandoverType_t *handovertype,
NGAP_Cause_t *cause,
NGAP_Source_ToTarget_TransparentContainer_t
*source_totarget_transparentContainer);
void ngap_send_handover_cancel_ack(gnb_ue_t *source_ue);
void ngap_send_amf_status_transfer(
gnb_ue_t *target_ue,
NGAP_ENB_StatusTransfer_TransparentContainer_t
*gnb_statustransfer_transparentContainer);
void ngap_send_error_indication(
amf_gnb_t *gnb,
NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id,
NGAP_ENB_UE_NGAP_ID_t *gnb_ue_ngap_id,
NGAP_Cause_PR group, long cause);
void ngap_send_ng_reset_ack(
amf_gnb_t *gnb,
NGAP_UE_associatedLogicalNG_ConnectionListRes_t *partOfNG_Interface);
#endif
#ifdef __cplusplus
}
#endif
#endif /* NGAP_PATH_H */

238
src/amf/ngap-sctp.c Normal file
View File

@ -0,0 +1,238 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-sctp.h"
#include "ngap-path.h"
#if HAVE_USRSCTP
static void usrsctp_recv_handler(struct socket *socket, void *data, int flags);
#else
static void lksctp_accept_handler(short when, ogs_socket_t fd, void *data);
#endif
void ngap_accept_handler(ogs_sock_t *sock);
void ngap_recv_handler(ogs_sock_t *sock);
ogs_sock_t *ngap_server(ogs_socknode_t *node)
{
char buf[OGS_ADDRSTRLEN];
ogs_sock_t *sock = NULL;
ogs_assert(node);
ogs_socknode_sctp_option(node, &ogs_config()->sockopt);
ogs_socknode_nodelay(node, true);
#if HAVE_USRSCTP
sock = ogs_sctp_server(SOCK_SEQPACKET, node);
ogs_assert(sock);
usrsctp_set_non_blocking((struct socket *)sock, 1);
usrsctp_set_upcall((struct socket *)sock, usrsctp_recv_handler, NULL);
#else
sock = ogs_sctp_server(SOCK_STREAM, node);
ogs_assert(sock);
node->poll = ogs_pollset_add(amf_self()->pollset,
OGS_POLLIN, sock->fd, lksctp_accept_handler, sock);
#endif
ogs_info("ngap_server() [%s]:%d",
OGS_ADDR(node->addr, buf), OGS_PORT(node->addr));
return sock;
}
void ngap_recv_upcall(short when, ogs_socket_t fd, void *data)
{
ogs_sock_t *sock = NULL;
ogs_assert(fd != INVALID_SOCKET);
sock = data;
ogs_assert(sock);
ngap_recv_handler(sock);
}
#if HAVE_USRSCTP
static void usrsctp_recv_handler(struct socket *socket, void *data, int flags)
{
int events;
while ((events = usrsctp_get_events(socket)) &&
(events & SCTP_EVENT_READ)) {
ngap_recv_handler((ogs_sock_t *)socket);
}
}
#else
static void lksctp_accept_handler(short when, ogs_socket_t fd, void *data)
{
ogs_assert(data);
ogs_assert(fd != INVALID_SOCKET);
ngap_accept_handler(data);
}
#endif
void ngap_accept_handler(ogs_sock_t *sock)
{
char buf[OGS_ADDRSTRLEN];
ogs_sock_t *new = NULL;
ogs_assert(sock);
new = ogs_sock_accept(sock);
if (new) {
ogs_sockaddr_t *addr = NULL;
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(addr);
memcpy(addr, &new->remote_addr, sizeof(ogs_sockaddr_t));
ogs_info("eNB-S1 accepted[%s]:%d in s1_path module",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ngap_event_push(AMF_EVT_NGAP_LO_ACCEPT,
new, addr, NULL, 0, 0);
} else {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, "accept() failed");
}
}
void ngap_recv_handler(ogs_sock_t *sock)
{
ogs_pkbuf_t *pkbuf;
int size;
ogs_sockaddr_t *addr = NULL;
ogs_sockaddr_t from;
ogs_sctp_info_t sinfo;
int flags = 0;
ogs_assert(sock);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN);
size = ogs_sctp_recvmsg(
sock, pkbuf->data, pkbuf->len, &from, &sinfo, &flags);
if (size < 0) {
ogs_error("ogs_sctp_recvmsg(%d) failed(%d:%s)",
size, errno, strerror(errno));
ogs_pkbuf_free(pkbuf);
return;
}
if (flags & MSG_NOTIFICATION) {
union sctp_notification *not =
(union sctp_notification *)pkbuf->data;
switch(not->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE :
ogs_debug("SCTP_ASSOC_CHANGE:"
"[T:%d, F:0x%x, S:%d, I/O:%d/%d]",
not->sn_assoc_change.sac_type,
not->sn_assoc_change.sac_flags,
not->sn_assoc_change.sac_state,
not->sn_assoc_change.sac_inbound_streams,
not->sn_assoc_change.sac_outbound_streams);
if (not->sn_assoc_change.sac_state == SCTP_COMM_UP) {
ogs_debug("SCTP_COMM_UP");
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(addr);
memcpy(addr, &from, sizeof(ogs_sockaddr_t));
ngap_event_push(AMF_EVT_NGAP_LO_SCTP_COMM_UP,
sock, addr, NULL,
not->sn_assoc_change.sac_inbound_streams,
not->sn_assoc_change.sac_outbound_streams);
} else if (not->sn_assoc_change.sac_state == SCTP_SHUTDOWN_COMP ||
not->sn_assoc_change.sac_state == SCTP_COMM_LOST) {
if (not->sn_assoc_change.sac_state == SCTP_SHUTDOWN_COMP)
ogs_debug("SCTP_SHUTDOWN_COMP");
if (not->sn_assoc_change.sac_state == SCTP_COMM_LOST)
ogs_debug("SCTP_COMM_LOST");
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(addr);
memcpy(addr, &from, sizeof(ogs_sockaddr_t));
ngap_event_push(AMF_EVT_NGAP_LO_CONNREFUSED,
sock, addr, NULL, 0, 0);
}
break;
case SCTP_SHUTDOWN_EVENT :
case SCTP_SEND_FAILED :
if (not->sn_header.sn_type == SCTP_SHUTDOWN_EVENT)
ogs_debug("SCTP_SHUTDOWN_EVENT:[T:%d, F:0x%x, L:%d]",
not->sn_shutdown_event.sse_type,
not->sn_shutdown_event.sse_flags,
not->sn_shutdown_event.sse_length);
if (not->sn_header.sn_type == SCTP_SEND_FAILED)
#if HAVE_USRSCTP
ogs_error("SCTP_SEND_FAILED:[T:%d, F:0x%x, S:%d]",
not->sn_send_failed_event.ssfe_type,
not->sn_send_failed_event.ssfe_flags,
not->sn_send_failed_event.ssfe_error);
#else
ogs_error("SCTP_SEND_FAILED:[T:%d, F:0x%x, S:%d]",
not->sn_send_failed.ssf_type,
not->sn_send_failed.ssf_flags,
not->sn_send_failed.ssf_error);
#endif
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(addr);
memcpy(addr, &from, sizeof(ogs_sockaddr_t));
ngap_event_push(AMF_EVT_NGAP_LO_CONNREFUSED,
sock, addr, NULL, 0, 0);
break;
case SCTP_PEER_ADDR_CHANGE:
ogs_warn("SCTP_PEER_ADDR_CHANGE:[T:%d, F:0x%x, S:%d]",
not->sn_paddr_change.spc_type,
not->sn_paddr_change.spc_flags,
not->sn_paddr_change.spc_error);
break;
case SCTP_REMOTE_ERROR:
ogs_warn("SCTP_REMOTE_ERROR:[T:%d, F:0x%x, S:%d]",
not->sn_remote_error.sre_type,
not->sn_remote_error.sre_flags,
not->sn_remote_error.sre_error);
break;
default :
ogs_error("Discarding event with unknown flags:0x%x type:0x%x",
flags, not->sn_header.sn_type);
break;
}
} else if (flags & MSG_EOR) {
ogs_pkbuf_trim(pkbuf, size);
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(addr);
memcpy(addr, &from, sizeof(ogs_sockaddr_t));
ngap_event_push(AMF_EVT_NGAP_MESSAGE, sock, addr, pkbuf, 0, 0);
return;
} else {
ogs_assert_if_reached();
}
ogs_pkbuf_free(pkbuf);
}

229
src/amf/ngap-sm.c Normal file
View File

@ -0,0 +1,229 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ngap-build.h"
#include "ngap-handler.h"
#include "ngap-path.h"
void ngap_state_initial(ogs_fsm_t *s, amf_event_t *e)
{
ogs_assert(s);
amf_sm_debug(e);
OGS_FSM_TRAN(s, &ngap_state_operational);
}
void ngap_state_final(ogs_fsm_t *s, amf_event_t *e)
{
ogs_assert(s);
amf_sm_debug(e);
}
void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e)
{
amf_gnb_t *gnb = NULL;
#if 0
ogs_pkbuf_t *pkbuf = NULL;
#endif
NGAP_NGAP_PDU_t *pdu = NULL;
NGAP_InitiatingMessage_t *initiatingMessage = NULL;
NGAP_SuccessfulOutcome_t *successfulOutcome = NULL;
NGAP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL;
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
gnb = e->gnb;
ogs_assert(gnb);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
break;
case OGS_FSM_EXIT_SIG:
break;
case AMF_EVT_NGAP_MESSAGE:
pdu = e->ngap.message;
ogs_assert(pdu);
switch (pdu->present) {
case NGAP_NGAP_PDU_PR_initiatingMessage :
initiatingMessage = pdu->choice.initiatingMessage;
ogs_assert(initiatingMessage);
switch (initiatingMessage->procedureCode) {
case NGAP_ProcedureCode_id_NGSetup :
ngap_handle_ng_setup_request(gnb, pdu);
break;
#if 0
case NGAP_ProcedureCode_id_initialUEMessage :
ngap_handle_initial_ue_message(gnb, pdu);
break;
case NGAP_ProcedureCode_id_uplinkNASTransport :
ngap_handle_uplink_nas_transport(gnb, pdu);
break;
case NGAP_ProcedureCode_id_UECapabilityInfoIndication :
ngap_handle_ue_capability_info_indication( gnb, pdu);
break;
case NGAP_ProcedureCode_id_UEContextReleaseRequest:
ngap_handle_ue_context_release_request( gnb, pdu);
break;
case NGAP_ProcedureCode_id_PathSwitchRequest:
ngap_handle_path_switch_request(gnb, pdu);
break;
case NGAP_ProcedureCode_id_eNBConfigurationTransfer:
pkbuf = e->pkbuf;
ogs_assert(pkbuf);
ngap_handle_gnb_configuration_transfer(gnb, pdu, pkbuf);
break;
case NGAP_ProcedureCode_id_HandoverPreparation:
ngap_handle_handover_required(gnb, pdu);
break;
case NGAP_ProcedureCode_id_HandoverCancel:
ngap_handle_handover_cancel(gnb, pdu);
break;
case NGAP_ProcedureCode_id_eNBStatusTransfer:
ngap_handle_gnb_status_transfer(gnb, pdu);
break;
case NGAP_ProcedureCode_id_HandoverNotification:
ngap_handle_handover_notification(gnb, pdu);
break;
case NGAP_ProcedureCode_id_Reset:
ngap_handle_s1_reset(gnb, pdu);
break;
#endif
default:
ogs_warn("Not implemented(choice:%d, proc:%d)",
pdu->present, (int)initiatingMessage->procedureCode);
break;
}
break;
case NGAP_NGAP_PDU_PR_successfulOutcome :
successfulOutcome = pdu->choice.successfulOutcome;
ogs_assert(successfulOutcome);
switch (successfulOutcome->procedureCode) {
#if 0
case NGAP_ProcedureCode_id_InitialContextSetup:
ngap_handle_initial_context_setup_response(gnb, pdu);
break;
case NGAP_ProcedureCode_id_UEContextModification:
ngap_handle_ue_context_modification_response(gnb, pdu);
break;
case NGAP_ProcedureCode_id_UEContextRelease:
ngap_handle_ue_context_release_complete(
gnb, pdu);
break;
case NGAP_ProcedureCode_id_E_RABSetup:
ngap_handle_e_rab_setup_response(gnb, pdu);
break;
case NGAP_ProcedureCode_id_E_RABModify:
break;
case NGAP_ProcedureCode_id_E_RABRelease:
break;
case NGAP_ProcedureCode_id_HandoverResourceAllocation:
ngap_handle_handover_request_ack(gnb, pdu);
break;
case NGAP_ProcedureCode_id_WriteReplaceWarning:
ngap_handle_write_replace_warning_response(gnb, pdu);
break;
case NGAP_ProcedureCode_id_Kill:
ngap_handle_kill_response(gnb, pdu);
break;
#endif
default:
ogs_warn("Not implemented(choice:%d, proc:%d)",
pdu->present, (int)successfulOutcome->procedureCode);
break;
}
break;
case NGAP_NGAP_PDU_PR_unsuccessfulOutcome :
unsuccessfulOutcome = pdu->choice.unsuccessfulOutcome;
ogs_assert(unsuccessfulOutcome);
switch (unsuccessfulOutcome->procedureCode) {
#if 0
case NGAP_ProcedureCode_id_InitialContextSetup :
ngap_handle_initial_context_setup_failure(gnb, pdu);
break;
case NGAP_ProcedureCode_id_UEContextModification:
ngap_handle_ue_context_modification_failure(gnb, pdu);
break;
case NGAP_ProcedureCode_id_HandoverResourceAllocation :
ngap_handle_handover_failure(gnb, pdu);
break;
#endif
default:
ogs_warn("Not implemented(choice:%d, proc:%d)",
pdu->present, (int)unsuccessfulOutcome->procedureCode);
break;
}
break;
default:
ogs_warn("Not implemented(choice:%d)", pdu->present);
break;
}
break;
case AMF_EVT_NGAP_TIMER:
switch (e->timer_id) {
#if 0
case AMF_TIMER_S1_DELAYED_SEND:
ogs_assert(e->gnb_ue);
ogs_assert(e->pkbuf);
ogs_expect(OGS_OK == ngap_send_to_gnb_ue(e->gnb_ue, e->pkbuf));
ogs_timer_delete(e->timer);
break;
#endif
default:
ogs_error("Unknown timer[%s:%d]",
amf_timer_get_name(e->timer_id), e->timer_id);
break;
}
break;
default:
ogs_error("Unknown event %s", amf_event_get_name(e));
break;
}
}
void ngap_state_exception(ogs_fsm_t *s, amf_event_t *e)
{
ogs_assert(s);
ogs_assert(e);
amf_sm_debug(e);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
break;
case OGS_FSM_EXIT_SIG:
break;
default:
ogs_error("Unknown event %s", amf_event_get_name(e));
break;
}
}

204
src/amf/nnrf-build.c Normal file
View File

@ -0,0 +1,204 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "nnrf-build.h"
ogs_sbi_request_t *amf_nnrf_build_nf_register(
ogs_sbi_nf_instance_t *nf_instance)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
ogs_sbi_client_t *client = NULL;
OpenAPI_nf_profile_t *NFProfile = NULL;
ogs_assert(nf_instance);
client = nf_instance->client;
ogs_assert(client);
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_PUT;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NRF_NFM;
message.h.api.version = (char *)OGS_SBI_API_VERSION;
message.h.resource.name = (char *)OGS_SBI_RESOURCE_NAME_NF_INSTANCES;
message.h.resource.id = ogs_sbi_self()->nf_instance_id;
message.http.content_encoding = (char*)ogs_sbi_self()->content_encoding;
NFProfile = ogs_sbi_nnrf_build_nf_profile(nf_instance);
ogs_assert(NFProfile);
NFProfile->heart_beat_timer = nf_instance->time.heartbeat;
message.NFProfile = NFProfile;
request = ogs_sbi_build_request(&message);
ogs_assert(request);
ogs_sbi_nnrf_free_nf_profile(NFProfile);
return request;
}
ogs_sbi_request_t *amf_nnrf_build_nf_update(ogs_sbi_nf_instance_t *nf_instance)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
OpenAPI_list_t *PatchItemList;
OpenAPI_patch_item_t item;
ogs_assert(nf_instance);
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_PATCH;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NRF_NFM;
message.h.api.version = (char *)OGS_SBI_API_VERSION;
message.h.resource.name = (char *)OGS_SBI_RESOURCE_NAME_NF_INSTANCES;
message.h.resource.id = ogs_sbi_self()->nf_instance_id;
message.http.content_type = (char *)OGS_SBI_CONTENT_PATCH_TYPE;
PatchItemList = OpenAPI_list_create();
ogs_assert(PatchItemList);
memset(&item, 0, sizeof(item));
item.op = OpenAPI_patch_operation_replace;
item.path = (char *)"/nfStatus";
item.value = OpenAPI_nf_status_ToString(OpenAPI_nf_status_REGISTERED);
OpenAPI_list_add(PatchItemList, &item);
message.PatchItemList = PatchItemList;
request = ogs_sbi_build_request(&message);
ogs_assert(request);
OpenAPI_list_free(PatchItemList);
return request;
}
ogs_sbi_request_t *amf_nnrf_build_nf_de_register(
ogs_sbi_nf_instance_t *nf_instance)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
ogs_assert(nf_instance);
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_DELETE;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NRF_NFM;
message.h.api.version = (char *)OGS_SBI_API_VERSION;
message.h.resource.name = (char *)OGS_SBI_RESOURCE_NAME_NF_INSTANCES;
message.h.resource.id = nf_instance->id;
request = ogs_sbi_build_request(&message);
ogs_assert(request);
return request;
}
ogs_sbi_request_t *amf_nnrf_build_nf_status_subscribe(
ogs_sbi_subscription_t *subscription)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
ogs_sbi_server_t *server = NULL;
OpenAPI_subscription_data_t *SubscriptionData = NULL;
ogs_assert(subscription);
ogs_assert(subscription->nf_type);
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NRF_NFM;
message.h.api.version = (char *)OGS_SBI_API_VERSION;
message.h.resource.name = (char *)OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS;
SubscriptionData = ogs_calloc(1, sizeof(*SubscriptionData));
ogs_assert(SubscriptionData);
server = ogs_list_first(&ogs_sbi_self()->server_list);
ogs_assert(server);
SubscriptionData->nf_status_notification_uri = ogs_sbi_server_uri(server,
OGS_SBI_SERVICE_NAME_NRF_NFM, OGS_SBI_API_VERSION,
OGS_SBI_RESOURCE_NAME_NF_STATUS_NOTIFY, NULL);
ogs_assert(SubscriptionData->nf_status_notification_uri);
SubscriptionData->req_nf_type = subscription->nf_type;
SubscriptionData->req_nf_instance_id = subscription->nf_instance_id;
message.SubscriptionData = SubscriptionData;
request = ogs_sbi_build_request(&message);
ogs_assert(request);
ogs_free(SubscriptionData->nf_status_notification_uri);
ogs_free(SubscriptionData);
return request;
}
ogs_sbi_request_t *amf_nnrf_build_nf_status_unsubscribe(
ogs_sbi_subscription_t *subscription)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
ogs_assert(subscription);
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_DELETE;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NRF_NFM;
message.h.api.version = (char *)OGS_SBI_API_VERSION;
message.h.resource.name = (char *)OGS_SBI_RESOURCE_NAME_SUBSCRIPTIONS;
message.h.resource.id = subscription->id;
request = ogs_sbi_build_request(&message);
ogs_assert(request);
return request;
}
ogs_sbi_request_t *amf_nnrf_build_nf_discover(
OpenAPI_nf_type_e target_nf_type, OpenAPI_nf_type_e requester_nf_type)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
ogs_assert(target_nf_type);
ogs_assert(requester_nf_type);
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_GET;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NRF_DISC;
message.h.api.version = (char *)OGS_SBI_API_VERSION;
message.h.resource.name = (char *)OGS_SBI_RESOURCE_NAME_NF_INSTANCES;
message.param.target_nf_type = target_nf_type;
message.param.requester_nf_type = requester_nf_type;
request = ogs_sbi_build_request(&message);
ogs_assert(request);
return request;
}

49
src/amf/nnrf-build.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AMF_NNRF_BUILD_H
#define AMF_NNRF_BUILD_H
#include "ogs-sbi.h"
#include "context.h"
#ifdef __cplusplus
extern "C" {
#endif
ogs_sbi_request_t *amf_nnrf_build_nf_register(
ogs_sbi_nf_instance_t *nf_instance);
ogs_sbi_request_t *amf_nnrf_build_nf_update(
ogs_sbi_nf_instance_t *nf_instance);
ogs_sbi_request_t *amf_nnrf_build_nf_de_register(
ogs_sbi_nf_instance_t *nf_instance);
ogs_sbi_request_t *amf_nnrf_build_nf_status_subscribe(
ogs_sbi_subscription_t *subscription);
ogs_sbi_request_t *amf_nnrf_build_nf_status_unsubscribe(
ogs_sbi_subscription_t *subscription);
ogs_sbi_request_t *amf_nnrf_build_nf_discover(
OpenAPI_nf_type_e target_nf_type, OpenAPI_nf_type_e requester_nf_type);
#ifdef __cplusplus
}
#endif
#endif /* AMF_NNRF_BUILD_H */

278
src/amf/nnrf-handler.c Normal file
View File

@ -0,0 +1,278 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "sbi-path.h"
#include "nnrf-handler.h"
void amf_nnrf_handle_nf_register(
ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_message_t *message)
{
OpenAPI_nf_profile_t *NFProfile = NULL;
ogs_sbi_client_t *client = NULL;
ogs_assert(message);
ogs_assert(nf_instance);
client = nf_instance->client;
ogs_assert(client);
NFProfile = message->NFProfile;
if (!NFProfile) {
ogs_error("No NFProfile");
return;
}
/* TIME : Update heartbeat from NRF */
nf_instance->time.heartbeat = NFProfile->heart_beat_timer;
}
void amf_nnrf_handle_nf_status_subscribe(
ogs_sbi_subscription_t *subscription, ogs_sbi_message_t *message)
{
OpenAPI_subscription_data_t *SubscriptionData = NULL;
ogs_sbi_client_t *client = NULL;
ogs_assert(message);
ogs_assert(subscription);
client = subscription->client;
ogs_assert(client);
SubscriptionData = message->SubscriptionData;
if (!SubscriptionData) {
ogs_error("No SubscriptionData");
return;
}
if (!SubscriptionData->subscription_id) {
ogs_error("No SubscriptionId");
return;
}
ogs_sbi_subscription_set_id(
subscription, SubscriptionData->subscription_id);
if (SubscriptionData->validity_time) {
struct timeval tv;
struct tm local, next;
ogs_time_t diff, duration;
if (ogs_strptime(SubscriptionData->validity_time,
OGS_TIME_ISO8601_FORMAT, &next)) {
ogs_gettimeofday(&tv);
ogs_localtime(tv.tv_sec, &local);
diff = ogs_mktime(&next) - ogs_mktime(&local);
#define VALIDITY_MARGIN 5 /* 5 seconds */
#define VALIDITY_MINIMUM 60 /* 60 seconds */
duration = diff - (int)VALIDITY_MARGIN;
if (duration < (int)VALIDITY_MINIMUM) {
ogs_warn("Validation period [%d seconds, %s] is too small",
(int)diff, SubscriptionData->validity_time);
duration = VALIDITY_MINIMUM;
ogs_warn("Forced to %d seconds", VALIDITY_MINIMUM);
}
subscription->t_validity = ogs_timer_add(amf_self()->timer_mgr,
amf_timer_subscription_validity, subscription);
ogs_assert(subscription->t_validity);
ogs_timer_start(
subscription->t_validity, ogs_time_from_sec(duration));
}
}
}
bool amf_nnrf_handle_nf_status_notify(ogs_sbi_server_t *server,
ogs_sbi_session_t *session, ogs_sbi_message_t *message)
{
ogs_sbi_response_t *response = NULL;
OpenAPI_notification_data_t *NotificationData = NULL;
OpenAPI_nf_profile_t *NFProfile = NULL;
ogs_sbi_nf_instance_t *nf_instance = NULL;
bool handled;
ogs_assert(session);
ogs_assert(message);
NotificationData = message->NotificationData;
if (!NotificationData) {
ogs_error("No NotificationData");
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "No NotificationData", NULL);
return false;
}
NFProfile = NotificationData->nf_profile;
if (!NFProfile) {
ogs_error("No NFProfile");
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "No NFProfile", NULL);
return false;
}
if (!NFProfile->nf_instance_id) {
ogs_error("No NFProfile.NFInstanceId");
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "No NFProfile", "NFInstanceId");
return false;
}
if (!NFProfile->nf_instance_id) {
ogs_error("No NFProfile.NFInstanceId");
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "No NFProfile", "NFInstanceId");
return false;
}
if (NF_INSTANCE_IS_SELF(NFProfile->nf_instance_id)) {
ogs_error("The notification is not allowed [%s]",
NFProfile->nf_instance_id);
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_FORBIDDEN,
message, "The notification is not allowed",
NFProfile->nf_instance_id);
return false;
}
if (NotificationData->event ==
OpenAPI_notification_event_type_NF_REGISTERED) {
ogs_sbi_client_t *client = NULL;
nf_instance = ogs_sbi_nf_instance_find(NFProfile->nf_instance_id);
if (!nf_instance) {
nf_instance = ogs_sbi_nf_instance_add(NFProfile->nf_instance_id);
ogs_assert(nf_instance);
amf_nf_fsm_init(nf_instance);
ogs_info("(NRF-notify) NF registered [%s]", nf_instance->id);
} else
ogs_warn("(NRF-notify) NF [%s] has already been added",
NFProfile->nf_instance_id);
handled = ogs_sbi_nnrf_handle_nf_profile(
nf_instance, NFProfile, session, message);
if (!handled) return false;
ogs_info("(NRF-notify) NF Profile updated [%s]", nf_instance->id);
client = ogs_sbi_nf_instance_find_client(nf_instance);
if (!client) {
ogs_error("Cannot find client [%s]", nf_instance->id);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "Cannot find client", nf_instance->id);
return false;
}
amf_sbi_nf_associate_client(nf_instance, client);
} else if (NotificationData->event ==
OpenAPI_notification_event_type_NF_DEREGISTERED) {
nf_instance = ogs_sbi_nf_instance_find(NFProfile->nf_instance_id);
if (nf_instance) {
ogs_info("(NRF-notify) NF de-registered [%s]", nf_instance->id);
amf_nf_fsm_fini(nf_instance);
ogs_sbi_nf_instance_remove(nf_instance);
/* FIXME : Remove unnecessary Client */
} else {
ogs_warn("(NRF-notify) Not found [%s]", NFProfile->nf_instance_id);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_NOT_FOUND,
message, "Not found", message->h.resource.id);
return false;
}
} else {
char *eventstr = OpenAPI_notification_event_type_ToString(
NotificationData->event);
ogs_error("Not supported event [%d:%s]",
NotificationData->event, eventstr ? eventstr : "Unknown");
ogs_sbi_server_send_error(session, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "Not supported event",
eventstr ? eventstr : "Unknown");
return false;
}
response = ogs_sbi_build_response(message);
ogs_assert(response);
ogs_sbi_server_send_response(session, response,
OGS_SBI_HTTP_STATUS_NO_CONTENT);
return true;
}
void amf_nnrf_handle_nf_discover(ogs_sbi_message_t *message)
{
OpenAPI_search_result_t *SearchResult = NULL;
OpenAPI_lnode_t *node = NULL;
bool handled;
ogs_assert(message);
SearchResult = message->SearchResult;
if (!SearchResult) {
ogs_error("No SearchResult");
return;
}
OpenAPI_list_for_each(SearchResult->nf_instances, node) {
OpenAPI_nf_profile_t *NFProfile = NULL;
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_client_t *client = NULL;
if (!node->data) continue;
NFProfile = node->data;
nf_instance = ogs_sbi_nf_instance_find(NFProfile->nf_instance_id);
if (!nf_instance) {
nf_instance = ogs_sbi_nf_instance_add(NFProfile->nf_instance_id);
ogs_assert(nf_instance);
amf_nf_fsm_init(nf_instance);
ogs_info("(NF-discover) NF registered [%s]", nf_instance->id);
} else
ogs_warn("(NF-discover) NF [%s] has already been added",
NFProfile->nf_instance_id);
if (NF_INSTANCE_IS_OTHERS(nf_instance->id)) {
handled = ogs_sbi_nnrf_handle_nf_profile(
nf_instance, NFProfile, NULL, NULL);
if (!handled) {
ogs_error("ogs_sbi_nnrf_handle_nf_profile() failed [%s]",
nf_instance->id);
continue;
}
client = ogs_sbi_nf_instance_find_client(nf_instance);
if (!client) {
ogs_error("Cannot find client [%s]", nf_instance->id);
continue;
}
amf_sbi_nf_associate_client(nf_instance, client);
/* TIME : Update validity from NRF */
if (SearchResult->validity_period) {
nf_instance->time.validity = SearchResult->validity_period;
ogs_assert(nf_instance->t_validity);
ogs_timer_start(nf_instance->t_validity,
ogs_time_from_sec(nf_instance->time.validity));
} else
ogs_warn("NF Instance validity-time should not 0");
ogs_info("(NF-discover) NF Profile updated [%s]", nf_instance->id);
}
}
}

44
src/amf/nnrf-handler.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AMF_NNRF_HANDLER_H
#define AMF_NNRF_HANDLER_H
#include "ogs-sbi.h"
#include "context.h"
#ifdef __cplusplus
extern "C" {
#endif
void amf_nnrf_handle_nf_register(
ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_message_t *message);
void amf_nnrf_handle_nf_status_subscribe(
ogs_sbi_subscription_t *subscription, ogs_sbi_message_t *message);
bool amf_nnrf_handle_nf_status_notify(ogs_sbi_server_t *server,
ogs_sbi_session_t *session, ogs_sbi_message_t *message);
void amf_nnrf_handle_nf_discover(ogs_sbi_message_t *message);
#ifdef __cplusplus
}
#endif
#endif /* AMF_NNRF_HANDLER_H */

199
src/amf/sbi-path.c Normal file
View File

@ -0,0 +1,199 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "context.h"
#include "sbi-path.h"
static int server_cb(ogs_sbi_server_t *server,
ogs_sbi_session_t *session, ogs_sbi_request_t *request)
{
amf_event_t *e = NULL;
int rv;
ogs_assert(session);
ogs_assert(request);
e = amf_event_new(AMF_EVT_SBI_SERVER);
ogs_assert(e);
e->sbi.server = server;
e->sbi.session = session;
e->sbi.request = request;
rv = ogs_queue_push(amf_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
amf_event_free(e);
return OGS_ERROR;
}
return OGS_OK;
}
static int client_cb(ogs_sbi_response_t *response, void *data)
{
amf_event_t *e = NULL;
int rv;
ogs_assert(response);
e = amf_event_new(AMF_EVT_SBI_CLIENT);
ogs_assert(e);
e->sbi.response = response;
e->sbi.data = data;
rv = ogs_queue_push(amf_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
amf_event_free(e);
return OGS_ERROR;
}
return OGS_OK;
}
int amf_sbi_open(void)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_sbi_client_t *client = NULL;
ogs_sbi_server_start_all(server_cb);
ogs_list_for_each(&ogs_sbi_self()->client_list, client) {
ogs_sbi_nf_service_t *service = NULL;
nf_instance = ogs_sbi_nf_instance_build_default(
amf_self()->nf_type, client);
ogs_assert(nf_instance);
service = ogs_sbi_nf_service_build_default(nf_instance,
(char*)OGS_SBI_SERVICE_NAME_SMF_PDUSESSION, client);
ogs_assert(service);
ogs_sbi_nf_service_add_version(service, (char*)OGS_SBI_API_VERSION,
(char*)OGS_SBI_API_FULL_VERSION, NULL);
amf_sbi_nf_associate_client(nf_instance, client);
amf_nf_fsm_init(nf_instance);
}
return OGS_OK;
}
void amf_sbi_close(void)
{
ogs_sbi_server_stop_all();
}
void amf_sbi_nf_associate_client(
ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_client_t *client)
{
ogs_assert(nf_instance);
ogs_assert(client);
OGS_SETUP_SBI_CLIENT(nf_instance, client);
client->cb = client_cb;
}
void amf_sbi_send_nf_register(ogs_sbi_nf_instance_t *nf_instance)
{
ogs_sbi_request_t *request = NULL;
ogs_sbi_client_t *client = NULL;
ogs_assert(nf_instance);
client = nf_instance->client;
ogs_assert(client);
request = amf_nnrf_build_nf_register(nf_instance);
ogs_assert(request);
ogs_sbi_client_send_request(client, request, nf_instance);
}
void amf_sbi_send_nf_update(ogs_sbi_nf_instance_t *nf_instance)
{
ogs_sbi_request_t *request = NULL;
ogs_sbi_client_t *client = NULL;
ogs_assert(nf_instance);
client = nf_instance->client;
ogs_assert(client);
request = amf_nnrf_build_nf_update(nf_instance);
ogs_assert(request);
ogs_sbi_client_send_request(client, request, nf_instance);
}
void amf_sbi_send_nf_de_register(ogs_sbi_nf_instance_t *nf_instance)
{
ogs_sbi_request_t *request = NULL;
ogs_sbi_client_t *client = NULL;
ogs_assert(nf_instance);
client = nf_instance->client;
ogs_assert(client);
request = amf_nnrf_build_nf_de_register(nf_instance);
ogs_assert(request);
ogs_sbi_client_send_request(client, request, nf_instance);
}
void amf_sbi_send_nf_status_subscribe(ogs_sbi_client_t *client,
OpenAPI_nf_type_e nf_type, char *nf_instance_id)
{
ogs_sbi_request_t *request = NULL;
ogs_sbi_subscription_t *subscription = NULL;
ogs_assert(client);
subscription = ogs_sbi_subscription_add();
ogs_assert(subscription);
subscription->client = client;
subscription->nf_type = nf_type;
if (nf_instance_id)
subscription->nf_instance_id = ogs_strdup(nf_instance_id);
request = amf_nnrf_build_nf_status_subscribe(subscription);
ogs_assert(request);
ogs_sbi_client_send_request(client, request, subscription);
}
void amf_sbi_send_nf_status_unsubscribe(ogs_sbi_subscription_t *subscription)
{
ogs_sbi_request_t *request = NULL;
ogs_sbi_client_t *client = NULL;
ogs_assert(subscription);
client = subscription->client;
ogs_assert(client);
request = amf_nnrf_build_nf_status_unsubscribe(subscription);
ogs_assert(request);
ogs_sbi_client_send_request(client, request, subscription);
}
void amf_sbi_send_nf_discover(ogs_sbi_client_t *client,
OpenAPI_nf_type_e target_nf_type, OpenAPI_nf_type_e requester_nf_type)
{
ogs_sbi_request_t *request = NULL;
ogs_assert(client);
request = amf_nnrf_build_nf_discover(target_nf_type, requester_nf_type);
ogs_assert(request);
ogs_sbi_client_send_request(client, request, NULL);
}

51
src/amf/sbi-path.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AMF_SBI_PATH_H
#define AMF_SBI_PATH_H
#include "nnrf-build.h"
#ifdef __cplusplus
extern "C" {
#endif
int amf_sbi_open(void);
void amf_sbi_close(void);
void amf_sbi_nf_associate_client(
ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_client_t *client);
void amf_sbi_send_nf_register(ogs_sbi_nf_instance_t *nf_instance);
void amf_sbi_send_nf_update(ogs_sbi_nf_instance_t *nf_instance);
void amf_sbi_send_nf_de_register(ogs_sbi_nf_instance_t *nf_instance);
void amf_sbi_send_nf_status_subscribe(ogs_sbi_client_t *client,
OpenAPI_nf_type_e nf_type, char *nf_instance_id);
void amf_sbi_send_nf_status_unsubscribe(ogs_sbi_subscription_t *subscription);
void amf_sbi_send_nf_discover(ogs_sbi_client_t *client,
OpenAPI_nf_type_e target_nf_type, OpenAPI_nf_type_e requester_nf_type);
#ifdef __cplusplus
}
#endif
#endif /* AMF_SBI_PATH_H */

107
src/amf/timer.c Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "context.h"
static amf_timer_cfg_t g_amf_timer_cfg[MAX_NUM_OF_AMF_TIMER] = {
[AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL] =
{ .duration = ogs_time_from_sec(3) },
};
amf_timer_cfg_t *amf_timer_cfg(amf_timer_e id)
{
ogs_assert(id < MAX_NUM_OF_AMF_TIMER);
return &g_amf_timer_cfg[id];
}
const char *amf_timer_get_name(amf_timer_e id)
{
switch (id) {
case AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL:
return "AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL";
case AMF_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL:
return "AMF_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL";
case AMF_TIMER_NF_INSTANCE_HEARTBEAT:
return "AMF_TIMER_NF_INSTANCE_HEARTBEAT";
case AMF_TIMER_NF_INSTANCE_VALIDITY:
return "AMF_TIMER_NF_INSTANCE_VALIDITY";
case AMF_TIMER_SUBSCRIPTION_VALIDITY:
return "AMF_TIMER_SUBSCRIPTION_VALIDITY";
default:
break;
}
return "UNKNOWN_TIMER";
}
static void timer_send_event(int timer_id, void *data)
{
int rv;
amf_event_t *e = NULL;
ogs_assert(data);
switch (timer_id) {
case AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL:
case AMF_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL:
case AMF_TIMER_NF_INSTANCE_HEARTBEAT:
case AMF_TIMER_NF_INSTANCE_VALIDITY:
case AMF_TIMER_SUBSCRIPTION_VALIDITY:
e = amf_event_new(AMF_EVT_SBI_TIMER);
ogs_assert(e);
e->timer_id = timer_id;
e->sbi.data = data;
break;
default:
ogs_fatal("Unknown timer id[%d]", timer_id);
ogs_assert_if_reached();
break;
}
rv = ogs_queue_push(amf_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed [%d] in %s",
(int)rv, amf_timer_get_name(e->timer_id));
amf_event_free(e);
}
}
void amf_timer_nf_instance_registration_interval(void *data)
{
timer_send_event(AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL, data);
}
void amf_timer_nf_instance_heartbeat_interval(void *data)
{
timer_send_event(AMF_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL, data);
}
void amf_timer_nf_instance_heartbeat(void *data)
{
timer_send_event(AMF_TIMER_NF_INSTANCE_HEARTBEAT, data);
}
void amf_timer_nf_instance_validity(void *data)
{
timer_send_event(AMF_TIMER_NF_INSTANCE_VALIDITY, data);
}
void amf_timer_subscription_validity(void *data)
{
timer_send_event(AMF_TIMER_SUBSCRIPTION_VALIDITY, data);
}

62
src/amf/timer.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef AMF_TIMER_H
#define AMF_TIMER_H
#include "ogs-core.h"
#ifdef __cplusplus
extern "C" {
#endif
/* forward declaration */
typedef enum {
AMF_TIMER_BASE = 0,
AMF_TIMER_NF_INSTANCE_REGISTRATION_INTERVAL,
AMF_TIMER_NF_INSTANCE_HEARTBEAT_INTERVAL,
AMF_TIMER_NF_INSTANCE_HEARTBEAT,
AMF_TIMER_NF_INSTANCE_VALIDITY,
AMF_TIMER_SUBSCRIPTION_VALIDITY,
MAX_NUM_OF_AMF_TIMER,
} amf_timer_e;
typedef struct amf_timer_cfg_s {
int max_count;
ogs_time_t duration;
} amf_timer_cfg_t;
amf_timer_cfg_t *amf_timer_cfg(amf_timer_e id);
const char *amf_timer_get_name(amf_timer_e id);
void amf_timer_nf_instance_registration_interval(void *data);
void amf_timer_nf_instance_heartbeat_interval(void *data);
void amf_timer_nf_instance_heartbeat(void *data);
void amf_timer_nf_instance_validity(void *data);
void amf_timer_subscription_validity(void *data);
#ifdef __cplusplus
}
#endif
#endif /* AMF_TIMER_H */

View File

@ -28,5 +28,6 @@ subdir('pgw')
subdir('pcrf')
subdir('nrf')
subdir('smf')
subdir('upf')
subdir('smf')
subdir('amf')

View File

@ -70,7 +70,7 @@ ogs_pkbuf_t *emm_build_attach_accept(
served_tai_index = mme_find_served_tai(&mme_ue->tai);
ogs_debug(" SERVED_TAI_INDEX[%d]", served_tai_index);
ogs_assert(served_tai_index >= 0 &&
served_tai_index < MAX_NUM_OF_SERVED_TAI);
served_tai_index < OGS_MAX_NUM_OF_SERVED_TAI);
ogs_nas_tai_list_build(&attach_accept->tai_list,
&mme_self()->served_tai[served_tai_index].list0,
&mme_self()->served_tai[served_tai_index].list2);
@ -368,7 +368,7 @@ ogs_pkbuf_t *emm_build_tau_accept(mme_ue_t *mme_ue)
served_tai_index = mme_find_served_tai(&mme_ue->tai);
ogs_debug(" SERVED_TAI_INDEX[%d]", served_tai_index);
ogs_assert(served_tai_index >= 0 &&
served_tai_index < MAX_NUM_OF_SERVED_TAI);
served_tai_index < OGS_MAX_NUM_OF_SERVED_TAI);
ogs_nas_tai_list_build(&tau_accept->tai_list,
&mme_self()->served_tai[served_tai_index].list0,
&mme_self()->served_tai[served_tai_index].list2);

View File

@ -39,7 +39,7 @@ int emm_handle_attach_request(
int served_tai_index = 0;
ogs_nas_eps_mobile_identity_guti_t *eps_mobile_identity_guti = NULL;
ogs_nas_guti_t nas_guti;
ogs_nas_eps_guti_t nas_guti;
enb_ue_t *enb_ue = NULL;
ogs_nas_eps_attach_type_t *eps_attach_type =
@ -101,7 +101,7 @@ int emm_handle_attach_request(
enb_ue->saved.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_tai_t));
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t));
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
/* Check TAI */
@ -120,7 +120,7 @@ int emm_handle_attach_request(
/* Store UE specific information */
if (attach_request->presencemask &
OGS_NAS_EPS_ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) {
ogs_nas_tracking_area_identity_t *last_visited_registered_tai =
ogs_nas_eps_tai_t *last_visited_registered_tai =
&attach_request->last_visited_registered_tai;
ogs_nas_to_plmn_id(&mme_ue->last_visited_plmn_id,
@ -426,7 +426,7 @@ int emm_handle_tau_request(mme_ue_t *mme_ue,
int served_tai_index = 0;
ogs_nas_eps_mobile_identity_guti_t *eps_mobile_identity_guti = NULL;
ogs_nas_guti_t nas_guti;
ogs_nas_eps_guti_t nas_guti;
ogs_nas_eps_update_type_t *eps_update_type =
&tau_request->eps_update_type;
@ -486,7 +486,7 @@ int emm_handle_tau_request(mme_ue_t *mme_ue,
enb_ue->saved.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_tai_t));
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t));
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
/* Check TAI */
@ -503,7 +503,7 @@ int emm_handle_tau_request(mme_ue_t *mme_ue,
/* Store UE specific information */
if (tau_request->presencemask &
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) {
ogs_nas_tracking_area_identity_t *last_visited_registered_tai =
ogs_nas_eps_tai_t *last_visited_registered_tai =
&tau_request->last_visited_registered_tai;
ogs_nas_to_plmn_id(&mme_ue->last_visited_plmn_id,
@ -609,7 +609,7 @@ int emm_handle_extended_service_request(mme_ue_t *mme_ue,
enb_ue->saved.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_tai_t));
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t));
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
/* Check TAI */

View File

@ -125,7 +125,7 @@ void mme_context_init()
ogs_pool_init(&mme_csmap_pool, ogs_config()->max.csmap);
/* Allocate TWICE the pool to check if maximum number of eNBs is reached */
ogs_pool_init(&mme_enb_pool, ogs_config()->max.enb*2);
ogs_pool_init(&mme_enb_pool, ogs_config()->max.gnb*2);
ogs_pool_init(&mme_ue_pool, ogs_config()->pool.ue);
ogs_pool_init(&enb_ue_pool, ogs_config()->pool.ue);
@ -704,7 +704,7 @@ int mme_context_parse_config()
ogs_plmn_id_t *plmn_id = NULL;
const char *mcc = NULL, *mnc = NULL;
ogs_assert(gummei->num_of_plmn_id <=
MAX_PLMN_ID);
OGS_MAX_NUM_OF_PLMN);
plmn_id = &gummei->plmn_id[
gummei->num_of_plmn_id];
ogs_assert(plmn_id);
@ -833,11 +833,11 @@ int mme_context_parse_config()
YAML_SEQUENCE_NODE);
} else if (!strcmp(mme_key, "tai")) {
int num_of_list0 = 0;
tai0_list_t *list0 = NULL;
tai2_list_t *list2 = NULL;
ogs_eps_tai0_list_t *list0 = NULL;
ogs_eps_tai2_list_t *list2 = NULL;
ogs_assert(self.num_of_served_tai <=
MAX_NUM_OF_SERVED_TAI);
OGS_MAX_NUM_OF_SERVED_TAI);
list0 = &self.served_tai[self.num_of_served_tai].list0;
ogs_assert(list0);
list2 = &self.served_tai[self.num_of_served_tai].list2;
@ -923,9 +923,9 @@ int mme_context_parse_config()
list2->num++;
if (list2->num > 1)
list2->type = TAI2_TYPE;
list2->type = OGS_TAI2_TYPE;
else
list2->type = TAI1_TYPE;
list2->type = OGS_TAI1_TYPE;
} else if (num_of_tac > 1) {
int i;
ogs_plmn_id_build(
@ -936,7 +936,7 @@ int mme_context_parse_config()
}
list0->tai[num_of_list0].num = num_of_tac;
list0->tai[num_of_list0].type = TAI0_TYPE;
list0->tai[num_of_list0].type = OGS_TAI0_TYPE;
num_of_list0++;
}
@ -1839,16 +1839,16 @@ void mme_csmap_remove_all(void)
mme_csmap_remove(csmap);
}
mme_csmap_t *mme_csmap_find_by_tai(ogs_tai_t *tai)
mme_csmap_t *mme_csmap_find_by_tai(ogs_eps_tai_t *tai)
{
mme_csmap_t *csmap = NULL;
ogs_assert(tai);
ogs_list_for_each(&self.csmap_list, csmap) {
ogs_nas_tai_t ogs_nas_tai;
ogs_nas_eps_tai_t ogs_nas_tai;
ogs_nas_from_plmn_id(&ogs_nas_tai.nas_plmn_id, &tai->plmn_id);
ogs_nas_tai.tac = tai->tac;
if (memcmp(&csmap->tai, &ogs_nas_tai, sizeof(ogs_nas_tai_t)) == 0)
if (memcmp(&csmap->tai, &ogs_nas_tai, sizeof(ogs_nas_eps_tai_t)) == 0)
return csmap;
}
@ -2134,11 +2134,11 @@ static int mme_ue_new_guti(mme_ue_t *mme_ue)
/* MME has a VALID GUTI
* As such, we need to remove previous GUTI in hash table */
ogs_hash_set(self.guti_ue_hash,
&mme_ue->guti, sizeof(ogs_nas_guti_t), NULL);
&mme_ue->guti, sizeof(ogs_nas_eps_guti_t), NULL);
ogs_assert(mme_m_tmsi_free(mme_ue->m_tmsi) == OGS_OK);
}
memset(&mme_ue->guti, 0, sizeof(ogs_nas_guti_t));
memset(&mme_ue->guti, 0, sizeof(ogs_nas_eps_guti_t));
/* Use the first configured plmn_id and mme group id */
ogs_nas_from_plmn_id(&mme_ue->guti.nas_plmn_id, &served_gummei->plmn_id[0]);
@ -2149,7 +2149,7 @@ static int mme_ue_new_guti(mme_ue_t *mme_ue)
ogs_assert(mme_ue->m_tmsi);
mme_ue->guti.m_tmsi = *(mme_ue->m_tmsi);
ogs_hash_set(self.guti_ue_hash,
&mme_ue->guti, sizeof(ogs_nas_guti_t), mme_ue);
&mme_ue->guti, sizeof(ogs_nas_eps_guti_t), mme_ue);
return OGS_OK;
}
@ -2258,7 +2258,7 @@ void mme_ue_remove(mme_ue_t *mme_ue)
/* Clear hash table */
if (mme_ue->m_tmsi) {
ogs_hash_set(self.guti_ue_hash,
&mme_ue->guti, sizeof(ogs_nas_guti_t), NULL);
&mme_ue->guti, sizeof(ogs_nas_eps_guti_t), NULL);
ogs_assert(mme_m_tmsi_free(mme_ue->m_tmsi) == OGS_OK);
}
if (mme_ue->imsi_len != 0)
@ -2271,10 +2271,10 @@ void mme_ue_remove(mme_ue_t *mme_ue)
CLEAR_SERVICE_INDICATOR(mme_ue);
/* Free UeRadioCapability */
OGS_S1AP_CLEAR_DATA(&mme_ue->ueRadioCapability);
OGS_ASN_CLEAR_DATA(&mme_ue->ueRadioCapability);
/* Clear Transparent Container */
OGS_S1AP_CLEAR_DATA(&mme_ue->container);
OGS_ASN_CLEAR_DATA(&mme_ue->container);
/* Delete All Timers */
CLEAR_MME_UE_ALL_TIMERS(mme_ue);
@ -2319,12 +2319,12 @@ mme_ue_t *mme_ue_find_by_imsi(uint8_t *imsi, int imsi_len)
return (mme_ue_t *)ogs_hash_get(self.imsi_ue_hash, imsi, imsi_len);
}
mme_ue_t *mme_ue_find_by_guti(ogs_nas_guti_t *guti)
mme_ue_t *mme_ue_find_by_guti(ogs_nas_eps_guti_t *guti)
{
ogs_assert(guti);
return (mme_ue_t *)ogs_hash_get(
self.guti_ue_hash, guti, sizeof(ogs_nas_guti_t));
self.guti_ue_hash, guti, sizeof(ogs_nas_eps_guti_t));
}
mme_ue_t *mme_ue_find_by_teid(uint32_t teid)
@ -2345,7 +2345,7 @@ mme_ue_t *mme_ue_find_by_message(ogs_nas_eps_message_t *message)
ogs_nas_eps_mobile_identity_guti_t *eps_mobile_identity_guti = NULL;
ogs_nas_mobile_identity_tmsi_t *mobile_identity_tmsi = NULL;
served_gummei_t *served_gummei = NULL;
ogs_nas_guti_t ogs_nas_guti;
ogs_nas_eps_guti_t ogs_nas_guti;
switch (message->emm.h.message_type) {
case OGS_NAS_EPS_ATTACH_REQUEST:
@ -3079,20 +3079,20 @@ ogs_pdn_t *mme_default_pdn(mme_ue_t *mme_ue)
return NULL;
}
int mme_find_served_tai(ogs_tai_t *tai)
int mme_find_served_tai(ogs_eps_tai_t *tai)
{
int i = 0, j = 0, k = 0;
ogs_assert(tai);
for (i = 0; i < self.num_of_served_tai; i++) {
tai0_list_t *list0 = &self.served_tai[i].list0;
ogs_eps_tai0_list_t *list0 = &self.served_tai[i].list0;
ogs_assert(list0);
tai2_list_t *list2 = &self.served_tai[i].list2;
ogs_eps_tai2_list_t *list2 = &self.served_tai[i].list2;
ogs_assert(list2);
for (j = 0; list0->tai[j].num; j++) {
ogs_assert(list0->tai[j].type == TAI0_TYPE);
ogs_assert(list0->tai[j].type == OGS_TAI0_TYPE);
ogs_assert(list0->tai[j].num < OGS_MAX_NUM_OF_TAI);
for (k = 0; k < list0->tai[j].num; k++) {
@ -3105,7 +3105,8 @@ int mme_find_served_tai(ogs_tai_t *tai)
}
if (list2->num) {
ogs_assert(list2->type == TAI1_TYPE || list2->type == TAI2_TYPE);
ogs_assert(list2->type == OGS_TAI1_TYPE ||
list2->type == OGS_TAI2_TYPE);
ogs_assert(list2->num < OGS_MAX_NUM_OF_TAI);
for (j = 0; j < list2->num; j++) {
@ -3208,17 +3209,3 @@ uint8_t mme_selected_enc_algorithm(mme_ue_t *mme_ue)
return 0;
}
bool mme_is_maximum_number_of_enbs_reached(void)
{
mme_enb_t *enb = NULL, *next_enb = NULL;
int number_of_enbs_online = 0;
ogs_list_for_each_safe(&self.enb_list, next_enb, enb) {
if (enb->state.s1_setup_success) {
number_of_enbs_online++;
}
}
return number_of_enbs_online >= ogs_config()->max.enb;
}

View File

@ -35,15 +35,10 @@
extern "C" {
#endif
#define MAX_PLMN_ID 6
#define GRP_PER_MME 256 /* According to spec it is 65535 */
#define CODE_PER_MME 256 /* According to spec it is 256 */
#define MAX_NUM_OF_SERVED_TAI 16
#define MAX_NUM_OF_SERVED_GUMMEI 8
#define MAX_NUM_OF_ALGORITHM 8
#define MAX_NUM_OF_BPLMN 6
extern int __mme_log_domain;
extern int __emm_log_domain;
@ -72,7 +67,7 @@ typedef enum {
typedef struct served_gummei_s {
uint32_t num_of_plmn_id;
ogs_plmn_id_t plmn_id[MAX_PLMN_ID];
ogs_plmn_id_t plmn_id[OGS_MAX_NUM_OF_PLMN];
uint32_t num_of_mme_gid;
uint16_t mme_gid[GRP_PER_MME];
@ -117,9 +112,9 @@ typedef struct mme_context_s {
/* Served TAI */
uint8_t num_of_served_tai;
struct {
tai0_list_t list0;
tai2_list_t list2;
} served_tai[MAX_NUM_OF_SERVED_TAI];
ogs_eps_tai0_list_t list0;
ogs_eps_tai2_list_t list2;
} served_tai[OGS_MAX_NUM_OF_SERVED_TAI];
/* defined in 'nas_ies.h'
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
@ -127,14 +122,14 @@ typedef struct mme_context_s {
* #define NAS_SECURITY_ALGORITHMS_128_EEA2 2
* #define NAS_SECURITY_ALGORITHMS_128_EEA3 3 */
uint8_t num_of_ciphering_order;
uint8_t ciphering_order[MAX_NUM_OF_ALGORITHM];
uint8_t ciphering_order[OGS_MAX_NUM_OF_ALGORITHM];
/* defined in 'nas_ies.h'
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
* #define NAS_SECURITY_ALGORITHMS_128_EIA1 1
* #define NAS_SECURITY_ALGORITHMS_128_EIA1 2
* #define NAS_SECURITY_ALGORITHMS_128_EIA3 3 */
uint8_t num_of_integrity_order;
uint8_t integrity_order[MAX_NUM_OF_ALGORITHM];
uint8_t integrity_order[OGS_MAX_NUM_OF_ALGORITHM];
/* S1SetupResponse */
uint8_t relative_capacity;
@ -209,7 +204,7 @@ typedef struct mme_vlr_s {
typedef struct mme_csmap_s {
ogs_lnode_t lnode;
ogs_nas_tai_t tai;
ogs_nas_eps_tai_t tai;
ogs_nas_lai_t lai;
mme_vlr_t *vlr;
@ -235,7 +230,7 @@ typedef struct mme_enb_s {
uint8_t num_of_supported_ta_list;
ogs_tai_t supported_ta_list[OGS_MAX_NUM_OF_TAI * MAX_NUM_OF_BPLMN];
ogs_eps_tai_t supported_ta_list[OGS_MAX_NUM_OF_TAI*OGS_MAX_NUM_OF_BPLMN];
ogs_list_t enb_ue_list;
@ -261,7 +256,7 @@ struct enb_ue_s {
*
* Save TAI and ECGI. And then, this will copy 'mme_ue_t' context later */
struct {
ogs_tai_t tai;
ogs_eps_tai_t tai;
ogs_e_cgi_t e_cgi;
} saved;
@ -317,7 +312,7 @@ struct mme_ue_s {
mme_m_tmsi_t *m_tmsi;
mme_p_tmsi_t p_tmsi;
ogs_nas_guti_t guti;
ogs_nas_eps_guti_t guti;
int guti_present;
uint32_t mme_s11_teid; /* MME-S11-TEID is derived from INDEX */
@ -326,7 +321,7 @@ struct mme_ue_s {
uint16_t vlr_ostream_id; /* SCTP output stream id for VLR */
/* UE Info */
ogs_tai_t tai;
ogs_eps_tai_t tai;
ogs_e_cgi_t e_cgi;
ogs_plmn_id_t last_visited_plmn_id;
@ -659,7 +654,7 @@ mme_csmap_t *mme_csmap_add(mme_vlr_t *vlr);
void mme_csmap_remove(mme_csmap_t *csmap);
void mme_csmap_remove_all(void);
mme_csmap_t *mme_csmap_find_by_tai(ogs_tai_t *tai);
mme_csmap_t *mme_csmap_find_by_tai(ogs_eps_tai_t *tai);
mme_csmap_t *mme_csmap_find_by_nas_lai(ogs_nas_lai_t *lai);
mme_enb_t *mme_enb_add(ogs_sock_t *sock, ogs_sockaddr_t *addr);
@ -669,7 +664,6 @@ mme_enb_t *mme_enb_find_by_addr(ogs_sockaddr_t *addr);
mme_enb_t *mme_enb_find_by_enb_id(uint32_t enb_id);
int mme_enb_set_enb_id(mme_enb_t *enb, uint32_t enb_id);
int mme_enb_sock_type(ogs_sock_t *sock);
bool mme_is_maximum_number_of_enbs_reached(void);
enb_ue_t *enb_ue_add(mme_enb_t *enb, uint32_t enb_ue_s1ap_id);
unsigned int enb_ue_count(void);
@ -688,7 +682,7 @@ void mme_ue_remove_all(void);
mme_ue_t *mme_ue_find_by_imsi(uint8_t *imsi, int imsi_len);
mme_ue_t *mme_ue_find_by_imsi_bcd(char *imsi_bcd);
mme_ue_t *mme_ue_find_by_guti(ogs_nas_guti_t *nas_guti);
mme_ue_t *mme_ue_find_by_guti(ogs_nas_eps_guti_t *nas_guti);
mme_ue_t *mme_ue_find_by_teid(uint32_t teid);
mme_ue_t *mme_ue_find_by_message(ogs_nas_eps_message_t *message);
@ -780,7 +774,7 @@ void mme_pdn_remove_all(mme_ue_t *mme_ue);
ogs_pdn_t *mme_pdn_find_by_apn(mme_ue_t *mme_ue, char *apn);
ogs_pdn_t *mme_default_pdn(mme_ue_t *mme_ue);
int mme_find_served_tai(ogs_tai_t *tai);
int mme_find_served_tai(ogs_eps_tai_t *tai);
int mme_m_tmsi_pool_generate(void);
mme_m_tmsi_t *mme_m_tmsi_alloc(void);

View File

@ -55,7 +55,7 @@ typedef enum {
} mme_event_e;
typedef long S1AP_ProcedureCode_t;
typedef struct S1AP_S1AP_PDU s1ap_message_t;
typedef struct S1AP_S1AP_PDU ogs_s1ap_message_t;
typedef struct ogs_nas_eps_message_s ogs_nas_eps_message_t;
typedef struct mme_vlr_s mme_vlr_t;
typedef struct mme_enb_s mme_enb_t;
@ -77,7 +77,7 @@ typedef struct mme_event_s {
uint16_t max_num_of_ostreams;
S1AP_ProcedureCode_t s1ap_code;
s1ap_message_t *s1ap_message;
ogs_s1ap_message_t *s1ap_message;
ogs_gtp_node_t *gnode;

View File

@ -103,7 +103,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
mme_enb_t *enb = NULL;
uint16_t max_num_of_ostreams = 0;
s1ap_message_t s1ap_message;
ogs_s1ap_message_t s1ap_message;
ogs_pkbuf_t *pkbuf = NULL;
int rc;

View File

@ -40,7 +40,8 @@ static bool served_tai_is_found(mme_enb_t *enb)
for (i = 0; i < enb->num_of_supported_ta_list; i++) {
served_tai_index = mme_find_served_tai(&enb->supported_ta_list[i]);
if (served_tai_index >= 0 && served_tai_index < MAX_NUM_OF_SERVED_TAI) {
if (served_tai_index >= 0 &&
served_tai_index < OGS_MAX_NUM_OF_SERVED_TAI) {
ogs_debug(" SERVED_TAI_INDEX[%d]", served_tai_index);
return true;
}
@ -60,7 +61,7 @@ static bool maximum_number_of_enbs_is_reached(void)
}
}
return number_of_enbs_online >= ogs_config()->max.enb;
return number_of_enbs_online >= ogs_config()->max.gnb;
}
void s1ap_handle_s1_setup_request(mme_enb_t *enb, ogs_s1ap_message_t *message)
@ -256,13 +257,14 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, ogs_s1ap_message_t *message)
/* Find MME_UE if S_TMSI included */
if (S_TMSI) {
served_gummei_t *served_gummei = &mme_self()->served_gummei[0];
ogs_nas_guti_t nas_guti;
ogs_nas_eps_guti_t nas_guti;
mme_ue_t *mme_ue = NULL;
memset(&nas_guti, 0, sizeof(ogs_nas_guti_t));
memset(&nas_guti, 0, sizeof(ogs_nas_eps_guti_t));
/* Use the first configured plmn_id and mme group id */
ogs_nas_from_plmn_id(&nas_guti.nas_plmn_id, &served_gummei->plmn_id[0]);
ogs_nas_from_plmn_id(&nas_guti.nas_plmn_id,
&served_gummei->plmn_id[0]);
nas_guti.mme_gid = served_gummei->mme_gid[0];
/* size must be 1 */
@ -434,7 +436,7 @@ void s1ap_handle_ue_capability_info_indication(
if (enb_ue->mme_ue) {
ogs_assert(UERadioCapability);
OGS_S1AP_STORE_DATA(&enb_ue->mme_ue->ueRadioCapability,
OGS_ASN_STORE_DATA(&enb_ue->mme_ue->ueRadioCapability,
UERadioCapability);
}
}
@ -1165,7 +1167,7 @@ void s1ap_handle_path_switch_request(
enb_ue->saved.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_tai_t));
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t));
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
memcpy(&eea, encryptionAlgorithms->buf, sizeof(eea));
@ -1529,7 +1531,7 @@ void s1ap_handle_handover_request_ack(mme_enb_t *enb, ogs_s1ap_message_t *messag
}
}
OGS_S1AP_STORE_DATA(&mme_ue->container,
OGS_ASN_STORE_DATA(&mme_ue->container,
Target_ToSource_TransparentContainer);
if (mme_ue_have_indirect_tunnel(mme_ue) == 1) {
@ -1858,7 +1860,7 @@ void s1ap_handle_handover_notification(mme_enb_t *enb, ogs_s1ap_message_t *messa
target_ue->saved.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &target_ue->saved.tai, sizeof(ogs_tai_t));
memcpy(&mme_ue->tai, &target_ue->saved.tai, sizeof(ogs_eps_tai_t));
memcpy(&mme_ue->e_cgi, &target_ue->saved.e_cgi, sizeof(ogs_e_cgi_t));
sess = mme_sess_first(mme_ue);

View File

@ -350,7 +350,7 @@ void s1ap_send_paging(mme_ue_t *mme_ue, S1AP_CNDomain_t cn_domain)
for (i = 0; i < enb->num_of_supported_ta_list; i++) {
if (memcmp(&enb->supported_ta_list[i], &mme_ue->tai,
sizeof(ogs_tai_t)) == 0) {
sizeof(ogs_eps_tai_t)) == 0) {
if (mme_ue->t3413.pkbuf) {
s1apbuf = mme_ue->t3413.pkbuf;

View File

@ -35,7 +35,7 @@ void sbc_handle_write_replace_warning_request(sbc_pws_data_t *sbc_pws)
for (i = 0, flag = 0; i < enb->num_of_supported_ta_list; i++) {
for (j = 0; j < sbc_pws->no_of_tai; j++) {
if (!memcmp(&enb->supported_ta_list[i],
&sbc_pws->tai[j], sizeof(ogs_tai_t)))
&sbc_pws->tai[j], sizeof(ogs_eps_tai_t)))
flag = 1;
if (flag) break;
@ -70,7 +70,7 @@ void sbc_handle_stop_warning_request(sbc_pws_data_t *sbc_pws)
for (i = 0, flag = 0; i < enb->num_of_supported_ta_list; i++) {
for (j = 0; j < sbc_pws->no_of_tai; j++) {
if (!memcmp(&enb->supported_ta_list[i],
&sbc_pws->tai[j], sizeof(ogs_tai_t)))
&sbc_pws->tai[j], sizeof(ogs_eps_tai_t)))
flag = 1;
if (flag) break;

View File

@ -38,7 +38,7 @@ typedef struct _sbc_pws_data_t {
uint16_t message_id;
uint16_t serial_number;
uint32_t no_of_tai;
ogs_tai_t tai[16]; /* TODO: max 65535 */
ogs_eps_tai_t tai[16]; /* TODO: max 65535 */
uint32_t repetition_period;
uint32_t number_of_broadcast;
uint8_t data_coding_scheme;

View File

@ -125,7 +125,7 @@ typedef struct sgw_bearer_s {
uint8_t ebi;
/* User-Lication-Info */
ogs_tai_t tai;
ogs_eps_tai_t tai;
ogs_e_cgi_t e_cgi;
/* Pkts which will be buffered in case of UE-IDLE */

View File

@ -503,7 +503,7 @@ int smf_context_parse_config(void)
} else if (!strcmp(smf_key, "pdn")) {
/* handle config in pfcp library */
} else if (!strcmp(smf_key, "sbi")) {
/* handle config in pfcp library */
/* handle config in sbi library */
} else
ogs_warn("unknown key `%s`", smf_key);
}

View File

@ -201,11 +201,12 @@ void smf_nf_state_registered(ogs_fsm_t *s, smf_event_t *e)
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
client = nf_instance->client;
ogs_assert(client);
if (NF_INSTANCE_IS_SELF(nf_instance->id)) {
ogs_info("NF registered [%s]", nf_instance->id);
client = nf_instance->client;
ogs_assert(client);
if (nf_instance->time.heartbeat) {
ogs_timer_start(nf_instance->t_heartbeat_interval,
ogs_time_from_sec(nf_instance->time.heartbeat));

View File

@ -153,18 +153,8 @@ bool smf_nnrf_handle_nf_status_notify(ogs_sbi_server_t *server,
if (!nf_instance) {
nf_instance = ogs_sbi_nf_instance_add(NFProfile->nf_instance_id);
ogs_assert(nf_instance);
smf_nf_fsm_init(nf_instance);
client = ogs_sbi_nf_instance_find_client(nf_instance);
if (!client) {
ogs_error("Cannot find client [%s]", nf_instance->id);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "Cannot find client", nf_instance->id);
return false;
}
smf_sbi_nf_associate_client(nf_instance, client);
ogs_info("(NRF-notify) NF registered [%s]", nf_instance->id);
} else
ogs_warn("(NRF-notify) NF [%s] has already been added",
@ -176,6 +166,15 @@ bool smf_nnrf_handle_nf_status_notify(ogs_sbi_server_t *server,
ogs_info("(NRF-notify) NF Profile updated [%s]", nf_instance->id);
client = ogs_sbi_nf_instance_find_client(nf_instance);
if (!client) {
ogs_error("Cannot find client [%s]", nf_instance->id);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
message, "Cannot find client", nf_instance->id);
return false;
}
smf_sbi_nf_associate_client(nf_instance, client);
} else if (NotificationData->event ==
OpenAPI_notification_event_type_NF_DEREGISTERED) {
@ -186,9 +185,13 @@ bool smf_nnrf_handle_nf_status_notify(ogs_sbi_server_t *server,
ogs_sbi_nf_instance_remove(nf_instance);
/* FIXME : Remove unnecessary Client */
} else
ogs_warn("(NRF-notify) NF [%s] has already been removed",
NFProfile->nf_instance_id);
} else {
ogs_warn("(NRF-notify) Not found [%s]", NFProfile->nf_instance_id);
ogs_sbi_server_send_error(session,
OGS_SBI_HTTP_STATUS_NOT_FOUND,
message, "Not found", message->h.resource.id);
return false;
}
} else {
char *eventstr = OpenAPI_notification_event_type_ToString(
NotificationData->event);
@ -235,18 +238,11 @@ void smf_nnrf_handle_nf_discover(ogs_sbi_message_t *message)
if (!nf_instance) {
nf_instance = ogs_sbi_nf_instance_add(NFProfile->nf_instance_id);
ogs_assert(nf_instance);
smf_nf_fsm_init(nf_instance);
client = ogs_sbi_nf_instance_find_client(nf_instance);
if (!client) {
ogs_error("Cannot find client [%s]", nf_instance->id);
continue;
}
smf_sbi_nf_associate_client(nf_instance, client);
ogs_info("(NF-Discover) NF registered [%s]", nf_instance->id);
ogs_info("(NF-discover) NF registered [%s]", nf_instance->id);
} else
ogs_warn("(NF-Discover) NF [%s] has already been added",
ogs_warn("(NF-discover) NF [%s] has already been added",
NFProfile->nf_instance_id);
if (NF_INSTANCE_IS_OTHERS(nf_instance->id)) {
@ -276,7 +272,7 @@ void smf_nnrf_handle_nf_discover(ogs_sbi_message_t *message)
} else
ogs_warn("NF Instance validity-time should not 0");
ogs_info("(NF-Discover) NF Profile updated [%s]", nf_instance->id);
ogs_info("(NF-discover) NF Profile updated [%s]", nf_instance->id);
}
}
}

88
tests/app/5gc-init.c Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "test-5gc.h"
static ogs_thread_t *nrf_thread = NULL;
static ogs_thread_t *smf_thread = NULL;
static ogs_thread_t *upf_thread = NULL;
#if 0
static ogs_thread_t *amf_thread = NULL;
#endif
int app_initialize(const char *const argv[])
{
int rv;
const char *argv_out[OGS_ARG_MAX];
bool user_config = false;
int i = 0;
for (i = 0; argv[i]; i++) {
if (strcmp("-c", argv[i]) == 0) {
user_config = true;
}
argv_out[i] = argv[i];
}
argv_out[i] = NULL;
if (!user_config) {
argv_out[i++] = "-c";
argv_out[i++] = DEFAULT_CONFIG_FILENAME;
argv_out[i] = NULL;
}
if (ogs_config()->parameter.no_nrf == 0)
nrf_thread = test_child_create("nrf", argv_out);
if (ogs_config()->parameter.no_upf == 0)
upf_thread = test_child_create("upf", argv_out);
if (ogs_config()->parameter.no_smf == 0)
smf_thread = test_child_create("smf", argv_out);
ogs_sctp_init(ogs_config()->usrsctp.udp_port);
rv = amf_initialize();
ogs_assert(rv == OGS_OK);
ogs_info("AMF initialize...done");
return OGS_OK;;
}
void app_terminate(void)
{
amf_terminate();
ogs_sctp_final();
ogs_info("AMF terminate...done");
if (smf_thread) ogs_thread_destroy(smf_thread);
if (upf_thread) ogs_thread_destroy(upf_thread);
if (nrf_thread) ogs_thread_destroy(nrf_thread);
}
void test_5gc_init(void)
{
ogs_log_install_domain(&__ogs_sctp_domain, "sctp", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_ngap_domain, "ngap", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_dbi_domain, "dbi", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_nas_domain, "nas", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_sbi_domain, "sbi", OGS_LOG_ERROR);
ogs_assert(ogs_mongoc_init(ogs_config()->db_uri) == OGS_OK);
}

View File

@ -17,86 +17,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-sctp.h"
#include "test-epc.h"
#include "test-config-private.h"
#define MAX_CHILD_PROCESS 8
#define OGS_ARG_MAX 256
static ogs_thread_t *pcrf_thread = NULL;
static ogs_thread_t *pgw_thread = NULL;
static ogs_thread_t *sgw_thread = NULL;
static ogs_thread_t *hss_thread = NULL;
static ogs_proc_t process[MAX_CHILD_PROCESS];
static int process_num = 0;
static void child_main(void *data)
{
const char **commandLine = data;
ogs_proc_t *current = NULL;
FILE *out = NULL;
char buf[OGS_HUGE_LEN];
int ret = 0, out_return_code = 0;;
current = &process[process_num++];
ret = ogs_proc_create(commandLine,
ogs_proc_option_combined_stdout_stderr|
ogs_proc_option_inherit_environment,
current);
ogs_assert(ret == 0);
out = ogs_proc_stdout(current);
ogs_assert(out);
while(fgets(buf, OGS_HUGE_LEN, out)) {
printf("%s", buf);
}
ret = ogs_proc_join(current, &out_return_code);
ogs_assert(ret == 0);
ogs_assert(out_return_code == 0);
ret = ogs_proc_destroy(current);
ogs_assert(ret == 0);
}
ogs_thread_t *test_child_create(const char *name, const char *const argv[])
{
ogs_thread_t *child = NULL;
const char *commandLine[OGS_ARG_MAX];
int i = 0;
char command[OGS_MAX_FILEPATH_LEN];
while(argv[i] && i < 32) {
commandLine[i] = argv[i];
i++;
}
commandLine[i] = NULL;
/* buildroot/src/mme/open5gs-mmed */
ogs_snprintf(command, sizeof command, "%s%s%s%sd",
MESON_BUILD_ROOT OGS_DIR_SEPARATOR_S "src" OGS_DIR_SEPARATOR_S,
name, OGS_DIR_SEPARATOR_S "open5gs-", name);
commandLine[0] = command;
child = ogs_thread_create(child_main, commandLine);
ogs_msleep(50);
return child;
}
void test_child_terminate(void)
{
int i;
ogs_proc_t *current = NULL;
for (i = 0; i < process_num; i++) {
current = &process[i];
ogs_proc_terminate(current);
}
}
int app_initialize(const char *const argv[])
{
int rv;
@ -149,3 +76,14 @@ void app_terminate(void)
if (pgw_thread) ogs_thread_destroy(pgw_thread);
if (pcrf_thread) ogs_thread_destroy(pcrf_thread);
}
void test_epc_init(void)
{
ogs_log_install_domain(&__ogs_sctp_domain, "sctp", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_s1ap_domain, "s1ap", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_diam_domain, "diam", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_dbi_domain, "dbi", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_nas_domain, "nas", OGS_LOG_ERROR);
ogs_assert(ogs_mongoc_init(ogs_config()->db_uri) == OGS_OK);
}

View File

@ -1,4 +1,4 @@
# Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
# Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
# This file is part of Open5GS.
@ -14,25 +14,77 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
libtestapp_sources = files('''
test-packet.h
test-app.h
test-packet.c
test-app.c
'''.split())
#
libtestapp_inc = include_directories('.')
libtestapp = static_library('testapp',
sources : libtestapp_sources,
c_args : testcore_cc_flags,
include_directories : libtestapp_inc,
dependencies : libtestepc_dep,
libtestepc_cc_args = '-DDEFAULT_CONFIG_FILENAME="@0@/configs/epc.yaml"'.format(meson.build_root())
libtestepc_sources = files('''
test-packet.c
epc-init.c
'''.split())
libtestepc = static_library('testepc',
sources : [libtestepc_sources],
c_args : libtestepc_cc_args,
include_directories : [libtestapp_inc, srcinc],
link_with : [libmme, libhss, libsgw, libpgw, libpcrf],
dependencies : [libtestcommon_dep,
libmme_dep,
libhss_dep,
libsgw_dep,
libpgw_dep,
libpcrf_dep],
install : false)
libtestapp_dep = declare_dependency(
link_with : libtestapp,
include_directories : libtestapp_inc,
dependencies : libtestepc_dep)
libtestepc_dep = declare_dependency(
link_with : libtestepc,
include_directories : [libtestapp_inc, srcinc],
dependencies : [libtestcommon_dep,
libmme_dep,
libhss_dep,
libsgw_dep,
libpgw_dep,
libpcrf_dep])
testepc_sources = files('''
../../src/main.c
'''.split())
executable('epc',
sources : [testepc_sources],
c_args : libtestepc_cc_args,
include_directories : srcinc,
dependencies : [libtestepc_dep])
libtest5gc_cc_args = '-DDEFAULT_CONFIG_FILENAME="@0@/configs/5gc.yaml"'.format(meson.build_root())
libtest5gc_sources = files('''
5gc-init.c
'''.split())
libtest5gc = static_library('test5gc',
sources : [libtest5gc_sources],
c_args : libtest5gc_cc_args,
include_directories : [libtestapp_inc, srcinc],
link_with : libamf,
dependencies : [libtestcommon_dep,
libamf_dep],
install : false)
libtest5gc_dep = declare_dependency(
link_with : libtest5gc,
include_directories : [libtestapp_inc, srcinc],
dependencies : [libtestcommon_dep,
libamf_dep])
test5gc_sources = files('''
../../src/main.c
'''.split())
executable('5gc',
sources : [test5gc_sources],
c_args : libtest5gc_cc_args,
include_directories : srcinc,
dependencies : [libtest5gc_dep])

39
tests/app/test-5gc.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TEST_5GC_H
#define TEST_5GC_H
#include "test-common.h"
#include "test-ngap.h"
#include "amf/context.h"
#ifdef __cplusplus
extern "C" {
#endif
void test_5gc_init(void);
#define test_5gc_final ogs_mongoc_final
#ifdef __cplusplus
}
#endif
#endif /* TEST_5GC_H */

View File

@ -1,93 +0,0 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "test-app.h"
#include "test-config-private.h"
static int connected_count = 0;
static void test_diam_logger_handler(enum fd_hook_type type, struct msg * msg,
struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd,
void * regdata)
{
if (type == HOOK_PEER_CONNECT_SUCCESS) {
connected_count++;
}
}
void test_app_run(int argc, const char *const argv[],
const char *name, void (*init)(const char * const argv[]))
{
int rv;
bool user_config;
/* '-f sample-XXXX.conf -e error' is always added */
const char *argv_out[argc+4], *new_argv[argc+4];
int argc_out;
char conf_file[OGS_MAX_FILEPATH_LEN];
user_config = false;
for (argc_out = 0; argc_out < argc; argc_out++) {
if (strcmp("-c", argv[argc_out]) == 0) {
user_config = true;
}
argv_out[argc_out] = argv[argc_out];
}
argv_out[argc_out] = NULL;
if (!user_config) {
/* buildroot/configs/XXX-conf.yaml */
ogs_snprintf(conf_file, sizeof conf_file, "%s%s",
MESON_BUILD_ROOT OGS_DIR_SEPARATOR_S
"configs" OGS_DIR_SEPARATOR_S, name);
argv_out[argc_out++] = "-c";
argv_out[argc_out++] = conf_file;
argv_out[argc_out] = NULL;
}
/* buildroot/src/open5gs-main */
argv_out[0] = MESON_BUILD_ROOT OGS_DIR_SEPARATOR_S
"src" OGS_DIR_SEPARATOR_S "open5gs-main";
rv = abts_main(argc_out, argv_out, new_argv);
ogs_assert(rv == OGS_OK);
ogs_diam_logger_register(test_diam_logger_handler);
(*init)(new_argv);
while(1) {
if (connected_count == 1) break;
ogs_msleep(50);
}
ogs_msleep(500); /* Wait for listening all sockets */
}
void test_app_init(void)
{
ogs_log_install_domain(&__ogs_sctp_domain, "sctp", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_s1ap_domain, "s1ap", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_diam_domain, "diam", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_dbi_domain, "dbi", OGS_LOG_ERROR);
ogs_log_install_domain(&__ogs_nas_domain, "nas", OGS_LOG_ERROR);
ogs_assert(ogs_mongoc_init(ogs_config()->db_uri) == OGS_OK);
}

View File

@ -1,28 +0,0 @@
#ifndef TEST_APP_H
#define TEST_APP_H
#ifdef __cplusplus
extern "C" {
#endif
#include "ogs-diameter-common.h"
#include "ogs-sctp.h"
#include "ogs-dbi.h"
#include "ogs-app.h"
#include "mme/mme-context.h"
#include "core/abts.h"
#include "test-epc.h"
#include "test-packet.h"
void test_app_run(int argc, const char *const argv[],
const char *name, void (*init)(const char * const argv[]));
void test_app_init(void);
#define test_app_final ogs_mongoc_final
#ifdef __cplusplus
}
#endif
#endif /* TEST_APP_H */

38
tests/app/test-epc.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TEST_EPC_H
#define TEST_EPC_H
#include "test-packet.h"
#include "mme/mme-context.h"
#ifdef __cplusplus
extern "C" {
#endif
void test_epc_init(void);
#define test_epc_final ogs_mongoc_final
#ifdef __cplusplus
}
#endif
#endif /* TEST_EPC_H */

View File

@ -44,128 +44,13 @@
#include "mme/sgsap-path.h"
ogs_socknode_t *testsctp_server(const char *ipstr)
{
int rv;
ogs_sockaddr_t *addr = NULL;
ogs_socknode_t *node = NULL;
rv = ogs_getaddrinfo(&addr, AF_UNSPEC, ipstr, OGS_SGSAP_SCTP_PORT, 0);
ogs_assert(rv == OGS_OK);
node = ogs_socknode_new(addr);
ogs_assert(node);
ogs_socknode_nodelay(node, true);
ogs_sctp_server(SOCK_SEQPACKET, node);
ogs_assert(node->sock);
return node;
}
ogs_socknode_t *testsctp_client(const char *ipstr)
{
int rv;
ogs_sockaddr_t *addr = NULL;
ogs_socknode_t *node = NULL;
rv = ogs_getaddrinfo(&addr, AF_UNSPEC, ipstr, OGS_S1AP_SCTP_PORT, 0);
ogs_assert(rv == OGS_OK);
node = ogs_socknode_new(addr);
ogs_assert(node);
ogs_socknode_nodelay(node, true);
ogs_sctp_client(SOCK_STREAM, node);
ogs_assert(node->sock);
return node;
}
static ogs_sockaddr_t sctp_last_addr;
ogs_pkbuf_t *testsctp_read(ogs_socknode_t *node, int type)
{
int size;
ogs_pkbuf_t *recvbuf = NULL;
ogs_assert(node);
ogs_assert(node->sock);
recvbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN);
size = ogs_sctp_recvdata(node->sock, recvbuf->data, OGS_MAX_SDU_LEN,
type == 1 ? &sctp_last_addr : NULL, NULL);
if (size <= 0) {
ogs_error("sgsap_recv() failed");
return NULL;
}
ogs_pkbuf_trim(recvbuf, size);
return recvbuf;;
}
int testenb_s1ap_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf)
{
return s1ap_send(node->sock, sendbuf, NULL, 0);
}
int testvlr_sgsap_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf)
{
return sgsap_send(node->sock, sendbuf, &sctp_last_addr, 0);
}
ogs_socknode_t *testenb_gtpu_server(const char *ipstr)
{
int rv;
ogs_sockaddr_t *addr = NULL;
ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL;
rv = ogs_getaddrinfo(&addr, AF_UNSPEC, ipstr, OGS_GTPV1_U_UDP_PORT, 0);
ogs_assert(rv == OGS_OK);
node = ogs_socknode_new(addr);
ogs_assert(node);
sock = ogs_udp_server(node);
ogs_assert(sock);
return node;
}
ogs_pkbuf_t *testenb_gtpu_read(ogs_socknode_t *node)
{
int rc = 0;
ogs_pkbuf_t *recvbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN);
ogs_assert(node);
ogs_assert(node->sock);
while (1) {
rc = ogs_recv(node->sock->fd, recvbuf->data, recvbuf->len, 0);
if (rc <= 0) {
if (errno == EAGAIN) {
continue;
}
break;
} else {
break;
}
}
recvbuf->len = rc;
return recvbuf;
}
#include "test-packet.h"
bool test_no_mme_self = 0;
int testenb_gtpu_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf)
{
int rv;
ogs_hash_index_t *hi = NULL;
mme_ue_t *mme_ue = NULL;
mme_sess_t *sess = NULL;
mme_bearer_t *bearer = NULL;
@ -213,17 +98,10 @@ int testenb_gtpu_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf)
return OGS_OK;
}
void testenb_gtpu_close(ogs_socknode_t *node)
{
ogs_socknode_free(node);
}
int tests1ap_build_setup_req(
ogs_pkbuf_t **pkbuf, S1AP_ENB_ID_PR present, uint32_t enb_id,
int tac, uint16_t mcc, uint16_t mnc, uint16_t mnc_len)
{
int rv;
ogs_plmn_id_t plmn_id;
S1AP_S1AP_PDU_t pdu;
@ -1187,12 +1065,9 @@ int tests1ap_build_ue_context_modification_response(
ogs_pkbuf_t **pkbuf,
uint32_t mme_ue_s1ap_id, uint32_t enb_ue_s1ap_id)
{
int rv;
S1AP_S1AP_PDU_t pdu;
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
S1AP_UEContextModificationResponse_t *UEContextModificationResponse = NULL;
ogs_sockaddr_t *addr = NULL;
S1AP_UEContextModificationResponseIEs_t *ie = NULL;
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
@ -2480,8 +2355,6 @@ static void build_bearer_resource_modification_request(ogs_pkbuf_t **pkbuf,
ogs_gtp_tft_t tft;
ogs_tlv_octet_t octet;
int len;
char tft_buf[OGS_GTP_MAX_TRAFFIC_FLOW_TEMPLATE];
ogs_ipsubnet_t ipsubnet;
memset(&message, 0, sizeof(message));
@ -2669,7 +2542,6 @@ int tests1ap_build_bearer_resource_modification_request(
uint8_t tft_code, uint8_t qci,
uint8_t ul_mbr, uint8_t dl_mbr, uint8_t ul_gbr, uint8_t dl_gbr)
{
int rv;
ogs_pkbuf_t *emmbuf = NULL;
S1AP_S1AP_PDU_t pdu;
@ -2680,8 +2552,6 @@ int tests1ap_build_bearer_resource_modification_request(
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
S1AP_NAS_PDU_t *NAS_PDU = NULL;
S1AP_EUTRAN_CGI_t *EUTRAN_CGI = NULL;
S1AP_TAI_t *TAI = NULL;
memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t));
pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
@ -3070,8 +2940,6 @@ int tests1ap_build_handover_request_ack(
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
S1AP_E_RABAdmittedList_t *E_RABAdmittedList = NULL;
S1AP_E_RABFailedtoSetupListHOReqAck_t
*E_RABFailedtoSetupListHOReqAck = NULL;
S1AP_Target_ToSource_TransparentContainer_t
*Target_ToSource_TransparentContainer = NULL;

View File

@ -22,7 +22,8 @@
#include "ogs-s1ap.h"
#include "mme/s1ap-build.h"
#include "core/abts.h"
#include "test-common.h"
#ifdef __cplusplus
extern "C" {
@ -30,24 +31,10 @@ extern "C" {
extern bool test_no_mme_self;
ogs_socknode_t *testsctp_server(const char *ipstr);
ogs_socknode_t *testsctp_client(const char *ipstr);
ogs_pkbuf_t *testsctp_read(ogs_socknode_t *node, int type);
#define testenb_s1ap_client testsctp_client
#define testenb_s1ap_read(x) testsctp_read(x, 0);
int testenb_s1ap_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf);
#define testenb_s1ap_close ogs_socknode_free
#define testvlr_sgsap_server testsctp_server
#define testvlr_sgsap_read(x) testsctp_read(x, 1);
int testvlr_sgsap_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf);
#define testvlr_sgsap_close ogs_socknode_free
ogs_socknode_t *testenb_gtpu_server(const char *ipstr);
ogs_pkbuf_t *testenb_gtpu_read(ogs_socknode_t *node);
#define testenb_gtpu_server(x) test_gtpu_server(x, OGS_GTPV1_U_UDP_PORT)
#define testenb_gtpu_read(x) test_gtpu_read(x)
int testenb_gtpu_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf);
void testenb_gtpu_close(ogs_socknode_t *node);
#define testenb_gtpu_close(x) test_gtpu_close(x)
int tests1ap_build_invalid_packet(ogs_pkbuf_t **pkbuf, int i);

172
tests/common/application.c Normal file
View File

@ -0,0 +1,172 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "test-config-private.h"
#include "test-common.h"
static int connected_count = 0;
static void test_diam_logger_handler(enum fd_hook_type type, struct msg * msg,
struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd,
void * regdata)
{
if (type == HOOK_PEER_CONNECT_SUCCESS) {
connected_count++;
}
}
static void test_app_run(int argc, const char *const argv[],
const char *name, void (*init)(const char * const argv[]))
{
int rv;
bool user_config;
/* '-f sample-XXXX.conf -e error' is always added */
const char *argv_out[argc+4], *new_argv[argc+4];
int argc_out;
char conf_file[OGS_MAX_FILEPATH_LEN];
user_config = false;
for (argc_out = 0; argc_out < argc; argc_out++) {
if (strcmp("-c", argv[argc_out]) == 0) {
user_config = true;
}
argv_out[argc_out] = argv[argc_out];
}
argv_out[argc_out] = NULL;
if (!user_config) {
/* buildroot/configs/XXX-conf.yaml */
ogs_snprintf(conf_file, sizeof conf_file, "%s%s",
MESON_BUILD_ROOT OGS_DIR_SEPARATOR_S
"configs" OGS_DIR_SEPARATOR_S, name);
argv_out[argc_out++] = "-c";
argv_out[argc_out++] = conf_file;
argv_out[argc_out] = NULL;
}
/* buildroot/src/open5gs-main */
argv_out[0] = MESON_BUILD_ROOT OGS_DIR_SEPARATOR_S
"src" OGS_DIR_SEPARATOR_S "open5gs-main";
rv = abts_main(argc_out, argv_out, new_argv);
ogs_assert(rv == OGS_OK);
(*init)(new_argv);
}
void test_epc_run(int argc, const char *const argv[],
const char *name, void (*init)(const char * const argv[]))
{
ogs_diam_logger_register(test_diam_logger_handler);
test_app_run(argc, argv, name, init);
while(1) {
if (connected_count == 1) break;
ogs_msleep(50);
}
ogs_msleep(500); /* Wait for listening all sockets */
}
void test_5gc_run(int argc, const char *const argv[],
const char *name, void (*init)(const char * const argv[]))
{
int rv;
test_app_run(argc, argv, name, init);
test_context_init();
rv = test_context_parse_config();
ogs_assert(rv == OGS_OK);
ogs_msleep(500); /* Wait for listening all sockets */
}
#define MAX_CHILD_PROCESS 8
#define OGS_ARG_MAX 256
static ogs_proc_t process[MAX_CHILD_PROCESS];
static int process_num = 0;
static void child_main(void *data)
{
const char **commandLine = data;
ogs_proc_t *current = NULL;
FILE *out = NULL;
char buf[OGS_HUGE_LEN];
int ret = 0, out_return_code = 0;;
current = &process[process_num++];
ret = ogs_proc_create(commandLine,
ogs_proc_option_combined_stdout_stderr|
ogs_proc_option_inherit_environment,
current);
ogs_assert(ret == 0);
out = ogs_proc_stdout(current);
ogs_assert(out);
while(fgets(buf, OGS_HUGE_LEN, out)) {
printf("%s", buf);
}
ret = ogs_proc_join(current, &out_return_code);
ogs_assert(ret == 0);
ogs_assert(out_return_code == 0);
ret = ogs_proc_destroy(current);
ogs_assert(ret == 0);
}
ogs_thread_t *test_child_create(const char *name, const char *const argv[])
{
ogs_thread_t *child = NULL;
const char *commandLine[OGS_ARG_MAX];
int i = 0;
char command[OGS_MAX_FILEPATH_LEN];
while(argv[i] && i < 32) {
commandLine[i] = argv[i];
i++;
}
commandLine[i] = NULL;
/* buildroot/src/mme/open5gs-mmed */
ogs_snprintf(command, sizeof command, "%s%s%s%sd",
MESON_BUILD_ROOT OGS_DIR_SEPARATOR_S "src" OGS_DIR_SEPARATOR_S,
name, OGS_DIR_SEPARATOR_S "open5gs-", name);
commandLine[0] = command;
child = ogs_thread_create(child_main, commandLine);
ogs_msleep(50);
return child;
}
void test_child_terminate(void)
{
int i;
ogs_proc_t *current = NULL;
for (i = 0; i < process_num; i++) {
current = &process[i];
ogs_proc_terminate(current);
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if !defined(OGS_TEST_INSIDE) && !defined(OGS_TEST_COMPILATION)
#error "This header cannot be included directly."
#endif
#ifndef TEST_COMMON_APPLICATION_H
#define TEST_COMMON_APPLICATION_H
#ifdef __cplusplus
extern "C" {
#endif
void test_epc_run(int argc, const char *const argv[],
const char *name, void (*init)(const char * const argv[]));
void test_5gc_run(int argc, const char *const argv[],
const char *name, void (*init)(const char * const argv[]));
void test_child_terminate(void);
ogs_thread_t *test_child_create(const char *name, const char *const argv[]);
#ifdef __cplusplus
}
#endif
#endif /* TEST_COMMON_APPLICATION_H */

451
tests/common/context.c Normal file
View File

@ -0,0 +1,451 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "test-config-private.h"
#include "test-common.h"
static test_context_t self;
static int context_initialized = 0;
void test_context_init(void)
{
ogs_assert(context_initialized == 0);
/* Initialize AMF context */
memset(&self, 0, sizeof(test_context_t));
context_initialized = 1;
}
void test_context_final(void)
{
ogs_assert(context_initialized == 1);
context_initialized = 0;
}
test_context_t *test_self(void)
{
return &self;
}
static int test_context_prepare(void)
{
return OGS_OK;
}
static int test_context_validation(void)
{
return OGS_OK;
}
int test_context_parse_config(void)
{
int rv;
yaml_document_t *document = NULL;
ogs_yaml_iter_t root_iter;
document = ogs_config()->document;
ogs_assert(document);
rv = test_context_prepare();
if (rv != OGS_OK) return rv;
ogs_yaml_iter_init(&root_iter, document);
while (ogs_yaml_iter_next(&root_iter)) {
const char *root_key = ogs_yaml_iter_key(&root_iter);
ogs_assert(root_key);
if (!strcmp(root_key, "amf")) {
ogs_yaml_iter_t amf_iter;
ogs_yaml_iter_recurse(&root_iter, &amf_iter);
while (ogs_yaml_iter_next(&amf_iter)) {
const char *amf_key = ogs_yaml_iter_key(&amf_iter);
ogs_assert(amf_key);
if (!strcmp(amf_key, "guami")) {
ogs_yaml_iter_t guami_array, guami_iter;
ogs_yaml_iter_recurse(&amf_iter, &guami_array);
do {
const char *mcc = NULL, *mnc = NULL;
const char *region = NULL, *set = NULL;
const char *pointer = NULL;
ogs_assert(self.num_of_served_guami <=
MAX_NUM_OF_SERVED_GUAMI);
if (ogs_yaml_iter_type(&guami_array) ==
YAML_MAPPING_NODE) {
memcpy(&guami_iter, &guami_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&guami_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&guami_array))
break;
ogs_yaml_iter_recurse(&guami_array,
&guami_iter);
} else if (ogs_yaml_iter_type(&guami_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&guami_iter)) {
const char *guami_key =
ogs_yaml_iter_key(&guami_iter);
ogs_assert(guami_key);
if (!strcmp(guami_key, "plmn_id")) {
ogs_yaml_iter_t plmn_id_iter;
ogs_yaml_iter_recurse(&guami_iter,
&plmn_id_iter);
while (ogs_yaml_iter_next(&plmn_id_iter)) {
const char *plmn_id_key =
ogs_yaml_iter_key(&plmn_id_iter);
ogs_assert(plmn_id_key);
if (!strcmp(plmn_id_key, "mcc")) {
mcc = ogs_yaml_iter_value(
&plmn_id_iter);
} else if (!strcmp(plmn_id_key, "mnc")) {
mnc = ogs_yaml_iter_value(
&plmn_id_iter);
}
}
if (mcc && mnc) {
ogs_plmn_id_build(
&self.served_guami[
self.num_of_served_guami].
plmn_id,
atoi(mcc), atoi(mnc), strlen(mnc));
}
} else if (!strcmp(guami_key, "amf_id")) {
ogs_yaml_iter_t amf_id_iter;
ogs_yaml_iter_recurse(&guami_iter,
&amf_id_iter);
while (ogs_yaml_iter_next(&amf_id_iter)) {
const char *amf_id_key =
ogs_yaml_iter_key(&amf_id_iter);
ogs_assert(amf_id_key);
if (!strcmp(amf_id_key, "region")) {
region = ogs_yaml_iter_value(
&amf_id_iter);
} else if (!strcmp(amf_id_key, "set")) {
set = ogs_yaml_iter_value(
&amf_id_iter);
} else if (!strcmp(amf_id_key, "pointer")) {
pointer = ogs_yaml_iter_value(
&amf_id_iter);
}
}
if (region && set) {
ogs_amf_id_build(
&self.served_guami[
self.num_of_served_guami].
amf_id,
atoi(region), atoi(set),
pointer ? atoi(pointer) : 0);
}
} else
ogs_warn("unknown key `%s`", guami_key);
}
if (mnc && mcc && region && set) {
self.num_of_served_guami++;
} else {
ogs_warn("Ignore guami : "
"mcc(%s), mnc(%s), region(%s), set(%s)",
mcc, mnc, region, set);
}
} while (ogs_yaml_iter_type(&guami_array) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(amf_key, "tai")) {
int num_of_list0 = 0;
ogs_5gs_tai0_list_t *list0 = NULL;
ogs_5gs_tai2_list_t *list2 = NULL;
ogs_assert(self.num_of_served_tai <=
OGS_MAX_NUM_OF_SERVED_TAI);
list0 = &self.served_tai[self.num_of_served_tai].list0;
ogs_assert(list0);
list2 = &self.served_tai[self.num_of_served_tai].list2;
ogs_assert(list2);
ogs_yaml_iter_t tai_array, tai_iter;
ogs_yaml_iter_recurse(&amf_iter, &tai_array);
do {
const char *mcc = NULL, *mnc = NULL;
ogs_uint24_t tac[OGS_MAX_NUM_OF_TAI];
int num_of_tac = 0;
if (ogs_yaml_iter_type(&tai_array) ==
YAML_MAPPING_NODE) {
memcpy(&tai_iter, &tai_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&tai_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&tai_array))
break;
ogs_yaml_iter_recurse(&tai_array,
&tai_iter);
} else if (ogs_yaml_iter_type(&tai_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&tai_iter)) {
const char *tai_key = ogs_yaml_iter_key(&tai_iter);
ogs_assert(tai_key);
if (!strcmp(tai_key, "plmn_id")) {
ogs_yaml_iter_t plmn_id_iter;
ogs_yaml_iter_recurse(&tai_iter, &plmn_id_iter);
while (ogs_yaml_iter_next(&plmn_id_iter)) {
const char *plmn_id_key =
ogs_yaml_iter_key(&plmn_id_iter);
ogs_assert(plmn_id_key);
if (!strcmp(plmn_id_key, "mcc")) {
mcc = ogs_yaml_iter_value(
&plmn_id_iter);
} else if (!strcmp(plmn_id_key, "mnc")) {
mnc = ogs_yaml_iter_value(
&plmn_id_iter);
}
}
} else if (!strcmp(tai_key, "tac")) {
ogs_yaml_iter_t tac_iter;
ogs_yaml_iter_recurse(&tai_iter, &tac_iter);
ogs_assert(ogs_yaml_iter_type(&tac_iter) !=
YAML_MAPPING_NODE);
do {
const char *v = NULL;
ogs_assert(num_of_tac <=
OGS_MAX_NUM_OF_TAI);
if (ogs_yaml_iter_type(&tac_iter) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&tac_iter))
break;
}
v = ogs_yaml_iter_value(&tac_iter);
if (v) {
tac[num_of_tac].v = atoi(v);
num_of_tac++;
}
} while (
ogs_yaml_iter_type(&tac_iter) ==
YAML_SEQUENCE_NODE);
} else
ogs_warn("unknown key `%s`", tai_key);
}
if (mcc && mnc && num_of_tac) {
if (num_of_tac == 1) {
ogs_plmn_id_build(
&list2->tai[list2->num].plmn_id,
atoi(mcc), atoi(mnc), strlen(mnc));
list2->tai[list2->num].tac.v = tac[0].v;
list2->num++;
if (list2->num > 1)
list2->type = OGS_TAI2_TYPE;
else
list2->type = OGS_TAI1_TYPE;
} else if (num_of_tac > 1) {
int i;
ogs_plmn_id_build(
&list0->tai[num_of_list0].plmn_id,
atoi(mcc), atoi(mnc), strlen(mnc));
for (i = 0; i < num_of_tac; i++) {
list0->tai[num_of_list0].tac[i].v =
tac[i].v;
}
list0->tai[num_of_list0].num = num_of_tac;
list0->tai[num_of_list0].type = OGS_TAI0_TYPE;
num_of_list0++;
}
} else {
ogs_warn("Ignore tai : mcc(%p), mnc(%p), "
"num_of_tac(%d)", mcc, mnc, num_of_tac);
}
} while (ogs_yaml_iter_type(&tai_array) ==
YAML_SEQUENCE_NODE);
if (list2->num || num_of_list0) {
self.num_of_served_tai++;
}
} else if (!strcmp(amf_key, "plmn")) {
ogs_yaml_iter_t plmn_array, plmn_iter;
ogs_yaml_iter_recurse(&amf_iter, &plmn_array);
do {
const char *mnc = NULL, *mcc = NULL;
ogs_assert(self.num_of_plmn_support <=
OGS_MAX_NUM_OF_PLMN);
if (ogs_yaml_iter_type(&plmn_array) ==
YAML_MAPPING_NODE) {
memcpy(&plmn_iter, &plmn_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(&plmn_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&plmn_array))
break;
ogs_yaml_iter_recurse(&plmn_array,
&plmn_iter);
} else if (ogs_yaml_iter_type(&plmn_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&plmn_iter)) {
const char *plmn_key =
ogs_yaml_iter_key(&plmn_iter);
ogs_assert(plmn_key);
if (!strcmp(plmn_key, "plmn_id")) {
ogs_yaml_iter_t plmn_id_iter;
ogs_yaml_iter_recurse(&plmn_iter,
&plmn_id_iter);
while (ogs_yaml_iter_next(&plmn_id_iter)) {
const char *plmn_id_key =
ogs_yaml_iter_key(&plmn_id_iter);
ogs_assert(plmn_id_key);
if (!strcmp(plmn_id_key, "mcc")) {
mcc = ogs_yaml_iter_value(
&plmn_id_iter);
} else if (!strcmp(plmn_id_key, "mnc")) {
mnc = ogs_yaml_iter_value(
&plmn_id_iter);
}
}
if (mcc && mnc) {
ogs_plmn_id_build(
&self.plmn_support[
self.num_of_plmn_support].
plmn_id,
atoi(mcc), atoi(mnc), strlen(mnc));
}
} else if (!strcmp(plmn_key, "s_nssai")) {
ogs_yaml_iter_t s_nssai_array, s_nssai_iter;
ogs_yaml_iter_recurse(&plmn_iter,
&s_nssai_array);
do {
ogs_s_nssai_t *s_nssai = NULL;
const char *sst = NULL, *sd = NULL;
ogs_assert(
self.plmn_support[
self.num_of_plmn_support].
num_of_s_nssai <=
OGS_MAX_NUM_OF_S_NSSAI);
s_nssai = &self.plmn_support[
self.num_of_plmn_support].s_nssai[
self.plmn_support[
self.num_of_plmn_support].
num_of_s_nssai];
ogs_assert(s_nssai);
if (ogs_yaml_iter_type(&s_nssai_array) ==
YAML_MAPPING_NODE) {
memcpy(&s_nssai_iter, &s_nssai_array,
sizeof(ogs_yaml_iter_t));
} else if (ogs_yaml_iter_type(
&s_nssai_array) ==
YAML_SEQUENCE_NODE) {
if (!ogs_yaml_iter_next(&s_nssai_array))
break;
ogs_yaml_iter_recurse(&s_nssai_array,
&s_nssai_iter);
} else if (ogs_yaml_iter_type(
&s_nssai_array) ==
YAML_SCALAR_NODE) {
break;
} else
ogs_assert_if_reached();
while (ogs_yaml_iter_next(&s_nssai_iter)) {
const char *s_nssai_key =
ogs_yaml_iter_key(&s_nssai_iter);
ogs_assert(s_nssai_key);
if (!strcmp(s_nssai_key, "sst")) {
sst = ogs_yaml_iter_value(
&s_nssai_iter);
} else if (!strcmp(
s_nssai_key, "sd")) {
sd = ogs_yaml_iter_value(
&s_nssai_iter);
}
}
if (sst) {
s_nssai->sst = atoi(sst);
if (sd) {
s_nssai->sd =
ogs_uint24_from_string(
(char*)sd);
} else {
s_nssai->sd.v =
OGS_S_NSSAI_NO_SD_VALUE;
}
self.plmn_support[
self.num_of_plmn_support].
num_of_s_nssai++;
}
} while (ogs_yaml_iter_type(&s_nssai_array) ==
YAML_SEQUENCE_NODE);
} else
ogs_warn("unknown key `%s`", plmn_key);
}
if (self.plmn_support[
self.num_of_plmn_support].num_of_s_nssai &&
mcc && mnc) {
self.num_of_plmn_support++;
} else {
ogs_warn("Ignore plmn : "
"s_nssai(%d) mcc(%s), mnc(%s)",
self.plmn_support[
self.num_of_plmn_support].num_of_s_nssai,
mcc, mnc);
self.plmn_support[
self.num_of_plmn_support].num_of_s_nssai = 0;
}
} while (ogs_yaml_iter_type(&plmn_array) ==
YAML_SEQUENCE_NODE);
} else if (!strcmp(amf_key, "sbi")) {
/* handle config in sbi library */
} else
ogs_warn("unknown key `%s`", amf_key);
}
}
}
rv = test_context_validation();
if (rv != OGS_OK) return rv;
return OGS_OK;
}

68
tests/common/context.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if !defined(OGS_TEST_INSIDE) && !defined(OGS_TEST_COMPILATION)
#error "This header cannot be included directly."
#endif
#ifndef TEST_COMMON_CONTEXT_H
#define TEST_COMMON_CONTEXT_H
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_NUM_OF_SERVED_GUAMI 8
typedef struct test_context_s {
/* Served GUMME */
uint8_t num_of_served_guami;
struct {
ogs_plmn_id_t plmn_id;
ogs_amf_id_t amf_id;
} served_guami[MAX_NUM_OF_SERVED_GUAMI];
/* Served TAI */
uint8_t num_of_served_tai;
struct {
ogs_5gs_tai0_list_t list0;
ogs_5gs_tai2_list_t list2;
} served_tai[OGS_MAX_NUM_OF_SERVED_TAI];
/* PLMN Support */
uint8_t num_of_plmn_support;
struct {
ogs_plmn_id_t plmn_id;
int num_of_s_nssai;
ogs_s_nssai_t s_nssai[OGS_MAX_NUM_OF_S_NSSAI];
} plmn_support[OGS_MAX_NUM_OF_PLMN];
} test_context_t;
void test_context_init(void);
void test_context_final(void);
test_context_t *test_self(void);
int test_context_parse_config(void);
#ifdef __cplusplus
}
#endif
#endif /* TEST_COMMON_CONTEXT_H */

69
tests/common/gtpu.c Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "test-common.h"
ogs_socknode_t *test_gtpu_server(const char *ipstr, int port)
{
int rv;
ogs_sockaddr_t *addr = NULL;
ogs_socknode_t *node = NULL;
ogs_sock_t *sock = NULL;
rv = ogs_getaddrinfo(&addr, AF_UNSPEC, ipstr, port, 0);
ogs_assert(rv == OGS_OK);
node = ogs_socknode_new(addr);
ogs_assert(node);
sock = ogs_udp_server(node);
ogs_assert(sock);
return node;
}
ogs_pkbuf_t *test_gtpu_read(ogs_socknode_t *node)
{
int rc = 0;
ogs_pkbuf_t *recvbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN);
ogs_assert(node);
ogs_assert(node->sock);
while (1) {
rc = ogs_recv(node->sock->fd, recvbuf->data, recvbuf->len, 0);
if (rc <= 0) {
if (errno == EAGAIN) {
continue;
}
break;
} else {
break;
}
}
recvbuf->len = rc;
return recvbuf;
}
void test_gtpu_close(ogs_socknode_t *node)
{
ogs_socknode_free(node);
}

35
tests/common/gtpu.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef TEST_COMMON_GTPU_H
#define TEST_COMMON_GTPU_H
#ifdef __cplusplus
extern "C" {
#endif
ogs_socknode_t *test_gtpu_server(const char *ipstr, int port);
ogs_pkbuf_t *test_gtpu_read(ogs_socknode_t *node);
void test_gtpu_close(ogs_socknode_t *node);
#ifdef __cplusplus
}
#endif
#endif /* TEST_COMMON_GTPU_H */

58
tests/common/meson.build Normal file
View File

@ -0,0 +1,58 @@
# Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
# This file is part of Open5GS.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
libtestcommon_conf = configuration_data()
libtestcommon_conf.set_quoted('MESON_BUILD_ROOT', meson.build_root())
configure_file(output : 'test-config-private.h',
configuration : libtestcommon_conf)
libtestcommon_sources = files('''
sctp.c
gtpu.c
context.c
application.c
ngap-build.c
'''.split())
libtestcommon_inc = include_directories('.')
libtestcommon = static_library('testcomon',
sources : libtestcommon_sources,
c_args : testcore_cc_flags,
include_directories : [libtestcommon_inc, testinc],
dependencies : [libcore_dep,
libapp_dep,
libdbi_dep,
libsctp_dep,
libngap_dep,
libnas_eps_dep,
libnas_5gs_dep,
libdiameter_common_dep],
install : false)
libtestcommon_dep = declare_dependency(
link_with : libtestcommon,
include_directories : [libtestcommon_inc, testinc],
dependencies : [libcore_dep,
libapp_dep,
libdbi_dep,
libsctp_dep,
libngap_dep,
libnas_eps_dep,
libnas_5gs_dep,
libdiameter_common_dep])

Some files were not shown because too many files have changed in this diff Show More