Merge branch 'main' into home-routed

This commit is contained in:
Sukchan Lee 2025-04-06 18:36:57 +09:00
parent 90afca821b
commit 46f74c8019
119 changed files with 2772 additions and 656 deletions

335
configs/attach.yaml.in Normal file
View file

@ -0,0 +1,335 @@
db_uri: mongodb://localhost/open5gs
logger:
test:
serving:
- plmn_id:
mcc: 999
mnc: 70
global:
parameter:
# no_nrf: true
# no_scp: true
no_sepp: true
# no_amf: true
# no_smf: true
# no_upf: true
# no_ausf: true
# no_udm: true
# no_pcf: true
# no_nssf: true
# no_bsf: true
# no_udr: true
# no_mme: true
# no_sgwc: true
# no_sgwu: true
# no_pcrf: true
# no_hss: true
mme:
freeDiameter:
identity: mme.localdomain
realm: localdomain
listen_on: 127.0.0.2
no_fwd: true
load_extension:
- module: @build_subprojects_freeDiameter_extensions_dir@/dbg_msg_dumps.fdx
conf: 0x8888
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_rfc5777.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_mip6i.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nasreq.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nas_mipv6.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca_3gpp/dict_dcca_3gpp.fdx
connect:
- identity: hss.localdomain
address: 127.0.0.8
s1ap:
server:
- address: 127.0.0.2
gtpc:
server:
- address: 127.0.0.2
client:
sgwc:
- address: 127.0.0.3
smf:
- address: 127.0.0.4
metrics:
server:
- address: 127.0.0.2
port: 9090
gummei:
- plmn_id:
mcc: 999
mnc: 70
mme_gid: 2
mme_code: 1
tai:
- plmn_id:
mcc: 999
mnc: 70
tac: 1
security:
integrity_order : [ EIA2, EIA1, EIA0 ]
ciphering_order : [ EEA0, EEA1, EEA2 ]
network_name:
full: Open5GS
time:
t3412:
value: 540
sgwc:
gtpc:
server:
- address: 127.0.0.3
pfcp:
server:
- address: 127.0.0.3
client:
sgwu:
- address: 127.0.0.6
smf:
# sbi:
# server:
# - address: 127.0.0.4
# port: 7777
# client:
# scp:
# - uri: http://127.0.0.200:7777
pfcp:
server:
- address: 127.0.0.4
client:
upf:
- address: 127.0.0.7
gtpc:
server:
- address: 127.0.0.4
gtpu:
server:
- address: 127.0.0.4
metrics:
server:
- address: 127.0.0.4
port: 9090
session:
- subnet: 10.45.0.0/16
gateway: 10.45.0.1
- subnet: 2001:db8:cafe::/48
gateway: 2001:db8:cafe::1
dns:
- 8.8.8.8
- 8.8.4.4
- 2001:4860:4860::8888
- 2001:4860:4860::8844
mtu: 1400
freeDiameter:
identity: smf.localdomain
realm: localdomain
listen_on: 127.0.0.4
no_fwd: true
load_extension:
- module: @build_subprojects_freeDiameter_extensions_dir@/dbg_msg_dumps.fdx
conf: 0x8888
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_rfc5777.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_mip6i.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nasreq.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nas_mipv6.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca_3gpp/dict_dcca_3gpp.fdx
connect:
- identity: pcrf.localdomain
address: 127.0.0.9
amf:
sbi:
server:
- address: 127.0.0.5
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
ngap:
server:
- address: 127.0.0.5
metrics:
server:
- address: 127.0.0.5
port: 9090
guami:
- plmn_id:
mcc: 999
mnc: 70
amf_id:
region: 2
set: 1
tai:
- plmn_id:
mcc: 999
mnc: 70
tac: 1
plmn_support:
- plmn_id:
mcc: 999
mnc: 70
s_nssai:
- sst: 1
security:
integrity_order : [ NIA2, NIA1, NIA0 ]
ciphering_order : [ NEA0, NEA1, NEA2 ]
network_name:
full: Open5GS
amf_name: open5gs-amf0
time:
t3512:
value: 540 # 9 mintues * 60 = 540 seconds
sgwu:
pfcp:
server:
- address: 127.0.0.6
gtpu:
server:
- address: 127.0.0.6
upf:
pfcp:
server:
- address: 127.0.0.7
gtpu:
server:
- address: 127.0.0.7
session:
- subnet: 10.45.0.0/16
gateway: 10.45.0.1
- subnet: 2001:db8:cafe::/48
gateway: 2001:db8:cafe::1
metrics:
server:
- address: 127.0.0.7
port: 9090
hss:
freeDiameter:
identity: hss.localdomain
realm: localdomain
listen_on: 127.0.0.8
no_fwd: true
load_extension:
- module: @build_subprojects_freeDiameter_extensions_dir@/dbg_msg_dumps.fdx
conf: 0x8888
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_rfc5777.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_mip6i.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nasreq.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nas_mipv6.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca_3gpp/dict_dcca_3gpp.fdx
connect:
- identity: mme.localdomain
address: 127.0.0.2
pcrf:
freeDiameter:
identity: pcrf.localdomain
realm: localdomain
listen_on: 127.0.0.9
no_fwd: true
load_extension:
- module: @build_subprojects_freeDiameter_extensions_dir@/dbg_msg_dumps.fdx
conf: 0x8888
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_rfc5777.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_mip6i.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nasreq.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_nas_mipv6.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca.fdx
- module: @build_subprojects_freeDiameter_extensions_dir@/dict_dcca_3gpp/dict_dcca_3gpp.fdx
connect:
- identity: smf.localdomain
address: 127.0.0.4
nrf:
sbi:
server:
- address: 127.0.0.10
port: 7777
scp:
sbi:
server:
- address: 127.0.0.200
port: 7777
client:
nrf:
- uri: http://127.0.0.10:7777
ausf:
sbi:
server:
- address: 127.0.0.11
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
udm:
hnet:
- id: 1
scheme: 1
key: @build_configs_dir@/open5gs/hnet/curve25519-1.key
- id: 2
scheme: 2
key: @build_configs_dir@/open5gs/hnet/secp256r1-2.key
sbi:
server:
- address: 127.0.0.12
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
pcf:
sbi:
server:
- address: 127.0.0.13
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
metrics:
server:
- address: 127.0.0.13
port: 9090
nssf:
sbi:
server:
- address: 127.0.0.14
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
nsi:
- uri: http://127.0.0.10:7777
s_nssai:
sst: 1
bsf:
sbi:
server:
- address: 127.0.0.15
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777
udr:
sbi:
server:
- address: 127.0.0.20
port: 7777
client:
scp:
- uri: http://127.0.0.200:7777

View file

@ -32,6 +32,7 @@ conf_data.set('build_subprojects_freeDiameter_extensions_dir',
example_conf = '''
sample.yaml
attach.yaml
310014.yaml
csfb.yaml
volte.yaml

36
debian/changelog vendored
View file

@ -1,3 +1,39 @@
open5gs (2.7.5) unstable; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Sun, 30 Mar 2025 22:01:17 +0900
open5gs (2.7.5~oracular) oracular; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Sun, 30 Mar 2025 22:00:22 +0900
open5gs (2.7.5~noble) noble; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Sun, 30 Mar 2025 21:59:27 +0900
open5gs (2.7.5~jammy) jammy; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Sun, 30 Mar 2025 21:58:02 +0900
open5gs (2.7.5~focal) focal; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Sun, 30 Mar 2025 21:56:59 +0900
open5gs (2.7.5~bionic) bionic; urgency=medium
* Bug Fixed
-- Sukchan Lee <acetcom@gmail.com> Sun, 30 Mar 2025 21:55:48 +0900
open5gs (2.7.2) unstable; urgency=medium
* Bug Fixed

View file

@ -80,14 +80,14 @@ Import the public key used by the package management system.
```bash
$ sudo apt update
$ sudo apt install gnupg
$ curl -fsSL https://pgp.mongodb.com/server-6.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg --dearmor
$ curl -fsSL https://pgp.mongodb.com/server-8.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
```
Create the list file /etc/apt/sources.list.d/mongodb-org-6.0.list for your version of Ubuntu.
Create the list file /etc/apt/sources.list.d/mongodb-org-8.0.list for your version of Ubuntu.
On ubuntu 22.04 (Jammy)
```bash
$ echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
$ echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
```
Install the MongoDB packages.

View file

@ -18,14 +18,14 @@ Import the public key used by the package management system.
```bash
$ sudo apt update
$ sudo apt install gnupg
$ curl -fsSL https://pgp.mongodb.com/server-6.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg --dearmor
$ curl -fsSL https://pgp.mongodb.com/server-8.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
```
Create the list file /etc/apt/sources.list.d/mongodb-org-6.0.list for your version of Ubuntu.
Create the list file /etc/apt/sources.list.d/mongodb-org-8.0.list for your version of Ubuntu.
On ubuntu 22.04 (Jammy)
```bash
$ echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
$ echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
```
Install the MongoDB packages.

View file

@ -55,6 +55,7 @@ If you have tested radio hardware from a vendor not listed with Open5GS, please
* Nokia FW2FA Flexi Zone Mini-Macro Outdoor BTS, 2x20w Band 39
* Nokia FWGR Flexi Zone Mini-Macro Outdoor BTS, 2x20w Band 1
* Nokia FWHG Flexi Zone Indoor Pico BTS, 2x250 mW Band 7
* Nokia FW2HHD Flexi Zone Multiband Indoor Pico BTS, Band 38/41(S/W TLS18SP_ENB)
* Ruckus Q710 and Q910
### 4G/5G Software Stacks + SDRs

View file

@ -165,8 +165,8 @@ $ make test
The Open5GS package is available on the recent versions of *Ubuntu*.
```bash
# Install the MongoDB Packages
$ curl -fsSL https://pgp.mongodb.com/server-6.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg --dearmor
$ echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
$ curl -fsSL https://pgp.mongodb.com/server-8.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
$ echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
$ sudo apt update
$ sudo apt install mongodb-org

View file

@ -0,0 +1,50 @@
---
title: "v2.7.5 - Bug fixed"
date: 2025-03-30 22:05:00 +0900
categories:
- Release
tags:
- News
- Release
head_inline: "<style> ul { padding-bottom: 1em; } .blue { color: blue; }</style>"
---
# Open5GS Release Note Summary
This release introduces numerous improvements and bug fixes across core network components, enhancing overall stability, performance, and security. Below is a concise overview of the key updates:
## Session & Subscription Management
- **SMF Enhancements:**
Improved handling of SDM subscriptions to UDM during the PDU session lifetime.
- **Optional PLMN-ID:**
Added support for an optional PLMN-ID parameter in SDM GET queries (AMF/SMF).
- **5GMM Cause Reporting:**
AMF now sends a 5GMM cause in the request to SMF when initiating a session release.
## Mobility & Authentication Improvements
- **Mobility Fixes:**
Corrected QoS values for 2G to 4G mobility and fixed issues with UE context release and cell reselection.
- **Security & Authentication:**
Enhanced UE authentication processes, prevented crashes during security mode command failures, and implemented HSS selection improvements.
## Interface & Protocol Enhancements
- **Diameter & PFCP:**
- Integrated statistics into the main loop for Diameter interfaces, with enhanced debug logging for HSS and PCRF.
- Addressed multiple PFCP issues, including memory management, header handling, and correct TEID restoration.
- **NAS Module:**
Fixed a heap-buffer overflow vulnerability in NAS message decoding.
## SBI and Other Module Updates
- **SBI Enhancements:**
Enabled custom User-Agent header information for HTTP/2 requests, support for custom port numbers, and direct NRF communication.
- **Additional Fixes:**
- Resolved UE context handling issues during handovers and state transitions.
- Implemented various cosmetic fixes, typo corrections, and documentation updates.
- Introduced support for new parameters and refined subscription conditions.
Overall, this release emphasizes improved network reliability, enhanced security measures, and better support for 5G core operations while also addressing legacy issues.
See [Release Note](https://github.com/open5gs/open5gs/releases/tag/v2.7.5)
Download -- [v2.7.5.tar.gz](https://github.com/open5gs/open5gs/archive/v2.7.5.tar.gz)
{: .notice--info}

View file

@ -1310,7 +1310,7 @@ ogs_app_policy_conf_t *ogs_app_policy_conf_add(
}
ogs_app_policy_conf_t *ogs_app_policy_conf_find(
char *supi, ogs_plmn_id_t *plmn_id)
const char *supi, const ogs_plmn_id_t *plmn_id)
{
ogs_app_policy_conf_t *policy_conf;
int i;
@ -1386,7 +1386,7 @@ void ogs_app_policy_conf_remove_all(void)
}
ogs_app_slice_conf_t *ogs_app_slice_conf_add(
ogs_app_policy_conf_t *policy_conf, ogs_s_nssai_t *s_nssai)
ogs_app_policy_conf_t *policy_conf, const ogs_s_nssai_t *s_nssai)
{
ogs_app_slice_conf_t *slice_conf = NULL;
@ -1416,7 +1416,7 @@ ogs_app_slice_conf_t *ogs_app_slice_conf_add(
}
ogs_app_slice_conf_t *ogs_app_slice_conf_find_by_s_nssai(
ogs_app_policy_conf_t *policy_conf, ogs_s_nssai_t *s_nssai)
ogs_app_policy_conf_t *policy_conf, const ogs_s_nssai_t *s_nssai)
{
ogs_app_slice_conf_t *slice_conf = NULL;
@ -1486,7 +1486,7 @@ int ogs_app_check_policy_conf(void)
}
ogs_app_session_conf_t *ogs_app_session_conf_add(
ogs_app_slice_conf_t *slice_conf, char *name)
ogs_app_slice_conf_t *slice_conf, const char *name)
{
ogs_app_session_conf_t *session_conf = NULL;
@ -1518,7 +1518,7 @@ ogs_app_session_conf_t *ogs_app_session_conf_add(
return session_conf;
}
ogs_app_session_conf_t *ogs_app_session_conf_find_by_dnn(
ogs_app_slice_conf_t *slice_conf, char *name)
ogs_app_slice_conf_t *slice_conf, const char *name)
{
ogs_app_session_conf_t *session_conf = NULL;
@ -1561,7 +1561,8 @@ void ogs_app_session_conf_remove_all(ogs_app_slice_conf_t *slice_conf)
}
int ogs_app_config_session_data(
char *supi, ogs_plmn_id_t *plmn_id, ogs_s_nssai_t *s_nssai, char *dnn,
const char *supi, const ogs_plmn_id_t *plmn_id,
const ogs_s_nssai_t *s_nssai, const char *dnn,
ogs_session_data_t *session_data)
{
ogs_app_policy_conf_t *policy_conf = NULL;

View file

@ -208,27 +208,28 @@ int ogs_app_parse_session_conf(
ogs_app_policy_conf_t *ogs_app_policy_conf_add(
ogs_supi_range_t *supi_range, ogs_plmn_id_t *plmn_id);
ogs_app_policy_conf_t *ogs_app_policy_conf_find(
char *supi, ogs_plmn_id_t *plmn_id);
const char *supi, const ogs_plmn_id_t *plmn_id);
void ogs_app_policy_conf_remove(ogs_app_policy_conf_t *policy_conf);
void ogs_app_policy_conf_remove_all(void);
ogs_app_slice_conf_t *ogs_app_slice_conf_add(
ogs_app_policy_conf_t *policy_conf, ogs_s_nssai_t *s_nssai);
ogs_app_policy_conf_t *policy_conf, const ogs_s_nssai_t *s_nssai);
ogs_app_slice_conf_t *ogs_app_slice_conf_find_by_s_nssai(
ogs_app_policy_conf_t *policy_conf, ogs_s_nssai_t *s_nssai);
ogs_app_policy_conf_t *policy_conf, const ogs_s_nssai_t *s_nssai);
void ogs_app_slice_conf_remove(ogs_app_slice_conf_t *slice_conf);
void ogs_app_slice_conf_remove_all(ogs_app_policy_conf_t *policy_conf);
ogs_app_session_conf_t *ogs_app_session_conf_add(
ogs_app_slice_conf_t *slice_conf, char *name);
ogs_app_slice_conf_t *slice_conf, const char *name);
ogs_app_session_conf_t *ogs_app_session_conf_find_by_dnn(
ogs_app_slice_conf_t *slice_conf, char *name);
ogs_app_slice_conf_t *slice_conf, const char *name);
void ogs_app_session_conf_remove(ogs_app_session_conf_t *session_conf);
void ogs_app_session_conf_remove_all(
ogs_app_slice_conf_t *slice_conf);
int ogs_app_config_session_data(
char *supi, ogs_plmn_id_t *plmn_id, ogs_s_nssai_t *s_nssai, char *dnn,
const char *supi, const ogs_plmn_id_t *plmn_id,
const ogs_s_nssai_t *s_nssai, const char *dnn,
ogs_session_data_t *session_data);
#ifdef __cplusplus

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -232,22 +232,7 @@ static int epoll_process(ogs_pollset_t *pollset, ogs_time_t timeout)
received = context->event_list[i].events;
if (received & EPOLLERR) {
/*
* The libevent library has OGS_POLLOUT turned on in EPOLLERR.
*
* However, SIGPIPE can occur if write() is called
* when the peer connection is closed.
*
* Therefore, Open5GS turns off OGS_POLLOUT
* so that write() cannot be called in case of EPOLLERR.
*
* See also #2411 and #2312
*/
#if 0
when = OGS_POLLIN|OGS_POLLOUT;
#else
when = OGS_POLLIN;
#endif
} else if ((received & EPOLLHUP) && !(received & EPOLLRDHUP)) {
when = OGS_POLLIN|OGS_POLLOUT;
} else {

View file

@ -15,7 +15,7 @@
*/
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -277,9 +277,20 @@ static void remove_sync_sigs(sigset_t *sig_mask)
#ifdef SIGIOT
sigdelset(sig_mask, SIGIOT);
#endif
/*
* SIGPIPE can occur if write() is called when the peer connection is closed.
*
* Therefore, Open5GS ignore SIGPIE signal
*
* See also #2411 and #2312
*/
#if 0
#ifdef SIGPIPE
sigdelset(sig_mask, SIGPIPE);
#endif
#endif
#ifdef SIGSEGV
sigdelset(sig_mask, SIGSEGV);
#endif

View file

@ -19,7 +19,8 @@
#include "ogs-dbi.h"
int ogs_dbi_session_data(char *supi, ogs_s_nssai_t *s_nssai, char *dnn,
int ogs_dbi_session_data(
const char *supi, const ogs_s_nssai_t *s_nssai, const char *dnn,
ogs_session_data_t *session_data)
{
int rv = OGS_OK;

View file

@ -28,7 +28,8 @@
extern "C" {
#endif
int ogs_dbi_session_data(char *supi, ogs_s_nssai_t *s_nssai, char *dnn,
int ogs_dbi_session_data(
const char *supi, const ogs_s_nssai_t *s_nssai, const char *dnn,
ogs_session_data_t *session_data);
#ifdef __cplusplus

View file

@ -36,6 +36,7 @@ extern "C" {
#define OGS_DIAM_S6A_AVP_CODE_ALL_APN_CONFIG_INC_IND (1428)
#define OGS_DIAM_S6A_AVP_CODE_APN_CONFIGURATION (1430)
#define OGS_DIAM_S6A_AVP_CODE_MIP_HOME_AGENT_ADDRESS (334)
#define OGS_DIAM_S6A_AVP_CODE_MIP_HOME_AGENT_HOST (348)
#define OGS_DIAM_S6A_AVP_CODE_SERVED_PARTY_IP_ADDRESS (848)
#define OGS_DIAM_S6A_RAT_TYPE_WLAN 0

View file

@ -209,6 +209,7 @@ static _MHD_Result mhd_server_access_handler(void *cls, struct MHD_Connection *c
if (strcmp(url, "/metrics") == 0) {
buf = prom_collector_registry_bridge(PROM_COLLECTOR_REGISTRY_DEFAULT);
rsp = MHD_create_response_from_buffer(strlen(buf), (void *)buf, MHD_RESPMEM_MUST_FREE);
MHD_add_response_header(rsp, "Content-Type", "text/plain; version=0.0.4; charset=utf-8");
ret = MHD_queue_response(connection, MHD_HTTP_OK, rsp);
MHD_destroy_response(rsp);
return ret;

View file

@ -131,56 +131,66 @@ int ogs_nas_gprs_timer_3_from_sec(
gprs_timer->unit = OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_2_SS;
gprs_timer->value = timer_value / 2;
} else {
if (timer_value%60 != 0) {
ogs_error("Not multiples of 1 minute");
if (timer_value%30 != 0) {
ogs_error("Not multiples of 30 seconds");
return OGS_ERROR;
}
timer_value /= 60; /* multiples of 1 minute */
timer_value /= 30; /* multiples of 30 seconds */
if (timer_value <= 31) {
gprs_timer->unit = OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_1_MM;
gprs_timer->unit = OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_30_SS;
gprs_timer->value = timer_value;
} else {
if (timer_value%10 != 0) {
ogs_error("Not multiples of decihours(= 10 minutes)");
if (timer_value%2 != 0) {
ogs_error("Not multiples of 1 minute");
return OGS_ERROR;
}
timer_value /= 10; /* multiples of decihours = 10 mintues */
timer_value /= 2; /* multiples of 1 minute */
if (timer_value <= 31) {
gprs_timer->unit = OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_10_MM;
gprs_timer->unit = OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_1_MM;
gprs_timer->value = timer_value;
} else {
if (timer_value%6 != 0) {
ogs_error("Not multiples of 1 hour");
if (timer_value%10 != 0) {
ogs_error("Not multiples of decihours(= 10 minutes)");
return OGS_ERROR;
}
timer_value /= 6; /* multiples of 1 hour */
timer_value /= 10; /* multiples of decihours = 10 mintues */
if (timer_value <= 31) {
gprs_timer->unit =
OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_1_HH;
gprs_timer->unit = OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_10_MM;
gprs_timer->value = timer_value;
} else {
if (timer_value%10 != 0) {
ogs_error("Not multiples of 10 hours");
if (timer_value%6 != 0) {
ogs_error("Not multiples of 1 hour");
return OGS_ERROR;
}
timer_value /= 10; /* multiples of 10 hours */
timer_value /= 6; /* multiples of 1 hour */
if (timer_value <= 31) {
gprs_timer->unit =
OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_10_HH;
OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_1_HH;
gprs_timer->value = timer_value;
} else {
if (timer_value%32 != 0) {
if (timer_value%10 != 0) {
ogs_error("Not multiples of 10 hours");
return OGS_ERROR;
}
timer_value /= 32; /* multiples of 320 hours */
timer_value /= 10; /* multiples of 10 hours */
if (timer_value <= 31) {
gprs_timer->unit =
OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_320_HH;
OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_10_HH;
gprs_timer->value = timer_value;
} else {
ogs_error("Overflow!");
return OGS_ERROR;
if (timer_value%32 != 0) {
ogs_error("Not multiples of 10 hours");
return OGS_ERROR;
}
timer_value /= 32; /* multiples of 320 hours */
if (timer_value <= 31) {
gprs_timer->unit =
OGS_NAS_GPRS_TIMER_3_UNIT_MULTIPLES_OF_320_HH;
gprs_timer->value = timer_value;
} else {
ogs_error("Overflow!");
return OGS_ERROR;
}
}
}
}

View file

@ -1081,6 +1081,7 @@ int ogs_pfcp_node_merge(ogs_pfcp_node_t *node,
ogs_freeaddrinfo(node->addr_list);
node->addr_list = tmp_list;
node->last_dns_refresh = now;
node->current_addr = NULL;
tmp_list = NULL;
}
}
@ -1355,14 +1356,30 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
return pdr;
}
void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
int ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
{
int i = 0;
ogs_assert(pdr);
ogs_assert(pdr->f_teid_len > 0);
ogs_assert(!pdr->f_teid.ch);
ogs_assert(pdr->f_teid.teid > 0 &&
pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size);
/*
* Issues #3747, #3574
*
* This code validates the F-TEID (Fully encapsulated TEID) information
* element within a PDR structure before further processing the PFCP
* message. The validation ensures that the F-TEID is present and
* within acceptable limits defined by the system.
*/
if (pdr->f_teid.teid > 0 &&
pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size) {
/* PASS OK */
} else {
ogs_error("PDR-ID[%d] F-TEID LEN[%d] TEID[0x%x]",
pdr->id, pdr->f_teid_len, pdr->f_teid.teid);
return OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
}
/* Find out the Array Index for the restored TEID. */
i = pdr_random_to_index[pdr->f_teid.teid];
@ -1378,6 +1395,8 @@ void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
ogs_pfcp_pdr_teid_pool.array[i] = *(pdr->teid_node);
*(pdr->teid_node) = pdr->f_teid.teid;
}
return OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
}
void ogs_pfcp_object_teid_hash_set(
@ -2328,7 +2347,7 @@ ogs_pfcp_dev_t *ogs_pfcp_dev_add(const char *ifname)
ogs_assert(dev);
memset(dev, 0, sizeof *dev);
strcpy(dev->ifname, ifname);
ogs_cpystrn(dev->ifname, ifname, OGS_MAX_IFNAME_LEN-1);
ogs_list_add(&self.dev_list, dev);
@ -2434,7 +2453,7 @@ ogs_pfcp_subnet_t *ogs_pfcp_subnet_add(
}
if (dnn)
strcpy(subnet->dnn, dnn);
ogs_cpystrn(subnet->dnn, dnn, OGS_MAX_DNN_LEN);
ogs_pool_init(&subnet->pool, ogs_app()->pool.sess);

View file

@ -436,7 +436,7 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr);
int ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr);
void ogs_pfcp_object_teid_hash_set(
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr,

View file

@ -133,6 +133,9 @@ ogs_sbi_client_t *ogs_sbi_client_add(
client->sslkeylog =
ogs_strdup(ogs_sbi_self()->tls.client.sslkeylog);
if (ogs_sbi_self()->local_if)
client->local_if = ogs_strdup(ogs_sbi_self()->local_if);
ogs_debug("ogs_sbi_client_add [%s]", OpenAPI_uri_scheme_ToString(scheme));
OGS_OBJECT_REF(client);
@ -217,6 +220,8 @@ void ogs_sbi_client_remove(ogs_sbi_client_t *client)
ogs_free(client->cert);
if (client->sslkeylog)
ogs_free(client->sslkeylog);
if (client->local_if)
ogs_free(client->local_if);
if (client->fqdn)
ogs_free(client->fqdn);
@ -558,6 +563,10 @@ static connection_t *connection_add(
curl_easy_setopt(conn->easy, CURLOPT_RESOLVE, conn->resolve_list);
}
if (client->local_if) {
curl_easy_setopt(conn->easy, CURLOPT_INTERFACE, client->local_if);
}
curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn);
curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn);
@ -640,11 +649,19 @@ static void connection_remove_all(ogs_sbi_client_t *client)
static void connection_timer_expired(void *data)
{
connection_t *conn = NULL;
CURLcode res;
char *effective_url = NULL;
conn = data;
ogs_assert(conn);
ogs_error("Connection timer expired");
ogs_error("Connection timer expired [METHOD:%s]", conn->method);
res = curl_easy_getinfo(conn->easy, CURLINFO_EFFECTIVE_URL, &effective_url);
if ((res == CURLE_OK) && effective_url)
ogs_error("Effective URL: %s", effective_url);
else
ogs_error("curl_easy_getinfo() failed [%s]", curl_easy_strerror(res));
ogs_assert(conn->client_cb);
conn->client_cb(OGS_TIMEUP, NULL, conn->data);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -40,15 +40,15 @@ extern "C" {
client = ((__cTX)->client); \
ogs_assert(client); \
if (client->fqdn) { \
ogs_warn("NF EndPoint(fqdn) updated [%s:%d]", \
ogs_warn("UnRef NF EndPoint(fqdn) [%s:%d]", \
client->fqdn, client->fqdn_port); \
} \
if (client->addr) { \
ogs_warn("NF EndPoint(addr) updated [%s:%d]", \
ogs_warn("UnRef NF EndPoint(addr) [%s:%d]", \
OGS_ADDR(client->addr, buf), OGS_PORT(client->addr)); \
} \
if (client->addr6) { \
ogs_warn("NF EndPoint(addr6) updated [%s:%d]", \
ogs_warn("UnRef NF EndPoint(addr6) [%s:%d]", \
OGS_ADDR(client->addr6, buf), OGS_PORT(client->addr6)); \
} \
ogs_sbi_client_remove(client); \
@ -58,15 +58,15 @@ extern "C" {
((__cTX)->client) = (__pClient); \
ogs_debug("CLIENT Ref [%d]", (__pClient)->reference_count); \
if ((__pClient)->fqdn) { \
ogs_info("NF EndPoint(fqdn) setup [%s:%d]", \
ogs_info("Setup NF EndPoint(fqdn) [%s:%d]", \
(__pClient)->fqdn, (__pClient)->fqdn_port); \
} \
if ((__pClient)->addr) { \
ogs_info("NF EndPoint(addr) setup [%s:%d]", \
ogs_info("Setup NF EndPoint(addr) [%s:%d]", \
OGS_ADDR((__pClient)->addr, buf), OGS_PORT((__pClient)->addr)); \
} \
if ((__pClient)->addr6) { \
ogs_info("NF EndPoint(addr6) setup [%s:%d]", \
ogs_info("Setup NF EndPoint(addr6) [%s:%d]", \
OGS_ADDR((__pClient)->addr6, buf), \
OGS_PORT((__pClient)->addr6)); \
} \
@ -81,6 +81,7 @@ typedef struct ogs_sbi_client_s {
OpenAPI_uri_scheme_e scheme;
bool insecure_skip_verify;
char *cacert, *private_key, *cert, *sslkeylog;
char *local_if;
char *fqdn;
uint16_t fqdn_port;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -256,7 +256,9 @@ int ogs_sbi_context_parse_config(
const char *default_key =
ogs_yaml_iter_key(&default_iter);
ogs_assert(default_key);
if (!strcmp(default_key, "tls")) {
if (!strcmp(default_key, "interface")) {
self.local_if = ogs_yaml_iter_value(&default_iter);
} else if (!strcmp(default_key, "tls")) {
ogs_yaml_iter_t tls_iter;
ogs_yaml_iter_recurse(&default_iter, &tls_iter);
while (ogs_yaml_iter_next(&tls_iter)) {
@ -1073,6 +1075,7 @@ ogs_sbi_client_t *ogs_sbi_context_parse_client_config(ogs_yaml_iter_t *iter)
const char *client_private_key = NULL;
const char *client_cert = NULL;
const char *client_sslkeylog = NULL;
const char *local_if = NULL;
bool rc;
@ -1116,6 +1119,8 @@ ogs_sbi_client_t *ogs_sbi_context_parse_client_config(ogs_yaml_iter_t *iter)
client_cert = ogs_yaml_iter_value(iter);
} else if (!strcmp(key, "client_sslkeylogfile")) {
client_sslkeylog = ogs_yaml_iter_value(iter);
} else if (!strcmp(key, "interface")) {
local_if = ogs_yaml_iter_value(iter);
}
}
@ -1192,6 +1197,13 @@ ogs_sbi_client_t *ogs_sbi_context_parse_client_config(ogs_yaml_iter_t *iter)
ogs_assert(client->sslkeylog);
}
if (local_if) {
if (client->local_if)
ogs_free(client->local_if);
client->local_if = ogs_strdup(local_if);
ogs_assert(client->local_if);
}
if ((!client_private_key && client_cert) ||
(client_private_key && !client_cert)) {
ogs_error("Either the private key or certificate is missing.");
@ -1381,7 +1393,19 @@ ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find(char *id)
{
ogs_sbi_nf_instance_t *nf_instance = NULL;
ogs_assert(id);
/*
* This is related to Issue #3093.
*
* We want to be able to use 'ogs_sbi_nf_instance_id_find(char *id)'
* even if the 'id' is NULL as in the use case below.
*
* ogs_sbi_nf_instance_find(
* sess->sbi.service_type_array[service_type].nf_instance_id));
*
* To do so, we changed the 'assert(id)' to 'if (!id) return NULL',
* as shown below.
*/
if (!id) return NULL;
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) {
if (nf_instance->id && strcmp(nf_instance->id, id) == 0)
@ -2407,7 +2431,7 @@ ogs_sbi_client_t *ogs_sbi_client_find_by_service_name(
}
}
return nf_instance->client;
return NULL;
}
ogs_sbi_client_t *ogs_sbi_client_find_by_service_type(
@ -2430,10 +2454,21 @@ ogs_sbi_client_t *ogs_sbi_client_find_by_service_type(
void ogs_sbi_object_free(ogs_sbi_object_t *sbi_object)
{
int i;
ogs_assert(sbi_object);
if (ogs_list_count(&sbi_object->xact_list))
ogs_error("SBI running [%d]", ogs_list_count(&sbi_object->xact_list));
for (i = 0; i < OGS_SBI_MAX_NUM_OF_SERVICE_TYPE; i++) {
if (sbi_object->service_type_array[i].nf_instance_id)
ogs_free(sbi_object->service_type_array[i].nf_instance_id);
}
for (i = 0; i < OGS_SBI_MAX_NUM_OF_NF_TYPE; i++) {
if (sbi_object->nf_type_array[i].nf_instance_id)
ogs_free(sbi_object->nf_type_array[i].nf_instance_id);
}
}
ogs_sbi_xact_t *ogs_sbi_xact_add(

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -88,6 +88,8 @@ typedef struct ogs_sbi_context_s {
} client;
} tls;
const char *local_if;
ogs_list_t server_list;
ogs_list_t client_list;
@ -201,8 +203,9 @@ typedef struct ogs_sbi_object_s {
ogs_sbi_obj_type_e type;
struct {
ogs_sbi_nf_instance_t *nf_instance;
char *nf_instance_id;
#if ENABLE_VALIDITY_TIMEOUT
/*
* Search.Result stored in nf_instance->time.validity_duration;
*
@ -212,8 +215,10 @@ typedef struct ogs_sbi_object_s {
* if no validityPeriod in SearchResult, validity_timeout is 0.
*/
ogs_time_t validity_timeout;
} service_type_array[OGS_SBI_MAX_NUM_OF_SERVICE_TYPE],
home_nsmf_pdusession;
#endif
} nf_type_array[OGS_SBI_MAX_NUM_OF_NF_TYPE],
service_type_array[OGS_SBI_MAX_NUM_OF_SERVICE_TYPE],
home_nsmf_pdusession;
ogs_list_t xact_list;
@ -360,8 +365,8 @@ typedef struct ogs_sbi_sepp_info_s {
} ogs_sbi_sepp_info_t;
typedef struct ogs_sbi_amf_info_s {
uint8_t amf_set_id;
uint16_t amf_region_id;
uint16_t amf_set_id;
uint8_t amf_region_id;
int num_of_guami;
ogs_guami_t guami[OGS_MAX_NUM_OF_SERVED_GUAMI];
@ -477,49 +482,77 @@ void ogs_sbi_client_associate(ogs_sbi_nf_instance_t *nf_instance);
int ogs_sbi_default_client_port(OpenAPI_uri_scheme_e scheme);
#if ENABLE_VALIDITY_TIMEOUT
#define OGS_SBI_SETUP_NF_INSTANCE(__cTX, __nFInstance) \
do { \
ogs_assert(__nFInstance); \
ogs_assert((__nFInstance)->id); \
ogs_assert((__nFInstance)->nf_type); \
ogs_assert((__nFInstance)->t_validity); \
\
if ((__cTX).nf_instance) { \
ogs_warn("[%s] NF Instance updated [type:%s validity:%ds]", \
((__cTX).nf_instance)->id, \
OpenAPI_nf_type_ToString(((__cTX).nf_instance)->nf_type), \
((__cTX).nf_instance)->time.validity_duration); \
if ((__cTX).nf_instance_id) { \
ogs_warn("[%s] Unlink NF Instance " \
"[type:%s validity:%d timeout:%lds]", \
((__cTX).nf_instance_id), \
OpenAPI_nf_type_ToString((__nFInstance)->nf_type), \
(__nFInstance)->time.validity_duration, \
(long)((__cTX).validity_timeout)); \
ogs_free((__cTX).nf_instance_id); \
} \
\
((__cTX).nf_instance) = __nFInstance; \
((__cTX).nf_instance_id) = ogs_strdup((__nFInstance)->id); \
if ((__nFInstance)->time.validity_duration) { \
((__cTX).validity_timeout) = (__nFInstance)->t_validity->timeout; \
} else { \
((__cTX).validity_timeout) = 0; \
} \
ogs_info("[%s] NF Instance setup [type:%s validity:%ds]", \
(__nFInstance)->id, \
ogs_info("[%s] Setup NF Instance [type:%s validity:%d timeout:%lds]", \
((__cTX).nf_instance_id), \
OpenAPI_nf_type_ToString((__nFInstance)->nf_type), \
(__nFInstance)->time.validity_duration); \
(__nFInstance)->time.validity_duration, \
(long)((__cTX).validity_timeout)); \
} while(0)
#else
#define OGS_SBI_SETUP_NF_INSTANCE(__cTX, __nFInstance) \
do { \
ogs_assert(__nFInstance); \
ogs_assert((__nFInstance)->id); \
ogs_assert((__nFInstance)->nf_type); \
\
if ((__cTX).nf_instance_id) { \
ogs_warn("[%s] Unlink NF Instance [type:%s]", \
((__cTX).nf_instance_id), \
OpenAPI_nf_type_ToString((__nFInstance)->nf_type)); \
ogs_free((__cTX).nf_instance_id); \
} \
\
((__cTX).nf_instance_id) = ogs_strdup((__nFInstance)->id); \
ogs_info("[%s] Setup NF Instance [type:%s]", \
((__cTX).nf_instance_id), \
OpenAPI_nf_type_ToString((__nFInstance)->nf_type)); \
} while(0)
#endif
/*
* Search.Result stored in nf_instance->time.validity_duration;
* Issue #3470
*
* validity_timeout = nf_instance->validity->timeout =
* ogs_get_monotonic_time() + nf_instance->time.validity_duration;
* Previously, nf_instance pointers were stored in nf_type_array and
* service_type_array. This led to a dangling pointer problem when an
* nf_instance was removed via ogs_sbi_nf_instance_remove().
*
* if no validityPeriod in SearchResult, validity_timeout is 0.
* To resolve this, we now store nf_instance_id instead, and use
* ogs_sbi_nf_instance_find(nf_instance_id) to verify the validity of an
* nf_instance.
*/
#if ENABLE_VALIDITY_TIMEOUT
#define OGS_SBI_GET_NF_INSTANCE(__cTX) \
((__cTX).validity_timeout == 0 || \
(__cTX).validity_timeout > ogs_get_monotonic_time() ? \
((__cTX).nf_instance) : NULL)
#define OGS_SBI_NF_INSTANCE_VALID(__nFInstance) \
(((__nFInstance) && ((__nFInstance)->t_validity) && \
((__nFInstance)->time.validity_duration == 0 || \
(__nFInstance)->t_validity->timeout > ogs_get_monotonic_time())) ? \
true : false)
(ogs_sbi_nf_instance_find((__cTX).nf_instance_id)) : NULL)
#else
#define OGS_SBI_GET_NF_INSTANCE(__cTX) \
ogs_sbi_nf_instance_find((__cTX).nf_instance_id)
#endif
bool ogs_sbi_discovery_param_is_matched(
ogs_sbi_nf_instance_t *nf_instance,

View file

@ -46,7 +46,8 @@ cJSON *ogs_sbi_links_convertToJSON(ogs_sbi_links_t *links)
ogs_assert(linksJSON);
cJSON_AddItemToObject(linksJSON, "items", itemsJSON);
cJSON_AddItemToObject(linksJSON, "self", selfJSON);
cJSON_AddItemToObject(linksJSON, "self", selfJSON);
cJSON_AddNumberToObject(linksJSON, "totalItemCount", cJSON_GetArraySize(itemsJSON));
/* root */
root = cJSON_CreateObject();
@ -56,3 +57,57 @@ cJSON *ogs_sbi_links_convertToJSON(ogs_sbi_links_t *links)
return root;
}
ogs_sbi_links_t *ogs_sbi_links_parseFromJSON(cJSON *json)
{
ogs_sbi_links_t *links;
cJSON *_links = NULL;
cJSON *_items = NULL, *_item = NULL;
cJSON *_self = NULL;
ogs_assert(json);
_links = cJSON_GetObjectItemCaseSensitive(json, "_links");
if (!_links) {
ogs_error("No _links");
return NULL;
}
_items = cJSON_GetObjectItemCaseSensitive(_links, "items");
if (!_items) {
ogs_error("No items");
return NULL;
}
links = ogs_malloc(sizeof(ogs_sbi_links_t));
ogs_assert(links);
memset(links, 0, sizeof(*links));
links->items = OpenAPI_list_create();
ogs_assert(links->items);
cJSON_ArrayForEach(_item, _items) {
cJSON *href;
char *link;
href = cJSON_GetObjectItemCaseSensitive(_item, "href");
if (href) {
link = cJSON_GetStringValue(href);
OpenAPI_list_add(links->items, ogs_strdup(link));
}
}
_self = cJSON_GetObjectItemCaseSensitive(_links, "self");
if (_self) {
cJSON *self_href;
self_href = cJSON_GetObjectItemCaseSensitive(_self, "href");
if (self_href)
links->self = ogs_strdup(cJSON_GetStringValue(self_href));
}
return links;
}

View file

@ -23,6 +23,7 @@ typedef struct ogs_sbi_links_s {
} ogs_sbi_links_t;
cJSON *ogs_sbi_links_convertToJSON(ogs_sbi_links_t *links);
ogs_sbi_links_t *ogs_sbi_links_parseFromJSON(cJSON *json);
#ifdef __cplusplus
}

View file

@ -63,6 +63,10 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message)
if (message->param.discovery_option)
ogs_sbi_discovery_option_free(message->param.discovery_option);
/* Query parameters */
for (i = 0; i < message->param.num_of_fields; i++)
ogs_free(message->param.fields[i]);
/* JSON Data */
if (message->NFProfile)
OpenAPI_nf_profile_free(message->NFProfile);
@ -109,6 +113,8 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message)
message->Amf3GppAccessRegistrationModification);
if (message->SmfRegistration)
OpenAPI_smf_registration_free(message->SmfRegistration);
if (message->Nssai)
OpenAPI_nssai_free(message->Nssai);
if (message->AccessAndMobilitySubscriptionData)
OpenAPI_access_and_mobility_subscription_data_free(
message->AccessAndMobilitySubscriptionData);
@ -219,6 +225,13 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message)
OpenAPI_ue_reg_status_update_req_data_free(message->UeRegStatusUpdateReqData);
if (message->UeRegStatusUpdateRspData)
OpenAPI_ue_reg_status_update_rsp_data_free(message->UeRegStatusUpdateRspData);
if (message->links) {
OpenAPI_clear_and_free_string_list(message->links->items);
if (message->links->self)
ogs_free(message->links->self);
ogs_free(message->links);
}
/* HTTP Part */
for (i = 0; i < message->num_of_part; i++) {
@ -706,6 +719,26 @@ ogs_sbi_request_t *ogs_sbi_build_request(ogs_sbi_message_t *message)
if (homeSnssai.sd)
ogs_free(homeSnssai.sd);
}
if (message->param.num_of_fields) {
char *fields;
fields = ogs_strdup(message->param.fields[0]);
if (!fields) {
ogs_error("ogs_strdup() failed");
return NULL;
}
for (i = 1; i < message->param.num_of_fields; i++)
fields = ogs_mstrcatf(
fields, ",%s", message->param.fields[i]);
if (fields) {
ogs_sbi_header_set(request->http.params,
OGS_SBI_PARAM_FIELDS, fields);
ogs_free(fields);
}
}
if (message->param.ipv4addr) {
ogs_sbi_header_set(request->http.params,
OGS_SBI_PARAM_IPV4ADDR, message->param.ipv4addr);
@ -1094,6 +1127,30 @@ int ogs_sbi_parse_request(
cJSON_Delete(item);
}
}
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_FIELDS)) {
char *_v = ogs_hash_this_val(hi), *v = NULL;
char *token = NULL;
char *saveptr = NULL;
v = ogs_strdup(_v);
ogs_assert(v);
token = ogs_strtok_r(v, ",", &saveptr);
while (token != NULL) {
if (message->param.num_of_fields < OGS_SBI_MAX_NUM_OF_FIELDS) {
message->param.fields
[message->param.num_of_fields] = ogs_strdup(token);
ogs_assert(message->param.fields
[message->param.num_of_fields]);
message->param.num_of_fields++;
token = ogs_strtok_r(NULL, ",", &saveptr);
} else {
ogs_error("Fields in query exceed MAX_NUM_OF_FIELDS");
break;
}
}
ogs_free(v);
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_IPV4ADDR)) {
message->param.ipv4addr = ogs_hash_this_val(hi);
} else if (!strcmp(ogs_hash_this_key(hi), OGS_SBI_PARAM_IPV6PREFIX)) {
@ -1133,7 +1190,7 @@ int ogs_sbi_parse_request(
ogs_sbi_parse_plmn_id(
&message->param.tai.plmn_id, tai->plmn_id);
message->param.tai.tac =
ogs_uint24_from_string(tai->tac);
ogs_uint24_from_string_hexadecimal(tai->tac);
message->param.tai_presence = true;
OpenAPI_tai_free(tai);
}
@ -1401,6 +1458,9 @@ static char *build_json(ogs_sbi_message_t *message)
} else if (message->SmfRegistration) {
item = OpenAPI_smf_registration_convertToJSON(message->SmfRegistration);
ogs_assert(item);
} else if (message->Nssai) {
item = OpenAPI_nssai_convertToJSON(message->Nssai);
ogs_assert(item);
} else if (message->AccessAndMobilitySubscriptionData) {
item = OpenAPI_access_and_mobility_subscription_data_convertToJSON(
message->AccessAndMobilitySubscriptionData);
@ -1668,15 +1728,27 @@ static int parse_json(ogs_sbi_message_t *message,
SWITCH(message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_NF_INSTANCES)
if (message->res_status < 300) {
message->NFProfile =
OpenAPI_nf_profile_parseFromJSON(item);
if (!message->NFProfile) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
if (message->h.resource.component[1]) {
if (message->res_status < 300) {
message->NFProfile =
OpenAPI_nf_profile_parseFromJSON(item);
if (!message->NFProfile) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
}
} else {
ogs_error("HTTP ERROR Status : %d", message->res_status);
}
} else {
ogs_error("HTTP ERROR Status : %d", message->res_status);
if (message->res_status < 300) {
message->links = ogs_sbi_links_parseFromJSON(item);
if (!message->links) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
}
} else {
ogs_error("HTTP ERROR Status : %d", message->res_status);
}
}
break;
@ -1907,6 +1979,18 @@ static int parse_json(ogs_sbi_message_t *message,
CASE(OGS_SBI_SERVICE_NAME_NUDM_SDM)
SWITCH(message->h.resource.component[1])
CASE(OGS_SBI_RESOURCE_NAME_NSSAI)
if (message->res_status < 300) {
message->Nssai = OpenAPI_nssai_parseFromJSON(item);
if (!message->Nssai) {
rv = OGS_ERROR;
ogs_error("JSON parse error");
}
} else {
ogs_error("HTTP ERROR Status : %d", message->res_status);
}
break;
CASE(OGS_SBI_RESOURCE_NAME_AM_DATA)
if (message->res_status < 300) {
message->AccessAndMobilitySubscriptionData =

View file

@ -93,6 +93,7 @@ extern "C" {
#define OGS_SBI_RESOURCE_NAME_SM_DATA "sm-data"
#define OGS_SBI_RESOURCE_NAME_SMF_SELECT_DATA "smf-select-data"
#define OGS_SBI_RESOURCE_NAME_UE_CONTEXT_IN_SMF_DATA "ue-context-in-smf-data"
#define OGS_SBI_RESOURCE_NAME_NSSAI "nssai"
#define OGS_SBI_RESOURCE_NAME_SMF_SELECTION_SUBSCRIPTION_DATA \
"smf-selection-subscription-data"
#define OGS_SBI_RESOURCE_NAME_SDM_SUBSCRIPTIONS "sdm-subscriptions"
@ -352,11 +353,17 @@ extern "C" {
#define OGS_SBI_PARAM_TAI "tai"
#define OGS_SBI_PARAM_SLICE_INFO_REQUEST_FOR_PDU_SESSION \
"slice-info-request-for-pdu-session"
#define OGS_SBI_PARAM_FIELDS "fields"
#define OGS_SBI_PARAM_IPV4ADDR "ipv4Addr"
#define OGS_SBI_PARAM_IPV6PREFIX "ipv6Prefix"
#define OGS_SBI_PARAM_HOME_PLMN_ID "home-plmn-id"
#define OGS_SBI_PARAM_HNRF_URI "hnrf-uri"
#define OGS_SBI_PARAM_FIELDS_GPSIS "gpsis"
#define OGS_SBI_PARAM_FIELDS_SUBSCRIBED_UE_AMBR "subscribedUeAmbr"
#define OGS_SBI_PARAM_FIELDS_NSSAI "nssai"
#define OGS_SBI_MAX_NUM_OF_FIELDS 8
#define OGS_SBI_CONTENT_JSON_TYPE \
OGS_SBI_APPLICATION_TYPE "/" OGS_SBI_APPLICATION_JSON_TYPE
#define OGS_SBI_CONTENT_PROBLEM_TYPE \
@ -411,6 +418,8 @@ extern "C" {
"N5g-ddnmf_Discovery_MonitorUpdateResult"
#define OGS_SBI_CALLBACK_N5G_DDNMF_DISCOVERY_MATCH_INFORMATION \
"N5g-ddnmf_Discovery_MatchInformation"
#define OGS_SBI_CALLBACK_NAMF_COMMUNICATION_ONN1N2TRANSFERFAILURE \
"Namf_Communication_onN1N2TransferFailure"
typedef struct ogs_sbi_header_s {
char *method;
@ -493,6 +502,8 @@ typedef struct ogs_sbi_message_s {
OpenAPI_nf_type_e nf_type;
int limit;
char *dnn;
int num_of_fields;
char *fields[OGS_SBI_MAX_NUM_OF_FIELDS];
/* Shared memory */
bool plmn_id_presence;
@ -536,6 +547,7 @@ typedef struct ogs_sbi_message_s {
OpenAPI_amf3_gpp_access_registration_t *Amf3GppAccessRegistration;
OpenAPI_amf3_gpp_access_registration_modification_t
*Amf3GppAccessRegistrationModification;
OpenAPI_nssai_t *Nssai;
OpenAPI_access_and_mobility_subscription_data_t
*AccessAndMobilitySubscriptionData;
OpenAPI_smf_selection_subscription_data_t *SmfSelectionSubscriptionData;

View file

@ -32,6 +32,7 @@ static void server_final(void);
static int server_start(ogs_sbi_server_t *server,
int (*cb)(ogs_sbi_request_t *request, void *data));
static void server_graceful_shutdown(ogs_sbi_server_t *server);
static void server_stop(ogs_sbi_server_t *server);
static bool server_send_rspmem_persistent(
@ -49,6 +50,7 @@ const ogs_sbi_server_actions_t ogs_mhd_server_actions = {
server_final,
server_start,
server_graceful_shutdown,
server_stop,
server_send_rspmem_persistent,
@ -287,6 +289,13 @@ static int server_start(ogs_sbi_server_t *server,
return OGS_OK;
}
static void server_graceful_shutdown(ogs_sbi_server_t *server)
{
ogs_assert(server);
/* No need to shutdown gracefully */
}
static void server_stop(ogs_sbi_server_t *server)
{
ogs_assert(server);

View file

@ -19,6 +19,93 @@
#include "ogs-sbi.h"
static void handle_nf_profile_retrieval(
char *nf_instance_id,
OpenAPI_nf_profile_t *NFProfile)
{
ogs_sbi_nf_instance_t *nf_instance;
ogs_sbi_subscription_spec_t *subscription_spec = NULL;
bool save = false;
ogs_assert(nf_instance_id);
ogs_assert(NFProfile);
nf_instance = ogs_sbi_nf_instance_find(nf_instance_id);
if (nf_instance) {
/* already have this nf_instance; done */
return;
}
if (NF_INSTANCE_ID_IS_SELF(nf_instance_id)) {
/* don't save ourselves */
return;
}
nf_instance = ogs_sbi_nf_instance_add();
ogs_assert(nf_instance);
ogs_sbi_nf_instance_set_id(nf_instance, nf_instance_id);
ogs_nnrf_nfm_handle_nf_profile(nf_instance, NFProfile);
/* verify against our subscription list that we want to save this
* nf instance to our context */
ogs_list_for_each(&ogs_sbi_self()->subscription_spec_list, subscription_spec) {
ogs_sbi_nf_service_t *nf_service = NULL;
if (subscription_spec->subscr_cond.nf_type == nf_instance->nf_type) {
/* ok; save the nf_instance */
save = true;
break;
}
ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
if (subscription_spec->subscr_cond.service_name &&
nf_service->name &&
!strcmp(subscription_spec->subscr_cond.service_name, nf_service->name))
{
/* ok; save the nf_instance */
save = true;
break;
}
}
if (save)
break;
}
if (!save) {
ogs_sbi_nf_instance_remove(nf_instance);
} else {
ogs_sbi_nf_fsm_init(nf_instance);
ogs_info("[%s] (NRF-profile-get) NF registered", nf_instance->id);
ogs_sbi_client_associate(nf_instance);
}
}
static void handle_nf_list_retrieval(ogs_sbi_links_t *links)
{
ogs_sbi_header_t header;
ogs_sbi_message_t msg;
OpenAPI_lnode_t *node = NULL;
OpenAPI_list_for_each(links->items, node) {
memset(&header, 0, sizeof(header));
header.uri = node->data;
if (ogs_sbi_parse_header(&msg, &header) != OGS_OK) {
ogs_error("Cannot parse href: %s", header.uri);
continue;
}
if (msg.h.resource.component[1])
ogs_nnrf_nfm_send_nf_profile_get(msg.h.resource.component[1]);
ogs_sbi_header_free(&header);
}
}
void ogs_sbi_nf_fsm_init(ogs_sbi_nf_instance_t *nf_instance)
{
ogs_event_t e;
@ -227,6 +314,8 @@ void ogs_sbi_nf_state_registered(ogs_fsm_t *s, ogs_event_t *e)
subscription_spec->subscr_cond.nf_type,
subscription_spec->subscr_cond.service_name);
}
ogs_nnrf_nfm_send_nf_list_retrieve();
}
break;
@ -252,19 +341,64 @@ void ogs_sbi_nf_state_registered(ogs_fsm_t *s, ogs_event_t *e)
SWITCH(message->h.resource.component[0])
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_interval)
ogs_timer_start(nf_instance->t_no_heartbeat,
ogs_time_from_sec(
nf_instance->time.heartbeat_interval +
ogs_local_conf()->time.nf_instance.
no_heartbeat_margin));
if (message->h.resource.component[1]) {
SWITCH(message->h.method)
CASE(OGS_SBI_HTTP_METHOD_PATCH)
if (message->res_status == OGS_SBI_HTTP_STATUS_NO_CONTENT ||
message->res_status == OGS_SBI_HTTP_STATUS_OK) {
if (nf_instance->time.heartbeat_interval)
ogs_timer_start(nf_instance->t_no_heartbeat,
ogs_time_from_sec(
nf_instance->time.heartbeat_interval +
ogs_local_conf()->time.nf_instance.
no_heartbeat_margin));
} else {
ogs_warn("[%s] HTTP response error [%d]",
NF_INSTANCE_ID(ogs_sbi_self()->nf_instance),
message->res_status);
OGS_FSM_TRAN(s, &ogs_sbi_nf_state_exception);
}
break;
CASE(OGS_SBI_HTTP_METHOD_GET)
if (message->res_status == OGS_SBI_HTTP_STATUS_OK) {
if (!message->h.resource.component[1]) {
ogs_error("No NFInstanceId");
break;
}
if (!message->NFProfile) {
ogs_error("No NFProfile");
break;
}
handle_nf_profile_retrieval(
message->h.resource.component[1],
message->NFProfile);
} else {
ogs_warn("[%s] HTTP response error [%d]",
NF_INSTANCE_ID(ogs_sbi_self()->nf_instance),
message->res_status);
OGS_FSM_TRAN(s, &ogs_sbi_nf_state_exception);
}
break;
DEFAULT
ogs_error("Unknown method [%s]", message->h.method);
break;
END
} else {
ogs_warn("[%s] HTTP response error [%d]",
NF_INSTANCE_ID(ogs_sbi_self()->nf_instance),
message->res_status);
OGS_FSM_TRAN(s, &ogs_sbi_nf_state_exception);
if (!message->links) {
ogs_warn("No links");
break;
}
if (message->res_status != OGS_SBI_HTTP_STATUS_OK) {
ogs_warn("[%s] HTTP response error [%d]",
NF_INSTANCE_ID(ogs_sbi_self()->nf_instance),
message->res_status);
break;
}
handle_nf_list_retrieval(message->links);
}
break;

View file

@ -30,6 +30,7 @@ static void server_final(void);
static int server_start(ogs_sbi_server_t *server,
int (*cb)(ogs_sbi_request_t *request, void *data));
static void server_graceful_shutdown(ogs_sbi_server_t *server);
static void server_stop(ogs_sbi_server_t *server);
static bool server_send_rspmem_persistent(
@ -47,6 +48,7 @@ const ogs_sbi_server_actions_t ogs_nghttp2_server_actions = {
server_final,
server_start,
server_graceful_shutdown,
server_stop,
server_send_rspmem_persistent,
@ -442,6 +444,33 @@ static int server_start(ogs_sbi_server_t *server,
return OGS_OK;
}
/* Gracefully shutdown the server by sending GOAWAY to each session. */
static void server_graceful_shutdown(ogs_sbi_server_t *server)
{
ogs_sbi_session_t *sbi_sess = NULL;
ogs_sbi_session_t *next_sbi_sess = NULL;
int rv;
/* Iterate over all active sessions in the server. */
ogs_list_for_each_safe(&server->session_list, next_sbi_sess, sbi_sess) {
/* Submit a GOAWAY frame using the last stream ID. */
rv = nghttp2_submit_goaway(sbi_sess->session,
NGHTTP2_FLAG_NONE,
sbi_sess->last_stream_id,
NGHTTP2_NO_ERROR,
NULL, 0);
if (rv != 0) {
ogs_error("nghttp2_submit_goaway() failed (%d:%s)",
rv, nghttp2_strerror(rv));
}
/* Send the GOAWAY frame to the client. */
if (session_send(sbi_sess) != OGS_OK) {
ogs_error("session_send() failed during graceful shutdown");
}
}
}
static void server_stop(ogs_sbi_server_t *server)
{
ogs_assert(server);

View file

@ -839,12 +839,8 @@ static OpenAPI_smf_info_t *build_smf_info(ogs_sbi_nf_info_t *nf_info)
ogs_uint24_to_0string(nf_info->smf.nr_tai[i].tac);
if (!TaiItem->tac) {
ogs_error("No TaiItem->tac");
if (TaiItem) {
if (TaiItem->plmn_id)
ogs_sbi_free_plmn_id(TaiItem->plmn_id);
ogs_free(TaiItem);
}
free_smf_info(SmfInfo);
OpenAPI_tai_free(TaiItem);
OpenAPI_smf_info_free(SmfInfo);
OpenAPI_list_free(TaiList);
return NULL;
}
@ -956,6 +952,7 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
return NULL;
}
/* Guami list */
guamiAmfInfoList = OpenAPI_list_create();
if (!guamiAmfInfoList) {
ogs_error("No guamiAmfInfoList");
@ -967,8 +964,8 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
guamiAmfInfoItem = ogs_calloc(1, sizeof(*guamiAmfInfoItem));
if (!guamiAmfInfoItem) {
ogs_error("guamiAmfInfoItem");
free_amf_info(AmfInfo);
ogs_error("No guamiAmfInfoItem");
OpenAPI_amf_info_free(AmfInfo);
OpenAPI_list_free(guamiAmfInfoList);
return NULL;
}
@ -976,23 +973,18 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
guamiAmfInfoItem->plmn_id =
ogs_sbi_build_plmn_id_nid(&nf_info->amf.guami[i].plmn_id);
if (!guamiAmfInfoItem->plmn_id) {
ogs_error("guamiAmfInfoItem->plmn_id");
if (guamiAmfInfoItem)
ogs_free(guamiAmfInfoItem);
free_amf_info(AmfInfo);
ogs_error("No guamiAmfInfoItem->plmn_id");
OpenAPI_guami_free(guamiAmfInfoItem);
OpenAPI_amf_info_free(AmfInfo);
OpenAPI_list_free(guamiAmfInfoList);
return NULL;
}
guamiAmfInfoItem->amf_id =
ogs_amf_id_to_string(&nf_info->amf.guami[i].amf_id);
if (!guamiAmfInfoItem->amf_id) {
ogs_error("guamiAmfInfoItem->amf_id");
if (guamiAmfInfoItem) {
if (guamiAmfInfoItem->plmn_id)
ogs_free(guamiAmfInfoItem->plmn_id);
ogs_free(guamiAmfInfoItem);
}
free_amf_info(AmfInfo);
ogs_error("No guamiAmfInfoItem->amf_id");
OpenAPI_guami_free(guamiAmfInfoItem);
OpenAPI_amf_info_free(AmfInfo);
OpenAPI_list_free(guamiAmfInfoList);
return NULL;
}
@ -1005,6 +997,8 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
else
OpenAPI_list_free(guamiAmfInfoList);
/* TAI list */
TaiList = OpenAPI_list_create();
if (!TaiList) {
ogs_error("No TaiList");
@ -1014,7 +1008,7 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
for (i = 0; i < nf_info->amf.num_of_nr_tai; i++) {
TaiItem = ogs_calloc(1, sizeof(*TaiItem));
if (!TaiList) {
if (!TaiItem) {
ogs_error("No TaiItem");
free_amf_info(AmfInfo);
OpenAPI_list_free(TaiList);
@ -1024,22 +1018,16 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
&nf_info->amf.nr_tai[i].plmn_id);
if (!TaiItem->plmn_id) {
ogs_error("No TaiItem->plmn_id");
if (TaiItem)
ogs_free(TaiItem);
free_amf_info(AmfInfo);
OpenAPI_tai_free(TaiItem);
OpenAPI_amf_info_free(AmfInfo);
OpenAPI_list_free(TaiList);
return NULL;
}
TaiItem->tac =
ogs_uint24_to_0string(nf_info->amf.nr_tai[i].tac);
TaiItem->tac = ogs_uint24_to_0string(nf_info->amf.nr_tai[i].tac);
if (!TaiItem->tac) {
ogs_error("No TaiItem->tac");
if (TaiItem) {
if (TaiItem->plmn_id)
ogs_sbi_free_plmn_id(TaiItem->plmn_id);
ogs_free(TaiItem);
}
free_amf_info(AmfInfo);
OpenAPI_tai_free(TaiItem);
OpenAPI_amf_info_free(AmfInfo);
OpenAPI_list_free(TaiList);
return NULL;
}
@ -1052,6 +1040,8 @@ static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info)
else
OpenAPI_list_free(TaiList);
/* TAI range list */
TaiRangeList = OpenAPI_list_create();
if (!TaiRangeList) {
ogs_error("No TaiRangeList");
@ -1696,9 +1686,6 @@ ogs_sbi_request_t *ogs_nnrf_nfm_build_status_subscribe(
message.SubscriptionData = SubscriptionData;
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NNRF_NFMANAGEMENT_NF_STATUS_NOTIFY;
request = ogs_sbi_build_request(&message);
ogs_expect(request);
@ -1787,9 +1774,6 @@ ogs_sbi_request_t *ogs_nnrf_nfm_build_status_unsubscribe(
message.h.method = (char *)OGS_SBI_HTTP_METHOD_DELETE;
message.h.uri = subscription_data->resource_uri;
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NNRF_NFMANAGEMENT_NF_STATUS_NOTIFY;
request = ogs_sbi_build_request(&message);
ogs_expect(request);
@ -1817,6 +1801,24 @@ ogs_sbi_request_t *ogs_nnrf_nfm_build_profile_retrieve(char *nf_instance_id)
return request;
}
ogs_sbi_request_t *ogs_nnrf_nfm_build_nflist_retrieve(void)
{
ogs_sbi_message_t message;
ogs_sbi_request_t *request = NULL;
memset(&message, 0, sizeof(message));
message.h.method = (char *)OGS_SBI_HTTP_METHOD_GET;
message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NNRF_NFM;
message.h.api.version = (char *)OGS_SBI_API_V1;
message.h.resource.component[0] =
(char *)OGS_SBI_RESOURCE_NAME_NF_INSTANCES;
request = ogs_sbi_build_request(&message);
ogs_expect(request);
return request;
}
ogs_sbi_request_t *ogs_nnrf_disc_build_discover(
OpenAPI_nf_type_e target_nf_type,
OpenAPI_nf_type_e requester_nf_type,

View file

@ -42,6 +42,7 @@ ogs_sbi_request_t *ogs_nnrf_nfm_build_status_update(
ogs_sbi_request_t *ogs_nnrf_nfm_build_status_unsubscribe(
ogs_sbi_subscription_data_t *subscription_data);
ogs_sbi_request_t *ogs_nnrf_nfm_build_profile_retrieve(char *nf_instance_id);
ogs_sbi_request_t *ogs_nnrf_nfm_build_nflist_retrieve(void);
ogs_sbi_request_t *ogs_nnrf_disc_build_discover(
OpenAPI_nf_type_e target_nf_type,

View file

@ -709,8 +709,8 @@ static void handle_amf_info(
AmfInfo->amf_set_id);
nf_info->amf.amf_region_id = ogs_uint64_from_string_hexadecimal(
AmfInfo->amf_region_id);
GuamiList = AmfInfo->guami_list;
GuamiList = AmfInfo->guami_list;
OpenAPI_list_for_each(GuamiList, node) {
GuamiAmfInfoItem = node->data;
if (GuamiAmfInfoItem) {
@ -741,7 +741,7 @@ static void handle_amf_info(
}
nr_tai = &nf_info->amf.nr_tai[nf_info->amf.num_of_nr_tai];
ogs_assert(nr_tai);
ogs_sbi_parse_plmn_id(&nr_tai->plmn_id, TaiItem->plmn_id);
nr_tai->tac = ogs_uint24_from_string_hexadecimal(TaiItem->tac);
nf_info->amf.num_of_nr_tai++;

View file

@ -180,3 +180,45 @@ bool ogs_nnrf_nfm_send_nf_status_unsubscribe(
return rc;
}
bool ogs_nnrf_nfm_send_nf_list_retrieve(void)
{
bool rc;
ogs_sbi_request_t *request = NULL;
request = ogs_nnrf_nfm_build_nflist_retrieve();
if (!request) {
ogs_error("No Request");
return false;
}
rc = ogs_sbi_send_request_to_nrf(
OGS_SBI_SERVICE_TYPE_NNRF_NFM, NULL,
ogs_sbi_client_handler, request, ogs_sbi_self()->nf_instance);
ogs_expect(rc == true);
ogs_sbi_request_free(request);
return rc;
}
bool ogs_nnrf_nfm_send_nf_profile_get(char *nf_instance_id)
{
bool rc;
ogs_sbi_request_t *request = NULL;
request = ogs_nnrf_nfm_build_profile_retrieve(nf_instance_id);
if (!request) {
ogs_error("No Request");
return false;
}
rc = ogs_sbi_send_request_to_nrf(
OGS_SBI_SERVICE_TYPE_NNRF_NFM, NULL,
ogs_sbi_client_handler, request, ogs_sbi_self()->nf_instance);
ogs_expect(rc == true);
ogs_sbi_request_free(request);
return rc;
}

View file

@ -37,6 +37,8 @@ bool ogs_nnrf_nfm_send_nf_status_update(
ogs_sbi_subscription_data_t *subscription_data);
bool ogs_nnrf_nfm_send_nf_status_unsubscribe(
ogs_sbi_subscription_data_t *subscription_data);
bool ogs_nnrf_nfm_send_nf_list_retrieve(void);
bool ogs_nnrf_nfm_send_nf_profile_get(char *nf_instance_id);
bool ogs_nnrf_nfm_send_to_nrf(
ogs_sbi_client_t *client, ogs_sbi_client_cb_f client_cb,

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -282,7 +282,17 @@ int ogs_sbi_discover_and_send(ogs_sbi_xact_t *xact)
ogs_assert(scp_client);
}
/* Target NF-Instance */
/*
* Issue #3470
*
* Previously, nf_instance pointers were stored in nf_type_array and
* service_type_array. This led to a dangling pointer problem when an
* nf_instance was removed via ogs_sbi_nf_instance_remove().
*
* To resolve this, we now store nf_instance_id instead, and use
* ogs_sbi_nf_instance_find(nf_instance_id) to verify the validity of an
* nf_instance.
*/
nf_instance = OGS_SBI_GET_NF_INSTANCE(
sbi_object->service_type_array[service_type]);
ogs_debug("OGS_SBI_GET_NF_INSTANCE [nf_instance:%p,service_name:%s]",

View file

@ -156,6 +156,14 @@ int ogs_sbi_server_start_all(
return OGS_OK;
}
void ogs_sbi_server_graceful_shutdown_all(void)
{
ogs_sbi_server_t *server = NULL, *next_server = NULL;
ogs_list_for_each_safe(&ogs_sbi_self()->server_list, next_server, server)
ogs_sbi_server_actions.graceful_shutdown(server);
}
void ogs_sbi_server_stop_all(void)
{
ogs_sbi_server_t *server = NULL, *next_server = NULL;

View file

@ -59,6 +59,7 @@ typedef struct ogs_sbi_server_actions_s {
int (*start)(ogs_sbi_server_t *server,
int (*cb)(ogs_sbi_request_t *request, void *data));
void (*graceful_shutdown)(ogs_sbi_server_t *server);
void (*stop)(ogs_sbi_server_t *server);
bool (*send_rspmem_persistent)(
@ -87,6 +88,7 @@ void ogs_sbi_server_set_advertise(
int ogs_sbi_server_start_all(
int (*cb)(ogs_sbi_request_t *request, void *data));
void ogs_sbi_server_graceful_shutdown_all(void);
void ogs_sbi_server_stop_all(void);
bool ogs_sbi_server_send_rspmem_persistent(

View file

@ -16,7 +16,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
project('open5gs', 'c', 'cpp',
version : '2.7.2',
version : '2.7.5',
license : 'AGPL-3.0-or-later',
meson_version : '>= 0.43.0',
default_options : [
@ -25,7 +25,7 @@ project('open5gs', 'c', 'cpp',
],
)
libogslib_version = '2.7.2'
libogslib_version = '2.7.5'
prefix = get_option('prefix')
bindir = join_paths(prefix, get_option('bindir'))

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -1104,16 +1104,20 @@ int amf_context_nf_info(void)
nf_info = ogs_sbi_nf_info_add(
&nf_instance->nf_info_list, OpenAPI_nf_type_AMF);
ogs_assert(nf_info);
nf_info->amf.amf_set_id = self.served_guami[next_new_i].amf_id.set2;
nf_info->amf.amf_region_id = self.served_guami[next_new_i].amf_id.region;
nf_info->amf.amf_set_id =
ogs_amf_set_id(&self.served_guami[next_new_i].amf_id);
nf_info->amf.amf_region_id =
ogs_amf_region_id(&self.served_guami[next_new_i].amf_id);
next_found = false;
info_i = 0;
for (served_i = next_new_i; served_i <
self.num_of_served_guami; served_i++) {
if (self.served_guami[served_i].amf_id.set2 ==
nf_info->amf.amf_set_id &&
self.served_guami[served_i].amf_id.region ==
nf_info->amf.amf_region_id) {
if ((ogs_amf_set_id(&self.served_guami[served_i].amf_id) ==
nf_info->amf.amf_set_id) &&
(ogs_amf_region_id(&self.served_guami[served_i].amf_id) ==
nf_info->amf.amf_region_id)) {
nf_info->amf.guami[info_i] = self.served_guami[served_i];
nf_info->amf.num_of_guami++;
info_i++;
@ -1121,21 +1125,25 @@ int amf_context_nf_info(void)
if (!next_found) {
int handled_i;
for (handled_i = 0; handled_i < served_i; handled_i++) {
if (self.served_guami[handled_i].amf_id.set2 ==
self.served_guami[served_i].amf_id.set2 &&
self.served_guami[handled_i].amf_id.region ==
self.served_guami[served_i].amf_id.region) {
if ((ogs_amf_set_id(
&self.served_guami[handled_i].amf_id) ==
ogs_amf_set_id(
&self.served_guami[served_i].amf_id)) &&
(ogs_amf_region_id(
&self.served_guami[handled_i].amf_id) ==
ogs_amf_region_id(
&self.served_guami[served_i].amf_id))) {
break;
}
next_found = true;
next_new_i = served_i;
next_found = true;
next_new_i = served_i;
}
}
}
}
nf_info->amf.num_of_nr_tai = 0;
int i = 0, j = 0, k = 0, info_tai_i = 0;
int i, j, k;
for (i = 0; i < self.num_of_served_tai; i++) {
ogs_5gs_tai0_list_t *list0 = &self.served_tai[i].list0;
ogs_5gs_tai1_list_t *list1 = &self.served_tai[i].list1;
@ -1144,47 +1152,72 @@ int amf_context_nf_info(void)
for (j = 0; list0->tai[j].num; j++) {
for (k = 0; k < list0->tai[j].num; k++) {
for (served_i = 0; served_i < info_i; served_i++) {
if (nf_info->amf.num_of_nr_tai >= OGS_MAX_NUM_OF_TAI) {
ogs_warn("Maximum number of TAI reached");
break;
}
if (ogs_plmn_id_hexdump(&list0->tai[j].plmn_id) ==
ogs_plmn_id_hexdump(
&nf_info->amf.guami[served_i].plmn_id)) {
nf_info->amf.nr_tai[info_tai_i].plmn_id =
list0->tai[j].plmn_id;
nf_info->amf.nr_tai[info_tai_i].tac =
list0->tai[j].tac[k];
ogs_plmn_id_hexdump(&nf_info->amf.guami[served_i].plmn_id)) {
ogs_5gs_tai_t *tai =
&nf_info->amf.nr_tai[
nf_info->amf.num_of_nr_tai];
tai->plmn_id = list0->tai[j].plmn_id;
tai->tac = list0->tai[j].tac[k];
nf_info->amf.num_of_nr_tai++;
info_tai_i++;
}
}
}
}
for (j = 0; list1->tai[j].num; j++) {
for (k = 0; k < list1->tai[j].num; k++) {
for (served_i = 0; served_i < info_i; served_i++) {
if (ogs_plmn_id_hexdump(&list1->tai[j].plmn_id) ==
ogs_plmn_id_hexdump(
&nf_info->amf.guami[served_i].plmn_id)) {
nf_info->amf.nr_tai[info_tai_i].plmn_id =
list1->tai[j].plmn_id;
nf_info->amf.nr_tai[info_tai_i].tac.v =
list1->tai[j].tac.v+k;
nf_info->amf.num_of_nr_tai++;
info_tai_i++;
}
for (served_i = 0; served_i < info_i; served_i++) {
if (nf_info->amf.num_of_nr_tai_range >= OGS_MAX_NUM_OF_TAI) {
ogs_warn("Maximum number of TAI range reached");
break;
}
if (ogs_plmn_id_hexdump(&list1->tai[j].plmn_id) ==
ogs_plmn_id_hexdump(&nf_info->amf.guami[served_i].plmn_id)) {
nf_info->amf.nr_tai_range[
nf_info->amf.num_of_nr_tai_range].plmn_id =
list1->tai[j].plmn_id;
nf_info->amf.nr_tai_range[
nf_info->amf.num_of_nr_tai_range].start[0].v =
list1->tai[j].tac.v;
nf_info->amf.nr_tai_range[
nf_info->amf.num_of_nr_tai_range].end[0].v =
list1->tai[j].tac.v + list1->tai[j].num - 1;
/* Supported is only 1 TAC range per TAI */
nf_info->amf.nr_tai_range[
nf_info->amf.num_of_nr_tai_range].num_of_tac_range = 1;
nf_info->amf.num_of_nr_tai_range++;
}
}
}
if (list2->num) {
for (j = 0; j < list2->num; j++) {
for (served_i = 0; served_i < info_i; served_i++) {
if (nf_info->amf.num_of_nr_tai >= OGS_MAX_NUM_OF_TAI) {
ogs_warn("Maximum number of TAI reached");
break;
}
if (ogs_plmn_id_hexdump(&list2->tai[j].plmn_id) ==
ogs_plmn_id_hexdump(
&nf_info->amf.guami[served_i].plmn_id)) {
nf_info->amf.nr_tai[info_tai_i].plmn_id =
list2->tai[j].plmn_id;
nf_info->amf.nr_tai[info_tai_i].tac =
list2->tai[j].tac;
ogs_plmn_id_hexdump(&nf_info->amf.guami[served_i].plmn_id)) {
ogs_5gs_tai_t *tai =
&nf_info->amf.nr_tai[
nf_info->amf.num_of_nr_tai];
tai->plmn_id = list2->tai[j].plmn_id;
tai->tac = list2->tai[j].tac;
nf_info->amf.num_of_nr_tai++;
info_tai_i++;
}
}
}
@ -2230,20 +2263,37 @@ void source_ue_deassociate_target_ue(ran_ue_t *ran_ue)
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
if (target_ue) {
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
} else
ogs_error("Target-UE-ID [%d] has already been removed "
"(RAN_UE_S1AP_ID[%lld] AMF_UE_S1AP_ID[%lld])",
source_ue->target_ue_id,
(long long)source_ue->ran_ue_ngap_id,
(long long)source_ue->amf_ue_ngap_id);
} else if (ran_ue->source_ue_id >= OGS_MIN_POOL_ID &&
ran_ue->source_ue_id <= OGS_MAX_POOL_ID) {
target_ue = ran_ue;
source_ue = ran_ue_find_by_id(ran_ue->source_ue_id);
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
if (source_ue) {
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
} else
ogs_error("Source-UE-ID [%d] has already been removed "
"(RAN_UE_S1AP_ID[%lld] AMF_UE_S1AP_ID[%lld])",
target_ue->source_ue_id,
(long long)target_ue->ran_ue_ngap_id,
(long long)target_ue->amf_ue_ngap_id);
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
}
}
@ -2633,6 +2683,63 @@ uint8_t amf_selected_enc_algorithm(amf_ue_t *amf_ue)
return 0;
}
/*
* Save the sensitive (partial) context fields
* from the UE context into the memento
*/
void amf_ue_save_memento(amf_ue_t *amf_ue, amf_ue_memento_t *memento)
{
ogs_assert(amf_ue);
ogs_assert(memento);
memcpy(&memento->ue_security_capability, &amf_ue->ue_security_capability,
sizeof(memento->ue_security_capability));
memcpy(&memento->ue_network_capability, &amf_ue->ue_network_capability,
sizeof(memento->ue_network_capability));
memcpy(memento->rand, amf_ue->rand, OGS_RAND_LEN);
memcpy(memento->autn, amf_ue->autn, OGS_AUTN_LEN);
memcpy(memento->xres_star, amf_ue->xres_star, OGS_MAX_RES_LEN);
memcpy(memento->abba, amf_ue->abba, OGS_NAS_MAX_ABBA_LEN);
memento->abba_len = amf_ue->abba_len;
memcpy(memento->hxres_star, amf_ue->hxres_star, OGS_MAX_RES_LEN);
memcpy(memento->kamf, amf_ue->kamf, OGS_SHA256_DIGEST_SIZE);
memcpy(memento->knas_int, amf_ue->knas_int, OGS_SHA256_DIGEST_SIZE/2);
memcpy(memento->knas_enc, amf_ue->knas_enc, OGS_SHA256_DIGEST_SIZE/2);
memento->dl_count = amf_ue->dl_count;
memento->ul_count = amf_ue->ul_count.i32;
memcpy(memento->kgnb, amf_ue->kgnb, OGS_SHA256_DIGEST_SIZE);
memcpy(memento->nh, amf_ue->nh, OGS_SHA256_DIGEST_SIZE);
memento->selected_enc_algorithm = amf_ue->selected_enc_algorithm;
memento->selected_int_algorithm = amf_ue->selected_int_algorithm;
}
/* Restore the sensitive context fields into the UE context */
void amf_ue_restore_memento(amf_ue_t *amf_ue, const amf_ue_memento_t *memento)
{
ogs_assert(amf_ue);
ogs_assert(memento);
memcpy(&amf_ue->ue_security_capability, &memento->ue_security_capability,
sizeof(amf_ue->ue_security_capability));
memcpy(&amf_ue->ue_network_capability, &memento->ue_network_capability,
sizeof(amf_ue->ue_network_capability));
memcpy(amf_ue->rand, memento->rand, OGS_RAND_LEN);
memcpy(amf_ue->autn, memento->autn, OGS_AUTN_LEN);
memcpy(amf_ue->xres_star, memento->xres_star, OGS_MAX_RES_LEN);
memcpy(amf_ue->abba, memento->abba, OGS_NAS_MAX_ABBA_LEN);
amf_ue->abba_len = memento->abba_len;
memcpy(amf_ue->hxres_star, memento->hxres_star, OGS_MAX_RES_LEN);
memcpy(amf_ue->kamf, memento->kamf, OGS_SHA256_DIGEST_SIZE);
memcpy(amf_ue->knas_int, memento->knas_int, OGS_SHA256_DIGEST_SIZE/2);
memcpy(amf_ue->knas_enc, memento->knas_enc, OGS_SHA256_DIGEST_SIZE/2);
amf_ue->dl_count = memento->dl_count;
amf_ue->ul_count.i32 = memento->ul_count;
memcpy(amf_ue->kgnb, memento->kgnb, OGS_SHA256_DIGEST_SIZE);
memcpy(amf_ue->nh, memento->nh, OGS_SHA256_DIGEST_SIZE);
amf_ue->selected_enc_algorithm = memento->selected_enc_algorithm;
amf_ue->selected_int_algorithm = memento->selected_int_algorithm;
}
void amf_clear_subscribed_info(amf_ue_t *amf_ue)
{
int i, j;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -237,6 +237,67 @@ struct ran_ue_s {
ogs_pool_id_t amf_ue_id;
};
typedef struct amf_ue_memento_s {
/* UE security capability info: supported security features. */
ogs_nas_ue_security_capability_t ue_security_capability;
/* UE network capability info: supported network features. */
ogs_nas_ue_network_capability_t ue_network_capability;
/* Random challenge value */
uint8_t rand[OGS_RAND_LEN];
/* Authentication token */
uint8_t autn[OGS_AUTN_LEN];
/* Expected auth response. */
uint8_t xres_star[OGS_MAX_RES_LEN];
/* NAS backoff parameter value. */
uint8_t abba[OGS_NAS_MAX_ABBA_LEN];
uint8_t abba_len;
/* Hash of XRES*. */
uint8_t hxres_star[OGS_MAX_RES_LEN];
/* Key for AMF derived from NAS key. */
uint8_t kamf[OGS_SHA256_DIGEST_SIZE];
/* Integrity and ciphering keys */
uint8_t knas_int[OGS_SHA256_DIGEST_SIZE/2];
uint8_t knas_enc[OGS_SHA256_DIGEST_SIZE/2];
/* Downlink counter */
uint32_t dl_count;
/* Uplink counter (24-bit stored in uint32_t) */
uint32_t ul_count;
/* gNB key derived from kasme */
uint8_t kgnb[OGS_SHA256_DIGEST_SIZE];
/*
* Next Hop Channing Counter
*
* Note that the "nhcc" field is not included in the backup
* because it is a transient counter used only during next-hop key
* derivation. In our design, only the persistent keying material
* and related values that are required to recreate the security context
* are backed up. The nhcc value is recalculated or updated dynamically
* when the next hop key is derived (e.g. via ogs_kdf_nh_enb()),
* so it is not necessary to store it in the backup.
*
* If there is a requirement to preserve the exact nhcc value across state
* transitions, you could add it to the backup structure, but typically
* it is treated as a computed, temporary value that can be reinitialized
* safely without compromising the security context.
* struct {
* ED2(uint8_t nhcc_spare:5;,
* uint8_t nhcc:3;)
* };
*/
/* Next hop key */
uint8_t nh[OGS_SHA256_DIGEST_SIZE];
/* Selected algorithms (set by UDM/subscription) */
uint8_t selected_enc_algorithm;
uint8_t selected_int_algorithm;
} amf_ue_memento_t;
struct amf_ue_s {
ogs_sbi_object_t sbi;
ogs_pool_id_t id;
@ -367,6 +428,12 @@ struct amf_ue_s {
int security_context_available;
int mac_failed;
/* flag: 1 = allow restoration of context, 0 = disallow */
bool can_restore_context;
/* Memento of context fields */
amf_ue_memento_t memento;
/* Security Context */
ogs_nas_ue_security_capability_t ue_security_capability;
ogs_nas_ue_network_capability_t ue_network_capability;
@ -391,20 +458,29 @@ struct amf_ue_s {
char *resource_uri;
ogs_sbi_client_t *client;
} confirmation_for_5g_aka;
/* Random challenge value */
uint8_t rand[OGS_RAND_LEN];
/* Authentication token */
uint8_t autn[OGS_AUTN_LEN];
/* Expected auth response. */
uint8_t xres_star[OGS_MAX_RES_LEN];
/* NAS backoff parameter value. */
uint8_t abba[OGS_NAS_MAX_ABBA_LEN];
uint8_t abba_len;
/* Hash of XRES*. */
uint8_t hxres_star[OGS_MAX_RES_LEN];
/* Key for AMF derived from NAS key. */
uint8_t kamf[OGS_SHA256_DIGEST_SIZE];
OpenAPI_auth_result_e auth_result;
/* Integrity and ciphering keys */
uint8_t knas_int[OGS_SHA256_DIGEST_SIZE/2];
uint8_t knas_enc[OGS_SHA256_DIGEST_SIZE/2];
/* Downlink counter */
uint32_t dl_count;
/* Uplink counter (24-bit stored in uint32_t) */
union {
struct {
ED3(uint8_t spare;,
@ -413,14 +489,17 @@ struct amf_ue_s {
} __attribute__ ((packed));
uint32_t i32;
} ul_count;
/* gNB key derived from kasme */
uint8_t kgnb[OGS_SHA256_DIGEST_SIZE];
struct {
ED2(uint8_t nhcc_spare:5;,
uint8_t nhcc:3;) /* Next Hop Channing Counter */
};
/* Next hop key */
uint8_t nh[OGS_SHA256_DIGEST_SIZE]; /* NH Security Key */
/* Selected algorithms (set by UDM/subscription) */
/* defined in 'lib/nas/common/types.h'
* #define OGS_NAS_SECURITY_ALGORITHMS_NEA0 0
* #define OGS_NAS_SECURITY_ALGORITHMS_128_NEA1 1
@ -1003,6 +1082,9 @@ int amf_m_tmsi_free(amf_m_tmsi_t *tmsi);
uint8_t amf_selected_int_algorithm(amf_ue_t *amf_ue);
uint8_t amf_selected_enc_algorithm(amf_ue_t *amf_ue);
void amf_ue_save_memento(amf_ue_t *amf_ue, amf_ue_memento_t *memento);
void amf_ue_restore_memento(amf_ue_t *amf_ue, const amf_ue_memento_t *memento);
void amf_clear_subscribed_info(amf_ue_t *amf_ue);
bool amf_update_allowed_nssai(amf_ue_t *amf_ue);

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -35,6 +35,24 @@
#undef OGS_LOG_DOMAIN
#define OGS_LOG_DOMAIN __gmm_log_domain
#define AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s) do { \
if ((amf_ue)->can_restore_context) { \
/* Restore context if allowed */ \
amf_ue_restore_memento((amf_ue), &((amf_ue)->memento)); \
(amf_ue)->security_context_available = 1; \
(amf_ue)->mac_failed = 0; \
if (!OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered)) \
OGS_FSM_TRAN((s), &gmm_state_registered); \
ogs_warn("[%s] Failure in transaction; restoring context and " \
"transitioning to REGISTERED.", (amf_ue)->supi); \
} else { \
/* Transition to exception state if not allowed */ \
OGS_FSM_TRAN((s), &gmm_state_exception); \
ogs_warn("[%s] Failure in transaction; no context " \
"restoration.", (amf_ue)->supi); \
} \
} while (0)
typedef enum {
GMM_COMMON_STATE_DEREGISTERED,
GMM_COMMON_STATE_REGISTERED,
@ -43,7 +61,6 @@ typedef enum {
static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
gmm_common_state_e state);
void gmm_state_initial(ogs_fsm_t *s, amf_event_t *e)
{
ogs_assert(s);
@ -1279,6 +1296,16 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
ogs_assert(amf_ue);
}
/* If transition is from REGISTERED, allow restoration */
if (state == GMM_COMMON_STATE_REGISTERED) {
amf_ue->can_restore_context = 1;
amf_ue_save_memento(amf_ue, &amf_ue->memento);
} else if (state == GMM_COMMON_STATE_DEREGISTERED) {
/* Transition from de-registered: do not restore */
amf_ue->can_restore_context = 0;
} else
ogs_assert_if_reached();
switch (e->h.id) {
case AMF_EVENT_5GMM_MESSAGE:
nas_message = e->nas.message;
@ -1321,7 +1348,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
r = nas_5gs_send_registration_reject(ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1382,7 +1409,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1395,7 +1422,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
OGS_5GMM_CAUSE_NO_NETWORK_SLICES_AVAILABLE);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1459,7 +1486,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
OGS_5GMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1471,7 +1498,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
r = nas_5gs_send_service_reject(ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1481,7 +1508,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
OGS_5GMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1491,7 +1518,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
OGS_5GMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1510,7 +1537,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
r = nas_5gs_send_service_reject(ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1526,7 +1553,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
NGAP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1542,7 +1569,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
r = nas_5gs_send_gmm_reject(ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1551,7 +1578,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
r = nas_5gs_send_gmm_reject(ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1581,7 +1608,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
if (!h.integrity_protected || !SECURITY_CONTEXT_IS_VALID(amf_ue)) {
ogs_error("No Security Context");
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1650,7 +1677,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e,
case OGS_NAS_5GS_UL_NAS_TRANSPORT:
if (!h.integrity_protected || !SECURITY_CONTEXT_IS_VALID(amf_ue)) {
ogs_error("No Security Context");
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1726,10 +1753,12 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
amf_ue, &nas_message->gmm.authentication_response);
if (rv != OGS_OK) {
ogs_error("gmm_handle_authentication_response() failed");
r = nas_5gs_send_authentication_reject(amf_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
break;
@ -1740,7 +1769,7 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
authentication_failure_parameter;
ogs_assert(authentication_failure_parameter);
ogs_debug("[%s] Authentication failure [%d]", amf_ue->suci,
ogs_warn("[%s] Authentication failure [%d]", amf_ue->suci,
authentication_failure->gmm_cause);
amf_metrics_inst_by_cause_add(authentication_failure->gmm_cause,
@ -1793,9 +1822,9 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
r = nas_5gs_send_authentication_reject(amf_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
case OGS_NAS_5GS_REGISTRATION_REQUEST:
ogs_warn("Registration request");
gmm_cause = gmm_handle_registration_request(
@ -1807,7 +1836,7 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
r = nas_5gs_send_registration_reject(ran_ue, amf_ue, gmm_cause);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1846,7 +1875,8 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
r = nas_5gs_send_authentication_reject(amf_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
} else {
amf_ue->t3560.retry_count++;
r = nas_5gs_send_authentication_request(amf_ue);
@ -1879,11 +1909,12 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
ogs_error("[%s] HTTP response error [%d]",
amf_ue->suci, sbi_message->res_status);
}
r = nas_5gs_send_gmm_reject_from_sbi(
amf_ue, sbi_message->res_status);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
@ -1897,7 +1928,8 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
r = nas_5gs_send_authentication_reject(amf_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}
break;
CASE(OGS_SBI_HTTP_METHOD_PUT)
@ -1909,7 +1941,8 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
r = nas_5gs_send_authentication_reject(amf_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
} else {
amf_ue->selected_int_algorithm =
amf_selected_int_algorithm(amf_ue);
@ -1923,7 +1956,7 @@ void gmm_state_authentication(ogs_fsm_t *s, amf_event_t *e)
"bypassed with NIA0",
amf_ue->selected_enc_algorithm,
amf_ue->selected_int_algorithm);
OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_exception);
AMF_RESTORE_CONTEXT_ON_FAILURE(amf_ue, s);
break;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -80,6 +80,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

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

View file

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

View file

@ -160,14 +160,19 @@ void ngap_recv_handler(ogs_sock_t *sock)
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));
if ((not->sn_assoc_change.sac_outbound_streams-1) >= 1) {
/* NEXT_ID(MAX >= MIN) */
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(addr);
memcpy(addr, &from, sizeof(ogs_sockaddr_t));
ngap_event_push(AMF_EVENT_NGAP_LO_SCTP_COMM_UP,
sock, addr, NULL,
not->sn_assoc_change.sac_inbound_streams,
not->sn_assoc_change.sac_outbound_streams);
ngap_event_push(AMF_EVENT_NGAP_LO_SCTP_COMM_UP,
sock, addr, NULL,
not->sn_assoc_change.sac_inbound_streams,
not->sn_assoc_change.sac_outbound_streams);
} else
ogs_error("Invalid sn_assoc_change.sac_outbound_streams %d",
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) {

View file

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

View file

@ -256,6 +256,15 @@ ogs_sbi_request_t *amf_nsmf_pdusession_build_create_sm_context(
message.http.accept = (char *)(OGS_SBI_CONTENT_JSON_TYPE ","
OGS_SBI_CONTENT_NGAP_TYPE "," OGS_SBI_CONTENT_PROBLEM_TYPE);
/*
* Callback Header Configuration
*
* The 3gpp-Sbi-Callback HTTP header (per 3GPP TS 29.500 v17.9.0) indicates that
* a message is an asynchronous notification or callback. This header should be
* included only in HTTP POST requests that are callbacks (e.g., event or
* notification messages) and must not be added to regular service requests,
* such as registration (HTTP PUT) or subscription requests.
*/
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NSMF_PDUSESSION_STATUS_NOTIFY;
@ -564,6 +573,18 @@ ogs_sbi_request_t *amf_nsmf_callback_build_n1_n2_failure_notify(
message.N1N2MsgTxfrFailureNotification = &N1N2MsgTxfrFailureNotification;
/*
* Callback Header Configuration
*
* The 3gpp-Sbi-Callback HTTP header (per 3GPP TS 29.500 v17.9.0) indicates that
* a message is an asynchronous notification or callback. This header should be
* included only in HTTP POST requests that are callbacks (e.g., event or
* notification messages) and must not be added to regular service requests,
* such as registration (HTTP PUT) or subscription requests.
*/
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NAMF_COMMUNICATION_ONN1N2TRANSFERFAILURE;
request = ogs_sbi_build_request(&message);
ogs_expect(request);

View file

@ -85,9 +85,6 @@ ogs_sbi_request_t *amf_nudm_uecm_build_registration(
message.Amf3GppAccessRegistration = &Amf3GppAccessRegistration;
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NUDM_UECM_DEREGISTRATION_NOTIFICATION;
request = ogs_sbi_build_request(&message);
ogs_expect(request);
@ -243,9 +240,6 @@ ogs_sbi_request_t *amf_nudm_sdm_build_subscription(amf_ue_t *amf_ue, void *data)
message.SDMSubscription = &SDMSubscription;
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NUDM_SDM_NOTIFICATION;
request = ogs_sbi_build_request(&message);
ogs_expect(request);

View file

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

View file

@ -135,7 +135,8 @@ void ausf_state_operational(ogs_fsm_t *s, ausf_event_t *e)
SWITCH(message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
if (message.AuthenticationInfo &&
message.AuthenticationInfo->supi_or_suci) {
message.AuthenticationInfo->supi_or_suci &&
strlen(message.AuthenticationInfo->supi_or_suci)) {
ausf_ue = ausf_ue_find_by_suci_or_supi(
message.AuthenticationInfo->supi_or_suci);
if (!ausf_ue) {
@ -348,10 +349,10 @@ void ausf_state_operational(ogs_fsm_t *s, ausf_event_t *e)
ogs_fsm_dispatch(&ausf_ue->sm, e);
if (OGS_FSM_CHECK(&ausf_ue->sm, ausf_ue_state_exception)) {
ogs_error("[%s] State machine exception", ausf_ue->suci);
ogs_warn("[%s] State machine exception", ausf_ue->suci);
ausf_ue_remove(ausf_ue);
} else if (OGS_FSM_CHECK(&ausf_ue->sm, ausf_ue_state_deleted)) {
ogs_debug("[%s] AUSF-UE removed", ausf_ue->supi);
ogs_info("[%s] AUSF-UE removed", ausf_ue->supi);
ausf_ue_remove(ausf_ue);
}
break;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -65,6 +65,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -181,7 +181,9 @@ void ausf_ue_state_operational(ogs_fsm_t *s, ausf_event_t *e)
ogs_sbi_server_send_error(
stream, message->res_status,
NULL, "HTTP response error", ausf_ue->suci,
message->ProblemDetails->cause));
(message->ProblemDetails) ?
message->ProblemDetails->cause : NULL));
OGS_FSM_TRAN(s, ausf_ue_state_exception);
break;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -67,6 +67,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -60,10 +60,6 @@ static int check_signal(int signum)
ogs_log_cycle();
break;
case SIGWINCH:
ogs_info("Signal-NUM[%d] received (%s)",
signum, ogs_signal_description_get(signum));
break;
case SIGUSR1:
fprintf(stderr,
"%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",

View file

@ -297,9 +297,10 @@ ogs_pkbuf_t *emm_build_authentication_request(mme_ue_t *mme_ue)
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_AUTHENTICATION_REQUEST;
authentication_request->nas_key_set_identifierasme.tsc = 0;
authentication_request->nas_key_set_identifierasme.tsc =
mme_ue->nas_eps.mme.tsc;
authentication_request->nas_key_set_identifierasme.value =
mme_ue->nas_eps.ksi;
mme_ue->nas_eps.mme.ksi;
memcpy(authentication_request->authentication_parameter_rand.rand,
mme_ue->rand, OGS_RAND_LEN);
memcpy(authentication_request->authentication_parameter_autn.autn,
@ -355,8 +356,8 @@ ogs_pkbuf_t *emm_build_security_mode_command(mme_ue_t *mme_ue)
selected_nas_security_algorithms->type_of_ciphering_algorithm =
mme_ue->selected_enc_algorithm;
nas_key_set_identifier->tsc = 0;
nas_key_set_identifier->value = 0;
nas_key_set_identifier->tsc = mme_ue->nas_eps.mme.tsc;
nas_key_set_identifier->value = mme_ue->nas_eps.mme.ksi;
replayed_ue_security_capabilities->eea = mme_ue->ue_network_capability.eea;
replayed_ue_security_capabilities->eia = mme_ue->ue_network_capability.eia;

View file

@ -78,13 +78,26 @@ int emm_handle_attach_request(enb_ue_t *enb_ue, mme_ue_t *mme_ue,
memcpy(&mme_ue->nas_eps.attach, eps_attach_type,
sizeof(ogs_nas_eps_attach_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_ATTACH_REQUEST;
mme_ue->nas_eps.ksi = eps_attach_type->nas_key_set_identifier;
ogs_debug(" OGS_NAS_EPS TYPE[%d] KSI[%d]",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi);
ogs_debug(" ATTACH TSC[%d] KSI[%d] VALUE[%d]",
ogs_debug(" ATTACH TYPE[%d] TSC[%d] KSI[%d] VALUE[%d]",
mme_ue->nas_eps.type,
mme_ue->nas_eps.attach.tsc,
mme_ue->nas_eps.attach.nas_key_set_identifier,
mme_ue->nas_eps.attach.value);
mme_ue->nas_eps.ue.tsc = eps_attach_type->tsc;
mme_ue->nas_eps.ue.ksi = eps_attach_type->nas_key_set_identifier;
ogs_debug(" OLD TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
if (mme_ue->nas_eps.ue.ksi < OGS_NAS_KSI_NO_KEY_IS_AVAILABLE) {
mme_ue->nas_eps.mme.tsc = mme_ue->nas_eps.ue.tsc;
mme_ue->nas_eps.mme.ksi = mme_ue->nas_eps.ue.ksi;
}
ogs_debug(" NEW TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
switch(mme_ue->nas_eps.attach.value){
case OGS_NAS_ATTACH_TYPE_EPS_ATTACH:
ogs_debug(" Requested EPS_ATTACH_TYPE[1, EPS_ATTACH]");
@ -99,6 +112,7 @@ int emm_handle_attach_request(enb_ue_t *enb_ue, mme_ue_t *mme_ue,
ogs_error(" Invalid Requested EPS_ATTACH_TYPE[%d]",
mme_ue->nas_eps.attach.value);
}
/*
* ATTACH_REQUEST
* TAU_REQUEST
@ -365,6 +379,50 @@ int emm_handle_attach_complete(
return r;
}
int emm_handle_authentication_response(
enb_ue_t *enb_ue, mme_ue_t *mme_ue,
ogs_nas_eps_authentication_response_t *authentication_response)
{
ogs_nas_authentication_response_parameter_t
*authentication_response_parameter =
&authentication_response->authentication_response_parameter;
ogs_assert(authentication_response);
ogs_assert(mme_ue);
ogs_assert(enb_ue);
ogs_debug("Authentication response");
ogs_debug(" IMSI[%s]", mme_ue->imsi_bcd);
CLEAR_MME_UE_TIMER(mme_ue->t3460);
if (authentication_response_parameter->length == 0 ||
memcmp(authentication_response_parameter->res, mme_ue->xres,
authentication_response_parameter->length) != 0) {
ogs_log_hexdump(OGS_LOG_WARN,
authentication_response_parameter->res,
authentication_response_parameter->length);
ogs_log_hexdump(OGS_LOG_WARN,
mme_ue->xres, OGS_MAX_RES_LEN);
return OGS_ERROR;
} else {
mme_ue->selected_int_algorithm = mme_selected_int_algorithm(mme_ue);
mme_ue->selected_enc_algorithm = mme_selected_enc_algorithm(mme_ue);
if (mme_ue->selected_int_algorithm ==
OGS_NAS_SECURITY_ALGORITHMS_EIA0) {
ogs_error("Encrypt[0x%x] can be skipped with EEA0, "
"but Integrity[0x%x] cannot be bypassed with EIA0",
mme_ue->selected_enc_algorithm,
mme_ue->selected_int_algorithm);
return OGS_ERROR;
}
}
return OGS_OK;
}
int emm_handle_identity_response(
enb_ue_t *enb_ue, mme_ue_t *mme_ue,
ogs_nas_eps_identity_response_t *identity_response)
@ -457,15 +515,26 @@ int emm_handle_detach_request(
mme_ue->nas_eps.type = MME_EPS_TYPE_DETACH_REQUEST_FROM_UE;
mme_ue->detach_type = MME_DETACH_TYPE_REQUEST_FROM_UE;
mme_ue->nas_eps.ksi = detach_type->nas_key_set_identifier;
ogs_debug(" OGS_NAS_EPS TYPE[%d] KSI[%d]",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi);
ogs_debug(" DETACH TSC[%d] KSI[%d] SWITCH_OFF[%d] VALUE[%d]",
mme_ue->nas_eps.attach.tsc,
ogs_debug(" DETACH TYPE[%d] TSC[%d] KSI[%d] SWITCH_OFF[%d] VALUE[%d]",
mme_ue->nas_eps.type,
mme_ue->nas_eps.detach.tsc,
mme_ue->nas_eps.detach.nas_key_set_identifier,
mme_ue->nas_eps.detach.switch_off,
mme_ue->nas_eps.attach.value);
mme_ue->nas_eps.ue.tsc = detach_type->tsc;
mme_ue->nas_eps.ue.ksi = detach_type->nas_key_set_identifier;
ogs_debug(" OLD TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
if (mme_ue->nas_eps.ue.ksi < OGS_NAS_KSI_NO_KEY_IS_AVAILABLE) {
mme_ue->nas_eps.mme.tsc = mme_ue->nas_eps.ue.tsc;
mme_ue->nas_eps.mme.ksi = mme_ue->nas_eps.ue.ksi;
}
ogs_debug(" NEW TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
switch (detach_request->detach_type.value) {
/* 0 0 1 : EPS detach */
case OGS_NAS_DETACH_TYPE_FROM_UE_EPS_DETACH:
@ -517,14 +586,24 @@ int emm_handle_service_request(
/* Set EPS Service */
mme_ue->nas_eps.type = MME_EPS_TYPE_SERVICE_REQUEST;
mme_ue->nas_eps.ksi = ksi_and_sequence_number->ksi;
ogs_debug(" OGS_NAS_EPS TYPE[%d] KSI[%d]",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi);
ogs_debug(" SERVICE TSC[%d] KSI[%d] VALUE[%d]",
ogs_debug(" SERVICE TYPE[%d] TSC[%d] KSI[%d] VALUE[%d]",
mme_ue->nas_eps.type,
mme_ue->nas_eps.service.tsc,
mme_ue->nas_eps.service.nas_key_set_identifier,
mme_ue->nas_eps.service.value);
mme_ue->nas_eps.ue.ksi = ksi_and_sequence_number->ksi;
ogs_debug(" OLD TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
if (mme_ue->nas_eps.ue.ksi < OGS_NAS_KSI_NO_KEY_IS_AVAILABLE) {
mme_ue->nas_eps.mme.tsc = mme_ue->nas_eps.ue.tsc;
mme_ue->nas_eps.mme.ksi = mme_ue->nas_eps.ue.ksi;
}
ogs_debug(" NEW TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
/*
* ATTACH_REQUEST
* TAU_REQUEST
@ -609,15 +688,26 @@ int emm_handle_tau_request(
memcpy(&mme_ue->nas_eps.update, eps_update_type,
sizeof(ogs_nas_eps_update_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_TAU_REQUEST;
mme_ue->nas_eps.ksi = eps_update_type->nas_key_set_identifier;
ogs_debug(" OGS_NAS_EPS TYPE[%d] KSI[%d]",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi);
ogs_debug(" UPDATE TSC[%d] KSI[%d] Active-flag[%d] VALUE[%d]",
ogs_debug(" UPDATE TYPE[%d] TSC[%d] KSI[%d] Active-flag[%d] VALUE[%d]",
mme_ue->nas_eps.type,
mme_ue->nas_eps.update.tsc,
mme_ue->nas_eps.update.nas_key_set_identifier,
mme_ue->nas_eps.update.active_flag,
mme_ue->nas_eps.update.value);
mme_ue->nas_eps.ue.tsc = eps_update_type->tsc;
mme_ue->nas_eps.ue.ksi = eps_update_type->nas_key_set_identifier;
ogs_debug(" OLD TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
if (mme_ue->nas_eps.ue.ksi < OGS_NAS_KSI_NO_KEY_IS_AVAILABLE) {
mme_ue->nas_eps.mme.tsc = mme_ue->nas_eps.ue.tsc;
mme_ue->nas_eps.mme.ksi = mme_ue->nas_eps.ue.ksi;
}
ogs_debug(" NEW TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
/*
* ATTACH_REQUEST
* TAU_REQUEST
@ -756,9 +846,24 @@ int emm_handle_extended_service_request(
memcpy(&mme_ue->nas_eps.service, service_type,
sizeof(ogs_nas_service_type_t));
mme_ue->nas_eps.type = MME_EPS_TYPE_EXTENDED_SERVICE_REQUEST;
mme_ue->nas_eps.ksi = service_type->nas_key_set_identifier;
ogs_debug(" OGS_NAS_EPS TYPE[%d] KSI[%d]",
mme_ue->nas_eps.type, mme_ue->nas_eps.ksi);
ogs_debug(" Extended SERVICE TYPE[%d] TSC[%d] KSI[%d] VALUE[%d]",
mme_ue->nas_eps.type,
mme_ue->nas_eps.service.tsc,
mme_ue->nas_eps.service.nas_key_set_identifier,
mme_ue->nas_eps.service.value);
mme_ue->nas_eps.ue.tsc = service_type->tsc;
mme_ue->nas_eps.ue.ksi = service_type->nas_key_set_identifier;
ogs_debug(" OLD TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
if (mme_ue->nas_eps.ue.ksi < OGS_NAS_KSI_NO_KEY_IS_AVAILABLE) {
mme_ue->nas_eps.mme.tsc = mme_ue->nas_eps.ue.tsc;
mme_ue->nas_eps.mme.ksi = mme_ue->nas_eps.ue.ksi;
}
ogs_debug(" NEW TSC[UE:%d,MME:%d] KSI[UE:%d,MME:%d]",
mme_ue->nas_eps.ue.tsc, mme_ue->nas_eps.mme.tsc,
mme_ue->nas_eps.ue.ksi, mme_ue->nas_eps.mme.ksi);
/*
* ATTACH_REQUEST

View file

@ -33,6 +33,10 @@ int emm_handle_attach_complete(
enb_ue_t *enb_ue, mme_ue_t *mme_ue,
ogs_nas_eps_attach_complete_t *attach_complete);
int emm_handle_authentication_response(
enb_ue_t *enb_ue, mme_ue_t *mme_ue,
ogs_nas_eps_authentication_response_t *authentication_response);
int emm_handle_identity_response(
enb_ue_t *enb_ue, mme_ue_t *mme_ue,
ogs_nas_eps_identity_response_t *identity_response);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -37,6 +37,24 @@
#undef OGS_LOG_DOMAIN
#define OGS_LOG_DOMAIN __emm_log_domain
#define MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s) do { \
if ((mme_ue)->can_restore_context) { \
/* Restore context if allowed */ \
mme_ue_restore_memento((mme_ue), &((mme_ue)->memento)); \
(mme_ue)->security_context_available = 1; \
(mme_ue)->mac_failed = 0; \
if (!OGS_FSM_CHECK(&mme_ue->sm, emm_state_registered)) \
OGS_FSM_TRAN((s), &emm_state_registered); \
ogs_warn("[%s] Failure in transaction; restoring context and " \
"transitioning to REGISTERED.", (mme_ue)->imsi_bcd); \
} else { \
/* Transition to exception state if not allowed */ \
OGS_FSM_TRAN((s), &emm_state_exception); \
ogs_warn("[%s] Failure in transaction; no context " \
"restoration.", (mme_ue)->imsi_bcd); \
} \
} while (0)
typedef enum {
EMM_COMMON_STATE_DEREGISTERED,
EMM_COMMON_STATE_REGISTERED,
@ -45,7 +63,6 @@ typedef enum {
static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
emm_common_state_e state);
void emm_state_initial(ogs_fsm_t *s, mme_event_t *e)
{
ogs_assert(s);
@ -304,6 +321,15 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
mme_ue = mme_ue_find_by_id(e->mme_ue_id);
ogs_assert(mme_ue);
/* If transition is from REGISTERED, allow restoration */
if (state == EMM_COMMON_STATE_REGISTERED) {
mme_ue->can_restore_context = 1;
mme_ue_save_memento(mme_ue, &mme_ue->memento);
} else if (state == EMM_COMMON_STATE_DEREGISTERED) {
/* Transition from de-registered: do not restore */
mme_ue->can_restore_context = 0;
}
switch (e->id) {
case MME_EVENT_EMM_MESSAGE:
message = e->nas_message;
@ -337,7 +363,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -345,7 +371,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
enb_ue, mme_ue, &message->emm.service_request);
if (rv != OGS_OK) {
ogs_error("emm_handle_service_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -355,7 +381,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -365,7 +391,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -375,7 +401,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -385,7 +411,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_NO_EPS_BEARER_CONTEXT_ACTIVATED);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -411,7 +437,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -422,13 +448,13 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
&message->emm.identity_response);
if (rv != OGS_OK) {
ogs_error("emm_handle_identity_response() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
if (!MME_UE_HAVE_IMSI(mme_ue)) {
ogs_error("No IMSI");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -450,7 +476,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
enb_ue, mme_ue, &message->emm.attach_request, e->pkbuf);
if (rv != OGS_OK) {
ogs_error("emm_handle_attach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -485,7 +511,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
}
@ -513,7 +539,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
&message->emm.tracking_area_update_request, e->pkbuf);
if (rv != OGS_OK) {
ogs_error("emm_handle_tau_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -531,7 +557,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
if (message->emm.tracking_area_update_request.presencemask & OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_OLD_P_TMSI_SIGNATURE_TYPE)
@ -547,7 +573,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -557,7 +583,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -567,7 +593,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_NO_EPS_BEARER_CONTEXT_ACTIVATED);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -752,7 +778,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
enb_ue, mme_ue, &message->emm.extended_service_request);
if (rv != OGS_OK) {
ogs_error("emm_handle_extended_service_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -762,7 +788,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -772,7 +798,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -782,7 +808,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -831,7 +857,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -874,7 +900,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -897,7 +923,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
enb_ue, mme_ue, &message->emm.detach_request_from_ue);
if (rv != OGS_OK) {
ogs_error("emm_handle_detach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -906,7 +932,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
ogs_assert(OGS_OK ==
nas_eps_send_service_reject(enb_ue, mme_ue,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK));
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -915,7 +941,7 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
ogs_assert(OGS_OK ==
nas_eps_send_service_reject(enb_ue, mme_ue,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK));
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -1060,6 +1086,8 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
enb_ue_t *enb_ue = NULL;
ogs_nas_eps_message_t *message = NULL;
ogs_nas_eps_authentication_failure_t *authentication_failure = NULL;
ogs_assert(s);
ogs_assert(e);
@ -1082,64 +1110,28 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
switch (message->emm.h.message_type) {
case OGS_NAS_EPS_AUTHENTICATION_RESPONSE:
{
ogs_nas_eps_authentication_response_t *authentication_response =
&message->emm.authentication_response;
ogs_nas_authentication_response_parameter_t
*authentication_response_parameter =
&authentication_response->
authentication_response_parameter;
ogs_debug("Authentication response");
ogs_debug(" IMSI[%s]", mme_ue->imsi_bcd);
CLEAR_MME_UE_TIMER(mme_ue->t3460);
if (authentication_response_parameter->length == 0 ||
memcmp(authentication_response_parameter->res,
mme_ue->xres,
authentication_response_parameter->length) != 0) {
ogs_log_hexdump(OGS_LOG_WARN,
authentication_response_parameter->res,
authentication_response_parameter->length);
ogs_log_hexdump(OGS_LOG_WARN,
mme_ue->xres, OGS_MAX_RES_LEN);
rv = emm_handle_authentication_response(enb_ue, mme_ue,
&message->emm.authentication_response);
if (rv != OGS_OK) {
ogs_error("emm_handle_authentication_response() failed");
r = nas_eps_send_authentication_reject(mme_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_exception);
} else {
mme_ue->selected_int_algorithm =
mme_selected_int_algorithm(mme_ue);
mme_ue->selected_enc_algorithm =
mme_selected_enc_algorithm(mme_ue);
if (mme_ue->selected_int_algorithm ==
OGS_NAS_SECURITY_ALGORITHMS_EIA0) {
ogs_error("Encrypt[0x%x] can be skipped with EEA0, "
"but Integrity[0x%x] cannot be bypassed with EIA0",
mme_ue->selected_enc_algorithm,
mme_ue->selected_int_algorithm);
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_exception);
break;
}
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_security_mode);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_security_mode);
break;
}
case OGS_NAS_EPS_AUTHENTICATION_FAILURE:
{
ogs_nas_eps_authentication_failure_t *authentication_failure =
&message->emm.authentication_failure;
authentication_failure = &message->emm.authentication_failure;
ogs_nas_authentication_failure_parameter_t
*authentication_failure_parameter =
&authentication_failure->
authentication_failure_parameter;
ogs_debug("Authentication failure");
ogs_debug(" IMSI[%s] OGS_NAS_EMM_CAUSE[%d]", mme_ue->imsi_bcd,
ogs_warn("Authentication failure");
ogs_warn(" IMSI[%s] OGS_NAS_EMM_CAUSE[%d]", mme_ue->imsi_bcd,
authentication_failure->emm_cause);
CLEAR_MME_UE_TIMER(mme_ue->t3460);
@ -1167,17 +1159,16 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
r = nas_eps_send_authentication_reject(mme_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
case OGS_NAS_EPS_ATTACH_REQUEST:
ogs_warn("[%s] Attach request", mme_ue->imsi_bcd);
rv = emm_handle_attach_request(
enb_ue, mme_ue, &message->emm.attach_request, e->pkbuf);
if (rv != OGS_OK) {
ogs_error("emm_handle_attach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -1194,7 +1185,7 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
enb_ue, mme_ue, &message->emm.detach_request_from_ue);
if (rv != OGS_OK) {
ogs_error("emm_handle_detach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -1203,7 +1194,7 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
ogs_assert(OGS_OK ==
nas_eps_send_service_reject(enb_ue, mme_ue,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK));
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -1212,7 +1203,7 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
ogs_assert(OGS_OK ==
nas_eps_send_service_reject(enb_ue, mme_ue,
OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK));
OGS_FSM_TRAN(s, &emm_state_exception);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
}
@ -1243,11 +1234,11 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
mme_timer_cfg(MME_TIMER_T3460)->max_count) {
ogs_warn("Retransmission of IMSI[%s] failed. "
"Stop retransmission", mme_ue->imsi_bcd);
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_exception);
r = nas_eps_send_authentication_reject(mme_ue);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
MME_RESTORE_CONTEXT_ON_FAILURE(mme_ue, s);
break;
} else {
mme_ue->t3460.retry_count++;
r = nas_eps_send_authentication_request(mme_ue);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -3617,6 +3617,9 @@ mme_ue_t *mme_ue_add(enb_ue_t *enb_ue)
mme_ue->csmap = NULL;
mme_ue->vlr_ostream_id = 0;
/* Initialization */
mme_ue->nas_eps.mme.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE;
mme_ue_fsm_init(mme_ue);
ogs_list_add(&self.mme_ue_list, mme_ue);
@ -4197,20 +4200,36 @@ void enb_ue_source_deassociate_target(enb_ue_t *enb_ue)
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
if (target_ue) {
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
} else
ogs_error("Target-UE-ID [%d] has already been removed "
"(ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d])",
source_ue->target_ue_id,
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
} else if (enb_ue->source_ue_id >= OGS_MIN_POOL_ID &&
enb_ue->source_ue_id <= OGS_MAX_POOL_ID) {
target_ue = enb_ue;
source_ue = enb_ue_find_by_id(enb_ue->source_ue_id);
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
if (source_ue) {
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
} else
ogs_error("Source-UE-ID [%d] has already been removed "
"(ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d])",
target_ue->source_ue_id,
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
}
}
@ -4250,6 +4269,7 @@ void sgw_ue_source_deassociate_target(sgw_ue_t *sgw_ue)
{
sgw_ue_t *source_ue = NULL;
sgw_ue_t *target_ue = NULL;
ogs_assert(sgw_ue);
if (sgw_ue->target_ue_id >= OGS_MIN_POOL_ID &&
@ -4259,20 +4279,33 @@ void sgw_ue_source_deassociate_target(sgw_ue_t *sgw_ue)
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
if (target_ue) {
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
} else
ogs_error("Target-UE-ID [%d] has already been removed "
"(SGW-S11-TEID[%d])",
source_ue->target_ue_id, source_ue->sgw_s11_teid);
} else if (sgw_ue->source_ue_id >= OGS_MIN_POOL_ID &&
sgw_ue->source_ue_id <= OGS_MAX_POOL_ID) {
target_ue = sgw_ue;
source_ue = sgw_ue_find_by_id(sgw_ue->source_ue_id);
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
if (source_ue) {
ogs_assert(source_ue->target_ue_id >= OGS_MIN_POOL_ID &&
source_ue->target_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
} else
ogs_error("Source-UE-ID [%d] has already been removed "
"(SGW-S11-TEID[%d])",
target_ue->source_ue_id, target_ue->sgw_s11_teid);
ogs_assert(target_ue->source_ue_id >= OGS_MIN_POOL_ID &&
target_ue->source_ue_id <= OGS_MAX_POOL_ID);
source_ue->target_ue_id = OGS_INVALID_POOL_ID;
target_ue->source_ue_id = OGS_INVALID_POOL_ID;
}
}
@ -5027,6 +5060,83 @@ uint8_t mme_selected_enc_algorithm(mme_ue_t *mme_ue)
return 0;
}
/*
* Save the sensitive (partial) context fields
* from the UE context into the memento
*/
void mme_ue_save_memento(mme_ue_t *mme_ue, mme_ue_memento_t *memento)
{
ogs_assert(mme_ue);
ogs_assert(memento);
memcpy(&memento->ue_network_capability,
&mme_ue->ue_network_capability,
sizeof(memento->ue_network_capability));
memcpy(&memento->ms_network_capability,
&mme_ue->ms_network_capability,
sizeof(memento->ms_network_capability));
memcpy(&memento->ue_additional_security_capability,
&mme_ue->ue_additional_security_capability,
sizeof(memento->ue_additional_security_capability));
memcpy(memento->xres, mme_ue->xres, OGS_MAX_RES_LEN);
memento->xres_len = mme_ue->xres_len;
memcpy(memento->kasme, mme_ue->kasme, OGS_SHA256_DIGEST_SIZE);
memcpy(memento->rand, mme_ue->rand, OGS_RAND_LEN);
memcpy(memento->autn, mme_ue->autn, OGS_AUTN_LEN);
memcpy(memento->knas_int, mme_ue->knas_int,
OGS_SHA256_DIGEST_SIZE / 2);
memcpy(memento->knas_enc, mme_ue->knas_enc,
OGS_SHA256_DIGEST_SIZE / 2);
memento->dl_count = mme_ue->dl_count;
memento->ul_count = mme_ue->ul_count.i32;
memcpy(memento->kenb, mme_ue->kenb, OGS_SHA256_DIGEST_SIZE);
memcpy(memento->hash_mme, mme_ue->hash_mme, OGS_HASH_MME_LEN);
memento->nonceue = mme_ue->nonceue;
memento->noncemme = mme_ue->noncemme;
memento->gprs_ciphering_key_sequence_number =
mme_ue->gprs_ciphering_key_sequence_number;
memcpy(memento->nh, mme_ue->nh, OGS_SHA256_DIGEST_SIZE);
memento->selected_enc_algorithm = mme_ue->selected_enc_algorithm;
memento->selected_int_algorithm = mme_ue->selected_int_algorithm;
}
/* Restore the sensitive context fields into the UE context */
void mme_ue_restore_memento(mme_ue_t *mme_ue, const mme_ue_memento_t *memento)
{
ogs_assert(mme_ue);
ogs_assert(memento);
memcpy(&mme_ue->ue_network_capability,
&memento->ue_network_capability,
sizeof(mme_ue->ue_network_capability));
memcpy(&mme_ue->ms_network_capability,
&memento->ms_network_capability,
sizeof(mme_ue->ms_network_capability));
memcpy(&mme_ue->ue_additional_security_capability,
&memento->ue_additional_security_capability,
sizeof(mme_ue->ue_additional_security_capability));
memcpy(mme_ue->xres, memento->xres, OGS_MAX_RES_LEN);
mme_ue->xres_len = memento->xres_len;
memcpy(mme_ue->kasme, memento->kasme, OGS_SHA256_DIGEST_SIZE);
memcpy(mme_ue->rand, memento->rand, OGS_RAND_LEN);
memcpy(mme_ue->autn, memento->autn, OGS_AUTN_LEN);
memcpy(mme_ue->knas_int, memento->knas_int,
OGS_SHA256_DIGEST_SIZE / 2);
memcpy(mme_ue->knas_enc, memento->knas_enc,
OGS_SHA256_DIGEST_SIZE / 2);
mme_ue->dl_count = memento->dl_count;
mme_ue->ul_count.i32 = memento->ul_count;
memcpy(mme_ue->kenb, memento->kenb, OGS_SHA256_DIGEST_SIZE);
memcpy(mme_ue->hash_mme, memento->hash_mme, OGS_HASH_MME_LEN);
mme_ue->nonceue = memento->nonceue;
mme_ue->noncemme = memento->noncemme;
mme_ue->gprs_ciphering_key_sequence_number =
memento->gprs_ciphering_key_sequence_number;
memcpy(mme_ue->nh, memento->nh, OGS_SHA256_DIGEST_SIZE);
mme_ue->selected_enc_algorithm = memento->selected_enc_algorithm;
mme_ue->selected_int_algorithm = memento->selected_int_algorithm;
}
static void stats_add_enb_ue(void)
{
mme_metrics_inst_global_inc(MME_METR_GLOB_GAUGE_ENB_UE);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -342,6 +342,69 @@ struct sgw_ue_s {
ogs_pool_id_t mme_ue_id;
};
typedef struct mme_ue_memento_s {
/* UE network capability info: supported network features. */
ogs_nas_ue_network_capability_t ue_network_capability;
/* MS network capability info: supported network features. */
ogs_nas_ms_network_capability_t ms_network_capability;
/* UE additional security capability: extra security features. */
ogs_nas_ue_additional_security_capability_t
ue_additional_security_capability;
/* Expected response and its length */
uint8_t xres[OGS_MAX_RES_LEN];
uint8_t xres_len;
/* Derived key from HSS */
uint8_t kasme[OGS_SHA256_DIGEST_SIZE];
/* Random challenge value */
uint8_t rand[OGS_RAND_LEN];
/* Authentication token */
uint8_t autn[OGS_AUTN_LEN];
/* Integrity and ciphering keys */
uint8_t knas_int[OGS_SHA256_DIGEST_SIZE/2];
uint8_t knas_enc[OGS_SHA256_DIGEST_SIZE/2];
/* Downlink counter */
uint32_t dl_count;
/* Uplink counter (24-bit stored in uint32_t) */
uint32_t ul_count;
/* eNB key derived from kasme */
uint8_t kenb[OGS_SHA256_DIGEST_SIZE];
/* Hash used for NAS message integrity */
uint8_t hash_mme[OGS_HASH_MME_LEN];
/* Nonces for resynchronization */
uint32_t nonceue;
uint32_t noncemme;
/* GPRS ciphering key sequence number */
uint8_t gprs_ciphering_key_sequence_number;
/*
* Next Hop Channing Counter
*
* Note that the "nhcc" field is not included in the backup
* because it is a transient counter used only during next-hop key
* derivation. In our design, only the persistent keying material
* and related values that are required to recreate the security context
* are backed up. The nhcc value is recalculated or updated dynamically
* when the next hop key is derived (e.g. via ogs_kdf_nh_enb()),
* so it is not necessary to store it in the backup.
*
* If there is a requirement to preserve the exact nhcc value across state
* transitions, you could add it to the backup structure, but typically
* it is treated as a computed, temporary value that can be reinitialized
* safely without compromising the security context.
* struct {
* ED2(uint8_t nhcc_spare:5;,
* uint8_t nhcc:3;)
* };
*/
/* Next hop key */
uint8_t nh[OGS_SHA256_DIGEST_SIZE];
/* Selected algorithms (set by HSS/subscription) */
uint8_t selected_enc_algorithm;
uint8_t selected_int_algorithm;
} mme_ue_memento_t;
struct mme_ue_s {
ogs_lnode_t lnode;
ogs_pool_id_t id;
@ -355,7 +418,13 @@ struct mme_ue_s {
#define MME_EPS_TYPE_DETACH_REQUEST_FROM_UE 5
#define MME_EPS_TYPE_DETACH_REQUEST_TO_UE 6
uint8_t type;
uint8_t ksi;
struct {
ED3(uint8_t tsc:1;,
uint8_t ksi:3;,
uint8_t spare:4;)
} mme, ue;
ogs_nas_eps_attach_type_t attach;
ogs_nas_eps_update_type_t update;
ogs_nas_service_type_t service;
@ -446,30 +515,42 @@ struct mme_ue_s {
((__mME) && \
((__mME)->security_context_available == 1) && \
((__mME)->mac_failed == 0) && \
((__mME)->nas_eps.ksi != OGS_NAS_KSI_NO_KEY_IS_AVAILABLE))
((__mME)->nas_eps.ue.ksi != OGS_NAS_KSI_NO_KEY_IS_AVAILABLE))
#define CLEAR_SECURITY_CONTEXT(__mME) \
do { \
ogs_assert((__mME)); \
(__mME)->security_context_available = 0; \
(__mME)->mac_failed = 0; \
(__mME)->nas_eps.ksi = 0; \
} while(0)
int security_context_available;
int mac_failed;
/* flag: 1 = allow restoration of context, 0 = disallow */
bool can_restore_context;
/* Memento of context fields */
mme_ue_memento_t memento;
/* Security Context */
ogs_nas_ue_network_capability_t ue_network_capability;
ogs_nas_ms_network_capability_t ms_network_capability;
ogs_nas_ue_additional_security_capability_t
ue_additional_security_capability;
/* Expected response and its length */
uint8_t xres[OGS_MAX_RES_LEN];
uint8_t xres_len;
/* Derived key from HSS */
uint8_t kasme[OGS_SHA256_DIGEST_SIZE];
/* Random challenge value */
uint8_t rand[OGS_RAND_LEN];
/* Authentication token */
uint8_t autn[OGS_AUTN_LEN];
/* Integrity and ciphering keys */
uint8_t knas_int[OGS_SHA256_DIGEST_SIZE/2];
uint8_t knas_enc[OGS_SHA256_DIGEST_SIZE/2];
/* Downlink counter */
uint32_t dl_count;
/* Uplink counter (24-bit stored in i32) */
union {
struct {
ED3(uint8_t spare;,
@ -478,17 +559,23 @@ struct mme_ue_s {
} __attribute__ ((packed));
uint32_t i32;
} ul_count;
/* eNB key derived from kasme */
uint8_t kenb[OGS_SHA256_DIGEST_SIZE];
/* Hash used for NAS message integrity */
uint8_t hash_mme[OGS_HASH_MME_LEN];
/* Nonces for resynchronization */
uint32_t nonceue, noncemme;
/* GPRS ciphering key sequence number */
uint8_t gprs_ciphering_key_sequence_number;
struct {
ED2(uint8_t nhcc_spare:5;,
uint8_t nhcc:3;) /* Next Hop Channing Counter */
};
uint8_t nh[OGS_SHA256_DIGEST_SIZE]; /* NH Security Key */
/* Next hop key */
uint8_t nh[OGS_SHA256_DIGEST_SIZE];
/* Selected algorithms (set by HSS/subscription) */
/* defined in 'nas_ies.h'
* #define NAS_SECURITY_ALGORITHMS_EIA0 0
* #define NAS_SECURITY_ALGORITHMS_128_EEA1 1
@ -1128,6 +1215,9 @@ void mme_ebi_pool_clear(mme_ue_t *mme_ue);
uint8_t mme_selected_int_algorithm(mme_ue_t *mme_ue);
uint8_t mme_selected_enc_algorithm(mme_ue_t *mme_ue);
void mme_ue_save_memento(mme_ue_t *mme_ue, mme_ue_memento_t *memento);
void mme_ue_restore_memento(mme_ue_t *mme_ue, const mme_ue_memento_t *memento);
#ifdef __cplusplus
}
#endif

View file

@ -636,6 +636,9 @@ static int mme_s6a_subscription_data_from_avp(struct avp *avp,
error++;
}
break;
case OGS_DIAM_S6A_AVP_CODE_MIP_HOME_AGENT_HOST:
ogs_error("Ignoring MIP-Home-Agent-Host...");
break;
default:
ogs_error("Unknown AVP-Code:%d",
hdr->avp_code);

View file

@ -32,7 +32,7 @@ static int sess_fill_mm_context_decoded(mme_sess_t *sess, ogs_gtp1_mm_context_de
*mmctx_dec = (ogs_gtp1_mm_context_decoded_t) {
.gupii = 1, /* Integrity Protection not required */
.ugipai = 1, /* Ignore "Used GPRS integrity protection algorithm" field" */
.ksi = mme_ue->nas_eps.ksi,
.ksi = mme_ue->nas_eps.mme.ksi,
.sec_mode = OGS_GTP1_SEC_MODE_UMTS_KEY_AND_QUINTUPLETS,
.num_vectors = 0, /* TODO: figure out how to fill the quintuplets */
.drx_param = {

View file

@ -407,7 +407,7 @@ int mme_gn_handle_sgsn_context_response(
ogs_min(gtp1_mm_ctx.ms_network_capability_len, sizeof(mme_ue->ms_network_capability) - 1));
/* TODO: how to fill first byte of mme_ue->ms_network_capability ? */
mme_ue->nas_eps.ksi = gtp1_mm_ctx.ksi;
mme_ue->nas_eps.mme.ksi = gtp1_mm_ctx.ksi;
/* 3GPP TS 33.401 A.10, A.11: */
mme_ue->noncemme = ogs_random32();
/* 3GPP TS 33.401 7.2.6.2 Establishment of keys for cryptographically protected radio bearers: */

View file

@ -63,8 +63,12 @@ uint8_t mme_s6a_handle_aia(
CLEAR_MME_UE_TIMER(mme_ue->t3460);
if (mme_ue->nas_eps.ksi == OGS_NAS_KSI_NO_KEY_IS_AVAILABLE)
mme_ue->nas_eps.ksi = 0;
if (mme_ue->nas_eps.mme.ksi < (OGS_NAS_KSI_NO_KEY_IS_AVAILABLE - 1))
mme_ue->nas_eps.mme.ksi++;
else
mme_ue->nas_eps.mme.ksi = 0;
mme_ue->nas_eps.ue.ksi = mme_ue->nas_eps.mme.ksi;
return OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED;
}

View file

@ -2268,7 +2268,7 @@ void s1ap_handle_enb_direct_information_transfer(
ogs_plmn_id_t plmn_id;
ogs_nas_rai_t rai;
uint16_t cell_id;
unsigned int i;
int i, r;
mme_sgsn_t *sgsn = NULL;
ogs_assert(enb);
@ -2293,7 +2293,15 @@ void s1ap_handle_enb_direct_information_transfer(
/* Clang scan-build SA: NULL pointer dereference: Inter_SystemInformationTransferType=NULL if above
* protocolIEs.list.count=0 in loop. */
ogs_assert(Inter_SystemInformationTransferType);
if (!Inter_SystemInformationTransferType) {
ogs_warn("No Inter_SystemInformationTransferType");
r = s1ap_send_error_indication(enb, NULL, NULL,
S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
return;
}
RIMTransfer = Inter_SystemInformationTransferType->choice.rIMTransfer;

View file

@ -160,14 +160,19 @@ void s1ap_recv_handler(ogs_sock_t *sock)
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));
if ((not->sn_assoc_change.sac_outbound_streams-1) >= 1) {
/* NEXT_ID(MAX >= MIN) */
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
ogs_assert(addr);
memcpy(addr, &from, sizeof(ogs_sockaddr_t));
s1ap_event_push(MME_EVENT_S1AP_LO_SCTP_COMM_UP,
sock, addr, NULL,
not->sn_assoc_change.sac_inbound_streams,
not->sn_assoc_change.sac_outbound_streams);
s1ap_event_push(MME_EVENT_S1AP_LO_SCTP_COMM_UP,
sock, addr, NULL,
not->sn_assoc_change.sac_inbound_streams,
not->sn_assoc_change.sac_outbound_streams);
} else
ogs_error("Invalid sn_assoc_change.sac_outbound_streams %d",
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) {

View file

@ -118,10 +118,13 @@ static void recv_handler(ogs_sock_t *sock)
if (not->sn_assoc_change.sac_state == SCTP_COMM_UP) {
ogs_debug("SCTP_COMM_UP");
sgsap_event_push(MME_EVENT_SGSAP_LO_SCTP_COMM_UP,
sock, NULL, NULL,
not->sn_assoc_change.sac_inbound_streams,
not->sn_assoc_change.sac_outbound_streams);
if ((not->sn_assoc_change.sac_outbound_streams-1) >= 1) {
/* NEXT_ID(MAX >= MIN) */
sgsap_event_push(MME_EVENT_SGSAP_LO_SCTP_COMM_UP,
sock, NULL, 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) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -59,9 +59,8 @@ static ogs_timer_t *t_termination_holding = NULL;
static void event_termination(void)
{
/*
* Add business-login during Daemon termination
*/
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Start holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);

View file

@ -81,6 +81,17 @@ ogs_sbi_request_t *nrf_nnrf_nfm_build_nf_status_notify(
goto end;
}
}
/*
* Callback Header Configuration
*
* The 3gpp-Sbi-Callback HTTP header (per 3GPP TS 29.500 v17.9.0) indicates that
* a message is an asynchronous notification or callback. This header should be
* included only in HTTP POST requests that are callbacks (e.g., event or
* notification messages) and must not be added to regular service requests,
* such as registration (HTTP PUT) or subscription requests.
*/
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NNRF_NFMANAGEMENT_NF_STATUS_NOTIFY;
message.NotificationData = NotificationData;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -65,6 +65,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -805,36 +805,45 @@ int pcf_instance_get_load(void)
ogs_pool_size(&pcf_ue_pool));
}
int pcf_db_qos_data(char *supi,
ogs_plmn_id_t *plmn_id, ogs_s_nssai_t *s_nssai, char *dnn,
ogs_session_data_t *session_data)
int pcf_get_session_data(const char *supi,
const ogs_plmn_id_t *plmn_id,
const ogs_s_nssai_t *s_nssai,
const char *dnn,
ogs_session_data_t *session_data,
int flags)
{
int rv;
int rv = OGS_OK;
ogs_app_policy_conf_t *policy_conf = NULL;
/* Validate input parameters */
ogs_assert(supi);
ogs_assert(s_nssai);
ogs_assert(dnn);
ogs_assert(session_data);
/* Initialize the session data structure */
memset(session_data, 0, sizeof(*session_data));
/* Attempt to locate a policy configuration */
policy_conf = ogs_app_policy_conf_find(supi, plmn_id);
if (policy_conf) {
rv = ogs_app_config_session_data(
supi, plmn_id, s_nssai, dnn, session_data);
if (rv != OGS_OK)
ogs_error("ogs_app_config_session_data() failed - "
"MCC[%d] MNC[%d] SST[%d] SD[0x%x] DNN[%s]",
ogs_plmn_id_mcc(plmn_id), ogs_plmn_id_mnc(plmn_id),
s_nssai->sst, s_nssai->sd.v, dnn);
if (rv != OGS_OK) {
if (!(flags & PCF_SESSION_DATA_FLAG_NO_ERROR_LOG))
ogs_error("ogs_app_config_session_data() failed - "
"MCC[%d] MNC[%d] SST[%d] SD[0x%x] DNN[%s]",
ogs_plmn_id_mcc(plmn_id), ogs_plmn_id_mnc(plmn_id),
s_nssai->sst, s_nssai->sd.v, dnn);
}
} else {
rv = ogs_dbi_session_data(supi, s_nssai, dnn, session_data);
if (rv != OGS_OK)
ogs_error("ogs_dbi_session_data() failed - "
"SUPI[%s] SST[%d] SD[0x%x] DNN[%s]",
supi, s_nssai->sst, s_nssai->sd.v, dnn);
if (rv != OGS_OK) {
if (!(flags & PCF_SESSION_DATA_FLAG_NO_ERROR_LOG))
ogs_error("ogs_dbi_session_data() failed - "
"SUPI[%s] SST[%d] SD[0x%x] DNN[%s]",
supi, s_nssai->sst, s_nssai->sd.v, dnn);
}
}
return rv;

View file

@ -214,9 +214,42 @@ pcf_app_t *pcf_app_find(uint32_t index);
pcf_app_t *pcf_app_find_by_app_session_id(char *app_session_id);
int pcf_instance_get_load(void);
int pcf_db_qos_data(char *supi,
ogs_plmn_id_t *plmn_id, ogs_s_nssai_t *s_nssai, char *dnn,
ogs_session_data_t *session_data);
/*------------------------------------------------------------------
* Flag definition(s) for pcf_get_session_data().
*------------------------------------------------------------------
* Use PCF_SESSION_DATA_FLAG_NO_ERROR_LOG to suppress error logs.
*/
#define PCF_SESSION_DATA_FLAG_NO_ERROR_LOG 0x01
/*------------------------------------------------------------------
* pcf_get_session_data - Retrieve session data from policy config or DB.
*
* This function retrieves session data for the given subscriber by
* first checking for a policy configuration; if none is found, it
* falls back to querying the database.
*
* Parameters:
* supi - Subscriber identifier (read-only).
* plmn_id - Pointer to a PLMN ID structure (read-only).
* s_nssai - Pointer to an S-NSSAI structure (read-only).
* dnn - Data network name (read-only).
* session_data - Pointer to the session data structure to be filled.
* flags - Flags to control behavior (e.g., error logging).
*
* Returns:
* OGS_OK on success, or an error code on failure.
*
* Note:
* To suppress error logging, pass the flag
* PCF_SESSION_DATA_FLAG_NO_ERROR_LOG in the flags parameter.
*------------------------------------------------------------------
*/
int pcf_get_session_data(const char *supi,
const ogs_plmn_id_t *plmn_id,
const ogs_s_nssai_t *s_nssai,
const char *dnn,
ogs_session_data_t *session_data,
int flags);
#ifdef __cplusplus
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -78,6 +78,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -832,10 +832,10 @@ bool pcf_npcf_policyauthorization_handle_create(pcf_sess_t *sess,
ogs_freeaddrinfo(addr);
ogs_freeaddrinfo(addr6);
rv = pcf_db_qos_data(
rv = pcf_get_session_data(
pcf_ue->supi,
sess->home.presence == true ? &sess->home.plmn_id : NULL,
&sess->s_nssai, sess->dnn, &session_data);
&sess->s_nssai, sess->dnn, &session_data, 0);
if (rv != OGS_OK) {
strerror = ogs_msprintf("[%s:%d] Cannot find SUPI in DB",
pcf_ue->supi, sess->psi);
@ -1280,10 +1280,10 @@ bool pcf_npcf_policyauthorization_handle_update(
}
}
rv = pcf_db_qos_data(
rv = pcf_get_session_data(
pcf_ue->supi,
sess->home.presence == true ? &sess->home.plmn_id : NULL,
&sess->s_nssai, sess->dnn, &session_data);
&sess->s_nssai, sess->dnn, &session_data, 0);
if (rv != OGS_OK) {
strerror = ogs_msprintf("[%s:%d] Cannot find SUPI in DB",
pcf_ue->supi, sess->psi);

View file

@ -331,10 +331,10 @@ bool pcf_sbi_send_smpolicycontrol_create_response(
ogs_assert(pcf_ue->supi);
ogs_assert(sess->dnn);
rv = pcf_db_qos_data(
rv = pcf_get_session_data(
pcf_ue->supi,
sess->home.presence == true ? &sess->home.plmn_id : NULL,
&sess->s_nssai, sess->dnn, &session_data);
&sess->s_nssai, sess->dnn, &session_data, 0);
if (rv != OGS_OK) {
strerror = ogs_msprintf("[%s:%d] Cannot find SUPI in DB",
pcf_ue->supi, sess->psi);

View file

@ -339,8 +339,6 @@ void scp_assoc_remove(scp_assoc_t *assoc)
if (assoc->client)
ogs_sbi_client_remove(assoc->client);
if (assoc->nrf_client)
ogs_sbi_client_remove(assoc->nrf_client);
if (assoc->target_apiroot)
ogs_free(assoc->target_apiroot);

View file

@ -46,7 +46,6 @@ typedef struct scp_assoc_s {
ogs_pool_id_t stream_id;
ogs_sbi_client_t *client;
ogs_sbi_client_t *nrf_client;
ogs_sbi_request_t *request;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -67,6 +67,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -567,8 +567,6 @@ void sepp_assoc_remove(sepp_assoc_t *assoc)
if (assoc->client)
ogs_sbi_client_remove(assoc->client);
if (assoc->nrf_client)
ogs_sbi_client_remove(assoc->nrf_client);
ogs_pool_free(&sepp_assoc_pool, assoc);
}

View file

@ -85,7 +85,6 @@ typedef struct sepp_assoc_s {
ogs_pool_id_t stream_id;
ogs_sbi_client_t *client;
ogs_sbi_client_t *nrf_client;
ogs_sbi_request_t *request;
ogs_sbi_service_type_e service_type;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2023-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -72,6 +72,9 @@ static void event_termination(void)
ogs_list_for_each(&sepp_self()->peer_list, sepp_node)
sepp_handshake_fsm_fini(sepp_node);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -105,8 +105,11 @@ void sgwu_sxa_handle_session_establishment_request(
* a new TEID for the first time, so performing a swap is not appropriate
* in this case.
*/
if (pdr->f_teid.ch == false && pdr->f_teid_len)
ogs_pfcp_pdr_swap_teid(pdr);
if (pdr->f_teid_len > 0 && pdr->f_teid.ch == false) {
cause_value = ogs_pfcp_pdr_swap_teid(pdr);
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
}
}
restoration_indication = true;
}
@ -116,6 +119,7 @@ void sgwu_sxa_handle_session_establishment_request(
if (OGS_ERROR == ogs_pfcp_setup_far_gtpu_node(far)) {
ogs_fatal("CHECK CONFIGURATION: sgwu.gtpu");
ogs_fatal("ogs_pfcp_setup_far_gtpu_node() failed");
cause_value = OGS_PFCP_CAUSE_SYSTEM_FAILURE;
goto cleanup;
}
if (far->gnode)

View file

@ -578,7 +578,8 @@ void smf_gsm_state_wait_5gc_sm_policy_association(ogs_fsm_t *s, smf_event_t *e)
ogs_sbi_server_send_error(
stream, sbi_message->res_status,
sbi_message, strerror, NULL,
sbi_message->ProblemDetails->cause));
(sbi_message->ProblemDetails) ?
sbi_message->ProblemDetails->cause : NULL));
ogs_free(strerror);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
@ -1100,7 +1101,8 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
ogs_sbi_server_send_error(
stream, sbi_message->res_status,
sbi_message, strerror, NULL,
sbi_message->ProblemDetails->cause));
(sbi_message->ProblemDetails) ?
sbi_message->ProblemDetails->cause : NULL));
ogs_free(strerror);
OGS_FSM_TRAN(s, smf_gsm_state_exception);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -105,6 +105,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -1360,7 +1360,7 @@ bool smf_nsmf_handle_create_pdu_session_in_hsmf(
if (sess->remote_dl_ip.ipv4 && sess->remote_dl_ip.ipv6)
sess->remote_dl_ip.len = OGS_IPV4V6_LEN;
sess->remote_dl_teid = ogs_uint64_from_string(vcnTunnelInfo->gtp_teid);
sess->remote_dl_teid = ogs_uint64_from_string_hexadecimal(vcnTunnelInfo->gtp_teid);
ogs_debug("vcnTunnelInfo->ipv4 = 0x%x", sess->remote_dl_ip.addr);
ogs_log_hexdump(OGS_LOG_DEBUG, sess->remote_dl_ip.addr6, OGS_IPV6_LEN);
ogs_debug("vcnTunnelInfo->gtp_teid = 0x%x", sess->remote_dl_teid);
@ -1752,7 +1752,7 @@ bool smf_nsmf_handle_create_pdu_session_in_vsmf(
if (sess->remote_ul_ip.ipv4 && sess->remote_ul_ip.ipv6)
sess->remote_ul_ip.len = OGS_IPV4V6_LEN;
sess->remote_ul_teid = ogs_uint64_from_string(hcnTunnelInfo->gtp_teid);
sess->remote_ul_teid = ogs_uint64_from_string_hexadecimal(hcnTunnelInfo->gtp_teid);
ogs_debug("hcnTunnelInfo->ipv4 = 0x%x", sess->remote_ul_ip.addr);
ogs_log_hexdump(OGS_LOG_DEBUG, sess->remote_ul_ip.addr6, OGS_IPV6_LEN);
ogs_debug("hcnTunnelInfo->gtp_teid = 0x%x", sess->remote_ul_teid);
@ -2029,7 +2029,7 @@ bool smf_nsmf_handle_create_pdu_session_in_vsmf(
}
if (PduSessionCreateError->n1sm_cause)
gsm_cause = ogs_uint64_from_string(
gsm_cause = ogs_uint64_from_string_hexadecimal(
PduSessionCreateError->n1sm_cause);
ogs_error("CreatePduSession() failed [%d] cause [%d]",

View file

@ -236,9 +236,6 @@ ogs_sbi_request_t *smf_nudm_sdm_build_subscription(
message.SDMSubscription = &SDMSubscription;
message.http.custom.callback =
(char *)OGS_SBI_CALLBACK_NUDM_SDM_NOTIFICATION;
request = ogs_sbi_build_request(&message);
ogs_expect(request);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -65,6 +65,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -75,7 +75,7 @@ bool udm_nudm_ueau_handle_get(
r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_authentication_subscription,
udm_ue, stream, NULL);
udm_ue, stream, UDM_SBI_NO_STATE, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
@ -165,7 +165,7 @@ bool udm_nudm_ueau_handle_get(
r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_authentication_subscription,
udm_ue, stream, udm_ue->sqn);
udm_ue, stream, UDM_SBI_NO_STATE, udm_ue->sqn);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}
@ -237,7 +237,7 @@ bool udm_nudm_ueau_handle_result_confirmation_inform(
r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_update_authentication_status,
udm_ue, stream, NULL);
udm_ue, stream, UDM_SBI_NO_STATE, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
@ -346,7 +346,8 @@ bool udm_nudm_uecm_handle_amf_registration(
message->Amf3GppAccessRegistration);
r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_update_amf_context, udm_ue, stream, NULL);
udm_nudr_dr_build_update_amf_context, udm_ue, stream,
UDM_SBI_NO_STATE, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
@ -473,7 +474,7 @@ bool udm_nudm_uecm_handle_amf_registration_update(
r = udm_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_patch_amf_context,
udm_ue, stream, PatchItemList);
udm_ue, stream, UDM_SBI_NO_STATE, PatchItemList);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
@ -587,7 +588,8 @@ bool udm_nudm_uecm_handle_smf_registration(
OpenAPI_smf_registration_copy(sess->smf_registration, SmfRegistration);
r = udm_sess_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_update_smf_context, sess, stream, NULL);
udm_nudr_dr_build_update_smf_context, sess, stream,
UDM_SBI_NO_STATE, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
@ -608,7 +610,8 @@ bool udm_nudm_uecm_handle_smf_deregistration(
ogs_assert(udm_ue);
r = udm_sess_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_delete_smf_context, sess, stream, NULL);
udm_nudr_dr_build_delete_smf_context, sess, stream,
UDM_SBI_NO_STATE, NULL);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);

View file

@ -239,6 +239,12 @@ ogs_sbi_request_t *udm_nudr_dr_build_query_subscription_provisioned(
(char *)OGS_SBI_RESOURCE_NAME_SMF_SELECTION_SUBSCRIPTION_DATA;
break;
CASE(OGS_SBI_RESOURCE_NAME_NSSAI)
sendmsg.h.resource.component[4] = (char *)OGS_SBI_RESOURCE_NAME_AM_DATA;
sendmsg.param.fields[0] = (char *)OGS_SBI_RESOURCE_NAME_NSSAI;
sendmsg.param.num_of_fields = 1;
break;
DEFAULT
END

View file

@ -18,6 +18,7 @@
*/
#include "nudr-handler.h"
#include "sbi-path.h"
bool udm_nudr_dr_handle_subscription_authentication(
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
@ -89,7 +90,8 @@ bool udm_nudr_dr_handle_subscription_authentication(
ogs_assert(true ==
ogs_sbi_server_send_error(
stream, recvmsg->res_status, recvmsg, strerror, NULL,
recvmsg->ProblemDetails->cause));
(recvmsg->ProblemDetails) ?
recvmsg->ProblemDetails->cause : NULL));
ogs_free(strerror);
return false;
}
@ -194,7 +196,8 @@ bool udm_nudr_dr_handle_subscription_authentication(
ogs_assert(true ==
ogs_sbi_server_send_error(
stream, recvmsg->res_status, recvmsg, strerror, NULL,
recvmsg->ProblemDetails->cause));
(recvmsg->ProblemDetails) ?
recvmsg->ProblemDetails->cause : NULL));
ogs_free(strerror);
return false;
}
@ -283,7 +286,8 @@ bool udm_nudr_dr_handle_subscription_authentication(
ogs_assert(true ==
ogs_sbi_server_send_error(
stream, recvmsg->res_status, recvmsg, strerror, NULL,
recvmsg->ProblemDetails->cause));
(recvmsg->ProblemDetails) ?
recvmsg->ProblemDetails->cause : NULL));
ogs_free(strerror);
return false;
}
@ -415,7 +419,8 @@ bool udm_nudr_dr_handle_subscription_context(
ogs_assert(true ==
ogs_sbi_server_send_error(stream, recvmsg->res_status,
NULL, "HTTP response error", udm_ue->supi,
recvmsg->ProblemDetails->cause));
(recvmsg->ProblemDetails) ?
recvmsg->ProblemDetails->cause : NULL));
return false;
}
@ -601,7 +606,8 @@ bool udm_nudr_dr_handle_subscription_context(
}
bool udm_nudr_dr_handle_subscription_provisioned(
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg)
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, int state,
ogs_sbi_message_t *recvmsg)
{
char *strerror = NULL;
ogs_sbi_server_t *server = NULL;
@ -636,6 +642,29 @@ bool udm_nudr_dr_handle_subscription_provisioned(
memset(&sendmsg, 0, sizeof(sendmsg));
/* Check if original request was for /nudm-sdm/v2/{supi}/nssai */
if (state == UDM_SBI_UE_PROVISIONED_NSSAI_ONLY) {
OpenAPI_nssai_t *Nssai = NULL;
Nssai = AccessAndMobilitySubscriptionData->nssai;
if (!Nssai) {
ogs_error("[%s] No Nssai", udm_ue->supi);
ogs_assert(true ==
ogs_sbi_server_send_error(
stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
recvmsg, "No Nssai",
udm_ue->supi, NULL));
return false;
}
sendmsg.Nssai = OpenAPI_nssai_copy(sendmsg.Nssai, Nssai);
response = ogs_sbi_build_response(&sendmsg, recvmsg->res_status);
ogs_assert(response);
ogs_assert(true == ogs_sbi_server_send_response(stream, response));
OpenAPI_nssai_free(sendmsg.Nssai);
break;
}
sendmsg.AccessAndMobilitySubscriptionData =
OpenAPI_access_and_mobility_subscription_data_copy(
sendmsg.AccessAndMobilitySubscriptionData,
@ -768,7 +797,8 @@ bool udm_nudr_dr_handle_smf_registration(
ogs_assert(true ==
ogs_sbi_server_send_error(stream, recvmsg->res_status,
NULL, "HTTP response error", udm_ue->supi,
recvmsg->ProblemDetails->cause));
(recvmsg->ProblemDetails) ?
recvmsg->ProblemDetails->cause : NULL));
return false;
}

View file

@ -31,7 +31,8 @@ bool udm_nudr_dr_handle_subscription_authentication(
bool udm_nudr_dr_handle_subscription_context(
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
bool udm_nudr_dr_handle_subscription_provisioned(
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, int state,
ogs_sbi_message_t *recvmsg);
bool udm_nudr_dr_handle_smf_registration(
udm_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);

View file

@ -102,7 +102,7 @@ static int udm_sbi_discover_and_send(
ogs_sbi_service_type_e service_type,
ogs_sbi_discovery_option_t *discovery_option,
ogs_sbi_build_f build,
void *context, ogs_sbi_stream_t *stream, void *data)
void *context, ogs_sbi_stream_t *stream, int state, void *data)
{
ogs_sbi_xact_t *xact = NULL;
int r;
@ -123,6 +123,8 @@ static int udm_sbi_discover_and_send(
return OGS_ERROR;
}
xact->state = state;
if (stream) {
xact->assoc_stream_id = ogs_sbi_id_from_stream(stream);
ogs_assert(xact->assoc_stream_id >= OGS_MIN_POOL_ID &&
@ -143,7 +145,7 @@ int udm_ue_sbi_discover_and_send(
ogs_sbi_service_type_e service_type,
ogs_sbi_discovery_option_t *discovery_option,
ogs_sbi_request_t *(*build)(udm_ue_t *udm_ue, void *data),
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, void *data)
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, int state, void *data)
{
int r;
@ -151,7 +153,7 @@ int udm_ue_sbi_discover_and_send(
r = udm_sbi_discover_and_send(
udm_ue->id, &udm_ue->sbi, service_type, discovery_option,
(ogs_sbi_build_f)build, udm_ue, stream, data);
(ogs_sbi_build_f)build, udm_ue, stream, state, data);
if (r != OGS_OK) {
ogs_error("udm_ue_sbi_discover_and_send() failed");
ogs_assert(true ==
@ -168,7 +170,7 @@ int udm_sess_sbi_discover_and_send(
ogs_sbi_service_type_e service_type,
ogs_sbi_discovery_option_t *discovery_option,
ogs_sbi_request_t *(*build)(udm_sess_t *sess, void *data),
udm_sess_t *sess, ogs_sbi_stream_t *stream, void *data)
udm_sess_t *sess, ogs_sbi_stream_t *stream, int state, void *data)
{
int r;
@ -176,7 +178,7 @@ int udm_sess_sbi_discover_and_send(
r = udm_sbi_discover_and_send(
sess->id, &sess->sbi, service_type, discovery_option,
(ogs_sbi_build_f)build, sess, stream, data);
(ogs_sbi_build_f)build, sess, stream, state, data);
if (r != OGS_OK) {
ogs_error("udm_sess_sbi_discover_and_send() failed");
ogs_assert(true ==

View file

@ -31,16 +31,20 @@ void udm_sbi_close(void);
bool udm_sbi_send_request(
ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_xact_t *xact);
#define UDM_SBI_NO_STATE 0
#define UDM_SBI_UE_PROVISIONED_NSSAI_ONLY 1
int udm_ue_sbi_discover_and_send(
ogs_sbi_service_type_e service_type,
ogs_sbi_discovery_option_t *discovery_option,
ogs_sbi_request_t *(*build)(udm_ue_t *udm_ue, void *data),
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, void *data);
udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, int state, void *data);
int udm_sess_sbi_discover_and_send(
ogs_sbi_service_type_e service_type,
ogs_sbi_discovery_option_t *discovery_option,
ogs_sbi_request_t *(*build)(udm_sess_t *sess, void *data),
udm_sess_t *sess, ogs_sbi_stream_t *stream, void *data);
udm_sess_t *sess, ogs_sbi_stream_t *stream, int state, void *data);
#ifdef __cplusplus
}

View file

@ -176,16 +176,19 @@ void udm_state_operational(ogs_fsm_t *s, udm_event_t *e)
udm_ue = udm_ue_find_by_suci_or_supi(
message.h.resource.component[0]);
if (!udm_ue) {
if (!strcmp(message.h.method,
OGS_SBI_HTTP_METHOD_POST)) {
SWITCH(message.h.method)
CASE(OGS_SBI_HTTP_METHOD_POST)
CASE(OGS_SBI_HTTP_METHOD_GET)
udm_ue = udm_ue_add(message.h.resource.component[0]);
if (!udm_ue) {
ogs_error("Invalid Request [%s]",
message.h.resource.component[0]);
}
} else {
break;
DEFAULT
ogs_error("Invalid HTTP method [%s]", message.h.method);
}
END
}
}
@ -461,6 +464,8 @@ void udm_state_operational(ogs_fsm_t *s, udm_event_t *e)
e->h.sbi.data =
OGS_UINT_TO_POINTER(sbi_xact->assoc_stream_id);
e->h.sbi.state = sbi_xact->state;
ogs_sbi_xact_remove(sbi_xact);
udm_ue = udm_ue_find_by_id(udm_ue_id);

View file

@ -196,7 +196,17 @@ void udm_ue_state_operational(ogs_fsm_t *s, udm_event_t *e)
r = udm_ue_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_query_subscription_provisioned,
udm_ue, stream, message);
udm_ue, stream, UDM_SBI_NO_STATE, message);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
break;
CASE(OGS_SBI_RESOURCE_NAME_NSSAI)
r = udm_ue_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL,
udm_nudr_dr_build_query_subscription_provisioned,
udm_ue, stream, UDM_SBI_UE_PROVISIONED_NSSAI_ONLY,
message);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
break;
@ -305,7 +315,7 @@ void udm_ue_state_operational(ogs_fsm_t *s, udm_event_t *e)
SWITCH(message->h.resource.component[3])
CASE(OGS_SBI_RESOURCE_NAME_PROVISIONED_DATA)
udm_nudr_dr_handle_subscription_provisioned(
udm_ue, stream, message);
udm_ue, stream, e->h.sbi.state, message);
break;
DEFAULT

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
@ -68,6 +68,9 @@ static void event_termination(void)
ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance)
ogs_sbi_nf_fsm_fini(nf_instance);
/* Gracefully shutdown the server by sending GOAWAY to each session. */
ogs_sbi_server_graceful_shutdown_all();
/* Starting holding timer */
t_termination_holding = ogs_timer_add(ogs_app()->timer_mgr, NULL, NULL);
ogs_assert(t_termination_holding);

View file

@ -467,6 +467,9 @@ bool udr_nudr_dr_handle_subscription_provisioned(
SWITCH(recvmsg->h.resource.component[4])
CASE(OGS_SBI_RESOURCE_NAME_AM_DATA)
int i;
bool processGpsi = false;
bool processUeAmbr = false;
bool processNssai = false;
OpenAPI_access_and_mobility_subscription_data_t
AccessAndMobilitySubscriptionData;
@ -480,77 +483,110 @@ bool udr_nudr_dr_handle_subscription_provisioned(
OpenAPI_lnode_t *node = NULL;
GpsiList = OpenAPI_list_create();
for (i = 0; i < subscription_data.num_of_msisdn; i++) {
char *gpsi = ogs_msprintf("%s-%s",
OGS_ID_GPSI_TYPE_MSISDN, subscription_data.msisdn[i].bcd);
ogs_assert(gpsi);
OpenAPI_list_add(GpsiList, gpsi);
}
SubscribedUeAmbr.uplink = ogs_sbi_bitrate_to_string(
subscription_data.ambr.uplink, OGS_SBI_BITRATE_KBPS);
SubscribedUeAmbr.downlink = ogs_sbi_bitrate_to_string(
subscription_data.ambr.downlink, OGS_SBI_BITRATE_KBPS);
memset(&NSSAI, 0, sizeof(NSSAI));
DefaultSingleNssaiList = OpenAPI_list_create();
for (i = 0; i < subscription_data.num_of_slice; i++) {
slice_data = &subscription_data.slice[i];
if (slice_data->default_indicator == false)
continue;
Snssai = ogs_calloc(1, sizeof(*Snssai));
ogs_assert(Snssai);
Snssai->sst = slice_data->s_nssai.sst;
Snssai->sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd);
OpenAPI_list_add(DefaultSingleNssaiList, Snssai);
}
if (DefaultSingleNssaiList->count) {
NSSAI.default_single_nssais = DefaultSingleNssaiList;
}
SingleNssaiList = OpenAPI_list_create();
for (i = 0; i < subscription_data.num_of_slice; i++) {
slice_data = &subscription_data.slice[i];
if (slice_data->default_indicator == true)
continue;
Snssai = ogs_calloc(1, sizeof(*Snssai));
ogs_assert(Snssai);
Snssai->sst = slice_data->s_nssai.sst;
Snssai->sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd);
OpenAPI_list_add(SingleNssaiList, Snssai);
}
if (DefaultSingleNssaiList->count) {
if (SingleNssaiList->count) {
NSSAI.single_nssais = SingleNssaiList;
}
} else {
if (SingleNssaiList->count) {
ogs_fatal("No Default S-NSSAI");
ogs_assert_if_reached();
}
}
memset(&AccessAndMobilitySubscriptionData, 0,
sizeof(AccessAndMobilitySubscriptionData));
if (GpsiList->count)
AccessAndMobilitySubscriptionData.gpsis = GpsiList;
memset(&SubscribedUeAmbr, 0, sizeof(SubscribedUeAmbr));
memset(&NSSAI, 0, sizeof(NSSAI));
AccessAndMobilitySubscriptionData.subscribed_ue_ambr =
&SubscribedUeAmbr;
/* Apply filtering based on fields query parameter */
if (recvmsg->param.num_of_fields) {
for (i = 0; i < recvmsg->param.num_of_fields; i++) {
SWITCH(recvmsg->param.fields[i])
CASE(OGS_SBI_PARAM_FIELDS_GPSIS)
processGpsi = true;
break;
CASE(OGS_SBI_PARAM_FIELDS_SUBSCRIBED_UE_AMBR)
processUeAmbr = true;
break;
CASE(OGS_SBI_PARAM_FIELDS_NSSAI)
processNssai = true;
break;
DEFAULT
ogs_error("Unexpected field! [%s]",
recvmsg->param.fields[i]);
END
}
} else {
processGpsi = true;
processUeAmbr = true;
processNssai = true;
}
if (DefaultSingleNssaiList->count)
AccessAndMobilitySubscriptionData.nssai = &NSSAI;
if (processGpsi) {
GpsiList = OpenAPI_list_create();
for (i = 0; i < subscription_data.num_of_msisdn; i++) {
char *gpsi = ogs_msprintf("%s-%s",
OGS_ID_GPSI_TYPE_MSISDN,
subscription_data.msisdn[i].bcd);
ogs_assert(gpsi);
OpenAPI_list_add(GpsiList, gpsi);
}
if (GpsiList->count)
AccessAndMobilitySubscriptionData.gpsis = GpsiList;
}
if (processUeAmbr) {
SubscribedUeAmbr.uplink = ogs_sbi_bitrate_to_string(
subscription_data.ambr.uplink, OGS_SBI_BITRATE_KBPS);
SubscribedUeAmbr.downlink = ogs_sbi_bitrate_to_string(
subscription_data.ambr.downlink, OGS_SBI_BITRATE_KBPS);
AccessAndMobilitySubscriptionData.subscribed_ue_ambr =
&SubscribedUeAmbr;
}
if (processNssai) {
DefaultSingleNssaiList = OpenAPI_list_create();
for (i = 0; i < subscription_data.num_of_slice; i++) {
slice_data = &subscription_data.slice[i];
if (slice_data->default_indicator == false)
continue;
Snssai = ogs_calloc(1, sizeof(*Snssai));
ogs_assert(Snssai);
Snssai->sst = slice_data->s_nssai.sst;
Snssai->sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd);
OpenAPI_list_add(DefaultSingleNssaiList, Snssai);
}
if (DefaultSingleNssaiList->count) {
NSSAI.default_single_nssais = DefaultSingleNssaiList;
}
SingleNssaiList = OpenAPI_list_create();
for (i = 0; i < subscription_data.num_of_slice; i++) {
slice_data = &subscription_data.slice[i];
if (slice_data->default_indicator == true)
continue;
Snssai = ogs_calloc(1, sizeof(*Snssai));
ogs_assert(Snssai);
Snssai->sst = slice_data->s_nssai.sst;
Snssai->sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd);
OpenAPI_list_add(SingleNssaiList, Snssai);
}
if (DefaultSingleNssaiList->count) {
if (SingleNssaiList->count) {
NSSAI.single_nssais = SingleNssaiList;
}
} else {
if (SingleNssaiList->count) {
ogs_fatal("No Default S-NSSAI");
ogs_assert_if_reached();
}
}
if (DefaultSingleNssaiList->count)
AccessAndMobilitySubscriptionData.nssai = &NSSAI;
}
memset(&sendmsg, 0, sizeof(sendmsg));
sendmsg.AccessAndMobilitySubscriptionData =
@ -565,8 +601,10 @@ bool udr_nudr_dr_handle_subscription_provisioned(
}
OpenAPI_list_free(GpsiList);
ogs_free(SubscribedUeAmbr.uplink);
ogs_free(SubscribedUeAmbr.downlink);
if (SubscribedUeAmbr.uplink)
ogs_free(SubscribedUeAmbr.uplink);
if (SubscribedUeAmbr.downlink)
ogs_free(SubscribedUeAmbr.downlink);
OpenAPI_list_for_each(DefaultSingleNssaiList, node) {
OpenAPI_snssai_t *Snssai = node->data;

View file

@ -400,7 +400,6 @@ uint8_t upf_sess_set_ue_ip(upf_sess_t *sess,
uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
ogs_assert(sess);
ogs_assert(session_type);
ogs_assert(pdr);
ogs_assert(pdr->ue_ip_addr_len);
ue_ip = &pdr->ue_ip_addr;
@ -487,9 +486,10 @@ uint8_t upf_sess_set_ue_ip(upf_sess_t *sess,
pdr->dnn ? pdr->dnn : "");
}
} else {
ogs_warn("Cannot support PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]",
ogs_error("Invalid PDN-Type[%d], [IPv4:%d IPv6:%d DNN:%s]",
session_type, ue_ip->ipv4, ue_ip->ipv6,
pdr->dnn ? pdr->dnn : "");
return OGS_PFCP_CAUSE_SERVICE_NOT_SUPPORTED;
}
ogs_info("UE F-SEID[UP:0x%lx CP:0x%lx] "

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