mirror of
https://github.com/open5gs/open5gs.git
synced 2026-04-26 10:30:41 +00:00
Merge branch 'main' into home-routed
This commit is contained in:
parent
90afca821b
commit
46f74c8019
119 changed files with 2772 additions and 656 deletions
335
configs/attach.yaml.in
Normal file
335
configs/attach.yaml.in
Normal 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
|
||||
|
|
@ -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
36
debian/changelog
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
50
docs/_posts/2025-03-30-release-v2.7.5.md
Normal file
50
docs/_posts/2025-03-30-release-v2.7.5.md
Normal 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}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
158
lib/sbi/nf-sm.c
158
lib/sbi/nf-sm.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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]",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
155
src/mme/emm-sm.c
155
src/mme/emm-sm.c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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: */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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]",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 ==
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue