From 453714292942869b32fb49a399dc46daafc7a0e9 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Mon, 21 Jun 2021 22:36:38 +0900 Subject: [PATCH] [EPC] Support ePDG Interface (#1039) --- README.md | 17 +- configs/310014.yaml.in | 4 + configs/csfb.yaml.in | 4 + configs/freeDiameter/hss.conf.in | 1 + configs/freeDiameter/mme.conf.in | 1 + configs/freeDiameter/pcrf.conf.in | 1 + configs/freeDiameter/smf.conf.in | 1 + configs/meson.build | 1 + configs/non3gpp.yaml.in | 233 +++++ configs/sample.yaml.in | 4 + configs/slice.yaml.in | 4 + configs/srslte.yaml.in | 4 + configs/volte.yaml.in | 4 + configs/vonr.yaml.in | 4 + lib/diameter/common/base.h | 12 +- lib/diameter/common/config.c | 3 + lib/diameter/common/init.c | 10 + lib/diameter/common/message.c | 14 + lib/diameter/common/message.h | 23 + lib/diameter/common/util.c | 18 +- lib/diameter/cx/dict.c | 22 +- lib/diameter/cx/meson.build | 1 - lib/diameter/cx/message.c | 4 - lib/diameter/cx/message.h | 1 - lib/diameter/gx/message.c | 24 +- lib/diameter/gx/message.h | 36 +- lib/diameter/meson.build | 2 + lib/diameter/rx/dict.c | 6 +- lib/diameter/rx/message.c | 2 - lib/diameter/rx/message.h | 13 - lib/diameter/s6a/message.c | 10 +- lib/diameter/s6a/message.h | 11 +- lib/diameter/s6b/meson.build | 38 + lib/diameter/s6b/message.c | 40 + lib/diameter/s6b/message.h | 43 + lib/diameter/s6b/ogs-diameter-s6b.h | 41 + lib/diameter/swx/meson.build | 38 + lib/diameter/swx/message.c | 46 + lib/diameter/swx/message.h | 52 + lib/diameter/swx/ogs-diameter-swx.h | 41 + lib/gtp/context.h | 1 - lib/gtp/message.c | 6 +- lib/gtp/message.h | 4 +- lib/gtp/support/README.md | 10 +- lib/gtp/support/cache/tlv-msg-100.py | 4 - lib/gtp/support/cache/tlv-msg-32.py | 11 + lib/gtp/support/cache/tlv-msg-33.py | 2 + lib/gtp/support/cache/tlv-msg-34.py | 6 - lib/gtp/support/cache/tlv-msg-36.py | 1 + lib/gtp/support/cache/tlv-msg-68.py | 1 - lib/gtp/support/cache/tlv-msg-95.py | 3 - lib/gtp/support/gtp-tlv.py | 59 +- lib/gtp/types.h | 2 +- lib/gtp/xact.c | 2 +- lib/nas/5gs/decoder.c | 2 +- lib/nas/5gs/encoder.c | 2 +- lib/nas/5gs/ies.c | 2 +- lib/nas/5gs/ies.h | 2 +- lib/nas/5gs/message.h | 2 +- lib/nas/5gs/support/README.md | 12 +- lib/nas/5gs/support/nas-message.py | 38 +- lib/nas/eps/decoder.c | 2 +- lib/nas/eps/encoder.c | 2 +- lib/nas/eps/ies.c | 2 +- lib/nas/eps/ies.h | 2 +- lib/nas/eps/message.h | 2 +- lib/nas/eps/support/README.md | 12 +- lib/nas/eps/support/nas-message.py | 38 +- lib/pfcp/message.c | 2 +- lib/pfcp/message.h | 2 +- lib/pfcp/support/README.md | 10 +- lib/pfcp/support/cache/tlv-msg-50.py | 4 + lib/pfcp/support/cache/tlv-msg-52.py | 4 - lib/pfcp/support/pfcp-tlv.py | 54 +- src/hss/hss-context.c | 3 + src/hss/hss-context.h | 1 + src/hss/hss-cx-path.c | 16 +- src/hss/hss-fd-path.c | 6 + src/hss/hss-fd-path.h | 2 + src/hss/hss-s6a-path.c | 55 +- src/hss/hss-swx-path.c | 927 +++++++++++++++++ src/hss/meson.build | 19 +- src/mme/mme-context.c | 3 + src/mme/mme-fd-path.c | 17 +- src/mme/mme-s11-build.c | 79 +- src/mme/mme-s11-handler.c | 23 + src/pcrf/pcrf-context.c | 3 + src/pcrf/pcrf-fd-path.c | 3 + src/pcrf/pcrf-gx-path.c | 8 +- src/pcrf/pcrf-rx-path.c | 8 +- src/sgwc/s11-build.c | 2 +- src/sgwc/s11-handler.c | 114 ++- src/sgwc/s5c-handler.c | 133 ++- src/sgwc/s5c-handler.h | 3 + src/sgwc/sgwc-sm.c | 4 + src/sgwc/sxa-handler.c | 151 ++- src/smf/binding.c | 30 +- src/smf/context.c | 59 +- src/smf/context.h | 29 +- src/smf/fd-path.c | 1273 +---------------------- src/smf/fd-path.h | 8 + src/smf/gtp-path.c | 70 ++ src/smf/gtp-path.h | 3 + src/smf/gx-handler.c | 6 + src/smf/gx-path.c | 1420 ++++++++++++++++++++++++++ src/smf/meson.build | 4 + src/smf/n4-handler.c | 56 +- src/smf/nsmf-handler.c | 2 +- src/smf/pfcp-path.c | 22 + src/smf/s5c-build.c | 129 ++- src/smf/s5c-build.h | 6 +- src/smf/s5c-handler.c | 390 +++++-- src/smf/s5c-handler.h | 3 + src/smf/s6b-path.c | 796 +++++++++++++++ src/smf/smf-sm.c | 4 + tests/310014/epc-test.c | 4 +- tests/attach/auth-test.c | 10 +- tests/attach/emm-status-test.c | 4 +- tests/attach/guti-test.c | 28 +- tests/attach/idle-test.c | 12 +- tests/attach/reset-test.c | 20 +- tests/attach/ue-context-test.c | 16 +- tests/common/context.c | 176 +++- tests/common/context.h | 38 +- tests/common/esm-build.c | 11 +- tests/common/esm-handler.c | 3 +- tests/common/meson.build | 4 + tests/common/test-common.h | 2 + tests/csfb/crash-test.c | 4 +- tests/csfb/mo-active-test.c | 4 +- tests/csfb/mo-idle-test.c | 16 +- tests/csfb/mo-sms-test.c | 4 +- tests/csfb/mt-active-test.c | 4 +- tests/csfb/mt-idle-test.c | 4 +- tests/csfb/mt-sms-test.c | 4 +- tests/handover/epc-s1-test.c | 12 +- tests/handover/epc-x2-test.c | 4 +- tests/meson.build | 1 + tests/non3gpp/abts-main.c | 224 ++++ tests/non3gpp/diameter-s6b-path.c | 362 +++++++ tests/non3gpp/diameter-swx-path.c | 666 ++++++++++++ tests/non3gpp/epdg-test.c | 754 ++++++++++++++ tests/non3gpp/gtp-path.c | 231 +++++ tests/non3gpp/gtp-path.h | 48 + tests/non3gpp/meson.build | 38 + tests/non3gpp/s2b-build.c | 285 ++++++ tests/non3gpp/s2b-build.h | 41 + tests/non3gpp/s2b-handler.c | 232 +++++ tests/non3gpp/s2b-handler.h | 47 + tests/non3gpp/test-fd-path.c | 100 ++ tests/non3gpp/test-fd-path.h | 51 + tests/volte/bearer-test.c | 4 +- tests/volte/cx-test.c | 9 +- tests/volte/diameter-cx-path.c | 2 +- tests/volte/diameter-rx-path.c | 5 +- tests/volte/rx-test.c | 76 +- tests/volte/session-test.c | 14 +- tests/volte/test-fd-path.c | 4 + tests/volte/test-fd-path.h | 3 - tests/volte/video-test.c | 9 +- 160 files changed, 8717 insertions(+), 1905 deletions(-) create mode 100644 configs/non3gpp.yaml.in create mode 100644 lib/diameter/s6b/meson.build create mode 100644 lib/diameter/s6b/message.c create mode 100644 lib/diameter/s6b/message.h create mode 100644 lib/diameter/s6b/ogs-diameter-s6b.h create mode 100644 lib/diameter/swx/meson.build create mode 100644 lib/diameter/swx/message.c create mode 100644 lib/diameter/swx/message.h create mode 100644 lib/diameter/swx/ogs-diameter-swx.h create mode 100644 src/hss/hss-swx-path.c create mode 100644 src/smf/gx-path.c create mode 100644 src/smf/s6b-path.c create mode 100644 tests/non3gpp/abts-main.c create mode 100644 tests/non3gpp/diameter-s6b-path.c create mode 100644 tests/non3gpp/diameter-swx-path.c create mode 100644 tests/non3gpp/epdg-test.c create mode 100644 tests/non3gpp/gtp-path.c create mode 100644 tests/non3gpp/gtp-path.h create mode 100644 tests/non3gpp/meson.build create mode 100644 tests/non3gpp/s2b-build.c create mode 100644 tests/non3gpp/s2b-build.h create mode 100644 tests/non3gpp/s2b-handler.c create mode 100644 tests/non3gpp/s2b-handler.h create mode 100644 tests/non3gpp/test-fd-path.c create mode 100644 tests/non3gpp/test-fd-path.h diff --git a/README.md b/README.md index ad2fd674a..dab46eb59 100644 --- a/README.md +++ b/README.md @@ -25,29 +25,24 @@ If you find Open5GS useful for work, please consider supporting this Open Source - - - - - - - + +
+ + - - - -
+ +
diff --git a/configs/310014.yaml.in b/configs/310014.yaml.in index eaafc45c8..90919c622 100644 --- a/configs/310014.yaml.in +++ b/configs/310014.yaml.in @@ -24,6 +24,7 @@ mme: identity: mme.localdomain realm: localdomain listen_on: 127.0.0.2 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -90,6 +91,7 @@ smf: identity: smf.localdomain realm: localdomain listen_on: 127.0.0.4 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -153,6 +155,7 @@ hss: identity: hss.localdomain realm: localdomain listen_on: 127.0.0.8 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -170,6 +173,7 @@ pcrf: identity: pcrf.localdomain realm: localdomain listen_on: 127.0.0.9 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 diff --git a/configs/csfb.yaml.in b/configs/csfb.yaml.in index b28cfae52..3adb8d552 100644 --- a/configs/csfb.yaml.in +++ b/configs/csfb.yaml.in @@ -24,6 +24,7 @@ mme: identity: mme.localdomain realm: localdomain listen_on: 127.0.0.2 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -124,6 +125,7 @@ smf: identity: smf.localdomain realm: localdomain listen_on: 127.0.0.4 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -187,6 +189,7 @@ hss: identity: hss.localdomain realm: localdomain listen_on: 127.0.0.8 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -204,6 +207,7 @@ pcrf: identity: pcrf.localdomain realm: localdomain listen_on: 127.0.0.9 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 diff --git a/configs/freeDiameter/hss.conf.in b/configs/freeDiameter/hss.conf.in index 619d98f89..10c4b78df 100644 --- a/configs/freeDiameter/hss.conf.in +++ b/configs/freeDiameter/hss.conf.in @@ -175,6 +175,7 @@ TLS_CA = "@sysconfdir@/freeDiameter/cacert.pem"; # exchanges. # Default: Relaying is enabled. #NoRelay; +NoRelay; # Number of server threads that can handle incoming messages at the same time. # Default: 4 diff --git a/configs/freeDiameter/mme.conf.in b/configs/freeDiameter/mme.conf.in index 56158501c..790ce9742 100644 --- a/configs/freeDiameter/mme.conf.in +++ b/configs/freeDiameter/mme.conf.in @@ -175,6 +175,7 @@ TLS_CA = "@sysconfdir@/freeDiameter/cacert.pem"; # exchanges. # Default: Relaying is enabled. #NoRelay; +NoRelay; # Number of server threads that can handle incoming messages at the same time. # Default: 4 diff --git a/configs/freeDiameter/pcrf.conf.in b/configs/freeDiameter/pcrf.conf.in index 7d6322c4b..d0cc2ec02 100644 --- a/configs/freeDiameter/pcrf.conf.in +++ b/configs/freeDiameter/pcrf.conf.in @@ -175,6 +175,7 @@ TLS_CA = "@sysconfdir@/freeDiameter/cacert.pem"; # exchanges. # Default: Relaying is enabled. #NoRelay; +NoRelay; # Number of server threads that can handle incoming messages at the same time. # Default: 4 diff --git a/configs/freeDiameter/smf.conf.in b/configs/freeDiameter/smf.conf.in index 02e1695c0..77b881076 100644 --- a/configs/freeDiameter/smf.conf.in +++ b/configs/freeDiameter/smf.conf.in @@ -175,6 +175,7 @@ TLS_CA = "@sysconfdir@/freeDiameter/cacert.pem"; # exchanges. # Default: Relaying is enabled. #NoRelay; +NoRelay; # Number of server threads that can handle incoming messages at the same time. # Default: 4 diff --git a/configs/meson.build b/configs/meson.build index da7c21bc1..f0cb05a93 100644 --- a/configs/meson.build +++ b/configs/meson.build @@ -42,6 +42,7 @@ example_conf = ''' slice.yaml srslte.yaml sample.yaml + non3gpp.yaml '''.split() foreach file : example_conf diff --git a/configs/non3gpp.yaml.in b/configs/non3gpp.yaml.in new file mode 100644 index 000000000..b223812bf --- /dev/null +++ b/configs/non3gpp.yaml.in @@ -0,0 +1,233 @@ +db_uri: mongodb://localhost/open5gs + +logger: + +parameter: +# no_nrf: 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: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx + conf: 0x8888 + - module: @freediameter_extensions_builddir@/dict_rfc5777.fdx + - module: @freediameter_extensions_builddir@/dict_mip6i.fdx + - module: @freediameter_extensions_builddir@/dict_nasreq.fdx + - module: @freediameter_extensions_builddir@/dict_nas_mipv6.fdx + - module: @freediameter_extensions_builddir@/dict_dcca.fdx + - module: @freediameter_extensions_builddir@/dict_dcca_3gpp.fdx + connect: + - identity: hss.localdomain + addr: 127.0.0.8 + + s1ap: + - addr: 127.0.0.2 + gtpc: + - addr: 127.0.0.2 + gummei: + plmn_id: + mcc: 901 + mnc: 70 + mme_gid: 2 + mme_code: 1 + tai: + plmn_id: + mcc: 901 + mnc: 70 + tac: 1 + security: + integrity_order : [ EIA2, EIA1, EIA0 ] + ciphering_order : [ EEA0, EEA1, EEA2 ] + + network_name: + full: Open5GS + +sgwc: + gtpc: + - addr: 127.0.0.3 + pfcp: + - addr: 127.0.0.3 + +smf: + sbi: + - addr: 127.0.0.4 + port: 7777 + pfcp: + - addr: 127.0.0.4 + gtpc: + - addr: 127.0.0.4 + - addr: ::1 + gtpu: + - addr: 127.0.0.4 + - addr: ::1 + subnet: + - addr: 10.45.0.1/16 + - addr: 2001:230:cafe::1/48 + 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: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx + conf: 0x8888 + - module: @freediameter_extensions_builddir@/dict_rfc5777.fdx + - module: @freediameter_extensions_builddir@/dict_mip6i.fdx + - module: @freediameter_extensions_builddir@/dict_nasreq.fdx + - module: @freediameter_extensions_builddir@/dict_nas_mipv6.fdx + - module: @freediameter_extensions_builddir@/dict_dcca.fdx + - module: @freediameter_extensions_builddir@/dict_dcca_3gpp.fdx + connect: + - identity: pcrf.localdomain + addr: 127.0.0.9 + - identity: aaa.localdomain + addr: 127.0.0.1 +amf: + sbi: + - addr: 127.0.0.5 + port: 7777 + ngap: + - addr: 127.0.0.5 + guami: + - plmn_id: + mcc: 901 + mnc: 70 + amf_id: + region: 2 + set: 1 + tai: + - plmn_id: + mcc: 901 + mnc: 70 + tac: 1 + plmn_support: + - plmn_id: + mcc: 901 + 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 + +sgwu: + pfcp: + - addr: 127.0.0.6 + gtpu: + - addr: 127.0.0.6 + +upf: + pfcp: + - addr: 127.0.0.7 + gtpu: + - addr: 127.0.0.7 + subnet: + - addr: 10.45.0.1/16 + - addr: 2001:230:cafe::1/48 + +hss: + freeDiameter: + identity: hss.localdomain + realm: localdomain + listen_on: 127.0.0.8 + no_fwd: true + load_extension: + - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx + conf: 0x8888 + - module: @freediameter_extensions_builddir@/dict_rfc5777.fdx + - module: @freediameter_extensions_builddir@/dict_mip6i.fdx + - module: @freediameter_extensions_builddir@/dict_nasreq.fdx + - module: @freediameter_extensions_builddir@/dict_nas_mipv6.fdx + - module: @freediameter_extensions_builddir@/dict_dcca.fdx + - module: @freediameter_extensions_builddir@/dict_dcca_3gpp.fdx + connect: + - identity: mme.localdomain + addr: 127.0.0.2 + - identity: aaa.localdomain + addr: 127.0.0.1 +pcrf: + freeDiameter: + identity: pcrf.localdomain + realm: localdomain + listen_on: 127.0.0.9 + no_fwd: true + load_extension: + - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx + conf: 0x8888 + - module: @freediameter_extensions_builddir@/dict_rfc5777.fdx + - module: @freediameter_extensions_builddir@/dict_mip6i.fdx + - module: @freediameter_extensions_builddir@/dict_nasreq.fdx + - module: @freediameter_extensions_builddir@/dict_nas_mipv6.fdx + - module: @freediameter_extensions_builddir@/dict_dcca.fdx + - module: @freediameter_extensions_builddir@/dict_dcca_3gpp.fdx + connect: + - identity: smf.localdomain + addr: 127.0.0.4 + +nrf: + sbi: + - addr: + - 127.0.0.10 + - ::1 + port: 7777 + +ausf: + sbi: + - addr: 127.0.0.11 + port: 7777 + +udm: + sbi: + - addr: 127.0.0.12 + port: 7777 + +pcf: + sbi: + - addr: 127.0.0.13 + port: 7777 + +nssf: + sbi: + - addr: 127.0.0.14 + port: 7777 + nsi: + - addr: ::1 + port: 7777 + s_nssai: + sst: 1 +bsf: + sbi: + - addr: 127.0.0.15 + port: 7777 + +udr: + sbi: + - addr: 127.0.0.20 + port: 7777 diff --git a/configs/sample.yaml.in b/configs/sample.yaml.in index fcffb11ba..0800ee3b4 100644 --- a/configs/sample.yaml.in +++ b/configs/sample.yaml.in @@ -24,6 +24,7 @@ mme: identity: mme.localdomain realm: localdomain listen_on: 127.0.0.2 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -90,6 +91,7 @@ smf: identity: smf.localdomain realm: localdomain listen_on: 127.0.0.4 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -153,6 +155,7 @@ hss: identity: hss.localdomain realm: localdomain listen_on: 127.0.0.8 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -170,6 +173,7 @@ pcrf: identity: pcrf.localdomain realm: localdomain listen_on: 127.0.0.9 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 diff --git a/configs/slice.yaml.in b/configs/slice.yaml.in index beb1792df..a177901da 100644 --- a/configs/slice.yaml.in +++ b/configs/slice.yaml.in @@ -24,6 +24,7 @@ mme: identity: mme.localdomain realm: localdomain listen_on: 127.0.0.2 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -90,6 +91,7 @@ smf: identity: smf.localdomain realm: localdomain listen_on: 127.0.0.4 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -157,6 +159,7 @@ hss: identity: hss.localdomain realm: localdomain listen_on: 127.0.0.8 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -174,6 +177,7 @@ pcrf: identity: pcrf.localdomain realm: localdomain listen_on: 127.0.0.9 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 diff --git a/configs/srslte.yaml.in b/configs/srslte.yaml.in index 9f3ad21ca..1dec96467 100644 --- a/configs/srslte.yaml.in +++ b/configs/srslte.yaml.in @@ -24,6 +24,7 @@ mme: identity: mme.localdomain realm: localdomain listen_on: 127.0.0.2 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -90,6 +91,7 @@ smf: identity: smf.localdomain realm: localdomain listen_on: 127.0.0.4 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -153,6 +155,7 @@ hss: identity: hss.localdomain realm: localdomain listen_on: 127.0.0.8 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -170,6 +173,7 @@ pcrf: identity: pcrf.localdomain realm: localdomain listen_on: 127.0.0.9 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 diff --git a/configs/volte.yaml.in b/configs/volte.yaml.in index 5a19ce51d..169c35721 100644 --- a/configs/volte.yaml.in +++ b/configs/volte.yaml.in @@ -24,6 +24,7 @@ mme: identity: mme.localdomain realm: localdomain listen_on: 127.0.0.2 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -93,6 +94,7 @@ smf: identity: smf.localdomain realm: localdomain listen_on: 127.0.0.4 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -156,6 +158,7 @@ hss: identity: hss.localdomain realm: localdomain listen_on: 127.0.0.8 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -175,6 +178,7 @@ pcrf: identity: pcrf.localdomain realm: localdomain listen_on: 127.0.0.9 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 diff --git a/configs/vonr.yaml.in b/configs/vonr.yaml.in index 21ce6b84d..08231e5fe 100644 --- a/configs/vonr.yaml.in +++ b/configs/vonr.yaml.in @@ -24,6 +24,7 @@ mme: identity: mme.localdomain realm: localdomain listen_on: 127.0.0.2 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -93,6 +94,7 @@ smf: identity: smf.localdomain realm: localdomain listen_on: 127.0.0.4 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -156,6 +158,7 @@ hss: identity: hss.localdomain realm: localdomain listen_on: 127.0.0.8 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 @@ -173,6 +176,7 @@ pcrf: identity: pcrf.localdomain realm: localdomain listen_on: 127.0.0.9 + no_fwd: true load_extension: - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx conf: 0x8888 diff --git a/lib/diameter/common/base.h b/lib/diameter/common/base.h index e6aa0ceb2..748f3271e 100644 --- a/lib/diameter/common/base.h +++ b/lib/diameter/common/base.h @@ -43,9 +43,12 @@ typedef struct ogs_diam_config_s { /* the local port for Diameter/TLS (default: 5658) in host byte order */ uint16_t cnf_port_tls; - struct { - unsigned no_sctp: 1; /* disable the use of SCTP */ - } cnf_flags; + struct { + /* the peer does not relay messages (0xffffff app id) */ + unsigned no_fwd: 1; + /* disable the use of SCTP */ + unsigned no_sctp: 1; + } cnf_flags; #define MAX_NUM_OF_FD_EXTENSION 32 struct { @@ -66,10 +69,11 @@ typedef struct ogs_diam_config_s { } ogs_diam_config_t; int ogs_diam_init(int mode, const char *conffile, ogs_diam_config_t *fd_config); +int ogs_diam_start(void); void ogs_diam_final(void); int ogs_diam_config_init(ogs_diam_config_t *fd_config); -bool ogs_diam_peer_connected(void); +bool ogs_diam_app_connected(uint32_t app_id); int fd_avp_search_avp ( struct avp * groupedavp, struct dict_object * what, struct avp ** avp ); diff --git a/lib/diameter/common/config.c b/lib/diameter/common/config.c index 086a58dee..5408c8392 100644 --- a/lib/diameter/common/config.c +++ b/lib/diameter/common/config.c @@ -66,6 +66,9 @@ static int diam_config_apply(ogs_diam_config_t *fd_config) if (fd_config->cnf_flags.no_sctp) fd_g_config->cnf_flags.no_sctp = fd_config->cnf_flags.no_sctp; + if (fd_config->cnf_flags.no_fwd) + fd_g_config->cnf_flags.no_fwd = fd_config->cnf_flags.no_fwd; + /******************************************************************** * Diameter Client */ diff --git a/lib/diameter/common/init.c b/lib/diameter/common/init.c index 5b68c6a94..3d4da846f 100644 --- a/lib/diameter/common/init.c +++ b/lib/diameter/common/init.c @@ -57,6 +57,16 @@ int ogs_diam_init(int mode, const char *conffile, ogs_diam_config_t *fd_config) /* Initialize FD logger */ CHECK_FCT_DO( ogs_diam_logger_init(mode), goto error ); + return 0; +error: + CHECK_FCT_DO( fd_core_shutdown(), ); + CHECK_FCT_DO( fd_core_wait_shutdown_complete(), ); + + return -1; +} + +int ogs_diam_start(void) +{ /* Start the servers */ CHECK_FCT_DO( fd_core_start(), goto error ); diff --git a/lib/diameter/common/message.c b/lib/diameter/common/message.c index 4b6ee0901..09de412d9 100644 --- a/lib/diameter/common/message.c +++ b/lib/diameter/common/message.c @@ -28,6 +28,9 @@ struct dict_object *ogs_diam_origin_realm = NULL; struct dict_object *ogs_diam_destination_host = NULL; struct dict_object *ogs_diam_destination_realm = NULL; struct dict_object *ogs_diam_user_name = NULL; +struct dict_object *ogs_diam_subscription_id = NULL; +struct dict_object *ogs_diam_subscription_id_type = NULL; +struct dict_object *ogs_diam_subscription_id_data = NULL; struct dict_object *ogs_diam_auth_session_state = NULL; struct dict_object *ogs_diam_auth_application_id = NULL; struct dict_object *ogs_diam_auth_request_type = NULL; @@ -41,6 +44,10 @@ struct dict_object *ogs_diam_mip_home_agent_address = NULL; struct dict_object *ogs_diam_authorization_lifetime = NULL; struct dict_object *ogs_diam_auth_grace_period = NULL; struct dict_object *ogs_diam_session_timeout = NULL; +struct dict_object *ogs_diam_rat_type = NULL; +struct dict_object *ogs_diam_service_selection = NULL; +struct dict_object *ogs_diam_visited_plmn_id = NULL; +struct dict_object *ogs_diam_visited_network_identifier = NULL; struct dict_object *ogs_diam_vendor = NULL; struct dict_object *ogs_diam_vendor_id = NULL; @@ -62,6 +69,9 @@ int ogs_diam_message_init() CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Destination-Host", &ogs_diam_destination_host); CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Destination-Realm", &ogs_diam_destination_realm); CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "User-Name", &ogs_diam_user_name); + CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Subscription-Id", &ogs_diam_subscription_id); + CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Subscription-Id-Type", &ogs_diam_subscription_id_type); + CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Subscription-Id-Data", &ogs_diam_subscription_id_data); CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Auth-Session-State", &ogs_diam_auth_session_state); CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Auth-Application-Id", &ogs_diam_auth_application_id); CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Auth-Request-Type", &ogs_diam_auth_request_type); @@ -75,6 +85,10 @@ int ogs_diam_message_init() CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Authorization-Lifetime", &ogs_diam_authorization_lifetime); CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Auth-Grace-Period", &ogs_diam_auth_grace_period); CHECK_dict_search( DICT_AVP, AVP_BY_NAME, "Session-Timeout", &ogs_diam_session_timeout); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "RAT-Type", &ogs_diam_rat_type); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Service-Selection", &ogs_diam_service_selection); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Visited-PLMN-Id", &ogs_diam_visited_plmn_id); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Visited-Network-Identifier", &ogs_diam_visited_network_identifier); return 0; } diff --git a/lib/diameter/common/message.h b/lib/diameter/common/message.h index e99245586..370d07549 100644 --- a/lib/diameter/common/message.h +++ b/lib/diameter/common/message.h @@ -47,6 +47,13 @@ extern struct dict_object *ogs_diam_origin_realm; extern struct dict_object *ogs_diam_destination_host; extern struct dict_object *ogs_diam_destination_realm; extern struct dict_object *ogs_diam_user_name; +extern struct dict_object *ogs_diam_subscription_id; +#define OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_E164 0 +#define OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_IMSI 1 +#define OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_SIP_URI 2 +#define OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_NAI 3 +extern struct dict_object *ogs_diam_subscription_id_type; +extern struct dict_object *ogs_diam_subscription_id_data; #define OGS_DIAM_AUTH_SESSION_STATE_MAINTAINED 0 #define OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED 1 extern struct dict_object *ogs_diam_auth_session_state; @@ -67,6 +74,22 @@ extern struct dict_object *ogs_diam_mip_home_agent_address; extern struct dict_object *ogs_diam_authorization_lifetime; extern struct dict_object *ogs_diam_auth_grace_period; extern struct dict_object *ogs_diam_session_timeout; +#define OGS_DIAM_RAT_TYPE_WLAN 0 +#define OGS_DIAM_RAT_TYPE_VIRTUAL 1 +#define OGS_DIAM_RAT_TYPE_UTRAN 1000 +#define OGS_DIAM_RAT_TYPE_GERAN 1001 +#define OGS_DIAM_RAT_TYPE_GAN 1002 +#define OGS_DIAM_RAT_TYPE_HSPA_EVOLUTION 1003 +#define OGS_DIAM_RAT_TYPE_EUTRAN 1004 +#define OGS_DIAM_RAT_TYPE_EUTRAN_NB_IoT 1005 +#define OGS_DIAM_RAT_TYPE_CDMA2000_1X 2000 +#define OGS_DIAM_RAT_TYPE_HRPD 2001 +#define OGS_DIAM_RAT_TYPE_UMB 2002 +#define OGS_DIAM_RAT_TYPE_EHRPD 2003 +extern struct dict_object *ogs_diam_rat_type; +extern struct dict_object *ogs_diam_service_selection; +extern struct dict_object *ogs_diam_visited_plmn_id; +extern struct dict_object *ogs_diam_visited_network_identifier; extern struct dict_object *ogs_diam_vendor; extern struct dict_object *ogs_diam_vendor_id; diff --git a/lib/diameter/common/util.c b/lib/diameter/common/util.c index c483ef081..7bc41f8cd 100644 --- a/lib/diameter/common/util.c +++ b/lib/diameter/common/util.c @@ -19,10 +19,10 @@ #include "ogs-diameter-common.h" -bool ogs_diam_peer_connected(void) +bool ogs_diam_app_connected(uint32_t app_id) { - struct fd_list *li; - bool connected = false; + struct fd_list *li = NULL; + struct fd_app *found = NULL; CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) ); for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { @@ -35,13 +35,19 @@ bool ogs_diam_peer_connected(void) if (state == STATE_OPEN) { ogs_debug("'%s' STATE is OPEN", p->info.pi_diamid); - connected = true; + + /* Check if the remote peer advertised the message's appli */ + fd_app_check(&p->info.runtime.pir_apps, app_id, &found); + + if (found) break; } else { ogs_debug("'%s' STATE[%d] is NOT open ", p->info.pi_diamid, state); } } CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) ); - return connected; + if (found) + return true; + else + return false; } - diff --git a/lib/diameter/cx/dict.c b/lib/diameter/cx/dict.c index f4119d29d..7d8ebfdec 100644 --- a/lib/diameter/cx/dict.c +++ b/lib/diameter/cx/dict.c @@ -151,8 +151,10 @@ int ogs_dict_cx_entry(char *conffile) { struct dict_object * vendor; CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "3GPP", &vendor, ENOENT)); - struct dict_application_data app_data = { 16777216, "Cx" }; - CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &app_data, vendor, NULL)); + struct dict_application_data cx = { 16777216, "Cx" }; + struct dict_application_data swx = { 16777265, "SWx" }; + CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &cx, vendor, NULL)); + CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &swx, vendor, NULL)); } } @@ -312,10 +314,18 @@ int ogs_dict_cx_entry(char *conffile) { { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 }, { { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 }, { { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 }, +#if 0 /* modified by acetcom */ { { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_REQUIRED, -1, 1 }, +#else + { { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, 1 }, +#endif { { .avp_vendor = 10415, .avp_name = "SIP-Auth-Data-Item" }, RULE_REQUIRED, -1, 1 }, { { .avp_vendor = 10415, .avp_name = "SIP-Number-Auth-Items" }, RULE_REQUIRED, -1, 1 }, +#if 0 /* modified by acetcom */ { { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_REQUIRED, -1, 1 }, +#else + { { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 }, +#endif { { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 }, { { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }, }; @@ -380,9 +390,17 @@ int ogs_dict_cx_entry(char *conffile) { { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 }, { { .avp_vendor = 10415, .avp_name = "Public-Identity" }, RULE_OPTIONAL, -1, -1 }, { { .avp_vendor = 10415, .avp_name = "Wildcarded-Public-Identity" }, RULE_OPTIONAL, -1, 1 }, +#if 0 /* modified by acetcom */ { { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_REQUIRED, -1, 1 }, +#else + { { .avp_vendor = 10415, .avp_name = "Server-Name" }, RULE_OPTIONAL, -1, 1 }, +#endif { { .avp_vendor = 10415, .avp_name = "Server-Assignment-Type" }, RULE_REQUIRED, -1, 1 }, +#if 0 /* modified by acetcom */ { { .avp_vendor = 10415, .avp_name = "User-Data-Already-Available" }, RULE_REQUIRED, -1, 1 }, +#else + { { .avp_vendor = 10415, .avp_name = "User-Data-Already-Available" }, RULE_OPTIONAL, -1, 1 }, +#endif { { .avp_vendor = 10415, .avp_name = "SCSCF-Restoration-Info" }, RULE_OPTIONAL, -1, 1 }, { { .avp_vendor = 10415, .avp_name = "Multiple-Registration-Indication" }, RULE_OPTIONAL, -1, 1 }, { { .avp_vendor = 10415, .avp_name = "Session-Priority" }, RULE_OPTIONAL, -1, 1 }, diff --git a/lib/diameter/cx/meson.build b/lib/diameter/cx/meson.build index efb1a2f8b..dda225549 100644 --- a/lib/diameter/cx/meson.build +++ b/lib/diameter/cx/meson.build @@ -17,7 +17,6 @@ libdiameter_cx_sources = files(''' ogs-diameter-cx.h - message.h dict.c diff --git a/lib/diameter/cx/message.c b/lib/diameter/cx/message.c index 93d2fa8bb..f298838a8 100644 --- a/lib/diameter/cx/message.c +++ b/lib/diameter/cx/message.c @@ -37,7 +37,6 @@ struct dict_object *ogs_diam_cx_cmd_lir = NULL; struct dict_object *ogs_diam_cx_cmd_lia = NULL; struct dict_object *ogs_diam_cx_public_identity = NULL; -struct dict_object *ogs_diam_cx_visited_network_identifier = NULL; struct dict_object *ogs_diam_cx_server_name = NULL; struct dict_object *ogs_diam_cx_sip_number_auth_items = NULL; @@ -170,9 +169,6 @@ int ogs_diam_cx_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Public-Identity", &ogs_diam_cx_public_identity); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, - "Visited-Network-Identifier", - &ogs_diam_cx_visited_network_identifier); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Server-Name", &ogs_diam_cx_server_name); diff --git a/lib/diameter/cx/message.h b/lib/diameter/cx/message.h index 3951507d0..4bfa68267 100644 --- a/lib/diameter/cx/message.h +++ b/lib/diameter/cx/message.h @@ -42,7 +42,6 @@ extern struct dict_object *ogs_diam_cx_cmd_lir; extern struct dict_object *ogs_diam_cx_cmd_lia; extern struct dict_object *ogs_diam_cx_public_identity; -extern struct dict_object *ogs_diam_cx_visited_network_identifier; extern struct dict_object *ogs_diam_cx_server_name; extern struct dict_object *ogs_diam_cx_sip_number_auth_items; diff --git a/lib/diameter/gx/message.c b/lib/diameter/gx/message.c index 34bfbf5df..47a09c8a0 100644 --- a/lib/diameter/gx/message.c +++ b/lib/diameter/gx/message.c @@ -32,16 +32,12 @@ struct dict_object *ogs_diam_gx_cmd_raa = NULL; struct dict_object *ogs_diam_gx_cc_request_type = NULL; struct dict_object *ogs_diam_gx_cc_request_number = NULL; struct dict_object *ogs_diam_gx_network_request_support = NULL; -struct dict_object *ogs_diam_gx_subscription_id = NULL; -struct dict_object *ogs_diam_gx_subscription_id_type = NULL; -struct dict_object *ogs_diam_gx_subscription_id_data = NULL; struct dict_object *ogs_diam_gx_supported_features = NULL; struct dict_object *ogs_diam_gx_feature_list_id = NULL; struct dict_object *ogs_diam_gx_feature_list = NULL; struct dict_object *ogs_diam_gx_framed_ip_address = NULL; struct dict_object *ogs_diam_gx_framed_ipv6_prefix = NULL; struct dict_object *ogs_diam_gx_ip_can_type = NULL; -struct dict_object *ogs_diam_gx_rat_type = NULL; struct dict_object *ogs_diam_gx_qos_information = NULL; struct dict_object *ogs_diam_gx_qos_class_identifier = NULL; struct dict_object *ogs_diam_gx_max_requested_bandwidth_ul = NULL; @@ -82,6 +78,14 @@ struct dict_object *ogs_diam_gx_codec_data = NULL; struct dict_object *ogs_diam_gx_media_sub_component = NULL; struct dict_object *ogs_diam_gx_flow_number = NULL; struct dict_object *ogs_diam_gx_flow_usage = NULL; +struct dict_object *ogs_diam_gx_3gpp_sgsn_mcc_mnc = NULL; +struct dict_object *ogs_diam_gx_an_gw_address = NULL; +struct dict_object *ogs_diam_gx_online = NULL; +struct dict_object *ogs_diam_gx_offline = NULL; +struct dict_object *ogs_diam_gx_access_network_charging_address = NULL; +struct dict_object *ogs_diam_gx_access_network_charging_identifier_gx = NULL; +struct dict_object *ogs_diam_gx_access_network_charging_identifier_value = NULL; +struct dict_object *ogs_diam_gx_an_trusted = NULL; extern int ogs_dict_gx_entry(char *conffile); @@ -101,16 +105,12 @@ int ogs_diam_gx_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "CC-Request-Type", &ogs_diam_gx_cc_request_type); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "CC-Request-Number", &ogs_diam_gx_cc_request_number); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Network-Request-Support", &ogs_diam_gx_network_request_support); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Subscription-Id", &ogs_diam_gx_subscription_id); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Subscription-Id-Type", &ogs_diam_gx_subscription_id_type); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Subscription-Id-Data", &ogs_diam_gx_subscription_id_data); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Supported-Features", &ogs_diam_gx_supported_features); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Feature-List-ID", &ogs_diam_gx_feature_list_id); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Feature-List", &ogs_diam_gx_feature_list); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Framed-IP-Address", &ogs_diam_gx_framed_ip_address); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Framed-IPv6-Prefix", &ogs_diam_gx_framed_ipv6_prefix); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "IP-CAN-Type", &ogs_diam_gx_ip_can_type); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "RAT-Type", &ogs_diam_gx_rat_type); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "QoS-Information", &ogs_diam_gx_qos_information); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "QoS-Class-Identifier" , &ogs_diam_gx_qos_class_identifier); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Max-Requested-Bandwidth-UL" , &ogs_diam_gx_max_requested_bandwidth_ul); @@ -154,6 +154,14 @@ int ogs_diam_gx_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Media-Sub-Component", &ogs_diam_gx_media_sub_component); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Flow-Number", &ogs_diam_gx_flow_number); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Flow-Usage", &ogs_diam_gx_flow_usage); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "3GPP-SGSN-MCC-MNC", &ogs_diam_gx_3gpp_sgsn_mcc_mnc); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "AN-GW-Address", &ogs_diam_gx_an_gw_address); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Online", &ogs_diam_gx_online); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Offline", &ogs_diam_gx_offline); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Access-Network-Charging-Address", &ogs_diam_gx_access_network_charging_address); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Access-Network-Charging-Identifier-Gx", &ogs_diam_gx_access_network_charging_identifier_gx); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Access-Network-Charging-Identifier-Value", &ogs_diam_gx_access_network_charging_identifier_value); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "AN-Trusted", &ogs_diam_gx_an_trusted); return 0; } diff --git a/lib/diameter/gx/message.h b/lib/diameter/gx/message.h index 3837a0668..a6e39157e 100644 --- a/lib/diameter/gx/message.h +++ b/lib/diameter/gx/message.h @@ -54,13 +54,6 @@ extern struct dict_object *ogs_diam_gx_cmd_raa; extern struct dict_object *ogs_diam_gx_cc_request_type; extern struct dict_object *ogs_diam_gx_cc_request_number; extern struct dict_object *ogs_diam_gx_network_request_support; -extern struct dict_object *ogs_diam_gx_subscription_id; -#define OGS_DIAM_GX_SUBSCRIPTION_ID_TYPE_END_USER_E164 0 -#define OGS_DIAM_GX_SUBSCRIPTION_ID_TYPE_END_USER_IMSI 1 -#define OGS_DIAM_GX_SUBSCRIPTION_ID_TYPE_END_USER_SIP_URI 2 -#define OGS_DIAM_GX_SUBSCRIPTION_ID_TYPE_END_USER_NAI 3 -extern struct dict_object *ogs_diam_gx_subscription_id_type; -extern struct dict_object *ogs_diam_gx_subscription_id_data; extern struct dict_object *ogs_diam_gx_supported_features; extern struct dict_object *ogs_diam_gx_feature_list_id; extern struct dict_object *ogs_diam_gx_feature_list; @@ -72,21 +65,8 @@ extern struct dict_object *ogs_diam_gx_framed_ipv6_prefix; #define OGS_DIAM_GX_IP_CAN_TYPE_WiMAX 3 #define OGS_DIAM_GX_IP_CAN_TYPE_3GPP2 4 #define OGS_DIAM_GX_IP_CAN_TYPE_3GPP_EPS 5 -#define OGS_DIAM_GX_IP_CAN_TYPE_Non_3GPP_EPS 6 +#define OGS_DIAM_GX_IP_CAN_TYPE_NON_3GPP_EPS 6 extern struct dict_object *ogs_diam_gx_ip_can_type; -#define OGS_DIAM_GX_RAT_TYPE_WLAN 0 -#define OGS_DIAM_GX_RAT_TYPE_VIRTUAL 1 -#define OGS_DIAM_GX_RAT_TYPE_UTRAN 1000 -#define OGS_DIAM_GX_RAT_TYPE_GERAN 1001 -#define OGS_DIAM_GX_RAT_TYPE_GAN 1002 -#define OGS_DIAM_GX_RAT_TYPE_HSPA_EVOLUTION 1003 -#define OGS_DIAM_GX_RAT_TYPE_EUTRAN 1004 -#define OGS_DIAM_GX_RAT_TYPE_EUTRAN_NB_IoT 1005 -#define OGS_DIAM_GX_RAT_TYPE_CDMA2000_1X 2000 -#define OGS_DIAM_GX_RAT_TYPE_HRPD 2001 -#define OGS_DIAM_GX_RAT_TYPE_UMB 2002 -#define OGS_DIAM_GX_RAT_TYPE_EHRPD 2003 -extern struct dict_object *ogs_diam_gx_rat_type; extern struct dict_object *ogs_diam_gx_qos_information; extern struct dict_object *ogs_diam_gx_qos_class_identifier; extern struct dict_object *ogs_diam_gx_max_requested_bandwidth_ul; @@ -128,6 +108,20 @@ extern struct dict_object *ogs_diam_gx_codec_data; extern struct dict_object *ogs_diam_gx_media_sub_component; extern struct dict_object *ogs_diam_gx_flow_number; extern struct dict_object *ogs_diam_gx_flow_usage; +extern struct dict_object *ogs_diam_gx_3gpp_sgsn_mcc_mnc; +extern struct dict_object *ogs_diam_gx_an_gw_address; +#define OGS_DIAM_GX_DISABLE_ONLINE 0 +#define OGS_DIAM_GX_ENABLE_ONLINE 1 +extern struct dict_object *ogs_diam_gx_online; +#define OGS_DIAM_GX_DISABLE_OFFLINE 0 +#define OGS_DIAM_GX_ENABLE_OFFLINE 1 +extern struct dict_object *ogs_diam_gx_offline; +extern struct dict_object *ogs_diam_gx_access_network_charging_address; +extern struct dict_object *ogs_diam_gx_access_network_charging_identifier_gx; +extern struct dict_object *ogs_diam_gx_access_network_charging_identifier_value; +#define OGS_DIAM_GX_AN_TRUSTED 0 +#define OGS_DIAM_GX_AN_UNTRUSTED 1 +extern struct dict_object *ogs_diam_gx_an_trusted; typedef struct ogs_diam_gx_message_s { #define OGS_DIAM_GX_CMD_CODE_CREDIT_CONTROL 272 diff --git a/lib/diameter/meson.build b/lib/diameter/meson.build index 5d31907b6..25fa8bc8b 100644 --- a/lib/diameter/meson.build +++ b/lib/diameter/meson.build @@ -20,3 +20,5 @@ subdir('gx') subdir('rx') subdir('s6a') subdir('cx') +subdir('swx') +subdir('s6b') diff --git a/lib/diameter/rx/dict.c b/lib/diameter/rx/dict.c index 95b788a97..e2b3298bf 100644 --- a/lib/diameter/rx/dict.c +++ b/lib/diameter/rx/dict.c @@ -151,8 +151,10 @@ int ogs_dict_rx_entry(char *conffile) { struct dict_object * vendor; CHECK_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "3GPP", &vendor, ENOENT)); - struct dict_application_data app_data = { 16777236, "Rx" }; - CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &app_data, vendor, NULL)); + struct dict_application_data rx = { 16777236, "Rx" }; + struct dict_application_data s6b = { 16777272, "S6b" }; + CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &rx, vendor, NULL)); + CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_APPLICATION, &s6b, vendor, NULL)); } } diff --git a/lib/diameter/rx/message.c b/lib/diameter/rx/message.c index 6b89b2aff..4de28a8bc 100644 --- a/lib/diameter/rx/message.c +++ b/lib/diameter/rx/message.c @@ -55,7 +55,6 @@ struct dict_object *ogs_diam_rx_specific_action = NULL; struct dict_object *ogs_diam_rx_framed_ip_address = NULL; struct dict_object *ogs_diam_rx_framed_ipv6_prefix = NULL; struct dict_object *ogs_diam_rx_ip_can_type = NULL; -struct dict_object *ogs_diam_rx_rat_type = NULL; struct dict_object *ogs_diam_rx_abort_cause = NULL; struct dict_object *ogs_diam_rx_termination_cause = NULL; @@ -100,7 +99,6 @@ int ogs_diam_rx_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Framed-IP-Address", &ogs_diam_rx_framed_ip_address); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Framed-IPv6-Prefix", &ogs_diam_rx_framed_ipv6_prefix); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "IP-CAN-Type", &ogs_diam_rx_ip_can_type); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "RAT-Type", &ogs_diam_rx_rat_type); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Abort-Cause", &ogs_diam_rx_abort_cause); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Termination-Cause", &ogs_diam_rx_termination_cause); diff --git a/lib/diameter/rx/message.h b/lib/diameter/rx/message.h index c99b235fa..24cfdc5e0 100644 --- a/lib/diameter/rx/message.h +++ b/lib/diameter/rx/message.h @@ -115,19 +115,6 @@ extern struct dict_object *ogs_diam_rx_framed_ipv6_prefix; #define OGS_DIAM_RX_IP_CAN_TYPE_3GPP_EPS 5 #define OGS_DIAM_RX_IP_CAN_TYPE_Non_3GPP_EPS 6 extern struct dict_object *ogs_diam_rx_ip_can_type; -#define OGS_DIAM_RX_RAT_TYPE_WLAN 0 -#define OGS_DIAM_RX_RAT_TYPE_VIRTUAL 1 -#define OGS_DIAM_RX_RAT_TYPE_UTRAN 1000 -#define OGS_DIAM_RX_RAT_TYPE_GERAN 1001 -#define OGS_DIAM_RX_RAT_TYPE_GAN 1002 -#define OGS_DIAM_RX_RAT_TYPE_HSPA_EVOLUTION 1003 -#define OGS_DIAM_RX_RAT_TYPE_EUTRAN 1004 -#define OGS_DIAM_RX_RAT_TYPE_EUTRAN_NB_IoT 1005 -#define OGS_DIAM_RX_RAT_TYPE_CDMA2000_1X 2000 -#define OGS_DIAM_RX_RAT_TYPE_HRPD 2001 -#define OGS_DIAM_RX_RAT_TYPE_UMB 2002 -#define OGS_DIAM_RX_RAT_TYPE_EHRPD 2003 -extern struct dict_object *ogs_diam_rx_rat_type; #define OGS_DIAM_RX_ABORT_CAUSE_BEARER_RELEASED 0 #define OGS_DIAM_RX_ABORT_CAUSE_INSUFFICIENT_SERVER_RESOURCES 1 #define OGS_DIAM_RX_ABORT_CAUSE_INSUFFICIENT_BEARER_RESOURCES 2 diff --git a/lib/diameter/s6a/message.c b/lib/diameter/s6a/message.c index 2b597f64f..3b60e8070 100644 --- a/lib/diameter/s6a/message.c +++ b/lib/diameter/s6a/message.c @@ -31,8 +31,6 @@ struct dict_object *ogs_diam_s6a_cmd_ula = NULL; struct dict_object *ogs_diam_s6a_cmd_pur = NULL; struct dict_object *ogs_diam_s6a_cmd_pua = NULL; -struct dict_object *ogs_diam_s6a_visited_plmn_id = NULL; -struct dict_object *ogs_diam_s6a_rat_type = NULL; struct dict_object *ogs_diam_s6a_ulr_flags = NULL; struct dict_object *ogs_diam_s6a_ula_flags = NULL; struct dict_object *ogs_diam_s6a_subscription_data = NULL; @@ -41,7 +39,6 @@ struct dict_object *ogs_diam_s6a_number_of_requested_vectors = NULL; struct dict_object *ogs_diam_s6a_immediate_response_preferred = NULL; struct dict_object *ogs_diam_s6a_authentication_info = NULL; struct dict_object *ogs_diam_s6a_re_synchronization_info = NULL; -struct dict_object *ogs_diam_s6a_service_selection = NULL; struct dict_object *ogs_diam_s6a_ue_srvcc_capability = NULL; struct dict_object *ogs_diam_s6a_e_utran_vector = NULL; struct dict_object *ogs_diam_s6a_rand = NULL; @@ -67,6 +64,8 @@ struct dict_object *ogs_diam_s6a_allocation_retention_priority = NULL; struct dict_object *ogs_diam_s6a_priority_level = NULL; struct dict_object *ogs_diam_s6a_pre_emption_capability = NULL; struct dict_object *ogs_diam_s6a_pre_emption_vulnerability = NULL; +struct dict_object *ogs_diam_s6a_pdn_gw_allocation_type = NULL; +struct dict_object *ogs_diam_s6a_vplmn_dynamic_address_allowed = NULL; struct dict_object *ogs_diam_s6a_terminal_information = NULL; struct dict_object *ogs_diam_s6a_imei = NULL; @@ -92,8 +91,6 @@ int ogs_diam_s6a_init(void) CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Purge-UE-Request", &ogs_diam_s6a_cmd_pur); CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Purge-UE-Answer", &ogs_diam_s6a_cmd_pua); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Visited-PLMN-Id", &ogs_diam_s6a_visited_plmn_id); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "RAT-Type", &ogs_diam_s6a_rat_type); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "ULR-Flags", &ogs_diam_s6a_ulr_flags); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "ULA-Flags", &ogs_diam_s6a_ula_flags); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "UE-SRVCC-Capability", &ogs_diam_s6a_ue_srvcc_capability); @@ -116,6 +113,8 @@ int ogs_diam_s6a_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Priority-Level", &ogs_diam_s6a_priority_level); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Pre-emption-Capability", &ogs_diam_s6a_pre_emption_capability); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Pre-emption-Vulnerability", &ogs_diam_s6a_pre_emption_vulnerability); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "PDN-GW-Allocation-Type", &ogs_diam_s6a_pdn_gw_allocation_type); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "VPLMN-Dynamic-Address-Allowed", &ogs_diam_s6a_vplmn_dynamic_address_allowed); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "AMBR", &ogs_diam_s6a_ambr); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Max-Requested-Bandwidth-UL", &ogs_diam_s6a_max_bandwidth_ul); @@ -125,7 +124,6 @@ int ogs_diam_s6a_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Context-Identifier", &ogs_diam_s6a_context_identifier); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "All-APN-Configurations-Included-Indicator", &ogs_diam_s6a_all_apn_configuration_included_indicator); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "APN-Configuration", &ogs_diam_s6a_apn_configuration); - CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Service-Selection", &ogs_diam_s6a_service_selection); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "PDN-Type", &ogs_diam_s6a_pdn_type); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Served-Party-IP-Address", &ogs_diam_s6a_served_party_ip_address); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Subscription-Data", &ogs_diam_s6a_subscription_data); diff --git a/lib/diameter/s6a/message.h b/lib/diameter/s6a/message.h index 747dbfa0f..7ddff6229 100644 --- a/lib/diameter/s6a/message.h +++ b/lib/diameter/s6a/message.h @@ -62,6 +62,12 @@ extern "C" { #define OGS_DIAM_S6A_UE_SRVCC_NOT_SUPPORTED (0) #define OGS_DIAM_S6A_UE_SRVCC_SUPPORTED (1) +#define OGS_DIAM_S6A_PDN_GW_ALLOCATION_STATIC (0) +#define OGS_DIAM_S6A_PDN_GW_ALLOCATION_DYNAMIC (1) + +#define OGS_DIAM_S6A_VPLMN_DYNAMIC_ADDRESS_NOTALLOWED (0) +#define OGS_DIAM_S6A_VPLMN_DYNAMIC_ADDRESS_ALLOWED (1) + extern struct dict_object *ogs_diam_s6a_application; extern struct dict_object *ogs_diam_s6a_cmd_air; @@ -71,8 +77,6 @@ extern struct dict_object *ogs_diam_s6a_cmd_ula; extern struct dict_object *ogs_diam_s6a_cmd_pur; extern struct dict_object *ogs_diam_s6a_cmd_pua; -extern struct dict_object *ogs_diam_s6a_visited_plmn_id; -extern struct dict_object *ogs_diam_s6a_rat_type; extern struct dict_object *ogs_diam_s6a_ulr_flags; extern struct dict_object *ogs_diam_s6a_ula_flags; extern struct dict_object *ogs_diam_s6a_subscription_data; @@ -81,7 +85,6 @@ extern struct dict_object *ogs_diam_s6a_number_of_requested_vectors; extern struct dict_object *ogs_diam_s6a_immediate_response_preferred; extern struct dict_object *ogs_diam_s6a_authentication_info; extern struct dict_object *ogs_diam_s6a_re_synchronization_info; -extern struct dict_object *ogs_diam_s6a_service_selection; extern struct dict_object *ogs_diam_s6a_ue_srvcc_capability; extern struct dict_object *ogs_diam_s6a_e_utran_vector; extern struct dict_object *ogs_diam_s6a_rand; @@ -107,6 +110,8 @@ extern struct dict_object *ogs_diam_s6a_allocation_retention_priority; extern struct dict_object *ogs_diam_s6a_priority_level; extern struct dict_object *ogs_diam_s6a_pre_emption_capability; extern struct dict_object *ogs_diam_s6a_pre_emption_vulnerability; +extern struct dict_object *ogs_diam_s6a_pdn_gw_allocation_type; +extern struct dict_object *ogs_diam_s6a_vplmn_dynamic_address_allowed; extern struct dict_object *ogs_diam_s6a_terminal_information; extern struct dict_object *ogs_diam_s6a_imei; diff --git a/lib/diameter/s6b/meson.build b/lib/diameter/s6b/meson.build new file mode 100644 index 000000000..611353be5 --- /dev/null +++ b/lib/diameter/s6b/meson.build @@ -0,0 +1,38 @@ +# Copyright (C) 2019 by Sukchan Lee + +# This file is part of Open5GS. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +libdiameter_s6b_sources = files(''' + ogs-diameter-s6b.h + message.h + + message.c +'''.split()) + +libdiameter_s6b_inc = include_directories('.') + +libdiameter_s6b = library('ogsdiameter-s6b', + sources : libdiameter_s6b_sources, + version : libogslib_version, + c_args : libdiameter_common_cc_flags, + include_directories : libdiameter_s6b_inc, + dependencies : libdiameter_rx_dep, + install : true) + +libdiameter_s6b_dep = declare_dependency( + link_with : libdiameter_s6b, + include_directories : libdiameter_s6b_inc, + dependencies : libdiameter_rx_dep) diff --git a/lib/diameter/s6b/message.c b/lib/diameter/s6b/message.c new file mode 100644 index 000000000..67ce6cb19 --- /dev/null +++ b/lib/diameter/s6b/message.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ogs-diameter-s6b.h" + +#define CHECK_dict_search( _type, _criteria, _what, _result ) \ + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) ); + +struct dict_object *ogs_diam_s6b_application = NULL; + +struct dict_object *ogs_diam_s6b_mip6_feature_vector = NULL; + +int ogs_diam_s6b_init(void) +{ + application_id_t id = OGS_DIAM_S6B_APPLICATION_ID; + + CHECK_dict_search(DICT_APPLICATION, APPLICATION_BY_ID, + (void *)&id, &ogs_diam_s6b_application); + + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, + "MIP6-Feature-Vector", &ogs_diam_s6b_mip6_feature_vector); + + return 0; +} diff --git a/lib/diameter/s6b/message.h b/lib/diameter/s6b/message.h new file mode 100644 index 000000000..d33ef167e --- /dev/null +++ b/lib/diameter/s6b/message.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if !defined(OGS_DIAMETER_INSIDE) && !defined(OGS_DIAMETER_COMPILATION) +#error "This header cannot be included directly." +#endif + +#ifndef OGS_DIAM_S6B_MESSAGE_H +#define OGS_DIAM_S6B_MESSAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define OGS_DIAM_S6B_APPLICATION_ID 16777272 + +extern struct dict_object *ogs_diam_s6b_application; + +extern struct dict_object *ogs_diam_s6b_mip6_feature_vector; + +int ogs_diam_s6b_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_DIAM_OGS_DIAM_S6B_MESSAGE_H */ diff --git a/lib/diameter/s6b/ogs-diameter-s6b.h b/lib/diameter/s6b/ogs-diameter-s6b.h new file mode 100644 index 000000000..fcb5b458a --- /dev/null +++ b/lib/diameter/s6b/ogs-diameter-s6b.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OGS_DIAMETER_S6B_H +#define OGS_DIAMETER_S6B_H + +#include "ogs-diameter-common.h" + +#define OGS_DIAMETER_INSIDE + +#include "diameter/s6b/message.h" + +#undef OGS_DIAMETER_INSIDE + +#ifdef __cplusplus +extern "C" { +#endif + +/* Nothing */ + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_DIAMETER_S6B_H */ diff --git a/lib/diameter/swx/meson.build b/lib/diameter/swx/meson.build new file mode 100644 index 000000000..629d56a1b --- /dev/null +++ b/lib/diameter/swx/meson.build @@ -0,0 +1,38 @@ +# Copyright (C) 2019 by Sukchan Lee + +# This file is part of Open5GS. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +libdiameter_swx_sources = files(''' + ogs-diameter-swx.h + message.h + + message.c +'''.split()) + +libdiameter_swx_inc = include_directories('.') + +libdiameter_swx = library('ogsdiameter-swx', + sources : libdiameter_swx_sources, + version : libogslib_version, + c_args : libdiameter_common_cc_flags, + include_directories : libdiameter_swx_inc, + dependencies : [libdiameter_cx_dep, libdiameter_s6a_dep], + install : true) + +libdiameter_swx_dep = declare_dependency( + link_with : libdiameter_swx, + include_directories : libdiameter_swx_inc, + dependencies : [libdiameter_cx_dep, libdiameter_s6a_dep]) diff --git a/lib/diameter/swx/message.c b/lib/diameter/swx/message.c new file mode 100644 index 000000000..5760e9a85 --- /dev/null +++ b/lib/diameter/swx/message.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ogs-diameter-swx.h" + +#define CHECK_dict_search( _type, _criteria, _what, _result ) \ + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) ); + +struct dict_object *ogs_diam_swx_application = NULL; + +struct dict_object *ogs_diam_swx_non_3gpp_user_data = NULL; +struct dict_object *ogs_diam_swx_non_3gpp_ip_access = NULL; +struct dict_object *ogs_diam_swx_non_3gpp_ip_access_apn = NULL; + +int ogs_diam_swx_init(void) +{ + application_id_t id = OGS_DIAM_SWX_APPLICATION_ID; + + CHECK_dict_search(DICT_APPLICATION, APPLICATION_BY_ID, + (void *)&id, &ogs_diam_swx_application); + + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, + "Non-3GPP-User-Data", &ogs_diam_swx_non_3gpp_user_data); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, + "Non-3GPP-IP-Access", &ogs_diam_swx_non_3gpp_ip_access); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, + "Non-3GPP-IP-Access-APN", &ogs_diam_swx_non_3gpp_ip_access_apn); + + return 0; +} diff --git a/lib/diameter/swx/message.h b/lib/diameter/swx/message.h new file mode 100644 index 000000000..4cd35bda3 --- /dev/null +++ b/lib/diameter/swx/message.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if !defined(OGS_DIAMETER_INSIDE) && !defined(OGS_DIAMETER_COMPILATION) +#error "This header cannot be included directly." +#endif + +#ifndef OGS_DIAM_SWX_MESSAGE_H +#define OGS_DIAM_SWX_MESSAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define OGS_DIAM_SWX_APPLICATION_ID 16777265 + +extern struct dict_object *ogs_diam_swx_application; + +extern struct dict_object *ogs_diam_swx_non_3gpp_user_data; +#define OGS_DIAM_SWX_NON_3GPP_SUBSCRIPTION_ALLOWED 0 +#define OGS_DIAM_SWX_NON_3GPP_SUBSCRIPTION_BARRED 1 +extern struct dict_object *ogs_diam_swx_non_3gpp_ip_access; +#define OGS_DIAM_SWX_NON_3GPP_APNS_ENABLE 0 +#define OGS_DIAM_SWX_NON_3GPP_APNS_DISABLE 1 +extern struct dict_object *ogs_diam_swx_non_3gpp_ip_access_apn; + +#define OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA "EAP-AKA" +#define OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA_QUOT "EAP-AKA'" + +int ogs_diam_swx_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_DIAM_OGS_DIAM_SWX_MESSAGE_H */ diff --git a/lib/diameter/swx/ogs-diameter-swx.h b/lib/diameter/swx/ogs-diameter-swx.h new file mode 100644 index 000000000..4887ae169 --- /dev/null +++ b/lib/diameter/swx/ogs-diameter-swx.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OGS_DIAMETER_SWX_H +#define OGS_DIAMETER_SWX_H + +#include "ogs-diameter-common.h" + +#define OGS_DIAMETER_INSIDE + +#include "diameter/swx/message.h" + +#undef OGS_DIAMETER_INSIDE + +#ifdef __cplusplus +extern "C" { +#endif + +/* Nothing */ + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_DIAMETER_SWX_H */ diff --git a/lib/gtp/context.h b/lib/gtp/context.h index 69ec417c0..9a233deb1 100644 --- a/lib/gtp/context.h +++ b/lib/gtp/context.h @@ -39,7 +39,6 @@ typedef struct ogs_gtp_context_s { ogs_sockaddr_t *gtpc_addr; /* GTPC IPv4 Address */ ogs_sockaddr_t *gtpc_addr6; /* GTPC IPv6 Address */ - ogs_list_t gtpu_list; /* GTPU IPv4/IPv6 Server List */ ogs_sock_t *gtpu_sock; /* GTPU IPv4 Socket */ ogs_sock_t *gtpu_sock6; /* GTPU IPv6 Socket */ diff --git a/lib/gtp/message.c b/lib/gtp/message.c index 8194bf154..8335da2c9 100644 --- a/lib/gtp/message.c +++ b/lib/gtp/message.c @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by gtp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2020-10-14 13:48:14.476575 by acetcom + * Created on: 2021-06-15 11:28:13.532535 by acetcom * from 29274-g30.docx ******************************************************************************/ @@ -490,10 +490,10 @@ ogs_tlv_desc_t ogs_gtp_tlv_desc_delay_value_0 = ogs_tlv_desc_t ogs_gtp_tlv_desc_charging_id_0 = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT32, "Charging ID", OGS_GTP_CHARGING_ID_TYPE, - 0, + 4, 0, sizeof(ogs_gtp_tlv_charging_id_t), { NULL } diff --git a/lib/gtp/message.h b/lib/gtp/message.h index 7021f4675..bb8a81f0f 100644 --- a/lib/gtp/message.h +++ b/lib/gtp/message.h @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by gtp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2020-10-14 13:48:14.468022 by acetcom + * Created on: 2021-06-15 11:28:13.527903 by acetcom * from 29274-g30.docx ******************************************************************************/ @@ -525,7 +525,7 @@ typedef ogs_tlv_octet_t ogs_gtp_tlv_global_cn_id_t; typedef ogs_tlv_octet_t ogs_gtp_tlv_s103pdf_t; typedef ogs_tlv_octet_t ogs_gtp_tlv_s1udf_t; typedef ogs_tlv_octet_t ogs_gtp_tlv_delay_value_t; -typedef ogs_tlv_octet_t ogs_gtp_tlv_charging_id_t; +typedef ogs_tlv_uint32_t ogs_gtp_tlv_charging_id_t; typedef ogs_tlv_octet_t ogs_gtp_tlv_charging_characteristics_t; typedef ogs_tlv_octet_t ogs_gtp_tlv_trace_information_t; typedef ogs_tlv_octet_t ogs_gtp_tlv_bearer_flags_t; diff --git a/lib/gtp/support/README.md b/lib/gtp/support/README.md index 09b961474..a9a9d02eb 100644 --- a/lib/gtp/support/README.md +++ b/lib/gtp/support/README.md @@ -1,16 +1,12 @@ -* Install python-pip -user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo apt-get install python-pip - * Install python-docx user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo pip install python-docx + sudo pip3 install python-docx * Change the format of standard specification from 29274-g30.doc to 29274-g30.docx using Microsoft Office 2007+ * Generate TLV support files -user@host ~/Documents/git/open5gs/lib/s1ap/support$ \ - python gtp-tlv.py -f 29274-g30.docx -o .. +user@host ~/Documents/git/open5gs/lib/gtp/support$ \ + python3 gtp-tlv.py -f 29274-g30.docx -o .. diff --git a/lib/gtp/support/cache/tlv-msg-100.py b/lib/gtp/support/cache/tlv-msg-100.py index 71f671a7d..923fd00b0 100644 --- a/lib/gtp/support/cache/tlv-msg-100.py +++ b/lib/gtp/support/cache/tlv-msg-100.py @@ -5,9 +5,7 @@ ies.append({ "ie_type" : "Bearer Context", "ie_value" : "Bearer Contexts", "pres ies.append({ "ie_type" : "Recovery", "ie_value" : "Recovery", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included on the S4/S11, S5/S8 and S2a/S2b interfaces if contacting the peer for the first time "}) ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "MME-FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included by MME the on S11 interface and shall be forwarded by the SGW on S5/S8 interface according to the requirements in 3GPP TS 23.007 [17]."}) ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-FQ-CSID", "presence" : "C", "instance" : "1", "comment" : "This IE shall be included by the SGW on the S5/S8 interface according to the requirements in 3GPP TS 23.007 [17]."}) -type_list["FQ-CSID"]["max_instance"] = "2" ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "ePDG-FQ-CSID", "presence" : "C", "instance" : "2", "comment" : "This IE shall be included by the ePDG on the S2b interface according to the requirements in 3GPP TS 23.007 [17]."}) -type_list["FQ-CSID"]["max_instance"] = "3" ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "TWAN-FQ-CSID", "presence" : "C", "instance" : "3", "comment" : "This IE shall be included by the TWAN on the S2a interface according to the requirements in 3GPP TS 23.007 [17]."}) ies.append({ "ie_type" : "PCO", "ie_value" : "Protocol Configuration Options", "presence" : "CO", "instance" : "0", "comment" : "An MME/SGSN shall include the PCO IE if such information was received from the UE. If the SGW receives this IE, the SGW shall forward it to PGW on the S5/S8 interface."}) ies.append({ "ie_type" : "UE Time Zone", "ie_value" : "UE Time Zone", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included, if available, by the MME on the S11 interface or by the SGSN on the S4 interface."}) @@ -19,9 +17,7 @@ ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "MME/S4-SG ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "SGW's Overload Control Information", "presence" : "O", "instance" : "1", "comment" : "During an overload condition, the SGW may include this IE over the S5/S8 interface if the overload control feature is supported by the SGW and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the SGW shall provide only one instance of this IE, representing its overload information."}) ies.append({ "ie_type" : "IP Address", "ie_value" : "MME/S4-SGSN Identifier", "presence" : "CO", "instance" : "0", "comment" : "If the overload control feature is supported by the MME/S4-SGSN and is activated for the PLMN to which the PGW belongs (see clause 12.3.11), the MME/S4-SGSN shall include this IE on the S11/S4 interface when there is at least one bearer remaining for the given PDN connection after the bearer deletion, and the PGW has not been updated with the identity of the currently serving MME/S4-SGSN, i.e. if no other message carrying MME/S4-SGSN identity has been sent to the PGW during/after an inter-MME/S4-SGSN intra-SGW mobility procedure."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "TWAN/ePDG's Overload Control Information", "presence" : "O", "instance" : "2", "comment" : "During an overload condition, the TWAN/ePDG may include this IE over the S2a/S2b interface if the overload control feature is supported by the TWAN/ePDG and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the TWAN/ePDG shall provide only one instance of this IE, representing its overload information."}) -type_list["TWAN Identifier"]["max_instance"] = "1" ies.append({ "ie_type" : "TWAN Identifier", "ie_value" : "WLAN Location Information", "presence" : "CO", "instance" : "1", "comment" : "The ePDG shall include this IE on the S2b interface if the WLAN Location Information is available. "}) -type_list["TWAN Identifier Timestamp"]["max_instance"] = "1" ies.append({ "ie_type" : "TWAN Identifier Timestamp", "ie_value" : "WLAN Location Timestamp", "presence" : "CO", "instance" : "1", "comment" : "The ePDG shall include this IE on the S2b interface, if the WLAN Location Timestamp is available. "}) ies.append({ "ie_type" : "Port Number", "ie_value" : "UE UDP Port", "presence" : "CO", "instance" : "0", "comment" : "The ePDG shall include this IE on the S2b interface if NAT is detected and UDP encapsulation is used."}) ies.append({ "ie_type" : "F-Container", "ie_value" : "NBIFOM Container", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S11/S4 or S2a/S2b interfaces if the MME/S4-SGSN or the TWAN/ePDG receives a NBIFOM Container from the UE as specified in 3GPP TS 24.161 73]. The Container Type shall be set to 4."}) diff --git a/lib/gtp/support/cache/tlv-msg-32.py b/lib/gtp/support/cache/tlv-msg-32.py index 0f070e710..684200d3e 100644 --- a/lib/gtp/support/cache/tlv-msg-32.py +++ b/lib/gtp/support/cache/tlv-msg-32.py @@ -18,17 +18,22 @@ ies.append({ "ie_type" : "EBI", "ie_value" : "Linked EPS Bearer ID", "presence" ies.append({ "ie_type" : "TWMI", "ie_value" : "Trusted WLAN Mode Indication", "presence" : "CO", "instance" : "0", "comment" : "The TWAN shall include this IE on S2a interface (during initial attach, handover to TWAN with GTP on S2a procedure, UE-initiated additional PDN connectivity procedures), if the single-connection mode or multiple-connection mode is used.The TWAN shall not include this IE if transparent single-connection mode is used. The PGW shall assume that transparent single-connection mode is used if it receives this message without this IE from the TWAN."}) ies.append({ "ie_type" : "PCO", "ie_value" : "Protocol Configuration Options", "presence" : "C", "instance" : "0", "comment" : "If MME/SGSN receives PCO from the UE during the Attach, PDN connectivity or Handover to 3GPP access procedures, the MME/SGSN shall forward the PCO IE to SGW. The SGW shall also forward it to PGW."}) ies.append({ "ie_type" : "Bearer Context", "ie_value" : "Bearer Contexts to be created", "presence" : "M", "instance" : "0", "comment" : "Several IEs with the same type and instance value shall be included on the S4/S11 and S5/S8 interfaces as necessary to represent a list of Bearers. One single IE shall be included on the S2a/S2b interface.One bearer shall be included for E-UTRAN Initial Attach, PDP Context Activation, UE requested PDN Connectivity, Attach with GTP on S2b, UE initiated Connectivity to Additional PDN with GTP on S2b, Handovers between Untrusted Non-3GPP IP Access with GTP on S2b and 3GPP Access, Initial Attach for emergency session (GTP on S2b), Initial Attach in WLAN on GTP S2a, an Initial Attach in WLAN for Emergency Service on GTP S2a, Handovers between TWAN with GTP on S2a and 3GPP Access and UE initiated Connectivity to Additional PDN with GTP on S2a.One or more bearers shall be included for a Handover/TAU/RAU with an SGW change. See NOTE 6 and NOTE 7."}) +type_list["Bearer Context"]["max_instance"] = "1" ies.append({ "ie_type" : "Bearer Context", "ie_value" : "Bearer Contexts to be removed", "presence" : "C", "instance" : "1", "comment" : "This IE shall be included on the S4/S11 interfaces for the TAU/RAU/Handover cases where any of the bearers existing before the TAU/RAU/Handover procedure will be deactivated as consequence of the TAU/RAU/Handover procedure.For each of those bearers, an IE with the same type and instance value shall be included.See NOTE 6 and NOTE 7."}) ies.append({ "ie_type" : "Trace Information", "ie_value" : "Trace Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included on the S4/S11 interface if an SGW trace is activated, and/or on the S5/S8 and S2a/2b interfaces if a PGW trace is activated. See 3GPP TS 32.422 [18]."}) ies.append({ "ie_type" : "Recovery", "ie_value" : "Recovery", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included on the S4/S11, S5/S8 and S S2a/2b interfaces if contacting the peer node for the first time."}) ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "MME-FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included by the MME on the S11 interface and shall be forwarded by an SGW on the S5/S8 interfaces according to the requirements in 3GPP TS 23.007 [17]."}) +type_list["FQ-CSID"]["max_instance"] = "1" ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-FQ-CSID", "presence" : "C", "instance" : "1", "comment" : "This IE shall be included by the SGW on the S5/S8 interfaces according to the requirements in 3GPP TS 23.007 [17]."}) +type_list["FQ-CSID"]["max_instance"] = "2" ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "ePDG-FQ-CSID", "presence" : "C", "instance" : "2", "comment" : "This IE shall be included by the ePDG on the S2b interface according to the requirements in 3GPP TS 23.007 [17]."}) +type_list["FQ-CSID"]["max_instance"] = "3" ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "TWAN-FQ-CSID", "presence" : "C", "instance" : "3", "comment" : "This IE shall be included by the TWAN on the S2a interface according to the requirements in 3GPP TS 23.007 [17]."}) ies.append({ "ie_type" : "UE Time Zone", "ie_value" : "UE Time Zone", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included by the MME over S11 during Initial Attach, a Handover from Trusted or Untrusted Non-3GPP IP Access to E-UTRAN and UE Requested PDN Connectivity procedure.This IE shall be included by the SGSN over S4 during PDP Context Activation procedure and a Handover from Trusted or Untrusted Non-3GPP IP Access to UTRAN/GERAN.This IE shall be included by the MME/SGSN over S11/S4 TAU/RAU/Handover with SGW relocation."}) ies.append({ "ie_type" : "UCI", "ie_value" : "User CSG Information", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S4/S11 interface for E-UTRAN Initial Attach, a Handover from Trusted or Untrusted Non-3GPP IP Access to E-UTRAN, UE-requested PDN Connectivity, PDP Context Activation and a Handover from Trusted or Untrusted Non-3GPP IP Access to UTRAN using S4 procedures, if the UE is accessed via CSG cell or hybrid cell. The MME/SGSN shall also include it for TAU/RAU/Handover procedures with SGW relocation if the UE is accessed via a CSG cell or hybrid cell or leaves a CSG or hybrid cell and the PGW/PCRF has requested CSG info reporting and MME/SGSN support CSG info reporting. NOTE 11.The SGW shall include this IE on S5/S8 if it receives the User CSG information from MME/SGSN.See NOTE 10."}) ies.append({ "ie_type" : "Charging Characteristics", "ie_value" : "Charging Characteristics", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included on the S4/S11, S5/S8 and S2a/S2b interfaces according to 3GPP TS 32.251 [8]"}) ies.append({ "ie_type" : "LDN", "ie_value" : "MME/S4-SGSN LDN", "presence" : "O", "instance" : "0", "comment" : "This IE is optionally sent by the MME to the SGW on the S11 interface and by the S4-SGSN to the SGW on the S4 interface (see 3GPP TS 32.423 [44]), when communicating the LDN to the peer node for the first time."}) +type_list["LDN"]["max_instance"] = "1" ies.append({ "ie_type" : "LDN", "ie_value" : "SGW LDN", "presence" : "O", "instance" : "1", "comment" : "This IE is optionally sent by the SGW to the PGW on the S5/S8 interfaces (see 3GPP TS 32.423 [44]), when communicating the LDN to the peer node for the first time."}) type_list["LDN"]["max_instance"] = "2" ies.append({ "ie_type" : "LDN", "ie_value" : "ePDG LDN", "presence" : "O", "instance" : "2", "comment" : "This IE is optionally sent by the ePDG to the PGW on the S2b interfaces (see 3GPP TS 32.423 [44]), when contacting the peer node for the first time. "}) @@ -39,7 +44,9 @@ ies.append({ "ie_type" : "IP Address", "ie_value" : "UE Local IP Address", "pres ies.append({ "ie_type" : "Port Number", "ie_value" : "UE UDP Port", "presence" : "CO", "instance" : "0", "comment" : "The ePDG shall include this IE on the S2b interface if NAT is detected, the UDP encapsulation is used and the UE Local IP Address is present."}) ies.append({ "ie_type" : "APCO", "ie_value" : "Additional Protocol Configuration Options", "presence" : "CO", "instance" : "0", "comment" : "If multiple authentications are supported by the ePDG, the ePDG shall include this IE on the S2b interface and perform the corresponding procedures as specified for PAP and CHAP authentication of the UE with external networks in 3GPP TS 33.402 [50]."}) ies.append({ "ie_type" : "IP Address", "ie_value" : "HNB Local IP Address", "presence" : "CO", "instance" : "1", "comment" : "The MME/SGSN shall include this IE on S11/S4 interface if the MME/SGSN receives this information from H(e)NB in UE associated S1/Iu signalling according (see 3GPP TS 23.139 [51]) during: E-UTRAN Initial Attach, a Handover from Trusted or Untrusted Non-3GPP IP Access to E-UTRAN, UE-requested PDN Connectivity, PDP Context Activation and a a Handover from Trusted or Untrusted Non-3GPP IP Access to UTRAN using S4;TAU/RAU/X2-based handover/Enhanced Serving RNS Relocation Procedure with SGW change, if the PGW/PCRF has requested H(e)NB information reporting for the PDN connection.The SGW shall forward this IE on S5/S8 interface if the SGW receives it from the MME/SGSN."}) +type_list["Port Number"]["max_instance"] = "1" ies.append({ "ie_type" : "Port Number", "ie_value" : "HNB UDP Port", "presence" : "CO", "instance" : "1", "comment" : "The MME/SGSN shall include this IE on S11/S4 interface if the MME/SGSN receives this information from H(e)NB in UE associated S1/Iu signalling according (see 3GPP TS 23.139 [51]) during: E-UTRAN Initial Attach, a Handover from Trusted or Untrusted Non-3GPP IP Access to E-UTRAN, UE-requested PDN Connectivity, PDP Context Activation and a Handover from Trusted or Untrusted Non-3GPP IP Access to UTRAN using S4;TAU/RAU/X2-based handover/Enhanced Serving RNS Relocation Procedure with SGW relocation, if the PGW/PCRF has requested H(e)NB information reporting for the PDN connection.The SGW shall forward this IE on S5/S8 interface if the SGW receives it from the MME/SGSN."}) +type_list["IP Address"]["max_instance"] = "2" ies.append({ "ie_type" : "IP Address", "ie_value" : "MME/S4-SGSN Identifier", "presence" : "CO", "instance" : "2", "comment" : "If the PGW triggered SGW restoration procedure is supported, the MME/S4-SGSN shall include this IE on S11/S4 interface and the SGW shall forward this IE on S5 interface in the existing signalling as specified in 3GPP TS 23.007 [17].If the overload control feature is supported by the MME/S4-SGSN and is activated for the PLMN to which the PGW belongs (see clause 12.3.11), the MME/S4-SGSN shall include this IE on the S11/S4 interface. In that case, the SGW shall forward this IE on the S5/S8 interface."}) ies.append({ "ie_type" : "TWAN Identifier", "ie_value" : "TWAN Identifier", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S2a interface for Initial Attach in WLAN procedure, UE-initiated Connectivity to Additional PDN with GTP on S2a and handover to TWAN with GTP on S2a procedure as specified in 3GPP TS 23.402 [45]. "}) type_list["IP Address"]["max_instance"] = "3" @@ -47,10 +54,13 @@ ies.append({ "ie_type" : "IP Address", "ie_value" : "ePDG IP Address", "presence ies.append({ "ie_type" : "CN Operator Selection Entity", "ie_value" : "CN Operator Selection Entity", "presence" : "CO", "instance" : "0", "comment" : "In shared networks, the SGSN shall include this IE on the S4 interface for a PDP Context Activation, a Handover from Trusted or Untrusted Non-3GPP IP Access to UTRAN/GERAN and RAU with SGW relocation procedures, if the information is available, to indicate whether the Serving Network has been selected by the UE or by the network."}) ies.append({ "ie_type" : "Presence Reporting Area Information", "ie_value" : "Presence Reporting Area Information", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN shall include this IE in the following procedures, if the PGW/PCRF/OCS requested reporting changes of UE presence in the Presence Reporting Area(s) and the MME/SGSN supports such reporting:- TAU/RAU/X2 Handover/Enhanced SRNS Relocation procedures with SGW relocation and MME/SGSN change. The new MME/SGSN shall then indicate whether the UE is inside or outside the PRA for each of the active Presence Reporting Area(s), or indicate that the Presence Reporting Area (s) is inactive; - TAU/RAU/X2 Handover/Enhanced SRNS Relocation procedures with SGW relocation and without MME/SGSN change, if the UE enters or leaves the Presence Reporting Area(s). In this case, this IE shall only include the active PRA(s) that the UE has newly entered or left.Several IEs with the same type and instance value may be included as necessary to represent a list of Presence Reporting Area Actions. See NOTE 20."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "MME/S4-SGSN's Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the MME/S4-SGSN may include this IE on the S11/S4 interface if the overload control feature is supported by the MME/S4-SGSN and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the MME/S4-SGSN shall provide only one instance of this IE, representing its overload information."}) +type_list["Overload Control Information"]["max_instance"] = "1" ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "SGW's Overload Control Information", "presence" : "O", "instance" : "1", "comment" : "During an overload condition, the SGW may include this IE over the S5/S8 interface if the overload control feature is supported by the SGW and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the SGW shall provide only one instance of this IE, representing its overload information."}) +type_list["Overload Control Information"]["max_instance"] = "2" ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "TWAN/ePDG's Overload Control Information", "presence" : "O", "instance" : "2", "comment" : "During an overload condition, the TWAN/ePDG may include this IE over the S2a/S2b interface if the overload control feature is supported by the TWAN/ePDG and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the TWAN/ePDG shall provide only one instance of this IE, representing its overload information."}) ies.append({ "ie_type" : "Millisecond Time Stamp", "ie_value" : "Origination Time Stamp", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN and the TWAN/ePDG shall include this IE on the S11/S4 and S2a/S2b interface respectively, in the conditions specified in clause 13.2.When present, the Origination Time Stamp shall contain the UTC time when the originating entity initiated the request."}) ies.append({ "ie_type" : "Integer Number", "ie_value" : "Maximum Wait Time", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN and the TWAN/ePDG shall include this IE on the S11/S4 and S2a/S2b interface respectively, in the conditions specified in clause 13.3.When present, the Maximum Wait Time shall contain the duration (number of milliseconds since the Origination Time Stamp) during which the originator of the request waits for a response."}) +type_list["TWAN Identifier"]["max_instance"] = "1" ies.append({ "ie_type" : "TWAN Identifier", "ie_value" : "WLAN Location Information", "presence" : "CO", "instance" : "1", "comment" : "This IE shall be included on the S2b interface if the WLAN Location Information is available. "}) ies.append({ "ie_type" : "TWAN Identifier Timestamp", "ie_value" : "WLAN Location Timestamp", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S2b interface, if the WLAN Location Timestamp is available. "}) ies.append({ "ie_type" : "F-Container", "ie_value" : "NBIFOM Container", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S11/S4 or S2a/S2b interfaces if the MME/S4-SGSN or the TWAN/ePDG receives an NBIFOM Container from the UE as specified in TS 24.161 73]. The Container Type shall be set to 4."}) @@ -62,6 +72,7 @@ ies.append({ "ie_type" : "Counter", "ie_value" : "MO Exception Data Counter", "p type_list["Port Number"]["max_instance"] = "2" ies.append({ "ie_type" : "Port Number", "ie_value" : "UE TCP Port", "presence" : "CO", "instance" : "2", "comment" : "The ePDG shall include this IE on the S2b interface if NAT is detected, the TCP encapsulation is used and the UE Local IP Address is present."}) ies.append({ "ie_type" : "Mapped UE Usage Type", "ie_value" : "Mapped UE Usage Type", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN shall include this IE on the S11/S4 interface, if available. When present, this IE shall contain the mapped UE usage type applicable to the PDN connection. See NOTE 21. "}) +type_list["ULI"]["max_instance"] = "1" ies.append({ "ie_type" : "ULI", "ie_value" : "User Location Information for SGW ", "presence" : "CO", "instance" : "1", "comment" : "The MME/SGSN shall include this IE on the S11/S4 interface, based on operator policy for the User Location Information to be sent to the SGW, if the user location information to be passed to the SGW is not already reported in the ULI IE in this message.When present, this IE shall include the ECGI, TAI, eNodeB ID, RAI and/or RNC-ID, based on local policy.See NOTE 21."}) ies.append({ "ie_type" : "FQDN", "ie_value" : "SGW-U node name", "presence" : "CO", "instance" : "0", "comment" : "The SGW-C shall include this IE on the S5 interface, if available. See NOTE 21. "}) ies.append({ "ie_type" : "Secondary RAT Usage Data Report", "ie_value" : "Secondary RAT Usage Data Report", "presence" : "CO", "instance" : "0", "comment" : "If the PLMN has configured secondary RAT usage reporting and PDN GW Secondary RAT reporting is active, the MME shall include this IE on the S11 interface if it has received Secondary RAT usage data from eNodeB in an X2-based handover with Serving GW relocation. The MME shall also set the IRSGW flag to 0, to indicate that the Secondary RAT usage data is reported for the Source SGW, and sent via the Target SGW to the PGW.Several IEs with the same type and instance value may be included, to represent multiple usage data reports."}) diff --git a/lib/gtp/support/cache/tlv-msg-33.py b/lib/gtp/support/cache/tlv-msg-33.py index 4833f7d6d..6efd6bec3 100644 --- a/lib/gtp/support/cache/tlv-msg-33.py +++ b/lib/gtp/support/cache/tlv-msg-33.py @@ -25,7 +25,9 @@ ies.append({ "ie_type" : "IP4CP", "ie_value" : "Trusted WLAN IPv4 Parameters ", ies.append({ "ie_type" : "Indication", "ie_value" : "Indication Flags", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included if any one of the applicable flags is set to 1.Applicable flags are:PDN Pause Support Indication: this flag shall be set to 1 on the S5/S8 interface if the PGW supports the PGW Pause of Charging procedure.PDN Pause Enable Indication: this flag shall be set to 1 on the S5/S8 interface if the PGW enables the SGW to use the PGW Pause of Charging procedure for this PDN connection.Associate OCI with PGW nodes identity: The PGW shall set this flag to 1 on the S5/S8 interface or S2a/S2b interface if it has included the PGWs Overload Control Information and if this information is to be associated with the node identity (i.e. FQDN or the IP address received from the HSS or DNS during the PGW selection) of the serving PGW. This flag shall be set to 1 by the PGW if the PGWs Overload Control Information is included and the Cause IE is set to a rejection cause code. The SGW shall set this flag on the S11/S4 interface if it supports the overload control feature and if the flag is set on the S5/S8 interface.Associate OCI with SGW nodes identity: The SGW shall set this flag to 1 on the S11/S4 interface if it has included the SGWs Overload Control Information and if this information is to be associated with the node identity (i.e. FQDN or the IP address received from the DNS during the SGW selection) of the serving SGW. This flag shall be set to 1 by the SGW if the SGWs Overload Control Information is included and the Cause IE is set to a rejection cause code. Delay Tolerant Connection Indication: the flag shall be set to 1 on the S5/S8 and S11/S4 interface if the PDN connection is Delay Tolerant (see clause 8.12).Triggering SGSN initiated PDP Context Creation/Modification Indication: this flag shall be set to 1 on the S5/S8 interfaces if the network-initiated NBIFOM mode is used for this PDN connection. The SGW shall set this flag on the S4 interface if it supports the NBIFOM feature and the flag is set on the S5/S8 interface."}) ies.append({ "ie_type" : "Presence Reporting Area Action", "ie_value" : "Presence Reporting Area Action", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S5/S8 and S11/S4 interfaces with the appropriate Action field if reporting changes of UE presence in a Presence Routing Area is to be started, stopped or modified for this subscriber in the MME/SGSN.Several IEs with the same type and instance value may be included as necessary to represent a list of Presence Reporting Area Actions. One IE shall be included per PRA to be started, stopped or modified."}) ies.append({ "ie_type" : "Load Control Information", "ie_value" : "PGW's node level Load Control Information", "presence" : "O", "instance" : "0", "comment" : "The PGW may include this IE on the S5/S8 or S2a/S2b interface, providing its node level load information, if the load control feature is supported by the PGW and is activated for the PLMN to which the access network node, i.e. MME/S4-SGSN for 3GPP access network, ePDG/TWAN for non-3GPP access network, belongs (see clause 12.2.6)."}) +type_list["Load Control Information"]["max_instance"] = "1" ies.append({ "ie_type" : "Load Control Information", "ie_value" : "PGW's APN level Load Control Information", "presence" : "O", "instance" : "1", "comment" : "The PGW may include this IE on the S5/S8 or S2a/S2b interface, providing APN level load information, if the APN level load control feature is supported by the PGW and is activated for the PLMN to which the access network node, i.e. MME/S4-SGSN for 3GPP access network, ePDG/TWAN for non-3GPP access based network, belongs (see clause 12.2.6).When present, the PGW shall provide one or more instances of this IE, up to maximum of 10, with the same type and instance value, each representing the load information for a list of APN(s).See NOTE 9, NOTE 11."}) +type_list["Load Control Information"]["max_instance"] = "2" ies.append({ "ie_type" : "Load Control Information", "ie_value" : "SGW's node level Load Control Information", "presence" : "O", "instance" : "2", "comment" : "The SGW may include this IE, over the S11/S4 interface if the load control feature is supported by the SGW and is activated in the network (see clause 12.2.6).When present, the SGW shall provide only one instance of this IE, representing its node level load information."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "PGW's Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the PGW may include this IE on the S5/S8 or S2a/S2b interface, if the overload control feature is supported by the PGW and is activated for the PLMN to which the access network node, i.e. MME/S4-SGSN for 3GPP access based network, ePDG/TWAN for non-3GPP access based network, belongs (see clause 12.3.11).When present, the PGW shall provide: node level overload control, in one instance of this IE; and/orAPN level overload control , in one or more instances of this IE, up to maximum of 10, with the same type and instance value, each representing the overload information for a list of APN(s).See NOTE 10, NOTE 12."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "SGW's Overload Control Information", "presence" : "O", "instance" : "1", "comment" : "During an overload condition, the SGW may include this IE over the S11/S4 interface if the overload control feature is supported by the SGW and is activated in the network (see clause 12.3.11).When present, the SGW shall provide only one instance of this IE, representing its overload information."}) diff --git a/lib/gtp/support/cache/tlv-msg-34.py b/lib/gtp/support/cache/tlv-msg-34.py index 0a2223391..0695d2934 100644 --- a/lib/gtp/support/cache/tlv-msg-34.py +++ b/lib/gtp/support/cache/tlv-msg-34.py @@ -8,32 +8,26 @@ ies.append({ "ie_type" : "F-TEID", "ie_value" : "Sender F-TEID for Control Plane ies.append({ "ie_type" : "AMBR", "ie_value" : "Aggregate Maximum Bit Rate", "presence" : "C", "instance" : "0", "comment" : "The APN-AMBR shall be sent for TAU/RAU/Handover from the Gn/Gp SGSN to the S4 SGSN/MME procedures."}) ies.append({ "ie_type" : "Delay Value", "ie_value" : "Delay Downlink Packet Notification Request", "presence" : "C", "instance" : "0", "comment" : "his IE shall be sent on the S11 interface for a UE triggered Service Request and UE initiated Connection Resume procedures. It shall contain the delay the SGW shall apply between receiving downlink data and sending Downlink Data Notification for all UEs served by that MME (see clause 5.3.4.2 of 3GPP TS 23.401 [3])."}) ies.append({ "ie_type" : "Bearer Context", "ie_value" : "Bearer Contexts to be modified", "presence" : "C", "instance" : "0", "comment" : "This IE shall be sent on the S4/S11 interface and S5/S8 interface, except on the S5/S8 interface for a UE triggered Service Request and UE initiated Connection Resume procedures. on the S5/S8 interface for a TAU/RAU/HO without SGW change procedure. See NOTE 10. .on the S5/S8 interface when requesting the PGW to pause or unpause charging for the PDN connection. on the S5/S8 interface for any other procedure without SGW change which requires to send a Modify Bearer Request to the PGW, e.g. HSS-based P-CSCF restoration for 3GPP access, reporting of UE presence in a Presence Reporting Area, implicit resume of suspended bearers.(see NOTE 6).When Handover Indication flag is set to 1 (i.e., for a Handover from Trusted or Untrusted Non-3GPP IP Access to E-UTRAN or a Handover from Trusted or Untrusted Non-3GPP IP Access to UTRAN/GERAN procedures), the PGW shall ignore this IE. See NOTE 1.Several IEs with the same type and instance value may be included as necessary to represent a list of Bearers to be modified.During a TAU/RAU/Handover procedure with an SGW change, the SGW includes all bearers it received from the MME/SGSN (Bearer Contexts to be created, or Bearer Contexts to be modified and also Bearer Contexts to be removed) into the list of Bearer Contexts to be modified IEs, which are then sent on the S5/S8 interface to the PGW (see NOTE 2, see NOTE 10). During an E-UTRAN Initiated E-RAB modification procedure the MME shall send a Modify Bearer Request, including all the bearers (those modified and those not modified), per PDN connection for which at least one bearer has changed. See NOTE 11."}) -type_list["Bearer Context"]["max_instance"] = "1" ies.append({ "ie_type" : "Bearer Context", "ie_value" : "Bearer Contexts to be removed", "presence" : "C", "instance" : "1", "comment" : "This IE shall be included on the S4 and S11 interfaces for the TAU/RAU/Handover, UE initiated Connection Resume and Service Request procedures where any of the bearers existing before the TAU/RAU/Handover procedure, UE initiated Connection Resume and Service Request procedures will be deactivated as consequence of the TAU/RAU/Handover procedure, UE initiated Connection Resume and Service Request procedures. See NOTE 3 and NOTE 6.For each of those bearers, an IE with the same type and instance value, shall be included. See NOTE 11."}) ies.append({ "ie_type" : "Recovery", "ie_value" : "Recovery", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if contacting the peer for the first time "}) ies.append({ "ie_type" : "UE Time Zone", "ie_value" : "UE Time Zone", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included by the MME/SGSN on the S11/S4 interfaces if the UE Time Zone has changed in the case of TAU/RAU/Handover or UE initiated Service Request procedure. See NOTE 5."}) ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "MME-FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included by MME on S11 and shall be forwarded by SGW on S5/S8 according to the requirements in 3GPP TS 23.007 [17]."}) ies.append({ "ie_type" : "UCI", "ie_value" : "User CSG Information", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN shall include this IE for Handover procedures, UE initiated Connection Resume and UE-initiated Service Request procedure if the PGW/PCRF has requested CSG Info reporting and the MME/SGSN support the CSG information reporting and the User CSG information has changed (i.e. the UE is accessed via a new CSG cell or hybrid cell or leaves a CSG or hybrid cell).In TAU/RAU procedure without SGW change, this IE shall also be sent if the PGW/PCRF has requested CSG info reporting and MME/SGSN supports CSG info reporting and the User CSG information has changed (i.e. the UE is accessed via a new CSG cell or hybrid cell or leaves a CSG or hybrid cell) when UE requested to activate E-RAB for all the active EPS bearers in TAU procedure or to keep the Iu connection after the completion of the RAU procedure. See NOTE 5. See NOTE 10. See NOTE 16.The SGW shall include this IE on S5/S8 if it receives the User CSG Information from MME/SGSN. See NOTE 15."}) ies.append({ "ie_type" : "IP Address", "ie_value" : "UE Local IP Address", "presence" : "CO", "instance" : "1", "comment" : "If the UE local IP Address has changed, the ePDG shall include this IE on S2b interface based on local policy for Fixed Broadband access network interworking (see 3GPP TS 23.139 [51]). "}) -type_list["Port Number"]["max_instance"] = "1" ies.append({ "ie_type" : "Port Number", "ie_value" : "UE UDP Port", "presence" : "CO", "instance" : "1", "comment" : "The ePDG shall include this IE on S2b interface if NAT is detected and UE Local IP Address is present for Fixed Broadband access network interworking (see 3GPP TS 23.139 [51]). "}) ies.append({ "ie_type" : "LDN", "ie_value" : "MME/S4-SGSN LDN", "presence" : "O", "instance" : "0", "comment" : "This IE is optionally sent by the MME to the SGW on the S11 interface and by the SGSN to the SGW on the S4 interface (see 3GPP TS 32.423 [44]), when communicating the LDN to the peer node for the first time."}) -type_list["LDN"]["max_instance"] = "1" ies.append({ "ie_type" : "LDN", "ie_value" : "SGW LDN", "presence" : "O", "instance" : "1", "comment" : "This IE is optionally sent by the SGW to the PGW on the S5/S8 interfaces (see 3GPP TS 32.423 [44]), for inter-SGW mobity, when communicating the LDN to the peer node for the first time."}) ies.append({ "ie_type" : "IP Address", "ie_value" : "HNB Local IP Address", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN shall include this IE on S11/S4 interface if the PGW/PCRF has requested H(e)NB information reporting and the MME/SGSN has received this information from H(e)NB in UE associated S1/Iu signalling (see 3GPP TS 23.139 [51]). The SGW shall forward this IE on S5/S8 interface if it is received from the MME/SGSN and the Modify Bearer Request message needs to be sent to the PGW as specified in the 3GPP TS 23.401 [3]; orthe Propagate BBAI information change flag is received from the MME/SGSN.(NOTE 7)"}) ies.append({ "ie_type" : "Port Number", "ie_value" : "HNB UDP Port", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN shall include this IE on S11/S4 interface if the PGW/PCRF has requested H(e)NB information reporting and the MME/SGSN has received this information from H(e)NB in UE associated S1/Iu signalling (see 3GPP TS 23.139 [51]). The SGW shall forward this IE on S5/S8 interface if it is received from the MME/SGSN and the Modify Bearer Request message needs to be sent to the PGW as specified in the 3GPP TS 23.401 [3]; orthe Propagate BBAI information change flag is received from the MME/SGSN.(NOTE 7)"}) -type_list["IP Address"]["max_instance"] = "2" ies.append({ "ie_type" : "IP Address", "ie_value" : "MME/S4-SGSN Identifier", "presence" : "CO", "instance" : "2", "comment" : "If the PGW triggered SGW restoration procedure is supported, the MME/S4-SGSN shall include this IE on S11/S4 interface and the SGW shall forward this IE on S5 interface in the existing signalling as specified in 3GPP TS 23.007 [17].If the overload control feature is supported by the MME/S4-SGSN and is activated for the PLMN to which the PGW belongs(see clause 12.3.11), the MME/S4-SGSN shall include this IE on the S11/S4 interface during mobility procedures with MME/S4-SGSN change."}) ies.append({ "ie_type" : "CN Operator Selection Entity", "ie_value" : "CN Operator Selection Entity", "presence" : "CO", "instance" : "0", "comment" : "In shared networks, the SGSN shall include this IE on the S4 interface for the RAU procedure, if the information is available, and if the Serving Network IE is present in the message or if the CN Operator Selection Entity has changed, to indicate whether the Serving Network has been selected by the UE or by the network."}) ies.append({ "ie_type" : "Presence Reporting Area Information", "ie_value" : "Presence Reporting Area Information", "presence" : "CO", "instance" : "0", "comment" : "The MME/SGSN shall include this IE: - if the PGW/PCRF/OCS has just requested to start or modify reporting changes of UE presence in a Presence Reporting Area and the MME/SGSN supports such reporting. The MME/SGSN shall then indicate whether the UE is inside or outside the newly started or modified Presence Reporting Area(s), or indicate the Presence Reporting Area(s) is inactive. Several IEs with the same type and instance value may be included as necessary to represent a list of Presence Reporting Area Information. One IE shall be included for each Presence Reporting Area newly started or modified.The MME/SGSN shall also include this IE in the following procedures, if the PGW/PCRF requested to report changes of UE presence in a Presence Reporting Area and the MME/SGSN supports such reporting: - TAU/RAU/Handover procedures without SGW change and with MME/SGSN change and S1-based handover procedure with SGW change. The MME/SGSN shall then indicate whether the UE is inside or outside the Presence Reporting Area(s) for each of the active Presence Reporting Area(s), or indicate that the Presence Reporting Area(s) is inactive. Several IEs with the same type and instance value may be included as necessary to represent a list of Presence Reporting Area Information.- TAU/RAU/Handover/Cell Update procedures without MME/SGSN change, UE initiated Connection Resume and UE-initiated Service Request procedure if the UE enters or leaves the Presence Reporting Area(s). Several IEs with the same type and instance value may be included as necessary to represent a list of Presence Reporting Area Information. One IE shall be included for each active Presence Reporting Area that the UE has newly entered or left. See NOTE 5, NOTE 10.- UE initiated Service Request, if ISR is active; See NOTE 22."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "MME/S4-SGSN's Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the MME/S4-SGSN may include this IE on the S11/S4 interface if the overload control feature is supported by the MME/S4-SGSN and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the MME/S4-SGSN shall provide only one instance of this IE, representing its overload information."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "SGW's Overload Control Information", "presence" : "O", "instance" : "1", "comment" : "During an overload condition, the SGW may include this IE over the S5/S8 interface if the overload control feature is supported by the SGW and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the SGW shall provide only one instance of this IE, representing its overload information."}) -type_list["Overload Control Information"]["max_instance"] = "2" ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "ePDG's Overload Control Information", "presence" : "O", "instance" : "2", "comment" : "During an overload condition, the ePDG may include this IE over the S2b interface if the overload control feature is supported by the ePDG and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the ePDG shall provide only one instance of this IE, representing its overload information."}) ies.append({ "ie_type" : "Serving PLMN Rate Control", "ie_value" : "Serving PLMN Rate Control", "presence" : "CO", "instance" : "0", "comment" : "The MME shall include this IE on the S11 interface if the Serving PLMN Rate is changed.The target MME shall also include this IE on the S11 interface during an Inter-MME mobility procedure if the Serving PLMN Rate control is configured, and if the configured value is different from the one received from the old MME. See NOTE 20.The SGW shall include this IE on S5/S8 if it receives this IE from MME via the Create Session Request or the Modify Bearer Request message. "}) ies.append({ "ie_type" : "Counter", "ie_value" : "MO Exception Data Counter", "presence" : "CO", "instance" : "0", "comment" : "The MME shall include this IE on the S11 interface when it needs to send a non-zero counter value for the MO Exception Data Counter. The timestamp in the counter shall be set with the time at which the counter value increased from 0 to 1."}) ies.append({ "ie_type" : "IMSI", "ie_value" : "IMSI", "presence" : "O", "instance" : "0", "comment" : "The MME/SGSN should include the IMSI if available. See NOTE 23."}) -type_list["ULI"]["max_instance"] = "1" ies.append({ "ie_type" : "ULI", "ie_value" : "User Location Information for SGW ", "presence" : "CO", "instance" : "1", "comment" : "The MME/SGSN shall include this IE on the S11/S4 interface, based on operator policy for the User Location Information to be sent to the SGW, if the user location information to be passed to the SGW is not already reported in the ULI IE in this message.When present, this IE shall include the ECGI, TAI, eNodeB ID, RAI and/or RNC-ID, based on local policy.See NOTE 25."}) ies.append({ "ie_type" : "TWAN Identifier", "ie_value" : "WLAN Location Information", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S2b interface, during a UE initiated IPsec tunnel update procedure, if the WLAN Location Information is available. "}) ies.append({ "ie_type" : "TWAN Identifier Timestamp", "ie_value" : "WLAN Location Timestamp", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S2b interface, during a UE initiated IPsec tunnel update procedure, if the WLAN Location Timestamp is available. "}) diff --git a/lib/gtp/support/cache/tlv-msg-36.py b/lib/gtp/support/cache/tlv-msg-36.py index aa9f3a6bf..8fdd2831d 100644 --- a/lib/gtp/support/cache/tlv-msg-36.py +++ b/lib/gtp/support/cache/tlv-msg-36.py @@ -15,6 +15,7 @@ ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "MME/S4-SG ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "SGW's Overload Control Information", "presence" : "O", "instance" : "1", "comment" : "During an overload condition, the SGW may include this IE over the S5/S8 interface if the overload control feature is supported by the SGW and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the SGW shall provide only one instance of this IE, representing its overload information."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "TWAN/ePDG's Overload Control Information", "presence" : "O", "instance" : "2", "comment" : "During an overload condition, the TWAN/ePDG may include this IE over the S2a/S2b interface if the overload control feature is supported by the TWAN/ePDG and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the TWAN/ePDG shall provide only one instance of this IE, representing its overload information."}) ies.append({ "ie_type" : "TWAN Identifier", "ie_value" : "WLAN Location Information", "presence" : "CO", "instance" : "1", "comment" : "The ePDG shall include this IE on the S2b interface if the WLAN Location Information is available. "}) +type_list["TWAN Identifier Timestamp"]["max_instance"] = "1" ies.append({ "ie_type" : "TWAN Identifier Timestamp", "ie_value" : "WLAN Location Timestamp", "presence" : "CO", "instance" : "1", "comment" : "The ePDG shall include this IE on the S2b interface, if the WLAN Location Timestamp is available. "}) ies.append({ "ie_type" : "IP Address", "ie_value" : "UE Local IP Address", "presence" : "CO", "instance" : "0", "comment" : "The ePDG shall include this IE on the S2b interface. "}) ies.append({ "ie_type" : "Port Number", "ie_value" : "UE UDP Port", "presence" : "CO", "instance" : "0", "comment" : "The ePDG shall include this IE on the S2b interface if NAT is detected and UDP encapsulation is used."}) diff --git a/lib/gtp/support/cache/tlv-msg-68.py b/lib/gtp/support/cache/tlv-msg-68.py index d2007503d..f40101d33 100644 --- a/lib/gtp/support/cache/tlv-msg-68.py +++ b/lib/gtp/support/cache/tlv-msg-68.py @@ -14,7 +14,6 @@ ies.append({ "ie_type" : "F-TEID", "ie_value" : "S12 RNC F-TEID", "presence" : " ies.append({ "ie_type" : "PCO", "ie_value" : "Protocol Configuration Options", "presence" : "O", "instance" : "0", "comment" : "If the UE includes the PCO IE, then the MME/SGSN shall copy the content of this IE transparently from the PCO IE included by the UE. If the SGW receives PCO from the MME/SGSN, the SGW shall forward it to the PGW."}) ies.append({ "ie_type" : "Signalling Priority Indication", "ie_value" : "Signalling Priority Indication ", "presence" : "CO", "instance" : "0", "comment" : "The SGSN/MME shall include this IE on the S4/S11 interface if the UE indicates low access priority during the procedure. The SGW shall forward this IE on the S5/S8 interfaces if received from the MME/SGSN. "}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "MME/S4-SGSN's Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the MME/S4-SGSN may include this IE on the S11/S4 interface if the overload control feature is supported by the MME/S4-SGSN and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the MME/S4-SGSN shall provide only one instance of this IE, representing its overload information."}) -type_list["Overload Control Information"]["max_instance"] = "1" ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "SGW's Overload Control Information", "presence" : "O", "instance" : "1", "comment" : "During an overload condition, the SGW may include this IE over the S5/S8 interface if the overload control feature is supported by the SGW and is activated for the PLMN to which the PGW belongs (see clause 12.3.11).When present, the SGW shall provide only one instance of this IE, representing its overload information."}) ies.append({ "ie_type" : "F-Container", "ie_value" : "NBIFOM Container", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S11/S4 or S2a/S2b interfaces if the MME/S4-SGSN or the TWAN/ePDG receives an NBIFOM Container from the UE as specified in 3GPP TS 24.161 73]. The Container Type shall be set to 4."}) ies.append({ "ie_type" : "ePCO", "ie_value" : "Extended Protocol Configuration Options", "presence" : "O", "instance" : "0", "comment" : "If the UE includes the ePCO IE, then the MME shall copy the content of this IE transparently from the ePCO IE included by the UE. If the SGW receives ePCO from the MME, the SGW shall forward it to the PGW."}) diff --git a/lib/gtp/support/cache/tlv-msg-95.py b/lib/gtp/support/cache/tlv-msg-95.py index 945e30a11..ceb7d7677 100644 --- a/lib/gtp/support/cache/tlv-msg-95.py +++ b/lib/gtp/support/cache/tlv-msg-95.py @@ -4,7 +4,6 @@ ies.append({ "ie_type" : "EBI", "ie_value" : "Linked EPS Bearer ID", "presence" ies.append({ "ie_type" : "PCO", "ie_value" : "Protocol Configuration Options", "presence" : "O", "instance" : "0", "comment" : "This IE may be sent on the S5/S8 and S4/S11 interfaces if ePCO is not supported by the UE or the network."}) ies.append({ "ie_type" : "Bearer Context", "ie_value" : "Bearer Contexts", "presence" : "M", "instance" : "0", "comment" : "Several IEs with this type and instance values shall be included as necessary to represent a list of Bearers."}) ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "PGW-FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included by the PGW on the S5/S8 and S2a/S2b interfaces and, when received from S5/S8 be forwarded by the SGW on the S11 interface according to the requirements in 3GPP TS 23.007 [17]."}) -type_list["FQ-CSID"]["max_instance"] = "1" ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-FQ-CSID", "presence" : "C", "instance" : "1", "comment" : "This IE shall be included by the SGW on the S11 interface according to the requirements in 3GPP TS 23.007 [17]."}) ies.append({ "ie_type" : "Change Reporting Action", "ie_value" : "Change Reporting Action", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included on the S5/S8 and S4/S11 interfaces with the appropriate Action field If the location Change Reporting mechanism is to be started or stopped for this subscriber in the SGSN/MME."}) ies.append({ "ie_type" : "CSG Information Reporting Action", "ie_value" : "CSG Information Reporting Action", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S5/S8 and S4/S11 interfaces with the appropriate Action field if the CSG Info reporting mechanism is to be started or stopped for this subscriber in the SGSN/MME."}) @@ -12,9 +11,7 @@ ies.append({ "ie_type" : "eNB Information Reporting", "ie_value" : "HNB Informat ies.append({ "ie_type" : "Presence Reporting Area Action", "ie_value" : "Presence Reporting Area Action", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included on the S5/S8 and S11/S4 interfaces with the appropriate Action field if reporting changes of UE presence in a Presence Routing Area is to be started, stopped or modified for this subscriber in the MME/SGSN.Several IEs with the same type and instance value may be included as necessary to represent a list of Presence Reporting Area Actions. One IE shall be included per PRA to be started, stopped or modified."}) ies.append({ "ie_type" : "Indication", "ie_value" : "Indication Flags", "presence" : "CO", "instance" : "0", "comment" : "This IE shall be included if any one of the applicable flags is set to 1.Applicable flags are:Associate OCI with PGW nodes identity: The PGW shall set this flag to 1 on the S5/S8 interface or S2a/S2b interface if it has included the PGWs Overload Control Information and if this information is to be associated with the node identity (i.e. FQDN or the IP address received from the HSS or DNS during the PGW selection) of the serving PGW. The SGW shall set this flag on the S11/S4 interface if it supports the overload control feature and if the flag is set on the S5/S8 interface.Associate OCI with SGW nodes identity: The SGW shall set this flag to 1 on the S11/S4 interface if it has included the SGWs Overload Control Information and if this information is to be associated with the node identity (i.e. FQDN or the IP address received from the DNS during the SGW selection) of the serving SGW. Extended EBI Value Range Support Indication: The PGW shall set this flag to 1 if it supports the 15 EPS Bearers."}) ies.append({ "ie_type" : "Load Control Information", "ie_value" : "PGW's node level Load Control Information", "presence" : "O", "instance" : "0", "comment" : "The PGW may include this IE on the S5/S8 or S2a/S2b interface, providing its node level load information, if the load control feature is supported by the PGW and is activated for the PLMN to which the access network node, i.e. MME/S4-SGSN for 3GPP access network, ePDG/TWAN for non-3GPP access network, belongs (see clause 12.2.6)."}) -type_list["Load Control Information"]["max_instance"] = "1" ies.append({ "ie_type" : "Load Control Information", "ie_value" : "PGW's APN level Load Control Information", "presence" : "O", "instance" : "1", "comment" : "The PGW may include this IE on the S5/S8 or S2a/S2b interface, providing APN level load information, if the APN level load control feature is supported by the PGW and is activated for the PLMN to which the access network node, i.e. MME/S4-SGSN for 3GPP access network, ePDG/TWAN for non-3GPP access based network, belongs (see clause 12.2.6).When present, the PGW shall provide one or more instances of this IE, up to maximum of 10, with the same type and instance value, each representing the load information for a list of APN(s).See NOTE 2, NOTE 4."}) -type_list["Load Control Information"]["max_instance"] = "2" ies.append({ "ie_type" : "Load Control Information", "ie_value" : "SGW's node level Load Control Information", "presence" : "O", "instance" : "2", "comment" : "The SGW may include this IE, over the S11/S4 interface if the load control feature is supported by the SGW and is activated in the network (see clause 12.2.6).When present, the SGW shall provide only one instance of this IE, representing its node level load information."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "PGW's Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the PGW may include this IE on the S5/S8 or S2a/S2b interface, if the overload control feature is supported by the PGW and is activated for the PLMN to which the access network node, i.e. MME/S4-SGSN for 3GPP access based network, ePDG/TWAN for non-3GPP access based network, belongs (see clause 12.3.11).When present, the PGW shall provide node level overload control, in one instance of this IE; and/orAPN level overload control, in one or more instances of this IE, up to maximum of 10, with the same type and instance value, each representing the overload information for a list of APN(s).See NOTE 3, NOTE 5."}) ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "SGW's Overload Control Information", "presence" : "O", "instance" : "1", "comment" : "During an overload condition, the SGW may include this IE over the S11/S4 interface if the overload control feature is supported by the SGW and is activated in the network (see clause 12.3.11).When present, the SGW shall provide only one instance of this IE, representing its overload information."}) diff --git a/lib/gtp/support/gtp-tlv.py b/lib/gtp/support/gtp-tlv.py index c201180dd..68fbb7bd7 100644 --- a/lib/gtp/support/gtp-tlv.py +++ b/lib/gtp/support/gtp-tlv.py @@ -80,14 +80,14 @@ def output_header_to_file(f): f.write(" ******************************************************************************/\n\n") def usage(): - print "Python generating TLV build/parser for GTPv2-C v%s" % (version) - print "Usage: python gtp-tlv.py [options]" - print "Available options:" - print "-d Enable script debug" - print "-f [file] Input file to parse" - print "-o [dir] Output files to given directory" - print "-c [dir] Cache files to given directory" - print "-h Print this help and return" + print("Python generating TLV build/parser for GTPv2-C v%s" % (version)) + print("Usage: python gtp-tlv.py [options]") + print("Available options:") + print("-d Enable script debug") + print("-f [file] Input file to parse") + print("-o [dir] Output files to given directory") + print("-c [dir] Cache files to given directory") + print("-h Print this help and return") def v_upper(v): return re.sub('3GPP', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).upper()) @@ -96,10 +96,10 @@ def v_lower(v): return re.sub('3gpp', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).lower()) def get_cells(cells): - instance = cells[4].text.encode('ascii', 'ignore') + instance = cells[4].text if instance.isdigit() is not True: return None - ie_type = re.sub('\s*$', '', re.sub('\s*\n*\s*\([A-z]*\s*NOTE.*\)*', '', cells[3].text.encode('ascii', 'ignore'))) + ie_type = re.sub('\s*$', '', re.sub('\s*\n*\s*\([A-z]*\s*NOTE.*\)*', '', cells[3].text)) if ie_type.find('LDN') != -1: ie_type = 'LDN' elif ie_type.find('APCO') != -1: @@ -119,10 +119,10 @@ def get_cells(cells): if ie_type not in type_list.keys(): assert False, "Unknown IE type : [" \ + cells[3].text + "]" + "(" + ie_type + ")" - presence = cells[1].text.encode('ascii', 'ignore') + presence = cells[1].text presence = re.sub('\n', '', presence); - ie_value = re.sub('\s*\n*\s*\([^\)]*\)*', '', cells[0].text).encode('ascii', 'ignore') - comment = cells[2].text.encode('ascii', 'ignore') + ie_value = re.sub('\s*\n*\s*\([^\)]*\)*', '', cells[0].text) + comment = cells[2].text.encode('ascii', 'ignore').decode('utf-8') comment = re.sub('\n|\"|\'|\\\\', '', comment); if int(instance) > int(type_list[ie_type]["max_instance"]): @@ -163,15 +163,15 @@ for o, a in opts: sys.exit(2) if os.path.isfile(filename) and os.access(filename, os.R_OK): - file = open(filename, 'r') + file = open(filename, 'r') else: d_error("Cannot find file : " + filename) d_info("[Message List]") cachefile = cachedir + 'tlv-msg-list.py' if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -184,8 +184,8 @@ else: d_print("Table Index = %d\n" % i) for row in msg_table.rows[2:-4]: - key = row.cells[1].text.encode('ascii', 'ignore') - type = row.cells[0].text.encode('ascii', 'ignore') + key = row.cells[1].text + type = row.cells[0].text if type.isdigit() is False: continue if int(type) in range(128, 160): @@ -202,8 +202,8 @@ else: d_info("[IE Type List]") cachefile = cachedir + 'tlv-type-list.py' if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -216,7 +216,7 @@ else: d_print("Table Index = %d\n" % i) for row in ie_table.rows[1:-5]: - key = row.cells[1].text.encode('ascii', 'ignore') + key = row.cells[1].text if key.find('Reserved') != -1: continue if key.find('MM Context') != -1: @@ -234,10 +234,10 @@ else: elif key.find('Procedure Transaction ID') != -1: key = 'PTI' else: - key = re.sub('.*\(', '', row.cells[1].text.encode('ascii', 'ignore')) + key = re.sub('.*\(', '', row.cells[1].text) key = re.sub('\)', '', key) key = re.sub('\s*$', '', key) - type = row.cells[0].text.encode('ascii', 'ignore') + type = row.cells[0].text type_list[key] = { "type": type , "max_instance" : "0" } write_file(f, "type_list[\"" + key + "\"] = { \"type\" : \"" + type) write_file(f, "\", \"max_instance\" : \"0\" }\n") @@ -247,8 +247,8 @@ type_list['MM Context'] = { "type": "107", "max_instance" : "0" } d_info("[Group IE List]") cachefile = cachedir + 'tlv-group-list.py' if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -262,8 +262,8 @@ else: if len(re.findall('\d+', row.cells[2].text)) == 0: continue; - ie_type = re.findall('\d+', row.cells[2].text)[0].encode('ascii', 'ignore') - ie_name = re.sub('\s*IE Type.*', '', row.cells[2].text.encode('ascii', 'ignore')) + ie_type = re.findall('\d+', row.cells[2].text)[0] + ie_name = re.sub('\s*IE Type.*', '', row.cells[2].text) if ie_name not in group_list.keys(): ies = [] @@ -347,8 +347,8 @@ for key in msg_list.keys(): d_info("[" + key + "]") cachefile = cachedir + "tlv-msg-" + msg_list[key]["type"] + ".py" if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -375,6 +375,7 @@ for key in msg_list.keys(): type_list["Recovery"]["size"] = 1 # Type : 3 type_list["EBI"]["size"] = 1 # Type : 73 type_list["RAT Type"]["size"] = 1 # Type : 82 +type_list["Charging ID"]["size"] = 4 # Type : 94 type_list["PDN Type"]["size"] = 1 # Type : 99 type_list["PTI"]["size"] = 1 # Type : 100 type_list["Port Number"]["size"] = 2 # Type : 126 diff --git a/lib/gtp/types.h b/lib/gtp/types.h index 90ab3bce9..d188971af 100644 --- a/lib/gtp/types.h +++ b/lib/gtp/types.h @@ -69,7 +69,7 @@ typedef struct ogs_gtp_extension_header_s { } __attribute__ ((packed)) ogs_gtp_extension_header_t; /* 8.4 Cause */ -#define OGS_GTP_CAUSE_INVALID_VALUE 0 +#define OGS_GTP_CAUSE_UNDEFINED_VALUE 0 #define OGS_GTP_CAUSE_LOCAL_DETACH 2 #define OGS_GTP_CAUSE_COMPLETE_DETACH_3 #define OGS_GTP_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP 4 diff --git a/lib/gtp/xact.c b/lib/gtp/xact.c index cb7dc278e..f249efe00 100644 --- a/lib/gtp/xact.c +++ b/lib/gtp/xact.c @@ -560,7 +560,7 @@ int ogs_gtp_xact_commit(ogs_gtp_xact_t *xact) rv = ogs_gtp_sendto(xact->gnode, pkbuf); ogs_expect(rv == OGS_OK); - return OGS_OK; + return rv; } static void response_timeout(void *data) diff --git a/lib/nas/5gs/decoder.c b/lib/nas/5gs/decoder.c index 18449c105..9252ebb19 100644 --- a/lib/nas/5gs/decoder.c +++ b/lib/nas/5gs/decoder.c @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.2.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:39.474183 by acetcom + * Created on: 2021-06-15 11:11:47.244075 by acetcom * from 24501-g41.docx ******************************************************************************/ diff --git a/lib/nas/5gs/encoder.c b/lib/nas/5gs/encoder.c index 80900edf2..42f14a567 100644 --- a/lib/nas/5gs/encoder.c +++ b/lib/nas/5gs/encoder.c @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.2.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:39.484594 by acetcom + * Created on: 2021-06-15 11:11:47.251176 by acetcom * from 24501-g41.docx ******************************************************************************/ diff --git a/lib/nas/5gs/ies.c b/lib/nas/5gs/ies.c index 1a3b2007a..e43bf08ba 100644 --- a/lib/nas/5gs/ies.c +++ b/lib/nas/5gs/ies.c @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.2.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:39.457575 by acetcom + * Created on: 2021-06-15 11:11:47.232648 by acetcom * from 24501-g41.docx ******************************************************************************/ diff --git a/lib/nas/5gs/ies.h b/lib/nas/5gs/ies.h index 405676f34..217e9639c 100644 --- a/lib/nas/5gs/ies.h +++ b/lib/nas/5gs/ies.h @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.2.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:39.454963 by acetcom + * Created on: 2021-06-15 11:11:47.230677 by acetcom * from 24501-g41.docx ******************************************************************************/ diff --git a/lib/nas/5gs/message.h b/lib/nas/5gs/message.h index d7d57e9d0..69ef11b8c 100644 --- a/lib/nas/5gs/message.h +++ b/lib/nas/5gs/message.h @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.2.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:39.466799 by acetcom + * Created on: 2021-06-15 11:11:47.238937 by acetcom * from 24501-g41.docx ******************************************************************************/ diff --git a/lib/nas/5gs/support/README.md b/lib/nas/5gs/support/README.md index 1a34152a9..7922d2fef 100644 --- a/lib/nas/5gs/support/README.md +++ b/lib/nas/5gs/support/README.md @@ -1,16 +1,12 @@ -* Install python-pip -user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo apt-get install python-pip - * Install python-docx -user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo pip install python-docx +user@host ~/Documents/git/open5gs/lib/nas/5gs/support$ \ + sudo pip3 install python-docx * Change the format of standard specification from 24301-d80.doc to 24301-d80.docx using Microsoft Office 2007+ * Generate Message support files -user@host ~/Documents/git/open5gs/lib/s1ap/support$ \ - python nas-message.py -f 24501-g41.docx -o .. +user@host ~/Documents/git/open5gs/lib/nas/5gs/support$ \ + python3 nas-message.py -f 24501-g41.docx -o .. diff --git a/lib/nas/5gs/support/nas-message.py b/lib/nas/5gs/support/nas-message.py index 35ba6e576..54c09318c 100644 --- a/lib/nas/5gs/support/nas-message.py +++ b/lib/nas/5gs/support/nas-message.py @@ -96,14 +96,14 @@ def output_header_to_file(f): f.write(" ******************************************************************************/\n\n") def usage(): - print "Python generating NAS Message encoder/decoder v%s" % (version) - print "Usage: python nas-message.py [options]" - print "Available options:" - print "-d Enable script debug" - print "-f [file] Input file to parse" - print "-o [dir] Output files to given directory" - print "-c [dir] Cache files to given directory" - print "-h Print this help and return" + print("Python generating NAS Message encoder/decoder v%s" % (version)) + print("Usage: python nas-message.py [options]") + print("Available options:") + print("-d Enable script debug") + print("-f [file] Input file to parse") + print("-o [dir] Output files to given directory") + print("-c [dir] Cache files to given directory") + print("-h Print this help and return") def v_upper(v): return re.sub('_TO_UE', '', re.sub('_FROM_UE', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).upper())) @@ -115,13 +115,13 @@ def get_value(v): return re.sub('5gs_', '', re.sub('5g_', '', re.sub('5gsm', 'gsm', re.sub('5gmm', 'gmm', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).lower())))) def get_cells(cells): - iei = cells[0].text.encode('ascii', 'ignore') - value = re.sub("\s*$", "", re.sub("\s*\n*\s*\([^\)]*\)*", "", re.sub("'s", "", cells[1].text))).encode('ascii', 'ignore') - type = re.sub("^NAS ", "", re.sub("'s", "", re.sub('\s*\n\s*[a-zA-Z0-9.]*', '', cells[2].text))).encode('ascii', 'ignore') - reference = re.sub('[a-zA-Z0-9\'\-\s]*\n\s*', '', cells[2].text).encode('ascii', 'ignore') - presence = cells[3].text.encode('ascii', 'ignore') - format = cells[4].text.encode('ascii', 'ignore') - length = cells[5].text.encode('ascii', 'ignore') + iei = cells[0].text + value = re.sub("\s*$", "", re.sub("\s*\n*\s*\([^\)]*\)*", "", re.sub("'s", "", cells[1].text))) + type = re.sub("^NAS ", "", re.sub("'s", "", re.sub('\s*\n\s*[a-zA-Z0-9.]*', '', cells[2].text))) + reference = re.sub('[a-zA-Z0-9\'\-\s]*\n\s*', '', cells[2].text) + presence = cells[3].text + format = cells[4].text + length = cells[5].text # Spec errata - workaround if (type == "Request type" and value == "Request type"): @@ -264,8 +264,8 @@ for key in msg_list.keys(): d_info("[" + key + "]") cachefile = cachedir + "nas-msg-" + msg_list[key]["type"] + ".py" if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -326,8 +326,8 @@ for (k, v) in sorted_msg_list: d_info("[Type List]") typefile = currentdir + "type-list.py" if os.path.isfile(typefile) and os.access(typefile, os.R_OK): - execfile(typefile) - print "Read from " + typefile + exec(open(typefile).read()) + print("Read from " + typefile) tmp = [(k, v["reference"]) for k, v in type_list.items()] sorted_type_list = sorted(tmp, key=lambda tup: tup[1]) diff --git a/lib/nas/eps/decoder.c b/lib/nas/eps/decoder.c index c07182fda..19b0a3a3f 100644 --- a/lib/nas/eps/decoder.c +++ b/lib/nas/eps/decoder.c @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:00.074257 by acetcom + * Created on: 2021-06-15 11:19:58.629247 by acetcom * from 24301-g40.docx ******************************************************************************/ diff --git a/lib/nas/eps/encoder.c b/lib/nas/eps/encoder.c index 40d02f127..bfe0abc34 100644 --- a/lib/nas/eps/encoder.c +++ b/lib/nas/eps/encoder.c @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:00.085478 by acetcom + * Created on: 2021-06-15 11:19:58.637113 by acetcom * from 24301-g40.docx ******************************************************************************/ diff --git a/lib/nas/eps/ies.c b/lib/nas/eps/ies.c index 6657ba22c..3809854f2 100644 --- a/lib/nas/eps/ies.c +++ b/lib/nas/eps/ies.c @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:00.058358 by acetcom + * Created on: 2021-06-15 11:19:58.617999 by acetcom * from 24301-g40.docx ******************************************************************************/ diff --git a/lib/nas/eps/ies.h b/lib/nas/eps/ies.h index 9a5d445ae..8c8d2108d 100644 --- a/lib/nas/eps/ies.h +++ b/lib/nas/eps/ies.h @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:00.055906 by acetcom + * Created on: 2021-06-15 11:19:58.616283 by acetcom * from 24301-g40.docx ******************************************************************************/ diff --git a/lib/nas/eps/message.h b/lib/nas/eps/message.h index f058caa71..14a383ae7 100644 --- a/lib/nas/eps/message.h +++ b/lib/nas/eps/message.h @@ -28,7 +28,7 @@ /******************************************************************************* * This file had been created by nas-message.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2021-05-30 21:57:00.065569 by acetcom + * Created on: 2021-06-15 11:19:58.623021 by acetcom * from 24301-g40.docx ******************************************************************************/ diff --git a/lib/nas/eps/support/README.md b/lib/nas/eps/support/README.md index b472a8988..18f5dd9ab 100644 --- a/lib/nas/eps/support/README.md +++ b/lib/nas/eps/support/README.md @@ -1,16 +1,12 @@ -* Install python-pip -user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo apt-get install python-pip - * Install python-docx -user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo pip install python-docx +user@host ~/Documents/git/open5gs/lib/nas/eps/support$ \ + sudo pip3 install python-docx * Change the format of standard specification from 24301-d80.doc to 24301-d80.docx using Microsoft Office 2007+ * Generate Message support files -user@host ~/Documents/git/open5gs/lib/s1ap/support$ \ - python nas-message.py -f 24301-g40.docx -o .. +user@host ~/Documents/git/open5gs/lib/nas/eps/support$ \ + python3 nas-message.py -f 24301-g40.docx -o .. diff --git a/lib/nas/eps/support/nas-message.py b/lib/nas/eps/support/nas-message.py index 00d16508d..aa1629e88 100644 --- a/lib/nas/eps/support/nas-message.py +++ b/lib/nas/eps/support/nas-message.py @@ -96,14 +96,14 @@ def output_header_to_file(f): f.write(" ******************************************************************************/\n\n") def usage(): - print "Python generating NAS Message encoder/decoder v%s" % (version) - print "Usage: python nas-message.py [options]" - print "Available options:" - print "-d Enable script debug" - print "-f [file] Input file to parse" - print "-o [dir] Output files to given directory" - print "-c [dir] Cache files to given directory" - print "-h Print this help and return" + print("Python generating NAS Message encoder/decoder v%s" % (version)) + print("Usage: python nas-message.py [options]") + print("Available options:") + print("-d Enable script debug") + print("-f [file] Input file to parse") + print("-o [dir] Output files to given directory") + print("-c [dir] Cache files to given directory") + print("-h Print this help and return") def v_upper(v): return re.sub('_TO_UE', '', re.sub('_FROM_UE', '', re.sub('3GPP', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).upper()))) @@ -112,15 +112,15 @@ def v_lower(v): return re.sub('3gpp', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).lower()) def get_cells(cells): - iei = cells[0].text.encode('ascii', 'ignore') - value = re.sub("\s*$", "", re.sub("\s*\n*\s*\([^\)]*\)*", "", re.sub("'s", "", cells[1].text))).encode('ascii', 'ignore') - type = re.sub("^NAS ", "", re.sub("'s", "", re.sub('\s*\n\s*[a-zA-Z0-9.]*', '', cells[2].text))).encode('ascii', 'ignore') + iei = cells[0].text + value = re.sub("\s*$", "", re.sub("\s*\n*\s*\([^\)]*\)*", "", re.sub("'s", "", cells[1].text))) + type = re.sub("^NAS ", "", re.sub("'s", "", re.sub('\s*\n\s*[a-zA-Z0-9.]*', '', cells[2].text))) if type == "message container": type = "EPS message container" - reference = re.sub('[a-zA-Z0-9\'\-\s]*\n\s*', '', cells[2].text).encode('ascii', 'ignore') - presence = cells[3].text.encode('ascii', 'ignore') - format = cells[4].text.encode('ascii', 'ignore') - length = cells[5].text.encode('ascii', 'ignore') + reference = re.sub('[a-zA-Z0-9\'\-\s]*\n\s*', '', cells[2].text) + presence = cells[3].text + format = cells[4].text + length = cells[5].text return { "iei" : iei, "value" : value, "type" : type, "reference" : reference, "presence" : presence, "format" : format, "length" : length } @@ -278,8 +278,8 @@ for key in msg_list.keys(): d_info("[" + key + "]") cachefile = cachedir + "nas-msg-" + msg_list[key]["type"] + ".py" if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -340,8 +340,8 @@ for (k, v) in sorted_msg_list: d_info("[Type List]") typefile = currentdir + "type-list.py" if os.path.isfile(typefile) and os.access(typefile, os.R_OK): - execfile(typefile) - print "Read from " + typefile + exec(open(typefile).read()) + print("Read from " + typefile) tmp = [(k, v["reference"]) for k, v in type_list.items()] sorted_type_list = sorted(tmp, key=lambda tup: tup[1]) diff --git a/lib/pfcp/message.c b/lib/pfcp/message.c index d1235f825..beeb680b5 100644 --- a/lib/pfcp/message.c +++ b/lib/pfcp/message.c @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by pfcp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2020-08-28 21:50:38.885547 by acetcom + * Created on: 2021-06-15 10:58:38.385939 by acetcom * from 29244-g10.docx ******************************************************************************/ diff --git a/lib/pfcp/message.h b/lib/pfcp/message.h index bd9c4055a..fd3b60fdf 100644 --- a/lib/pfcp/message.h +++ b/lib/pfcp/message.h @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by pfcp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2020-08-28 21:50:38.876204 by acetcom + * Created on: 2021-06-15 10:58:38.379862 by acetcom * from 29244-g10.docx ******************************************************************************/ diff --git a/lib/pfcp/support/README.md b/lib/pfcp/support/README.md index f3d51a1c6..6a27e20ce 100644 --- a/lib/pfcp/support/README.md +++ b/lib/pfcp/support/README.md @@ -1,11 +1,7 @@ -* Install python-pip -user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo apt-get install python-pip - * Install python-docx -user@host ~/Documents/git/open5gs/lib/gtp/support$ \ - sudo pip install python-docx +user@host ~/Documents/git/open5gs/lib/pfcp/support$ \ + sudo pip3 install python-docx * Change the format of standard specification from 29244-f40.doc to 29274-f40.docx @@ -13,4 +9,4 @@ user@host ~/Documents/git/open5gs/lib/gtp/support$ \ * Generate TLV support files user@host ~/Documents/git/open5gs/lib/pfcp/support$ \ - python pfcp-tlv.py -f 29244-g10.docx -o .. + python3 pfcp-tlv.py -f 29244-g10.docx -o .. diff --git a/lib/pfcp/support/cache/tlv-msg-50.py b/lib/pfcp/support/cache/tlv-msg-50.py index c5d73bc80..eaca0a162 100644 --- a/lib/pfcp/support/cache/tlv-msg-50.py +++ b/lib/pfcp/support/cache/tlv-msg-50.py @@ -1,9 +1,13 @@ ies = [] ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) ies.append({ "ie_type" : "F-SEID", "ie_value" : "CP F-SEID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the unique identifier allocated by the CP function identifying the session."}) +type_list["Create PDR"]["max_tlv_more"] = "7" ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "M", "tlv_more" : "7", "comment" : "This IE shall be present for at least one PDR to be associated to the PFCP session.Several IEs with the same IE type may be present to represent multiple PDRs.See Table 7.5.2.2-1."}) +type_list["Create FAR"]["max_tlv_more"] = "7" ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "M", "tlv_more" : "7", "comment" : "This IE shall be present for at least one FAR to be associated to the PFCP session.Several IEs with the same IE type may be present to represent multiple FARs.See Table 7.5.2.3-1."}) +type_list["Create URR"]["max_tlv_more"] = "1" ies.append({ "ie_type" : "Create URR", "ie_value" : "Create URR", "presence" : "C", "tlv_more" : "1", "comment" : "This IE shall be present if a measurement action shall be applied to packets matching one or more PDR(s) of this PFCP session.Several IEs within the same IE type may be present to represent multiple URRs.See Table 7.5.2.4-1."}) +type_list["Create QER"]["max_tlv_more"] = "3" ies.append({ "ie_type" : "Create QER", "ie_value" : "Create QER", "presence" : "C", "tlv_more" : "3", "comment" : "This IE shall be present if a QoS enforcement or QoS marking action shall be applied to packets matching one or more PDR(s) of this PFCP session.Several IEs within the same IE type may be present to represent multiple QERs.See Table 7.5.2.5-1."}) ies.append({ "ie_type" : "Create BAR", "ie_value" : "Create BAR", "presence" : "O", "tlv_more" : "0", "comment" : "When present, this IE shall contain the buffering instructions to be applied by the UP function to any FAR of this PFCP session set with the Apply Action requesting the packets to be buffered and with a BAR ID IE referring to this BAR. See table 7.5.2.6-1."}) ies.append({ "ie_type" : "Create Traffic Endpoint", "ie_value" : "Create Traffic Endpoint", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present if the UP function has indicated support of PDI optimization.Several IEs within the same IE type may be present to represent multiple Traffic Endpoints.See Table 7.5.2.7-1."}) diff --git a/lib/pfcp/support/cache/tlv-msg-52.py b/lib/pfcp/support/cache/tlv-msg-52.py index 08fda64ee..2988e6222 100644 --- a/lib/pfcp/support/cache/tlv-msg-52.py +++ b/lib/pfcp/support/cache/tlv-msg-52.py @@ -10,13 +10,9 @@ type_list["Remove QER"]["max_tlv_more"] = "3" ies.append({ "ie_type" : "Remove QER", "ie_value" : "Remove QER", "presence" : "C", "tlv_more" : "3", "comment" : "When present, this IE shall contain the QER Rule which is requested to be removed. See Table 7.5.4-9-1.Several IEs within the same IE type may be present to represent a list of QERs to remove."}) ies.append({ "ie_type" : "Remove BAR", "ie_value" : "Remove BAR", "presence" : "C", "tlv_more" : "0", "comment" : "When present, this IE shall contain the BAR Rule which is requested to be removed. See Table 7.5.4.12-1."}) ies.append({ "ie_type" : "Remove Traffic Endpoint", "ie_value" : "Remove Traffic Endpoint", "presence" : "C", "tlv_more" : "0", "comment" : "When present, this IE shall contain the Traffic Endpoint ID identifying the traffic endpoint to be removed, if the UP function has indicated support of PDI optimization.All the PDRs that refer to the removed Traffic Endpoint shall be deleted.See Table 7.5.4.14-1."}) -type_list["Create PDR"]["max_tlv_more"] = "7" ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "C", "tlv_more" : "7", "comment" : "This IE shall be present if the CP function requests the UP function to create a new PDR.See Table 7.5.2.2-1.Several IEs within the same IE type may be present to represent a list of PDRs to create."}) -type_list["Create FAR"]["max_tlv_more"] = "7" ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "C", "tlv_more" : "7", "comment" : "This IE shall be present if the CP function requests the UP function to create a new FAR.See Table 7.5.2.3-1.Several IEs within the same IE type may be present to represent a list of FARs to create."}) -type_list["Create URR"]["max_tlv_more"] = "1" ies.append({ "ie_type" : "Create URR", "ie_value" : "Create URR", "presence" : "C", "tlv_more" : "1", "comment" : "This IE shall be present if the CP function requests the UP function to create a new URR. See Table 7.5.2.4-1.Several IEs within the same IE type may be present to represent a list of URRs to create."}) -type_list["Create QER"]["max_tlv_more"] = "3" ies.append({ "ie_type" : "Create QER", "ie_value" : "Create QER", "presence" : "C", "tlv_more" : "3", "comment" : "This IE shall be present if the CP function requests the UP function to create a new QER. See Table 7.5.2.5-1.Several IEs within the same IE type may be present to represent a list of QERs to create."}) ies.append({ "ie_type" : "Create BAR", "ie_value" : "Create BAR", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the CP function requests the UP function to create a new BAR.See Table 7.5.2.6-1."}) ies.append({ "ie_type" : "Create Traffic Endpoint", "ie_value" : "Create Traffic Endpoint", "presence" : "C", "tlv_more" : "0", "comment" : "When present this IE shall contain the information associated with the Traffic Endpoint to be created, if the UP function has indicated support of PDI optimization. See Table 7.5.2.7-1."}) diff --git a/lib/pfcp/support/pfcp-tlv.py b/lib/pfcp/support/pfcp-tlv.py index 4efbc0748..a09178b98 100644 --- a/lib/pfcp/support/pfcp-tlv.py +++ b/lib/pfcp/support/pfcp-tlv.py @@ -80,14 +80,14 @@ def output_header_to_file(f): f.write(" ******************************************************************************/\n\n") def usage(): - print "Python generating TLV build/parser for PFCP v%s" % (version) - print "Usage: python pfcp-tlv.py [options]" - print "Available options:" - print "-d Enable script debug" - print "-f [file] Input file to parse" - print "-o [dir] Output files to given directory" - print "-c [dir] Cache files to given directory" - print "-h Print this help and return" + print("Python generating TLV build/parser for PFCP v%s" % (version)) + print("Usage: python pfcp-tlv.py [options]") + print("Available options:") + print("-d Enable script debug") + print("-f [file] Input file to parse") + print("-o [dir] Output files to given directory") + print("-c [dir] Cache files to given directory") + print("-h Print this help and return") def v_upper(v): return re.sub('3GPP', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).upper()) @@ -96,13 +96,13 @@ def v_lower(v): return re.sub('3gpp', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).lower()) def get_cells(cells): - note = cells[0].text.encode('ascii', 'ignore') + note = cells[0].text if note.find('NOTE') != -1: return None - comment = cells[2].text.encode('ascii', 'ignore') + comment = cells[2].text.encode('ascii', 'ignore').decode('utf-8') comment = re.sub('\n|\"|\'|\\\\', '', comment); #print comment - ie_type = re.sub('\s*$', '', re.sub('\'\s*\n*\s*\(NOTE.*\)*', '', cells[-1].text.encode('ascii', 'ignore'))) + ie_type = re.sub('\s*$', '', re.sub('\'\s*\n*\s*\(NOTE.*\)*', '', cells[-1].text)) #if ie_type.find('Usage Report') != -1: if ie_type == 'Usage Report': @@ -136,8 +136,8 @@ def get_cells(cells): if ie_type not in type_list.keys(): assert False, "Unknown IE type : [" \ + cells[-1].text + "]" + "(" + ie_type + ")" - presence = cells[1].text.encode('ascii', 'ignore') - ie_value = re.sub('\s*\n*\s*\([^\)]*\)*', '', cells[0].text).encode('ascii', 'ignore') + presence = cells[1].text + ie_value = re.sub('\s*\n*\s*\([^\)]*\)*', '', cells[0].text) if ie_value[len(ie_value)-1] == ' ': ie_value = ie_value[:len(ie_value)-1] @@ -200,8 +200,8 @@ else: d_info("[Message List]") cachefile = cachedir + 'tlv-msg-list.py' if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -218,8 +218,8 @@ else: d_print("Table Index = %d\n" % i) for row in msg_table.rows[2:-3]: - key = row.cells[1].text.encode('ascii', 'ignore') - type = row.cells[0].text.encode('ascii', 'ignore') + key = row.cells[1].text + type = row.cells[0].text if type.isdigit() is False: continue if key.find('Reserved') != -1: @@ -232,8 +232,8 @@ else: d_info("[IE Type List]") cachefile = cachedir + 'tlv-type-list.py' if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -250,14 +250,14 @@ else: d_print("Table Index = %d\n" % i) for row in ie_table.rows[1:-1]: - key = row.cells[1].text.encode('ascii', 'ignore') + key = row.cells[1].text if key.find('Reserved') != -1: continue key = re.sub('\(', '', key) key = re.sub('\)', '', key) key = re.sub('\s*$', '', key) - type = row.cells[0].text.encode('ascii', 'ignore') + type = row.cells[0].text type_list[key] = { "type": type , "max_tlv_more" : "0" } write_file(f, "type_list[\"" + key + "\"] = { \"type\" : \"" + type) write_file(f, "\", \"max_tlv_more\" : \"0\" }\n") @@ -266,8 +266,8 @@ else: d_info("[Group IE List]") cachefile = cachedir + 'tlv-group-list.py' if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') @@ -298,8 +298,8 @@ else: if len(re.findall('\d+', row.cells[num].text)) == 0: continue; - ie_type = re.findall('\d+', row.cells[num].text)[-1].encode('ascii', 'ignore') - ie_name = re.sub('\s*IE Type.*', '', row.cells[num].text.encode('ascii', 'ignore')) + ie_type = re.findall('\d+', row.cells[num].text)[-1] + ie_name = re.sub('\s*IE Type.*', '', row.cells[num].text) d_print("TYPE:%s NAME:%s\n" % (ie_type, ie_name)) @@ -366,8 +366,8 @@ for key in msg_list.keys(): d_info("[" + key + "]") cachefile = cachedir + "tlv-msg-" + msg_list[key]["type"] + ".py" if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK): - execfile(cachefile) - print "Read from " + cachefile + exec(open(cachefile).read()) + print("Read from " + cachefile) else: document = Document(filename) f = open(cachefile, 'w') diff --git a/src/hss/hss-context.c b/src/hss/hss-context.c index d1458e904..2a9f6998d 100644 --- a/src/hss/hss-context.c +++ b/src/hss/hss-context.c @@ -208,6 +208,9 @@ int hss_context_parse_config(void) } else if (!strcmp(fd_key, "listen_on")) { self.diam_config->cnf_addr = ogs_yaml_iter_value(&fd_iter); + } else if (!strcmp(fd_key, "no_fwd")) { + self.diam_config->cnf_flags.no_fwd = + ogs_yaml_iter_bool(&fd_iter); } else if (!strcmp(fd_key, "load_extension")) { ogs_yaml_iter_t ext_array, ext_iter; ogs_yaml_iter_recurse(&fd_iter, &ext_array); diff --git a/src/hss/hss-context.h b/src/hss/hss-context.h index 0382bf694..dff669a7b 100644 --- a/src/hss/hss-context.h +++ b/src/hss/hss-context.h @@ -22,6 +22,7 @@ #include "ogs-diameter-s6a.h" #include "ogs-diameter-cx.h" +#include "ogs-diameter-swx.h" #include "ogs-dbi.h" #include "ogs-app.h" diff --git a/src/hss/hss-cx-path.c b/src/hss/hss-cx-path.c index 8062ae53e..e9c59f43e 100644 --- a/src/hss/hss-cx-path.c +++ b/src/hss/hss-cx-path.c @@ -129,7 +129,7 @@ static int hss_ogs_diam_cx_uar_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -176,7 +176,7 @@ out: /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -429,7 +429,7 @@ static int hss_ogs_diam_cx_mar_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -567,7 +567,7 @@ out: /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -711,7 +711,7 @@ static int hss_ogs_diam_cx_sar_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -824,7 +824,7 @@ out: /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -893,7 +893,7 @@ static int hss_ogs_diam_cx_lir_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -941,7 +941,7 @@ out: /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); diff --git a/src/hss/hss-fd-path.c b/src/hss/hss-fd-path.c index 0c66d5ac4..de82d48b2 100644 --- a/src/hss/hss-fd-path.c +++ b/src/hss/hss-fd-path.c @@ -34,6 +34,11 @@ int hss_fd_init(void) ogs_assert(rv == OGS_OK); rv = hss_cx_init(); ogs_assert(rv == OGS_OK); + rv = hss_swx_init(); + ogs_assert(rv == OGS_OK); + + rv = ogs_diam_start(); + ogs_assert(rv == 0); return OGS_OK; } @@ -42,6 +47,7 @@ void hss_fd_final(void) { hss_s6a_final(); hss_cx_final(); + hss_swx_final(); ogs_diam_final(); } diff --git a/src/hss/hss-fd-path.h b/src/hss/hss-fd-path.h index 4e08b11ef..b8bf8c2bd 100644 --- a/src/hss/hss-fd-path.h +++ b/src/hss/hss-fd-path.h @@ -31,6 +31,8 @@ int hss_s6a_init(void); void hss_s6a_final(void); int hss_cx_init(void); void hss_cx_final(void); +int hss_swx_init(void); +void hss_swx_final(void); #ifdef __cplusplus } diff --git a/src/hss/hss-s6a-path.c b/src/hss/hss-s6a-path.c index 2700e57ba..d460b312e 100644 --- a/src/hss/hss-s6a-path.c +++ b/src/hss/hss-s6a-path.c @@ -30,7 +30,7 @@ static struct disp_hdl *hdl_s6a_air = NULL; static struct disp_hdl *hdl_s6a_ulr = NULL; /* Default callback for the application. */ -static int hss_ogs_diam_s6a_fb_cb(struct msg **msg, struct avp *avp, +static int hss_ogs_diam_s6a_fb_cb(struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { /* This CB should never be called */ @@ -153,7 +153,7 @@ static int hss_ogs_diam_s6a_air_cb( struct msg **msg, struct avp *avp, goto out; } - ret = fd_msg_search_avp(qry, ogs_diam_s6a_visited_plmn_id, &avp); + ret = fd_msg_search_avp(qry, ogs_diam_visited_plmn_id, &avp); ogs_assert(ret == 0); ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); @@ -220,7 +220,7 @@ static int hss_ogs_diam_s6a_air_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -251,7 +251,7 @@ out: /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -269,7 +269,7 @@ out: } /* Callback for incoming Update-Location-Request messages */ -static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, +static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) { int ret; @@ -316,7 +316,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, goto out; } - ret = fd_msg_search_avp(qry, ogs_diam_s6a_visited_plmn_id, &avp); + ret = fd_msg_search_avp(qry, ogs_diam_visited_plmn_id, &avp); ogs_assert(ret == 0); ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); @@ -331,7 +331,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -410,7 +410,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, val.i32 = subscription_data.access_restriction_data; ret = fd_msg_avp_setvalue( avp_access_restriction_data, &val); ogs_assert(ret == 0); - ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_access_restriction_data); ogs_assert(ret == 0); } @@ -520,6 +520,8 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, struct avp *allocation_retention_priority, *priority_level; struct avp *pre_emption_capability, *pre_emption_vulnerability; struct avp *mip6_agent_info, *mip_home_agent_address; + struct avp *pdn_gw_allocation_type; + struct avp *vplmn_dynamic_address_allowed; ogs_session_t *session = &slice_data->session[i]; ogs_assert(session); @@ -583,7 +585,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, } /* Set Service-Selection */ - ret = fd_msg_avp_new(ogs_diam_s6a_service_selection, 0, + ret = fd_msg_avp_new(ogs_diam_service_selection, 0, &service_selection); ogs_assert(ret == 0); ogs_assert(session->name); @@ -606,7 +608,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, val.i32 = session->qos.index; ret = fd_msg_avp_setvalue(qos_class_identifier, &val); ogs_assert(ret == 0); - ret = fd_msg_avp_add(eps_subscribed_qos_profile, + ret = fd_msg_avp_add(eps_subscribed_qos_profile, MSG_BRW_LAST_CHILD, qos_class_identifier); ogs_assert(ret == 0); @@ -694,11 +696,36 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, ogs_assert(ret == 0); } - ret = fd_msg_avp_add(apn_configuration, + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, mip6_agent_info); ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_pdn_gw_allocation_type, 0, + &pdn_gw_allocation_type); + ogs_assert(ret == 0); + + val.u32 = OGS_DIAM_S6A_PDN_GW_ALLOCATION_DYNAMIC; + ret = fd_msg_avp_setvalue(pdn_gw_allocation_type, &val); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, pdn_gw_allocation_type); + ogs_assert(ret == 0); } + /* Set VPLMN-Dynamic-Address-Allowed */ + ret = fd_msg_avp_new(ogs_diam_s6a_vplmn_dynamic_address_allowed, 0, + &vplmn_dynamic_address_allowed); + ogs_assert(ret == 0); + + val.u32 = OGS_DIAM_S6A_VPLMN_DYNAMIC_ADDRESS_ALLOWED; + ret = fd_msg_avp_setvalue(vplmn_dynamic_address_allowed, &val); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, vplmn_dynamic_address_allowed); + ogs_assert(ret == 0); + /* Set AMBR */ if (session->ambr.downlink || session->ambr.uplink) { ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr); @@ -722,7 +749,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, avp_max_bandwidth_dl); ogs_assert(ret == 0); - ret = fd_msg_avp_add(apn_configuration, + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, avp_ambr); ogs_assert(ret == 0); } @@ -766,7 +793,7 @@ out: /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -810,7 +837,7 @@ int hss_s6a_init(void) /* Specific handler for Location-Update-Request */ data.command = ogs_diam_s6a_cmd_ulr; - ret = fd_disp_register(hss_ogs_diam_s6a_ulr_cb, DISP_HOW_CC, &data, NULL, + ret = fd_disp_register(hss_ogs_diam_s6a_ulr_cb, DISP_HOW_CC, &data, NULL, &hdl_s6a_ulr); ogs_assert(ret == 0); diff --git a/src/hss/hss-swx-path.c b/src/hss/hss-swx-path.c new file mode 100644 index 000000000..236a47eba --- /dev/null +++ b/src/hss/hss-swx-path.c @@ -0,0 +1,927 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ogs-crypt.h" + +#include "hss-context.h" +#include "hss-fd-path.h" + +/* handler for fallback cb */ +static struct disp_hdl *hdl_swx_fb = NULL; +/* handler for Multimedia-Auth-Request cb */ +static struct disp_hdl *hdl_swx_mar = NULL; +/* handler for Server-Assignment-Request cb */ +static struct disp_hdl *hdl_swx_sar = NULL; + +/* Default callback for the application. */ +static int hss_ogs_diam_swx_fb_cb(struct msg **msg, struct avp *avp, + struct session *session, void *opaque, enum disp_action *act) +{ + /* This CB should never be called */ + ogs_warn("Unexpected message received!"); + + return ENOTSUP; +} + +/* Callback for incoming Multimedia-Auth-Request messages */ +static int hss_ogs_diam_swx_mar_cb( struct msg **msg, struct avp *avp, + struct session *session, void *opaque, enum disp_action *act) +{ + int rv, ret; + uint32_t result_code = 0; + + struct msg *ans, *qry; + + struct avp *sip_auth_data_item_avp = NULL; + struct avp *authentication_scheme_avp = NULL; + struct avp *sip_authorization_avp = NULL; + + struct avp *avpch = NULL; + struct avp_hdr *hdr; + union avp_value val; + + char *user_name = NULL; + char *authentication_scheme = NULL; + + char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; + + ogs_dbi_auth_info_t auth_info; + uint8_t zero[OGS_RAND_LEN]; + + uint8_t authenticate[OGS_KEY_LEN*2]; + + uint8_t opc[OGS_KEY_LEN]; + uint8_t sqn[OGS_SQN_LEN]; + + uint8_t autn[OGS_AUTN_LEN]; + uint8_t ik[OGS_KEY_LEN]; + uint8_t ck[OGS_KEY_LEN]; + uint8_t ak[OGS_AK_LEN]; + uint8_t xres[OGS_MAX_RES_LEN]; + size_t xres_len = 8; + + uint8_t mac_s[OGS_MAC_S_LEN]; + + ogs_assert(msg); + + ogs_debug("Multimedia-Auth-Request"); + + /* Create answer header */ + qry = *msg; + ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0); + ogs_assert(ret == 0); + ans = *msg; + + /* Get User-Name AVP (Mandatory) */ + ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + + user_name = ogs_strndup( + (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); + ogs_assert(user_name); + + ogs_extract_digit_from_string(imsi_bcd, user_name); + + /* Get the SIP-Auth-Data-Item AVP (Mandatory) */ + ret = fd_msg_search_avp( + qry, ogs_diam_cx_sip_auth_data_item, &sip_auth_data_item_avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_hdr(sip_auth_data_item_avp, &hdr); + ogs_assert(ret == 0); + + /* Get the Authentication-Scheme AVP */ + ret = fd_msg_search_avp(sip_auth_data_item_avp, + ogs_diam_cx_sip_authentication_scheme, &authentication_scheme_avp); + ogs_assert(ret == 0); + if (authentication_scheme_avp) { + ret = fd_msg_avp_hdr(authentication_scheme_avp, &hdr); + ogs_assert(ret == 0); + + authentication_scheme = ogs_strndup( + (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); + ogs_assert(authentication_scheme); + } + + /* EAP-AKA is only supported */ + if (authentication_scheme && + ogs_strcasecmp(authentication_scheme, + OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA) != 0) { + ogs_error("Authentication-Scheme[%s] is not supported", + authentication_scheme); + result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; + goto out; + } + + /* DB : HSS Auth-Info */ + rv = hss_db_auth_info(imsi_bcd, &auth_info); + if (rv != OGS_OK) { + ogs_error("Cannot get IMS-Data for IMSI:'%s'", imsi_bcd); + result_code = OGS_DIAM_CX_ERROR_USER_UNKNOWN; + goto out; + } + + memset(zero, 0, sizeof(zero)); + if (memcmp(auth_info.rand, zero, OGS_RAND_LEN) == 0) { + ogs_random(auth_info.rand, OGS_RAND_LEN); + } + + if (auth_info.use_opc) + memcpy(opc, auth_info.opc, sizeof(opc)); + else + milenage_opc(auth_info.k, auth_info.op, opc); + + /* Get the SIP-Authorization AVP */ + ret = fd_msg_search_avp(sip_auth_data_item_avp, + ogs_diam_cx_sip_authorization, &sip_authorization_avp); + ogs_assert(ret == 0); + if (sip_authorization_avp) { + ret = fd_msg_avp_hdr(sip_authorization_avp, &hdr); + ogs_assert(ret == 0); + + ogs_auc_sqn(opc, auth_info.k, + hdr->avp_value->os.data, + hdr->avp_value->os.data + OGS_RAND_LEN, + sqn, mac_s); + if (memcmp(mac_s, hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN, OGS_MAC_S_LEN) == 0) { + ogs_random(auth_info.rand, OGS_RAND_LEN); + auth_info.sqn = ogs_buffer_to_uint64(sqn, OGS_SQN_LEN); + /* 33.102 C.3.4 Guide : IND + 1 */ + auth_info.sqn = (auth_info.sqn + 32 + 1) & OGS_MAX_SQN; + } else { + ogs_error("Re-synch MAC failed for IMSI:`%s`", imsi_bcd); + ogs_log_print(OGS_LOG_ERROR, "MAC_S: "); + ogs_log_hexdump(OGS_LOG_ERROR, mac_s, OGS_MAC_S_LEN); + ogs_log_hexdump(OGS_LOG_ERROR, + (void*)(hdr->avp_value->os.data + + OGS_RAND_LEN + OGS_SQN_LEN), + OGS_MAC_S_LEN); + ogs_log_print(OGS_LOG_ERROR, "SQN: "); + ogs_log_hexdump(OGS_LOG_ERROR, sqn, OGS_SQN_LEN); + result_code = OGS_DIAM_CX_ERROR_AUTH_SCHEME_NOT_SUPPORTED; + goto out; + } + } + + rv = hss_db_update_sqn(imsi_bcd, auth_info.rand, auth_info.sqn); + if (rv != OGS_OK) { + ogs_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd); + result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE; + goto out; + } + + rv = hss_db_increment_sqn(imsi_bcd); + if (rv != OGS_OK) { + ogs_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd); + result_code = OGS_DIAM_CX_ERROR_IN_ASSIGNMENT_TYPE; + goto out; + } + + milenage_generate(opc, auth_info.amf, auth_info.k, + ogs_uint64_to_buffer(auth_info.sqn, OGS_SQN_LEN, sqn), auth_info.rand, + autn, ik, ck, ak, xres, &xres_len); + + memcpy(authenticate, auth_info.rand, OGS_RAND_LEN); + memcpy(authenticate + OGS_RAND_LEN, autn, OGS_AUTN_LEN); + + ogs_log_print(OGS_LOG_DEBUG, "K - "); + ogs_log_hexdump(OGS_LOG_DEBUG, auth_info.k, OGS_KEY_LEN); + ogs_log_print(OGS_LOG_DEBUG, "AMF - "); + ogs_log_hexdump(OGS_LOG_DEBUG, auth_info.amf, OGS_AMF_LEN); + ogs_log_print(OGS_LOG_DEBUG, "OPc - "); + ogs_log_hexdump(OGS_LOG_DEBUG, opc, OGS_KEY_LEN); + ogs_log_print(OGS_LOG_DEBUG, "RAND - "); + ogs_log_hexdump(OGS_LOG_DEBUG, auth_info.rand, OGS_RAND_LEN); + ogs_log_print(OGS_LOG_DEBUG, "SQN - "); + ogs_log_hexdump(OGS_LOG_DEBUG, sqn, OGS_SQN_LEN); + + ogs_log_print(OGS_LOG_DEBUG, "AUTN - "); + ogs_log_hexdump(OGS_LOG_DEBUG, autn, OGS_KEY_LEN); + ogs_log_print(OGS_LOG_DEBUG, "ck - "); + ogs_log_hexdump(OGS_LOG_DEBUG, ck, OGS_KEY_LEN); + ogs_log_print(OGS_LOG_DEBUG, "ik - "); + ogs_log_hexdump(OGS_LOG_DEBUG, ik, OGS_KEY_LEN); + ogs_log_print(OGS_LOG_DEBUG, "ak - "); + ogs_log_hexdump(OGS_LOG_DEBUG, ak, OGS_KEY_LEN); + ogs_log_print(OGS_LOG_DEBUG, "xles - "); + ogs_log_hexdump(OGS_LOG_DEBUG, xres, xres_len); + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + ogs_assert(ret == 0); + + /* Set the User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the SIP-Number-Auth-Items AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp); + ogs_assert(ret == 0); + val.u32 = 1; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the SIP-Auth-Data-Item AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp); + ogs_assert(ret == 0); + + /* Set the SIP-Item-Number AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_item_number, 0, &avpch); + ogs_assert(ret == 0); + val.u32 = 1; + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + + /* Set the SIP-Authentication-Scheme AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA; + val.os.len = strlen(OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA); + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + + /* Set the SIP-Authenticatie AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authenticate, 0, &avpch); + ogs_assert(ret == 0); + val.os.data = authenticate; + val.os.len = OGS_KEY_LEN * 2; + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + + /* Set the SIP-Authorization AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch); + ogs_assert(ret == 0); + val.os.data = xres; + val.os.len = xres_len; + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + + /* Set the Confidentiality-Key AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_confidentiality_key, 0, &avpch); + ogs_assert(ret == 0); + val.os.data = ck; + val.os.len = OGS_KEY_LEN; + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + + /* Set the Integirty-Key AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_integrity_key, 0, &avpch); + ogs_assert(ret == 0); + val.os.data = ik; + val.os.len = OGS_KEY_LEN; + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + ogs_debug("Multimedia-Auth-Answer"); + + /* Add this value to the stats */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_echoed++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + if (authentication_scheme) + ogs_free(authentication_scheme); + + ogs_free(user_name); + + return 0; + +out: + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + ogs_assert(ret == 0); + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + if (authentication_scheme) + ogs_free(authentication_scheme); + + ogs_free(user_name); + + return 0; +} + +/* Callback for incoming Server-Assignment-Request messages */ +static int hss_ogs_diam_swx_sar_cb( struct msg **msg, struct avp *avp, + struct session *session, void *opaque, enum disp_action *act) +{ + int rv, ret; + uint32_t result_code = 0; + + struct msg *ans, *qry; + + struct avp_hdr *hdr; + union avp_value val; + + char *user_name = NULL; + ogs_s_nssai_t s_nssai; + + char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; + + ogs_subscription_data_t subscription_data; + ogs_slice_data_t *slice_data = NULL; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + + ogs_assert(msg); + + ogs_debug("Server-Assignment-Request"); + + memset(&subscription_data, 0, sizeof(ogs_subscription_data_t)); + + /* Create answer header */ + qry = *msg; + ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0); + ogs_assert(ret == 0); + ans = *msg; + + /* Get User-Name AVP (Mandatory) */ + ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + + user_name = ogs_strndup( + (char*)hdr->avp_value->os.data, hdr->avp_value->os.len); + ogs_assert(user_name); + + ogs_extract_digit_from_string(imsi_bcd, user_name); + + /* DB : HSS Subscription Data */ + rv = hss_db_subscription_data(imsi_bcd, &subscription_data); + if (rv != OGS_OK) { + ogs_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd); + result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + goto out; + } + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + ogs_assert(ret == 0); + + /* Set the User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Get Server-Assignment-Type AVP (Mandatory) */ + ret = fd_msg_search_avp(qry, + ogs_diam_cx_server_assignment_type, &avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + if (hdr->avp_value->i32 == OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION || + hdr->avp_value->i32 == + OGS_DIAM_CX_SERVER_ASSIGNMENT_AAA_USER_DATA_REQUEST) { + + struct avp *avp_subscription_id; + struct avp *avp_subscription_id_type, *avp_subscription_id_data; + struct avp *avp_non_3gpp_ip_access, *avp_non_3gpp_ip_access_apn; + struct avp *avp_ambr, *avp_max_bandwidth_ul, *avp_max_bandwidth_dl; + + /* Set the APN Configuration Profile */ + struct avp *context_identifier; + + int i; + + /* Set the Non-3GPP-User-Data */ + ret = fd_msg_avp_new(ogs_diam_swx_non_3gpp_user_data, 0, &avp); + ogs_assert(ret == 0); + + /* Set Subscription-Id */ + if (subscription_data.num_of_msisdn >= 1) { + ret = fd_msg_avp_new(ogs_diam_subscription_id, 0, + &avp_subscription_id); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_subscription_id_type, 0, + &avp_subscription_id_type); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_E164; + ret = fd_msg_avp_setvalue (avp_subscription_id_type, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp_subscription_id, MSG_BRW_LAST_CHILD, + avp_subscription_id_type); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_subscription_id_data, 0, + &avp_subscription_id_data); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)subscription_data.msisdn[0].bcd; + val.os.len = strlen(subscription_data.msisdn[0].bcd); + ret = fd_msg_avp_setvalue (avp_subscription_id_data, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp_subscription_id, MSG_BRW_LAST_CHILD, + avp_subscription_id_data); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_subscription_id); + ogs_assert(ret == 0); + } + + /* Set Non-3GPP-IP-Access */ + ret = fd_msg_avp_new(ogs_diam_swx_non_3gpp_ip_access, 0, + &avp_non_3gpp_ip_access); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_SWX_NON_3GPP_SUBSCRIPTION_ALLOWED; + ret = fd_msg_avp_setvalue(avp_non_3gpp_ip_access, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_non_3gpp_ip_access); + ogs_assert(ret == 0); + + /* Set Non-3GPP-IP-Access-APN */ + ret = fd_msg_avp_new(ogs_diam_swx_non_3gpp_ip_access_apn, 0, + &avp_non_3gpp_ip_access_apn); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_SWX_NON_3GPP_APNS_ENABLE; + ret = fd_msg_avp_setvalue(avp_non_3gpp_ip_access_apn, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, + avp_non_3gpp_ip_access_apn); + ogs_assert(ret == 0); + + /* Set the AMBR */ + ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr); + ogs_assert(ret == 0); + ret = fd_msg_avp_new( + ogs_diam_s6a_max_bandwidth_ul, 0, &avp_max_bandwidth_ul); + ogs_assert(ret == 0); + val.u32 = ogs_uint64_to_uint32(subscription_data.ambr.uplink); + ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add( + avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_ul); + ogs_assert(ret == 0); + ret = fd_msg_avp_new( + ogs_diam_s6a_max_bandwidth_dl, 0, &avp_max_bandwidth_dl); + ogs_assert(ret == 0); + val.u32 = ogs_uint64_to_uint32(subscription_data.ambr.downlink); + ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add( + avp_ambr, MSG_BRW_LAST_CHILD, avp_max_bandwidth_dl); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_ambr); + ogs_assert(ret == 0); + + /* For EPC, we'll use SST:1 */ + s_nssai.sst = 1; + s_nssai.sd.v = OGS_S_NSSAI_NO_SD_VALUE; + + slice_data = ogs_slice_find_by_s_nssai( + subscription_data.slice, subscription_data.num_of_slice, + &s_nssai); + if (!slice_data) { + ogs_error("[%s] Cannot find S-NSSAI", imsi_bcd); + result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION; + goto out; + } + + if (!slice_data->num_of_session) { + ogs_error("[%s] No PDN", imsi_bcd); + result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION; + goto out; + } + + ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0, + &context_identifier); + ogs_assert(ret == 0); + val.i32 = 1; /* Context Identifier : 1 */ + ret = fd_msg_avp_setvalue(context_identifier, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, context_identifier); + ogs_assert(ret == 0); + + for (i = 0; i < slice_data->num_of_session; i++) { + /* Set the APN Configuration */ + struct avp *apn_configuration, *context_identifier, *pdn_type; + struct avp *served_party_ip_address, *service_selection; + struct avp *eps_subscribed_qos_profile, *qos_class_identifier; + struct avp *allocation_retention_priority, *priority_level; + struct avp *pre_emption_capability, *pre_emption_vulnerability; + struct avp *mip6_agent_info, *mip_home_agent_address; + struct avp *pdn_gw_allocation_type; + struct avp *vplmn_dynamic_address_allowed; + + ogs_session_t *session = &slice_data->session[i]; + ogs_assert(session); + session->context_identifier = i+1; + + ret = fd_msg_avp_new(ogs_diam_s6a_apn_configuration, 0, + &apn_configuration); + ogs_assert(ret == 0); + + /* Set Context-Identifier */ + ret = fd_msg_avp_new(ogs_diam_s6a_context_identifier, 0, + &context_identifier); + ogs_assert(ret == 0); + val.i32 = session->context_identifier; + ret = fd_msg_avp_setvalue(context_identifier, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, context_identifier); + ogs_assert(ret == 0); + + /* Set PDN-Type */ + ret = fd_msg_avp_new(ogs_diam_s6a_pdn_type, 0, &pdn_type); + ogs_assert(ret == 0); + val.i32 = OGS_PDU_SESSION_TYPE_TO_DIAMETER(session->session_type); + ret = fd_msg_avp_setvalue(pdn_type, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, pdn_type); + ogs_assert(ret == 0); + + /* Set Served-Party-IP-Address */ + if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV4 || + session->session_type == OGS_PDU_SESSION_TYPE_IPV4V6) && + session->ue_ip.ipv4) { + ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address, + 0, &served_party_ip_address); + ogs_assert(ret == 0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = session->ue_ip.addr; + ret = fd_msg_avp_value_encode(&sin, served_party_ip_address); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, + served_party_ip_address); + ogs_assert(ret == 0); + } + + if ((session->session_type == OGS_PDU_SESSION_TYPE_IPV6 || + session->session_type == OGS_PDU_SESSION_TYPE_IPV4V6) && + session->ue_ip.ipv6) { + ret = fd_msg_avp_new(ogs_diam_s6a_served_party_ip_address, + 0, &served_party_ip_address); + ogs_assert(ret == 0); + sin6.sin6_family = AF_INET6; + memcpy(sin6.sin6_addr.s6_addr, + session->ue_ip.addr6, OGS_IPV6_LEN); + ret = fd_msg_avp_value_encode(&sin6, served_party_ip_address); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, + served_party_ip_address); + ogs_assert(ret == 0); + } + + /* Set Service-Selection */ + ret = fd_msg_avp_new(ogs_diam_service_selection, 0, + &service_selection); + ogs_assert(ret == 0); + ogs_assert(session->name); + val.os.data = (uint8_t *)session->name; + val.os.len = strlen(session->name); + ret = fd_msg_avp_setvalue(service_selection, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, service_selection); + ogs_assert(ret == 0); + + /* Set the EPS Subscribed QoS Profile */ + ret = fd_msg_avp_new(ogs_diam_s6a_eps_subscribed_qos_profile, 0, + &eps_subscribed_qos_profile); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_qos_class_identifier, 0, + &qos_class_identifier); + ogs_assert(ret == 0); + val.i32 = session->qos.index; + ret = fd_msg_avp_setvalue(qos_class_identifier, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(eps_subscribed_qos_profile, + MSG_BRW_LAST_CHILD, qos_class_identifier); + ogs_assert(ret == 0); + + /* Set Allocation retention priority */ + ret = fd_msg_avp_new(ogs_diam_s6a_allocation_retention_priority, 0, + &allocation_retention_priority); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new( + ogs_diam_s6a_priority_level, 0, &priority_level); + ogs_assert(ret == 0); + val.u32 = session->qos.arp.priority_level; + ret = fd_msg_avp_setvalue(priority_level, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(allocation_retention_priority, + MSG_BRW_LAST_CHILD, priority_level); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_capability, 0, + &pre_emption_capability); + ogs_assert(ret == 0); + val.u32 = OGS_EPC_PRE_EMPTION_DISABLED; + if (session->qos.arp.pre_emption_capability == + OGS_5GC_PRE_EMPTION_ENABLED) + val.u32 = OGS_EPC_PRE_EMPTION_ENABLED; + ret = fd_msg_avp_setvalue(pre_emption_capability, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(allocation_retention_priority, + MSG_BRW_LAST_CHILD, pre_emption_capability); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_pre_emption_vulnerability, 0, + &pre_emption_vulnerability); + ogs_assert(ret == 0); + val.u32 = OGS_EPC_PRE_EMPTION_DISABLED; + if (session->qos.arp.pre_emption_vulnerability == + OGS_5GC_PRE_EMPTION_ENABLED) + val.u32 = OGS_EPC_PRE_EMPTION_ENABLED; + ret = fd_msg_avp_setvalue(pre_emption_vulnerability, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(allocation_retention_priority, + MSG_BRW_LAST_CHILD, pre_emption_vulnerability); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(eps_subscribed_qos_profile, + MSG_BRW_LAST_CHILD, allocation_retention_priority); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, eps_subscribed_qos_profile); + ogs_assert(ret == 0); + + /* Set MIP6-Agent-Info */ + if (session->smf_ip.ipv4 || session->smf_ip.ipv6) { + ret = fd_msg_avp_new(ogs_diam_mip6_agent_info, 0, + &mip6_agent_info); + ogs_assert(ret == 0); + + if (session->smf_ip.ipv4) { + ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0, + &mip_home_agent_address); + ogs_assert(ret == 0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = session->smf_ip.addr; + ret = fd_msg_avp_value_encode ( + &sin, mip_home_agent_address ); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(mip6_agent_info, + MSG_BRW_LAST_CHILD, mip_home_agent_address); + ogs_assert(ret == 0); + } + + if (session->smf_ip.ipv6) { + ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0, + &mip_home_agent_address); + ogs_assert(ret == 0); + sin6.sin6_family = AF_INET6; + memcpy(sin6.sin6_addr.s6_addr, session->smf_ip.addr6, + sizeof session->smf_ip.addr6); + ret = fd_msg_avp_value_encode ( + &sin6, mip_home_agent_address ); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(mip6_agent_info, + MSG_BRW_LAST_CHILD, mip_home_agent_address); + ogs_assert(ret == 0); + } + + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, mip6_agent_info); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_pdn_gw_allocation_type, 0, + &pdn_gw_allocation_type); + ogs_assert(ret == 0); + + val.u32 = OGS_DIAM_S6A_PDN_GW_ALLOCATION_DYNAMIC; + ret = fd_msg_avp_setvalue(pdn_gw_allocation_type, &val); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, pdn_gw_allocation_type); + ogs_assert(ret == 0); + } + + /* Set VPLMN-Dynamic-Address-Allowed */ + ret = fd_msg_avp_new(ogs_diam_s6a_vplmn_dynamic_address_allowed, 0, + &vplmn_dynamic_address_allowed); + ogs_assert(ret == 0); + + val.u32 = OGS_DIAM_S6A_VPLMN_DYNAMIC_ADDRESS_ALLOWED; + ret = fd_msg_avp_setvalue(vplmn_dynamic_address_allowed, &val); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, vplmn_dynamic_address_allowed); + ogs_assert(ret == 0); + + /* Set AMBR */ + if (session->ambr.downlink || session->ambr.uplink) { + ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr); + ogs_assert(ret == 0); + ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_ul, 0, + &avp_max_bandwidth_ul); + ogs_assert(ret == 0); + val.u32 = ogs_uint64_to_uint32(session->ambr.uplink); + ret = fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD, + avp_max_bandwidth_ul); + ogs_assert(ret == 0); + ret = fd_msg_avp_new(ogs_diam_s6a_max_bandwidth_dl, 0, + &avp_max_bandwidth_dl); + ogs_assert(ret == 0); + val.u32 = ogs_uint64_to_uint32(session->ambr.downlink); + ret = fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD, + avp_max_bandwidth_dl); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(apn_configuration, + MSG_BRW_LAST_CHILD, avp_ambr); + ogs_assert(ret == 0); + } + + ret = fd_msg_avp_add(avp, + MSG_BRW_LAST_CHILD, apn_configuration); + ogs_assert(ret == 0); + } + + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + ogs_debug("Server-Assignment-Answer"); + + /* Add this value to the stats */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_echoed++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + ogs_subscription_data_free(&subscription_data); + ogs_free(user_name); + + return 0; + +out: + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_CX_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Set the Experimental-Result, Origin-Host and Origin-Realm AVPs */ + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + ogs_assert(ret == 0); + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + ogs_subscription_data_free(&subscription_data); + ogs_free(user_name); + + return 0; +} + +int hss_swx_init(void) +{ + int ret; + struct disp_when data; + + /* Install objects definitions for this application */ + ret = ogs_diam_swx_init(); + ogs_assert(ret == 0); + + memset(&data, 0, sizeof(data)); + data.app = ogs_diam_swx_application; + + /* Fallback CB if command != unexpected message received */ + ret = fd_disp_register(hss_ogs_diam_swx_fb_cb, DISP_HOW_APPID, + &data, NULL, &hdl_swx_fb); + ogs_assert(ret == 0); + + /* Specific handler for Multimedia-Auth-Request */ + data.command = ogs_diam_cx_cmd_mar; + ret = fd_disp_register(hss_ogs_diam_swx_mar_cb, DISP_HOW_CC, &data, NULL, + &hdl_swx_mar); + ogs_assert(ret == 0); + + /* Specific handler for Server-Assignment-Request */ + data.command = ogs_diam_cx_cmd_sar; + ret = fd_disp_register(hss_ogs_diam_swx_sar_cb, DISP_HOW_CC, &data, NULL, + &hdl_swx_sar); + ogs_assert(ret == 0); + + /* Advertise the support for the application in the peer */ + ret = fd_disp_app_support(ogs_diam_swx_application, ogs_diam_vendor, 1, 0); + ogs_assert(ret == 0); + + return OGS_OK; +} + +void hss_swx_final(void) +{ + if (hdl_swx_fb) + (void) fd_disp_unregister(&hdl_swx_fb, NULL); + if (hdl_swx_mar) + (void) fd_disp_unregister(&hdl_swx_mar, NULL); + if (hdl_swx_sar) + (void) fd_disp_unregister(&hdl_swx_sar, NULL); +} diff --git a/src/hss/meson.build b/src/hss/meson.build index f6977926d..d80707dcc 100644 --- a/src/hss/meson.build +++ b/src/hss/meson.build @@ -21,21 +21,32 @@ libhss_sources = files(''' hss-init.c hss-context.c + hss-s6a-path.c hss-cx-path.c + hss-swx-path.c + hss-fd-path.c '''.split()) libhss = static_library('hss', sources : libhss_sources, - dependencies : [libapp_dep, libcrypt_dep, libdbi_dep, - libdiameter_s6a_dep, libdiameter_cx_dep], + dependencies : [libapp_dep, + libcrypt_dep, + libdbi_dep, + libdiameter_s6a_dep, + libdiameter_cx_dep, + libdiameter_swx_dep], install : false) libhss_dep = declare_dependency( link_with : libhss, - dependencies : [libapp_dep, libcrypt_dep, libdbi_dep, - libdiameter_s6a_dep, libdiameter_cx_dep]) + dependencies : [libapp_dep, + libcrypt_dep, + libdbi_dep, + libdiameter_s6a_dep, + libdiameter_cx_dep, + libdiameter_swx_dep]) hss_sources = files(''' app-init.c diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index 9416a0406..6619a9f8a 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -295,6 +295,9 @@ int mme_context_parse_config() } else if (!strcmp(fd_key, "listen_on")) { self.diam_config->cnf_addr = ogs_yaml_iter_value(&fd_iter); + } else if (!strcmp(fd_key, "no_fwd")) { + self.diam_config->cnf_flags.no_fwd = + ogs_yaml_iter_bool(&fd_iter); } else if (!strcmp(fd_key, "load_extension")) { ogs_yaml_iter_t ext_array, ext_iter; ogs_yaml_iter_recurse(&fd_iter, &ext_array); diff --git a/src/mme/mme-fd-path.c b/src/mme/mme-fd-path.c index 1af24fe3b..6d41431d0 100644 --- a/src/mme/mme-fd-path.c +++ b/src/mme/mme-fd-path.c @@ -80,7 +80,7 @@ void mme_s6a_send_air(mme_ue_t *mme_ue, /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); @@ -147,7 +147,7 @@ void mme_s6a_send_air(mme_ue_t *mme_ue, ogs_assert(ret == 0); /* Set the Visited-PLMN-Id AVP */ - ret = fd_msg_avp_new(ogs_diam_s6a_visited_plmn_id, 0, &avp); + ret = fd_msg_avp_new(ogs_diam_visited_plmn_id, 0, &avp); ogs_assert(ret == 0); val.os.data = ogs_nas_from_plmn_id(&nas_plmn_id, &mme_ue->tai.plmn_id); val.os.len = OGS_PLMN_ID_LEN; @@ -476,7 +476,7 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue) /* Set the Auth-Session-State AVP */ ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); @@ -534,9 +534,9 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue) } /* Set the RAT-Type */ - ret = fd_msg_avp_new(ogs_diam_s6a_rat_type, 0, &avp); + ret = fd_msg_avp_new(ogs_diam_rat_type, 0, &avp); ogs_assert(ret == 0); - val.u32 = OGS_DIAM_S6A_RAT_TYPE_EUTRAN; + val.u32 = OGS_DIAM_RAT_TYPE_EUTRAN; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); @@ -552,7 +552,7 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue) ogs_assert(ret == 0); /* Set the Visited-PLMN-Id */ - ret = fd_msg_avp_new(ogs_diam_s6a_visited_plmn_id, 0, &avp); + ret = fd_msg_avp_new(ogs_diam_visited_plmn_id, 0, &avp); ogs_assert(ret == 0); val.os.data = ogs_nas_from_plmn_id(&nas_plmn_id, &mme_ue->tai.plmn_id); val.os.len = OGS_PLMN_ID_LEN; @@ -837,7 +837,7 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) &slice_data->session[slice_data->num_of_session]; ogs_assert(session); ret = fd_avp_search_avp( - avpch2, ogs_diam_s6a_service_selection, &avpch3); + avpch2, ogs_diam_service_selection, &avpch3); ogs_assert(ret == 0); if (avpch3) { ret = fd_msg_avp_hdr(avpch3, &hdr); @@ -1177,6 +1177,9 @@ int mme_fd_init(void) /* Advertise the support for the application in the peer */ ret = fd_disp_app_support(ogs_diam_s6a_application, ogs_diam_vendor, 1, 0); ogs_assert(ret == 0); + + ret = ogs_diam_start(); + ogs_assert(ret == 0); return 0; } diff --git a/src/mme/mme-s11-build.c b/src/mme/mme-s11-build.c index 2d94f018d..e0e44e79c 100644 --- a/src/mme/mme-s11-build.c +++ b/src/mme/mme-s11-build.c @@ -157,19 +157,16 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( req->selection_mode.presence = 1; req->selection_mode.u8 = - OGS_GTP_SELECTION_MODE_MS_OR_NETWORK_PROVIDED_APN | 0xfc; + OGS_GTP_SELECTION_MODE_MS_OR_NETWORK_PROVIDED_APN; ogs_assert(sess->request_type.type == OGS_NAS_EPS_PDN_TYPE_IPV4 || sess->request_type.type == OGS_NAS_EPS_PDN_TYPE_IPV6 || sess->request_type.type == OGS_NAS_EPS_PDN_TYPE_IPV4V6); - req->pdn_type.u8 = ((session->session_type + 1) & - sess->request_type.type); if (session->session_type == OGS_PDU_SESSION_TYPE_IPV4 || session->session_type == OGS_PDU_SESSION_TYPE_IPV6 || session->session_type == OGS_PDU_SESSION_TYPE_IPV4V6) { - req->pdn_type.u8 = - (session->session_type & sess->request_type.type); + req->pdn_type.u8 = (session->session_type & sess->request_type.type); if (req->pdn_type.u8 == 0) { ogs_fatal("Cannot derive PDN Type [UE:%d,HSS:%d]", sess->request_type.type, session->session_type); @@ -196,9 +193,16 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( memcpy(session->paa.addr6, &addr, OGS_IPV6_LEN); } + memset(&indication, 0, sizeof(ogs_gtp_indication_t)); if (req->pdn_type.u8 == OGS_PDU_SESSION_TYPE_IPV4V6) { - memset(&indication, 0, sizeof(ogs_gtp_indication_t)); indication.daf = 1; + } + + if (sess->request_type.value == OGS_NAS_EPS_REQUEST_TYPE_HANDOVER) { + indication.hi = 1; + } + + if (indication.daf || indication.hi) { req->indication_flags.presence = 1; req->indication_flags.data = &indication; req->indication_flags.len = sizeof(ogs_gtp_indication_t); @@ -293,10 +297,15 @@ ogs_pkbuf_t *mme_s11_build_modify_bearer_request( ogs_gtp_uli_t uli; char uli_buf[OGS_GTP_MAX_ULI_LEN]; + ogs_gtp_indication_t indication; + mme_ue_t *mme_ue = NULL; + mme_sess_t *sess = NULL; ogs_assert(bearer); - mme_ue = bearer->mme_ue; + sess = bearer->sess; + ogs_assert(sess); + mme_ue = sess->mme_ue; ogs_assert(mme_ue); ogs_debug("Modifty Bearer Request"); @@ -307,6 +316,14 @@ ogs_pkbuf_t *mme_s11_build_modify_bearer_request( memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + if (sess->request_type.value == OGS_NAS_EPS_REQUEST_TYPE_HANDOVER) { + memset(&indication, 0, sizeof(ogs_gtp_indication_t)); + indication.hi = 1; + req->indication_flags.presence = 1; + req->indication_flags.data = &indication; + req->indication_flags.len = sizeof(ogs_gtp_indication_t); + } + /* Bearer Context : EBI */ req->bearer_contexts_to_be_modified.presence = 1; req->bearer_contexts_to_be_modified.eps_bearer_id.presence = 1; @@ -598,15 +615,47 @@ ogs_pkbuf_t *mme_s11_build_delete_bearer_response( rsp->cause.data = &cause; if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - /* Bearer Context : EBI */ - rsp->bearer_contexts.presence = 1; - rsp->bearer_contexts.eps_bearer_id.presence = 1; - rsp->bearer_contexts.eps_bearer_id.u8 = bearer->ebi; + mme_bearer_t *linked_bearer = mme_linked_bearer(bearer); + ogs_assert(linked_bearer); - /* Bearer Context : Cause */ - rsp->bearer_contexts.cause.presence = 1; - rsp->bearer_contexts.cause.len = sizeof(cause); - rsp->bearer_contexts.cause.data = &cause; + if (bearer->ebi == linked_bearer->ebi) { + /* + * << Linked EPS Bearer ID >> + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + */ + rsp->linked_eps_bearer_id.presence = 1; + rsp->linked_eps_bearer_id.u8 = bearer->ebi; + } else { + /* + * << EPS Bearer IDs >> + * + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ + + /* Bearer Context : EBI */ + rsp->bearer_contexts.presence = 1; + rsp->bearer_contexts.eps_bearer_id.presence = 1; + rsp->bearer_contexts.eps_bearer_id.u8 = bearer->ebi; + + /* Bearer Context : Cause */ + rsp->bearer_contexts.cause.presence = 1; + rsp->bearer_contexts.cause.len = sizeof(cause); + rsp->bearer_contexts.cause.data = &cause; + } } /* User Location Information(ULI) */ diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index 16141f25c..6e6846a6d 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -675,11 +675,34 @@ void mme_s11_handle_delete_bearer_request( ogs_debug("Delete Bearer Request"); if (mme_ue && req->linked_eps_bearer_id.presence == 1) { + /* + * << Linked EPS Bearer ID >> + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + */ bearer = mme_bearer_find_by_ue_ebi( mme_ue, req->linked_eps_bearer_id.u8); if (!bearer) ogs_error("Cannot find Bearer [%d]", req->linked_eps_bearer_id.u8); } else if (mme_ue && req->eps_bearer_ids.presence == 1) { + /* + * << EPS Bearer IDs >> + * + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ bearer = mme_bearer_find_by_ue_ebi( mme_ue, req->eps_bearer_ids.u8); if (!bearer) diff --git a/src/pcrf/pcrf-context.c b/src/pcrf/pcrf-context.c index 6f0ea7b3d..534e5447b 100644 --- a/src/pcrf/pcrf-context.c +++ b/src/pcrf/pcrf-context.c @@ -140,6 +140,9 @@ int pcrf_context_parse_config(void) } else if (!strcmp(fd_key, "listen_on")) { self.diam_config->cnf_addr = ogs_yaml_iter_value(&fd_iter); + } else if (!strcmp(fd_key, "no_fwd")) { + self.diam_config->cnf_flags.no_fwd = + ogs_yaml_iter_bool(&fd_iter); } else if (!strcmp(fd_key, "load_extension")) { ogs_yaml_iter_t ext_array, ext_iter; ogs_yaml_iter_recurse(&fd_iter, &ext_array); diff --git a/src/pcrf/pcrf-fd-path.c b/src/pcrf/pcrf-fd-path.c index 419e72289..94cc1e18b 100644 --- a/src/pcrf/pcrf-fd-path.c +++ b/src/pcrf/pcrf-fd-path.c @@ -33,6 +33,9 @@ int pcrf_fd_init(void) rv = pcrf_rx_init(); ogs_assert(rv == OGS_OK); + rv = ogs_diam_start(); + ogs_assert(rv == 0); + return OGS_OK; } diff --git a/src/pcrf/pcrf-gx-path.c b/src/pcrf/pcrf-gx-path.c index 65ee68540..5bccb1123 100644 --- a/src/pcrf/pcrf-gx-path.c +++ b/src/pcrf/pcrf-gx-path.c @@ -358,18 +358,18 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, } /* Get IMSI + APN */ - ret = fd_msg_search_avp(qry, ogs_diam_gx_subscription_id, &avp); + ret = fd_msg_search_avp(qry, ogs_diam_subscription_id, &avp); ogs_assert(ret == 0); if (avp) { ret = fd_msg_avp_hdr(avp, &hdr); ogs_assert(ret == 0); - ret = fd_avp_search_avp(avp, ogs_diam_gx_subscription_id_type, &avpch1); + ret = fd_avp_search_avp(avp, ogs_diam_subscription_id_type, &avpch1); ogs_assert(ret == 0); if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); ogs_assert(ret == 0); if (hdr->avp_value->i32 != - OGS_DIAM_GX_SUBSCRIPTION_ID_TYPE_END_USER_IMSI) { + OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_IMSI) { ogs_error("Not implemented Subscription-Id-Type(%d)", hdr->avp_value->i32); result_code = OGS_DIAM_AVP_UNSUPPORTED; @@ -380,7 +380,7 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, result_code = OGS_DIAM_MISSING_AVP; goto out; } - ret = fd_avp_search_avp(avp, ogs_diam_gx_subscription_id_data, &avpch1); + ret = fd_avp_search_avp(avp, ogs_diam_subscription_id_data, &avpch1); ogs_assert(ret == 0); if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); diff --git a/src/pcrf/pcrf-rx-path.c b/src/pcrf/pcrf-rx-path.c index 7b6882654..4be068bf8 100644 --- a/src/pcrf/pcrf-rx-path.c +++ b/src/pcrf/pcrf-rx-path.c @@ -149,7 +149,7 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Request-Type AVP */ ret = fd_msg_avp_new(ogs_diam_auth_request_type, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHENTICATE_ONLY; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -448,9 +448,9 @@ static int pcrf_rx_aar_cb( struct msg **msg, struct avp *avp, ogs_assert(ret == 0); /* Set RAT-Type */ - ret = fd_msg_avp_new(ogs_diam_rx_rat_type, 0, &avp); + ret = fd_msg_avp_new(ogs_diam_rat_type, 0, &avp); ogs_assert(ret == 0); - val.i32 = OGS_DIAM_RX_RAT_TYPE_EUTRAN; + val.i32 = OGS_DIAM_RAT_TYPE_EUTRAN; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -743,7 +743,7 @@ static int pcrf_rx_str_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Request-Type AVP */ ret = fd_msg_avp_new(ogs_diam_auth_request_type, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHENTICATE_ONLY; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); diff --git a/src/sgwc/s11-build.c b/src/sgwc/s11-build.c index 71a7069fb..766e9eb3d 100644 --- a/src/sgwc/s11-build.c +++ b/src/sgwc/s11-build.c @@ -42,7 +42,7 @@ ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification( * 0 : Reserved. Shall not be sent and * if received the Cause shall be treated as an invalid IE */ - if (cause_value != OGS_GTP_CAUSE_INVALID_VALUE) { + if (cause_value != OGS_GTP_CAUSE_UNDEFINED_VALUE) { memset(&cause, 0, sizeof(cause)); cause.value = cause_value; noti->cause.presence = 1; diff --git a/src/sgwc/s11-handler.c b/src/sgwc/s11-handler.c index df2a3b2e2..ecd2d2aad 100644 --- a/src/sgwc/s11-handler.c +++ b/src/sgwc/s11-handler.c @@ -772,24 +772,15 @@ void sgwc_s11_handle_delete_bearer_response( cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; - rv = ogs_gtp_xact_commit(s11_xact); - ogs_expect(rv == OGS_OK); - - if (rsp->bearer_contexts.presence == 0) { - ogs_error("No Bearer"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; - } - if (rsp->bearer_contexts.eps_bearer_id.presence == 0) { - ogs_error("No EPS Bearer ID"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; - } - if (s11_xact->xid & OGS_GTP_CMD_XACT_ID) /* MME received Bearer Resource Modification Request */ bearer = s5c_xact->data; else bearer = s11_xact->data; + rv = ogs_gtp_xact_commit(s11_xact); + ogs_expect(rv == OGS_OK); + ogs_assert(bearer); sess = bearer->sess; ogs_assert(sess); @@ -803,37 +794,88 @@ void sgwc_s11_handle_delete_bearer_response( cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; } - if (rsp->cause.presence) { - ogs_gtp_cause_t *cause = rsp->cause.data; - ogs_assert(cause); + if (rsp->linked_eps_bearer_id.presence) { + /* + * << Linked EPS Bearer ID >> + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + */ + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); - cause_value = cause->value; - if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - if (rsp->bearer_contexts.cause.presence) { - cause = rsp->bearer_contexts.cause.data; - ogs_assert(cause); - - cause_value = cause->value; + cause_value = cause->value; + if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { } else { - ogs_error("No Cause"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + ogs_error("GTP Failed [CAUSE:%d]", cause_value); } } else { - ogs_warn("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("No Cause"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + + ogs_assert(OGS_OK == + sgwc_pfcp_send_session_deletion_request(sess, s5c_xact, gtpbuf)); } else { - ogs_error("No Cause"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + /* + * << EPS Bearer IDs >> + * + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ + if (rsp->bearer_contexts.presence == 0) { + ogs_error("No Bearer"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (rsp->bearer_contexts.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + cause_value = cause->value; + if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + if (rsp->bearer_contexts.cause.presence) { + cause = rsp->bearer_contexts.cause.data; + ogs_assert(cause); + + cause_value = cause->value; + } else { + ogs_error("No Cause"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + } else { + ogs_warn("GTP Failed [CAUSE:%d]", cause_value); + } + } else { + ogs_error("No Cause"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", + sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid); + ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", + sess->sgw_s5c_teid, sess->pgw_s5c_teid); + + ogs_assert(OGS_OK == + sgwc_pfcp_send_bearer_modification_request( + bearer, s5c_xact, gtpbuf, OGS_PFCP_MODIFY_REMOVE)); } - - ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid); - ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", - sess->sgw_s5c_teid, sess->pgw_s5c_teid); - - ogs_assert(OGS_OK == - sgwc_pfcp_send_bearer_modification_request( - bearer, s5c_xact, gtpbuf, OGS_PFCP_MODIFY_REMOVE)); } void sgwc_s11_handle_release_access_bearers_request( diff --git a/src/sgwc/s5c-handler.c b/src/sgwc/s5c-handler.c index 29318248b..2c2e9a025 100644 --- a/src/sgwc/s5c-handler.c +++ b/src/sgwc/s5c-handler.c @@ -180,8 +180,6 @@ void sgwc_s5c_handle_create_session_response( } if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - ogs_assert(OGS_OK == - sgwc_pfcp_send_session_deletion_request(sess, NULL, NULL)); ogs_gtp_send_error_message( s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value); @@ -294,10 +292,85 @@ void sgwc_s5c_handle_delete_session_response( ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", sess->sgw_s5c_teid, sess->pgw_s5c_teid); + /* + * 1. MME sends Delete Session Request to SGW/SMF. + * 2. SMF sends Delete Session Response to SGW/MME. + */ ogs_assert(OGS_OK == sgwc_pfcp_send_session_deletion_request(sess, s11_xact, gtpbuf)); } +void sgwc_s5c_handle_modify_bearer_response( + sgwc_sess_t *sess, ogs_gtp_xact_t *s5c_xact, + ogs_pkbuf_t *gtpbuf, ogs_gtp_message_t *message) +{ + int rv; + uint8_t cause_value; + + sgwc_ue_t *sgwc_ue = NULL; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_gtp_xact_t *s11_xact = NULL; + ogs_gtp_modify_bearer_response_t *rsp = NULL; + + ogs_assert(s5c_xact); + s11_xact = s5c_xact->assoc_xact; + ogs_assert(s11_xact); + ogs_assert(message); + rsp = &message->modify_bearer_response; + ogs_assert(rsp); + + ogs_debug("Modify Bearer Response"); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + rv = ogs_gtp_xact_commit(s5c_xact); + ogs_expect(rv == OGS_OK); + + if (!sess) { + ogs_warn("No Context in TEID"); + sess = s5c_xact->data; + ogs_assert(sess); + } + + sgwc_ue = sess->sgwc_ue; + ogs_assert(sgwc_ue); + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + cause_value = cause->value; + } else { + ogs_error("No Cause"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE, cause_value); + return; + } + + ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", + sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid); + ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", + sess->sgw_s5c_teid, sess->pgw_s5c_teid); + + message->h.type = OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE; + message->h.teid = sgwc_ue->mme_s11_teid; + + pkbuf = ogs_gtp_build_msg(message); + ogs_expect_or_return(pkbuf); + + rv = ogs_gtp_xact_update_tx(s11_xact, &message->h, pkbuf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_gtp_xact_commit(s11_xact); + ogs_expect(rv == OGS_OK); +} + void sgwc_s5c_handle_create_bearer_request( sgwc_sess_t *sess, ogs_gtp_xact_t *s5c_xact, ogs_pkbuf_t *gtpbuf, ogs_gtp_message_t *message) @@ -516,10 +589,41 @@ void sgwc_s5c_handle_delete_bearer_request( } if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - bearer = sgwc_bearer_find_by_sess_ebi(sess, req->eps_bearer_ids.u8); + uint8_t ebi; + + if (req->linked_eps_bearer_id.presence) { + /* + * << Linked EPS Bearer ID >> + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + */ + ebi = req->linked_eps_bearer_id.u8; + } else if (req->eps_bearer_ids.presence) { + /* + * << EPS Bearer IDs >> + * + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ + ebi = req->eps_bearer_ids.u8; + } else + ogs_assert_if_reached(); + + bearer = sgwc_bearer_find_by_sess_ebi(sess, ebi); if (!bearer) - ogs_error("No Context for EPS Bearer ID[%d]", - req->eps_bearer_ids.u8); + ogs_error("No Context for EPS Bearer ID[%d]", ebi); } if (!bearer) { ogs_warn("No Context"); @@ -552,12 +656,31 @@ void sgwc_s5c_handle_delete_bearer_request( s11_xact = s5c_xact->assoc_xact; if (!s11_xact) { + /* + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ s11_xact = ogs_gtp_xact_local_create( sgwc_ue->gnode, &message->h, pkbuf, bearer_timeout, bearer); ogs_expect_or_return(s11_xact); ogs_gtp_xact_associate(s5c_xact, s11_xact); } else { + /* + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ rv = ogs_gtp_xact_update_tx(s11_xact, &message->h, pkbuf); ogs_expect_or_return(rv == OGS_OK); } diff --git a/src/sgwc/s5c-handler.h b/src/sgwc/s5c-handler.h index b1238ee71..505f0d7f8 100644 --- a/src/sgwc/s5c-handler.h +++ b/src/sgwc/s5c-handler.h @@ -32,6 +32,9 @@ void sgwc_s5c_handle_create_session_response( void sgwc_s5c_handle_delete_session_response( sgwc_sess_t *sess, ogs_gtp_xact_t *s5c_xact, ogs_pkbuf_t *gtpbuf, ogs_gtp_message_t *message); +void sgwc_s5c_handle_modify_bearer_response( + sgwc_sess_t *sess, ogs_gtp_xact_t *s5c_xact, + ogs_pkbuf_t *gtpbuf, ogs_gtp_message_t *message); void sgwc_s5c_handle_create_bearer_request( sgwc_sess_t *sess, ogs_gtp_xact_t *s5c_xact, ogs_pkbuf_t *gtpbuf, ogs_gtp_message_t *message); diff --git a/src/sgwc/sgwc-sm.c b/src/sgwc/sgwc-sm.c index 01c1d8f29..500763dd1 100644 --- a/src/sgwc/sgwc-sm.c +++ b/src/sgwc/sgwc-sm.c @@ -272,6 +272,10 @@ void sgwc_state_operational(ogs_fsm_t *s, sgwc_event_t *e) sgwc_s5c_handle_delete_session_response( sess, gtp_xact, recvbuf, >p_message); break; + case OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE: + sgwc_s5c_handle_modify_bearer_response( + sess, gtp_xact, recvbuf, >p_message); + break; case OGS_GTP_CREATE_BEARER_REQUEST_TYPE: sgwc_s5c_handle_create_bearer_request( sess, gtp_xact, recvbuf, >p_message); diff --git a/src/sgwc/sxa-handler.c b/src/sgwc/sxa-handler.c index dc32a006b..fe5c9763d 100644 --- a/src/sgwc/sxa-handler.c +++ b/src/sgwc/sxa-handler.c @@ -890,21 +890,48 @@ void sgwc_sxa_handle_session_modification_response( ogs_gtp_modify_bearer_request_t *gtp_req = NULL; ogs_gtp_modify_bearer_response_t *gtp_rsp = NULL; + ogs_gtp_indication_t *indication = NULL; + ogs_assert(recv_message); gtp_req = &recv_message->modify_bearer_request; ogs_assert(gtp_req); - gtp_rsp = &send_message.modify_bearer_response; - ogs_assert(gtp_rsp); + if (gtp_req->indication_flags.presence && + gtp_req->indication_flags.data && + gtp_req->indication_flags.len) { + indication = gtp_req->indication_flags.data; + } - memset(&send_message, 0, sizeof(ogs_gtp_message_t)); + if (indication && indication->hi) { + recv_message->h.type = OGS_GTP_MODIFY_BEARER_REQUEST_TYPE; + recv_message->h.teid = sess->pgw_s5c_teid; - memset(&cause, 0, sizeof(cause)); - cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + pkbuf = ogs_gtp_build_msg(recv_message); + ogs_expect_or_return(pkbuf); - gtp_rsp->cause.presence = 1; - gtp_rsp->cause.data = &cause; - gtp_rsp->cause.len = sizeof(cause); + ogs_assert(sess->gnode); + s5c_xact = ogs_gtp_xact_local_create( + sess->gnode, &recv_message->h, pkbuf, + sess_timeout, sess); + ogs_expect_or_return(s5c_xact); + + ogs_gtp_xact_associate(s11_xact, s5c_xact); + + rv = ogs_gtp_xact_commit(s5c_xact); + ogs_expect(rv == OGS_OK); + + } else { + gtp_rsp = &send_message.modify_bearer_response; + ogs_assert(gtp_rsp); + + memset(&send_message, 0, sizeof(ogs_gtp_message_t)); + + memset(&cause, 0, sizeof(cause)); + cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + gtp_rsp->cause.presence = 1; + gtp_rsp->cause.data = &cause; + gtp_rsp->cause.len = sizeof(cause); /* Copy Bearer-Contexts-Modified from Modify-Bearer-Request * @@ -919,31 +946,35 @@ void sgwc_sxa_handle_session_modification_response( * both an IPv4 address and an IPv6 address * (see also subclause 8.22 "F-TEID"). */ - gtp_rsp->bearer_contexts_modified.presence = 1; - gtp_rsp->bearer_contexts_modified.eps_bearer_id.presence = 1; - gtp_rsp->bearer_contexts_modified.eps_bearer_id.u8 = - gtp_req->bearer_contexts_to_be_modified.eps_bearer_id.u8; - gtp_rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.presence = 1; - gtp_rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.data = - gtp_req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.data; - gtp_rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.len = - gtp_req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.len; + gtp_rsp->bearer_contexts_modified.presence = 1; + gtp_rsp->bearer_contexts_modified.eps_bearer_id.presence = 1; + gtp_rsp->bearer_contexts_modified.eps_bearer_id.u8 = + gtp_req->bearer_contexts_to_be_modified.eps_bearer_id.u8; + gtp_rsp->bearer_contexts_modified. + s1_u_enodeb_f_teid.presence = 1; + gtp_rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.data = + gtp_req->bearer_contexts_to_be_modified. + s1_u_enodeb_f_teid.data; + gtp_rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.len = + gtp_req->bearer_contexts_to_be_modified. + s1_u_enodeb_f_teid.len; - gtp_rsp->bearer_contexts_modified.cause.presence = 1; - gtp_rsp->bearer_contexts_modified.cause.len = sizeof(cause); - gtp_rsp->bearer_contexts_modified.cause.data = &cause; + gtp_rsp->bearer_contexts_modified.cause.presence = 1; + gtp_rsp->bearer_contexts_modified.cause.len = sizeof(cause); + gtp_rsp->bearer_contexts_modified.cause.data = &cause; - send_message.h.type = OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE; - send_message.h.teid = sgwc_ue->mme_s11_teid; + send_message.h.type = OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE; + send_message.h.teid = sgwc_ue->mme_s11_teid; - pkbuf = ogs_gtp_build_msg(&send_message); - ogs_expect_or_return(pkbuf); + pkbuf = ogs_gtp_build_msg(&send_message); + ogs_expect_or_return(pkbuf); - rv = ogs_gtp_xact_update_tx(s11_xact, &send_message.h, pkbuf); - ogs_expect_or_return(rv == OGS_OK); + rv = ogs_gtp_xact_update_tx(s11_xact, &send_message.h, pkbuf); + ogs_expect_or_return(rv == OGS_OK); - rv = ogs_gtp_xact_commit(s11_xact); - ogs_expect(rv == OGS_OK); + rv = ogs_gtp_xact_commit(s11_xact); + ogs_expect(rv == OGS_OK); + } } else { ogs_fatal("Invalid modify_flags[0x%llx]", (long long)flags); @@ -1017,18 +1048,18 @@ void sgwc_sxa_handle_session_deletion_response( { int rv; uint8_t cause_value = 0; + uint32_t teid = 0; sgwc_ue_t *sgwc_ue = NULL; - ogs_gtp_xact_t *s11_xact = NULL; + ogs_gtp_xact_t *gtp_xact = NULL; ogs_pkbuf_t *pkbuf = NULL; ogs_debug("Session Deletion Response"); ogs_assert(pfcp_xact); ogs_assert(pfcp_rsp); - - ogs_pfcp_xact_commit(pfcp_xact); + ogs_assert(gtp_message); cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; @@ -1047,14 +1078,44 @@ void sgwc_sxa_handle_session_deletion_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } - s11_xact = pfcp_xact->assoc_xact; + gtp_xact = pfcp_xact->assoc_xact; + + ogs_pfcp_xact_commit(pfcp_xact); + + switch (gtp_message->h.type) { + case OGS_GTP_DELETE_SESSION_RESPONSE_TYPE: + /* + * 1. MME sends Delete Session Request to SGW/SMF. + * 2. SMF sends Delete Session Response to SGW/MME. + */ + if (sess) sgwc_ue = sess->sgwc_ue; + teid = sgwc_ue ? sgwc_ue->mme_s11_teid : 0; + break; + case OGS_GTP_DELETE_BEARER_RESPONSE_TYPE: + /* + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + * + * Note that the following messages are not processed here. + * - Bearer Resource Command + * - Delete Bearer Request/Response with DEDICATED BEARER. + */ + teid = sess ? sess->pgw_s5c_teid : 0; + break; + default: + ogs_fatal("Unknown GTP message type [%d]", gtp_message->h.type); + ogs_assert_if_reached(); + } if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - if (sess) sgwc_ue = sess->sgwc_ue; - if (s11_xact) { + if (gtp_xact) { ogs_gtp_send_error_message( - s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, - OGS_GTP_DELETE_SESSION_RESPONSE_TYPE, cause_value); + gtp_xact, teid, gtp_message->h.type, cause_value); } return; } @@ -1063,17 +1124,23 @@ void sgwc_sxa_handle_session_deletion_response( sgwc_ue = sess->sgwc_ue; ogs_assert(sgwc_ue); - if (s11_xact) { - gtp_message->h.type = OGS_GTP_DELETE_SESSION_RESPONSE_TYPE; - gtp_message->h.teid = sgwc_ue->mme_s11_teid; + if (gtp_xact) { + /* + * If gtp_message->h.type == OGS_GTP_DELETE_SESSION_RESPONSE_TYPE + * Then gtp_xact is S11-XACT + * + * If gtp_message->h.type == OGS_GTP_DELETE_BEARER_RESPONSE_TYPE + * Then gtp_xact is S5C-XACT + */ + gtp_message->h.teid = teid; pkbuf = ogs_gtp_build_msg(gtp_message); ogs_expect_or_return(pkbuf); - rv = ogs_gtp_xact_update_tx(s11_xact, >p_message->h, pkbuf); + rv = ogs_gtp_xact_update_tx(gtp_xact, >p_message->h, pkbuf); ogs_expect_or_return(rv == OGS_OK); - rv = ogs_gtp_xact_commit(s11_xact); + rv = ogs_gtp_xact_commit(gtp_xact); ogs_expect(rv == OGS_OK); } @@ -1153,7 +1220,7 @@ void sgwc_sxa_handle_session_report_request( if (tunnel->pdr->id == pdr_id) { ogs_assert(OGS_OK == sgwc_gtp_send_downlink_data_notification( - OGS_GTP_CAUSE_INVALID_VALUE, bearer)); + OGS_GTP_CAUSE_UNDEFINED_VALUE, bearer)); return; } } diff --git a/src/smf/binding.c b/src/smf/binding.c index ddbd5bfe4..c0650e9ac 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -20,6 +20,7 @@ #include "binding.h" #include "s5c-build.h" #include "pfcp-path.h" +#include "gtp-path.h" #include "ipfw/ipfw2.h" @@ -52,17 +53,6 @@ static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) case OGS_GTP_UPDATE_BEARER_REQUEST_TYPE: ogs_error("[%s] No Update Bearer Response", smf_ue->imsi_bcd); break; - case OGS_GTP_DELETE_BEARER_REQUEST_TYPE: - ogs_error("[%s] No Delete Bearer Response", smf_ue->imsi_bcd); - if (!smf_bearer_cycle(bearer)) { - ogs_warn("[%s] Bearer has already been removed", smf_ue->imsi_bcd); - break; - } - - ogs_assert(OGS_OK == - smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_REMOVE)); - break; default: ogs_error("GTP Timeout : IMSI[%s] Message-Type[%d]", smf_ue->imsi_bcd, type); @@ -384,20 +374,10 @@ void smf_bearer_binding(smf_sess_t *sess) continue; } - memset(&h, 0, sizeof(ogs_gtp_header_t)); - h.type = OGS_GTP_DELETE_BEARER_REQUEST_TYPE; - h.teid = sess->sgw_s5c_teid; - - pkbuf = smf_s5c_build_delete_bearer_request(h.type, bearer, - OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED); - ogs_expect_or_return(pkbuf); - - xact = ogs_gtp_xact_local_create( - sess->gnode, &h, pkbuf, bearer_timeout, bearer); - ogs_expect_or_return(xact); - - rv = ogs_gtp_xact_commit(xact); - ogs_expect(rv == OGS_OK); + ogs_assert(OGS_OK == + smf_gtp_send_delete_bearer_request( + bearer, OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); } else { ogs_error("Invalid Type[%d]", pcc_rule->type); } diff --git a/src/smf/context.c b/src/smf/context.c index 65809f49c..c3ce1a5cd 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -217,6 +217,9 @@ int smf_context_parse_config(void) } else if (!strcmp(fd_key, "listen_on")) { self.diam_config->cnf_addr = ogs_yaml_iter_value(&fd_iter); + } else if (!strcmp(fd_key, "no_fwd")) { + self.diam_config->cnf_flags.no_fwd = + ogs_yaml_iter_bool(&fd_iter); } else if (!strcmp(fd_key, "load_extension")) { ogs_yaml_iter_t ext_array, ext_iter; ogs_yaml_iter_recurse(&fd_iter, &ext_array); @@ -949,7 +952,7 @@ void smf_sess_select_upf(smf_sess_t *sess) OGS_ADDR(&ogs_pfcp_self()->pfcp_node->addr, buf)); } -smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn) +smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn, uint8_t rat_type) { smf_event_t e; @@ -977,6 +980,9 @@ smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn) sess->smf_n4_teid = sess->index; sess->smf_n4_seid = sess->index; + /* Set Charging ID */ + sess->charging.id = sess->index; + /* Create BAR in PFCP Session */ ogs_pfcp_bar_new(&sess->pfcp); @@ -984,6 +990,10 @@ smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn) sess->session.name = ogs_strdup(apn); ogs_assert(sess->session.name); + /* Set RAT-Type */ + sess->gtp_rat_type = rat_type; + ogs_assert(sess->gtp_rat_type); + /* Setup Timer */ sess->t_release_holding = ogs_timer_add( ogs_app()->timer_mgr, smf_timer_release_holding_expire, sess); @@ -1018,6 +1028,10 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message) ogs_error("No APN"); return NULL; } + if (req->rat_type.presence == 0) { + ogs_error("No RAT Type"); + return NULL; + } ogs_fqdn_parse(apn, req->access_point_name.data, req->access_point_name.len); @@ -1049,14 +1063,14 @@ smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message) ogs_assert(smf_ue); } - sess = smf_sess_find_by_apn(smf_ue, apn); + sess = smf_sess_find_by_apn(smf_ue, apn, req->rat_type.u8); if (sess) { ogs_warn("OLD Session Release [IMSI:%s,APN:%s]", smf_ue->imsi_bcd, sess->session.name); smf_sess_remove(sess); } - sess = smf_sess_add_by_apn(smf_ue, apn); + sess = smf_sess_add_by_apn(smf_ue, apn, req->rat_type.u8); return sess; } @@ -1088,6 +1102,7 @@ smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi) sess->index = ogs_pool_index(&smf_sess_pool, sess); ogs_assert(sess->index > 0 && sess->index <= ogs_app()->pool.sess); + /* Set SmContextRef in 5GC */ sess->sm_context_ref = ogs_msprintf("%d", (int)ogs_pool_index(&smf_sess_pool, sess)); ogs_assert(sess->sm_context_ref); @@ -1108,6 +1123,9 @@ smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi) sess->smf_n4_teid = sess->index; sess->smf_n4_seid = sess->index; + /* Set Charging Id */ + sess->charging.id = sess->index; + /* Setup Timer */ sess->t_release_holding = ogs_timer_add( ogs_app()->timer_mgr, smf_timer_release_holding_expire, sess); @@ -1472,7 +1490,7 @@ smf_sess_t *smf_sess_find_by_seid(uint64_t seid) return smf_sess_find(seid); } -smf_sess_t *smf_sess_find_by_apn(smf_ue_t *smf_ue, char *apn) +smf_sess_t *smf_sess_find_by_apn(smf_ue_t *smf_ue, char *apn, uint8_t rat_type) { smf_sess_t *sess = NULL; @@ -1480,7 +1498,8 @@ smf_sess_t *smf_sess_find_by_apn(smf_ue_t *smf_ue, char *apn) ogs_assert(apn); ogs_list_for_each(&smf_ue->sess_list, sess) { - if (!ogs_strcasecmp(sess->session.name, apn)) + if (ogs_strcasecmp(sess->session.name, apn) == 0 && + sess->gtp_rat_type == rat_type) return sess; } @@ -1502,6 +1521,12 @@ smf_sess_t *smf_sess_find_by_psi(smf_ue_t *smf_ue, uint8_t psi) return NULL; } +smf_sess_t *smf_sess_find_by_charging_id(uint32_t charging_id) +{ + ogs_assert(charging_id); + return smf_sess_find(charging_id); +} + smf_sess_t *smf_sess_find_by_sm_context_ref(char *sm_context_ref) { ogs_assert(sm_context_ref); @@ -2066,35 +2091,11 @@ smf_bearer_t *smf_bearer_find_by_pdr_id( } smf_bearer_t *smf_default_bearer_in_sess(smf_sess_t *sess) -{ - return smf_bearer_first(sess); -} - -bool smf_bearer_is_default(smf_bearer_t *bearer) -{ - smf_sess_t *sess = NULL; - smf_bearer_t *default_bearer = NULL; - - ogs_assert(bearer); - sess = bearer->sess; - ogs_assert(sess); - default_bearer = smf_default_bearer_in_sess(sess); - ogs_assert(default_bearer); - - return bearer == default_bearer; -} - -smf_bearer_t *smf_bearer_first(smf_sess_t *sess) { ogs_assert(sess); return ogs_list_first(&sess->bearer_list); } -smf_bearer_t *smf_bearer_next(smf_bearer_t *bearer) -{ - return ogs_list_next(bearer); -} - smf_ue_t *smf_ue_cycle(smf_ue_t *smf_ue) { return ogs_pool_cycle(&smf_ue_pool, smf_ue); diff --git a/src/smf/context.h b/src/smf/context.h index 29e9b55b0..2a2777f9d 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -24,6 +24,8 @@ #include "ogs-gtp.h" #include "ogs-diameter-gx.h" +#include "ogs-diameter-rx.h" +#include "ogs-diameter-s6b.h" #include "ogs-pfcp.h" #include "ogs-sbi.h" #include "ogs-app.h" @@ -168,8 +170,8 @@ typedef struct smf_bearer_s { ogs_ip_t sgw_s5u_ip; /* SGW-S5U IPv4/IPv6 */ struct { - char *name; /* EPC: PCC Rule Name */ - char *id; /* 5GC: PCC Rule Id */ + char *name; /* EPC: PCC Rule Name */ + char *id; /* 5GC: PCC Rule Id */ } pcc_rule; ogs_qos_t qos; /* QoS Infomration */ @@ -193,7 +195,9 @@ typedef struct smf_sess_s { uint64_t smpolicycontrol_features; /* SBI features */ uint32_t smf_n4_teid; /* SMF-N4-TEID is derived from INDEX */ + uint32_t sgw_s5c_teid; /* SGW-S5C-TEID is received from SGW */ + ogs_ip_t sgw_s5c_ip; /* SGW-S5C IPv4/IPv6 */ uint64_t smf_n4_seid; /* SMF SEID is dervied from INDEX */ uint64_t upf_n4_seid; /* UPF SEID is received from Peer */ @@ -206,6 +210,7 @@ typedef struct smf_sess_s { ogs_ip_t gnb_n3_ip; /* gNB-N3 IPv4/IPv6 */ char *gx_sid; /* Gx Session ID */ + char *s6b_sid; /* S6b Session ID */ OGS_POOL(pf_precedence_pool, uint8_t); @@ -237,9 +242,6 @@ typedef struct smf_sess_s { ogs_eps_tai_t e_tai; ogs_e_cgi_t e_cgi; - /* Rat Type */ - OpenAPI_rat_type_e rat_type; - /* NR Location */ ogs_5gs_tai_t nr_tai; ogs_nr_cgi_t nr_cgi; @@ -266,6 +268,10 @@ typedef struct smf_sess_s { ogs_pfcp_ue_ip_t *ipv4; ogs_pfcp_ue_ip_t *ipv6; + /* RAT Type */ + uint8_t gtp_rat_type; + OpenAPI_rat_type_e sbi_rat_type; + struct { ogs_tlv_octet_t ue_pco; ogs_tlv_octet_t user_location_information; @@ -316,6 +322,11 @@ typedef struct smf_sess_s { ogs_ip_t gnb_dl_ip; } handover; + /* Charging */ + struct { + uint32_t id; + } charging; + /* Data Forwarding between the CP and UP functions */ ogs_pfcp_pdr_t *cp2up_pdr; ogs_pfcp_pdr_t *up2cp_pdr; @@ -344,7 +355,7 @@ smf_ue_t *smf_ue_find_by_supi(char *supi); smf_ue_t *smf_ue_find_by_imsi(uint8_t *imsi, int imsi_len); smf_sess_t *smf_sess_add_by_gtp_message(ogs_gtp_message_t *message); -smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn); +smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn, uint8_t rat_type); smf_sess_t *smf_sess_add_by_sbi_message(ogs_sbi_message_t *message); smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi); @@ -360,8 +371,9 @@ void smf_sess_remove_all(smf_ue_t *smf_ue); smf_sess_t *smf_sess_find(uint32_t index); smf_sess_t *smf_sess_find_by_teid(uint32_t teid); smf_sess_t *smf_sess_find_by_seid(uint64_t seid); -smf_sess_t *smf_sess_find_by_apn(smf_ue_t *smf_ue, char *apn); +smf_sess_t *smf_sess_find_by_apn(smf_ue_t *smf_ue, char *apn, uint8_t rat_type); smf_sess_t *smf_sess_find_by_psi(smf_ue_t *smf_ue, uint8_t psi); +smf_sess_t *smf_sess_find_by_charging_id(uint32_t charging_id); smf_sess_t *smf_sess_find_by_sm_context_ref(char *sm_context_ref); smf_sess_t *smf_sess_find_by_ipv4(uint32_t addr); smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6); @@ -394,9 +406,6 @@ smf_bearer_t *smf_bearer_find_by_pcc_rule_name( smf_bearer_t *smf_bearer_find_by_pdr_id( smf_sess_t *sess, ogs_pfcp_pdr_id_t pdr_id); smf_bearer_t *smf_default_bearer_in_sess(smf_sess_t *sess); -bool smf_bearer_is_default(smf_bearer_t *bearer); -smf_bearer_t *smf_bearer_first(smf_sess_t *sess); -smf_bearer_t *smf_bearer_next(smf_bearer_t *bearer); smf_ue_t *smf_ue_cycle(smf_ue_t *smf_ue); smf_sess_t *smf_sess_cycle(smf_sess_t *sess); diff --git a/src/smf/fd-path.c b/src/smf/fd-path.c index d8101a7ba..9e073a94b 100644 --- a/src/smf/fd-path.c +++ b/src/smf/fd-path.c @@ -17,1045 +17,11 @@ * along with this program. If not, see . */ -#include "event.h" #include "fd-path.h" -static struct session_handler *smf_gx_reg = NULL; -static struct disp_hdl *hdl_gx_fb = NULL; -static struct disp_hdl *hdl_gx_rar = NULL; - -struct sess_state { - os0_t gx_sid; /* Gx Session-Id */ - -#define MAX_CC_REQUEST_NUMBER 32 - smf_sess_t *sess; - ogs_gtp_xact_t *xact[MAX_CC_REQUEST_NUMBER]; - - uint32_t cc_request_type; - uint32_t cc_request_number; - - struct timespec ts; /* Time of sending the message */ -}; - -static OGS_POOL(sess_state_pool, struct sess_state); -static ogs_thread_mutex_t sess_state_mutex; - -static int decode_pcc_rule_definition( - ogs_pcc_rule_t *pcc_rule, struct avp *avpch1, int *perror); -static void smf_gx_cca_cb(void *data, struct msg **msg); - -static __inline__ struct sess_state *new_state(os0_t sid) -{ - struct sess_state *new = NULL; - - ogs_thread_mutex_lock(&sess_state_mutex); - ogs_pool_alloc(&sess_state_pool, &new); - ogs_expect_or_return_val(new, NULL); - ogs_thread_mutex_unlock(&sess_state_mutex); - - new->gx_sid = (os0_t)ogs_strdup((char *)sid); - ogs_expect_or_return_val(new->gx_sid, NULL); - - return new; -} - -static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) -{ - if (sess_data->gx_sid) - ogs_free(sess_data->gx_sid); - - ogs_thread_mutex_lock(&sess_state_mutex); - ogs_pool_free(&sess_state_pool, sess_data); - ogs_thread_mutex_unlock(&sess_state_mutex); -} - -void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, - uint32_t cc_request_type) -{ - int ret; - smf_ue_t *smf_ue = NULL; - - struct msg *req = NULL; - struct avp *avp; - struct avp *avpch1, *avpch2; - union avp_value val; - struct sess_state *sess_data = NULL, *svg; - struct session *session = NULL; - int new; - ogs_paa_t paa; /* For changing Framed-IPv6-Prefix Length to 128 */ - - ogs_assert(sess); - ogs_assert(sess->ipv4 || sess->ipv6); - smf_ue = sess->smf_ue; - ogs_assert(smf_ue); - - ogs_debug("[Credit-Control-Request]"); - - /* Create the request */ - ret = fd_msg_new(ogs_diam_gx_cmd_ccr, MSGFL_ALLOC_ETEID, &req); - ogs_assert(ret == 0); - - /* Find Diameter Gx Session */ - if (sess->gx_sid) { - /* Retrieve session by Session-Id */ - size_t sidlen = strlen(sess->gx_sid); - ret = fd_sess_fromsid_msg((os0_t)sess->gx_sid, sidlen, &session, &new); - ogs_assert(ret == 0); - ogs_assert(new == 0); - - ogs_debug(" Found GX Session-Id: [%s]", sess->gx_sid); - - /* Add Session-Id to the message */ - ret = ogs_diam_message_session_id_set(req, (os0_t)sess->gx_sid, sidlen); - ogs_assert(ret == 0); - /* Save the session associated with the message */ - ret = fd_msg_sess_set(req, session); - } else { - /* Create a new session */ - #define OGS_DIAM_GX_APP_SID_OPT "app_gx" - ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_GX_APP_SID_OPT, - CONSTSTRLEN(OGS_DIAM_GX_APP_SID_OPT)); - ogs_assert(ret == 0); - ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL); - ogs_assert(ret == 0); - ogs_debug(" Create a New Session"); - } - - /* Retrieve session state in this session */ - ret = fd_sess_state_retrieve(smf_gx_reg, session, &sess_data); - if (!sess_data) { - os0_t sid; - size_t sidlen; - - ret = fd_sess_getsid(session, &sid, &sidlen); - ogs_assert(ret == 0); - - /* Allocate new session state memory */ - sess_data = new_state(sid); - ogs_assert(sess_data); - - ogs_debug(" Allocate new session: [%s]", sess_data->gx_sid); - - /* Save Session-Id to SMF Session Context */ - sess->gx_sid = (char*)sess_data->gx_sid; - } else - ogs_debug(" Retrieve session: [%s]", sess_data->gx_sid); - - /* - * 8.2. CC-Request-Number AVP - * - * The CC-Request-Number AVP (AVP Code 415) is of type Unsigned32 and - * identifies this request within one session. As Session-Id AVPs are - * globally unique, the combination of Session-Id and CC-Request-Number - * AVPs is also globally unique and can be used in matching credit- - * control messages with confirmations. An easy way to produce unique - * numbers is to set the value to 0 for a credit-control request of type - * INITIAL_REQUEST and EVENT_REQUEST and to set the value to 1 for the - * first UPDATE_REQUEST, to 2 for the second, and so on until the value - * for TERMINATION_REQUEST is one more than for the last UPDATE_REQUEST. - */ - - sess_data->cc_request_type = cc_request_type; - if (cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST || - cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_EVENT_REQUEST) - sess_data->cc_request_number = 0; - else - sess_data->cc_request_number++; - - ogs_debug(" CC Request Type[%d] Number[%d]", - sess_data->cc_request_type, sess_data->cc_request_number); - ogs_assert(sess_data->cc_request_number <= MAX_CC_REQUEST_NUMBER); - - /* Update session state */ - sess_data->sess = sess; - sess_data->xact[sess_data->cc_request_number] = xact; - - /* Set Origin-Host & Origin-Realm */ - ret = fd_msg_add_origin(req, 0); - ogs_assert(ret == 0); - - /* Set the Destination-Realm AVP */ - ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); - val.os.len = strlen(fd_g_config->cnf_diamrlm); - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set the Auth-Application-Id AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_GX_APPLICATION_ID; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set CC-Request-Type, CC-Request-Number */ - ret = fd_msg_avp_new(ogs_diam_gx_cc_request_type, 0, &avp); - ogs_assert(ret == 0); - val.i32 = sess_data->cc_request_type; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_cc_request_number, 0, &avp); - ogs_assert(ret == 0); - val.i32 = sess_data->cc_request_number; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set Subscription-Id */ - ret = fd_msg_avp_new(ogs_diam_gx_subscription_id, 0, &avp); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_subscription_id_type, 0, &avpch1); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_GX_SUBSCRIPTION_ID_TYPE_END_USER_IMSI; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_subscription_id_data, 0, &avpch1); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)smf_ue->imsi_bcd; - val.os.len = strlen(smf_ue->imsi_bcd); - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - if (cc_request_type != OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { - /* Set Supported-Features */ - ret = fd_msg_avp_new(ogs_diam_gx_supported_features, 0, &avp); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_feature_list_id, 0, &avpch1); - ogs_assert(ret == 0); - val.i32 = 1; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_feature_list, 0, &avpch1); - ogs_assert(ret == 0); - val.u32 = 0x0000000b; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set Network-Request-Support */ - ret = fd_msg_avp_new(ogs_diam_gx_network_request_support, 0, &avp); - ogs_assert(ret == 0); - val.i32 = 1; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set Framed-IP-Address */ - if (sess->ipv4) { - ret = fd_msg_avp_new(ogs_diam_gx_framed_ip_address, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t*)&sess->ipv4->addr; - val.os.len = OGS_IPV4_LEN; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - } - - /* Set Framed-IPv6-Prefix */ - if (sess->ipv6) { - ret = fd_msg_avp_new(ogs_diam_gx_framed_ipv6_prefix, 0, &avp); - ogs_assert(ret == 0); - memcpy(&paa, &sess->session.paa, OGS_PAA_IPV6_LEN); -#define FRAMED_IPV6_PREFIX_LENGTH 128 /* from spec document */ - paa.len = FRAMED_IPV6_PREFIX_LENGTH; - val.os.data = (uint8_t*)&paa; - val.os.len = OGS_PAA_IPV6_LEN; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - } - - /* Set IP-Can-Type */ - ret = fd_msg_avp_new(ogs_diam_gx_ip_can_type, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_GX_IP_CAN_TYPE_3GPP_EPS; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set RAT-Type */ - ret = fd_msg_avp_new(ogs_diam_gx_rat_type, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_GX_RAT_TYPE_EUTRAN; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set QoS-Information */ - if (sess->session.ambr.downlink || sess->session.ambr.uplink) { - ret = fd_msg_avp_new(ogs_diam_gx_qos_information, 0, &avp); - ogs_assert(ret == 0); - - if (sess->session.ambr.uplink) { - ret = fd_msg_avp_new(ogs_diam_gx_apn_aggregate_max_bitrate_ul, - 0, &avpch1); - ogs_assert(ret == 0); - val.u32 = sess->session.ambr.uplink; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - } - - if (sess->session.ambr.downlink) { - ret = fd_msg_avp_new( - ogs_diam_gx_apn_aggregate_max_bitrate_dl, 0, &avpch1); - ogs_assert(ret == 0); - val.u32 = sess->session.ambr.downlink; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - } - - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - } - - /* Set Default-EPS-Bearer-QoS */ - ret = fd_msg_avp_new(ogs_diam_gx_default_eps_bearer_qos, 0, &avp); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_qos_class_identifier, 0, &avpch1); - ogs_assert(ret == 0); - val.u32 = sess->session.qos.index; - ret = fd_msg_avp_setvalue (avpch1, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new( - ogs_diam_gx_allocation_retention_priority, 0, &avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_priority_level, 0, &avpch2); - ogs_assert(ret == 0); - val.u32 = sess->session.qos.arp.priority_level; - ret = fd_msg_avp_setvalue (avpch2, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_pre_emption_capability, 0, &avpch2); - ogs_assert(ret == 0); - val.u32 = sess->session.qos.arp.pre_emption_capability; - ret = fd_msg_avp_setvalue (avpch2, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); - ogs_assert(ret == 0); - - ret = fd_msg_avp_new(ogs_diam_gx_pre_emption_vulnerability, 0, &avpch2); - ogs_assert(ret == 0); - val.u32 = sess->session.qos.arp.pre_emption_vulnerability; - ret = fd_msg_avp_setvalue (avpch2, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); - ogs_assert(ret == 0); - - ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); - ogs_assert(ret == 0); - - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set 3GPP-User-Location-Info */ - if (sess->gtp.user_location_information.presence) { - ogs_gtp_uli_t uli; - int16_t uli_len; - - uint8_t uli_buf[OGS_GTP_MAX_ULI_LEN]; - - uli_len = ogs_gtp_parse_uli( - &uli, &sess->gtp.user_location_information); - ogs_assert(sess->gtp.user_location_information.len == uli_len); - - ogs_assert(sess->gtp.user_location_information.data); - ogs_assert(sess->gtp.user_location_information.len); - memcpy(&uli_buf, sess->gtp.user_location_information.data, - sess->gtp.user_location_information.len); - - /* Update Gx ULI Type */ - if (uli.flags.tai && uli.flags.e_cgi) - uli_buf[0] = - OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI; - else if (uli.flags.tai) - uli_buf[0] = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI; - else if (uli.flags.e_cgi) - uli_buf[0] = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_ECGI; - - if (uli_buf[0]) { - ret = fd_msg_avp_new( - ogs_diam_gx_3gpp_user_location_info, 0, &avp); - ogs_assert(ret == 0); - val.os.data = (uint8_t *)&uli_buf; - val.os.len = sess->gtp.user_location_information.len; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - } - } - - /* Set 3GPP-MS-Timezone */ - if (sess->gtp.ue_timezone.presence && - sess->gtp.ue_timezone.len && sess->gtp.ue_timezone.data) { - ret = fd_msg_avp_new(ogs_diam_gx_3gpp_ms_timezone, 0, &avp); - ogs_assert(ret == 0); - val.os.data = sess->gtp.ue_timezone.data; - val.os.len = sess->gtp.ue_timezone.len; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - } - } - - /* Set Called-Station-Id */ - ret = fd_msg_avp_new(ogs_diam_gx_called_station_id, 0, &avp); - ogs_assert(ret == 0); - ogs_assert(sess->session.name); - val.os.data = (uint8_t*)sess->session.name; - val.os.len = strlen(sess->session.name); - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts); - - /* Keep a pointer to the session data for debug purpose, - * in real life we would not need it */ - svg = sess_data; - - /* Store this value in the session */ - ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data == NULL); - - /* Send the request */ - ret = fd_msg_send(&req, smf_gx_cca_cb, svg); - ogs_assert(ret == 0); - - /* Increment the counter */ - ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); - ogs_diam_logger_self()->stats.nb_sent++; - ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); -} - -static void smf_gx_cca_cb(void *data, struct msg **msg) -{ - int rv; - int ret; - - struct sess_state *sess_data = NULL; - struct timespec ts; - struct session *session; - struct avp *avp, *avpch1, *avpch2; - struct avp_hdr *hdr; - unsigned long dur; - int error = 0; - int new; - - smf_event_t *e = NULL; - ogs_gtp_xact_t *xact = NULL; - smf_sess_t *sess = NULL; - ogs_pcc_rule_t *pcc_rule = NULL; - ogs_pkbuf_t *gxbuf = NULL; - ogs_diam_gx_message_t *gx_message = NULL; - uint16_t gxbuf_len = 0; - uint32_t cc_request_number = 0; - - ogs_debug("[Credit-Control-Answer]"); - - ret = clock_gettime(CLOCK_REALTIME, &ts); - ogs_assert(ret == 0); - - /* Search the session, retrieve its data */ - ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); - ogs_assert(ret == 0); - ogs_assert(new == 0); - - ogs_debug(" Search the session"); - - ret = fd_sess_state_retrieve(smf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data); - ogs_assert((void *)sess_data == data); - - ogs_debug(" Retrieve its data: [%s]", sess_data->gx_sid); - - /* Value of CC-Request-Number */ - ret = fd_msg_search_avp(*msg, ogs_diam_gx_cc_request_number, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - cc_request_number = hdr->avp_value->i32; - } else { - ogs_error("no_CC-Request-Number"); - ogs_assert_if_reached(); - } - - ogs_debug(" CC-Request-Number[%d]", cc_request_number); - - xact = sess_data->xact[cc_request_number]; - ogs_assert(xact); - sess = sess_data->sess; - ogs_assert(sess); - - gxbuf_len = sizeof(ogs_diam_gx_message_t); - ogs_assert(gxbuf_len < 8192); - gxbuf = ogs_pkbuf_alloc(NULL, gxbuf_len); - ogs_assert(gxbuf); - ogs_pkbuf_put(gxbuf, gxbuf_len); - gx_message = (ogs_diam_gx_message_t *)gxbuf->data; - ogs_assert(gx_message); - - /* Set Credit Control Command */ - memset(gx_message, 0, gxbuf_len); - gx_message->cmd_code = OGS_DIAM_GX_CMD_CODE_CREDIT_CONTROL; - - /* Value of Result Code */ - ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - gx_message->result_code = hdr->avp_value->i32; - gx_message->err = &gx_message->result_code; - ogs_debug(" Result Code: %d", hdr->avp_value->i32); - } else { - ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_avp_search_avp( - avp, ogs_diam_experimental_result_code, &avpch1); - ogs_assert(ret == 0); - if (avpch1) { - ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - gx_message->result_code = hdr->avp_value->i32; - gx_message->exp_err = &gx_message->result_code; - ogs_debug(" Experimental Result Code: %d", - gx_message->result_code); - } - } else { - ogs_error("no Result-Code"); - error++; - } - } - - /* Value of Origin-Host */ - ret = fd_msg_search_avp(*msg, ogs_diam_origin_host, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - ogs_debug(" From '%.*s'", - (int)hdr->avp_value->os.len, hdr->avp_value->os.data); - } else { - ogs_error("no_Origin-Host"); - error++; - } - - /* Value of Origin-Realm */ - ret = fd_msg_search_avp(*msg, ogs_diam_origin_realm, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - ogs_debug(" ('%.*s')", - (int)hdr->avp_value->os.len, hdr->avp_value->os.data); - } else { - ogs_error("no_Origin-Realm"); - error++; - } - - /* Value of CC-Request-Type */ - ret = fd_msg_search_avp(*msg, ogs_diam_gx_cc_request_type, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - gx_message->cc_request_type = hdr->avp_value->i32; - } else { - ogs_error("no_CC-Request-Type"); - error++; - } - - if (gx_message->result_code != ER_DIAMETER_SUCCESS) { - ogs_warn("ERROR DIAMETER Result Code(%d)", gx_message->result_code); - goto out; - } - - ret = fd_msg_search_avp(*msg, ogs_diam_gx_qos_information, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_avp_search_avp( - avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1); - ogs_assert(ret == 0); - if (avpch1) { - ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - gx_message->session_data.session.ambr.uplink = hdr->avp_value->u32; - } - ret = fd_avp_search_avp( - avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1); - ogs_assert(ret == 0); - if (avpch1) { - ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - gx_message->session_data.session.ambr.downlink = - hdr->avp_value->u32; - } - } - - ret = fd_msg_search_avp(*msg, ogs_diam_gx_default_eps_bearer_qos, &avp); - ogs_assert(ret == 0); - if (avp) { - ret = fd_avp_search_avp(avp, ogs_diam_gx_qos_class_identifier, &avpch1); - ogs_assert(ret == 0); - if (avpch1) { - ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - gx_message->session_data.session.qos.index = hdr->avp_value->u32; - } - - ret = fd_avp_search_avp( - avp, ogs_diam_gx_allocation_retention_priority, &avpch1); - ogs_assert(ret == 0); - if (avpch1) { - ret = fd_avp_search_avp( - avpch1, ogs_diam_gx_priority_level, &avpch2); - ogs_assert(ret == 0); - if (avpch2) { - ret = fd_msg_avp_hdr(avpch2, &hdr); - ogs_assert(ret == 0); - gx_message->session_data.session.qos.arp.priority_level = - hdr->avp_value->u32; - } - - /* - * Ch 7.3.40 Allocation-Retenion-Proirty in TS 29.272 V15.9.0 - * - * If the Pre-emption-Capability AVP is not present in the - * Allocation-Retention-Priority AVP, the default value shall be - * PRE-EMPTION_CAPABILITY_DISABLED (1). - * - * If the Pre-emption-Vulnerability AVP is not present in the - * Allocation-Retention-Priority AVP, the default value shall be - * PRE-EMPTION_VULNERABILITY_ENABLED (0). - * - * However, to easily set up VoLTE service, - * enable Pre-emption Capability/Vulnerablility - * in Default Bearer - */ - ret = fd_avp_search_avp( - avpch1, ogs_diam_gx_pre_emption_capability, &avpch2); - ogs_assert(ret == 0); - if (avpch2) { - ret = fd_msg_avp_hdr(avpch2, &hdr); - ogs_assert(ret == 0); - gx_message->session_data. - session.qos.arp.pre_emption_capability = - hdr->avp_value->u32; - } else { - gx_message->session_data. - session.qos.arp.pre_emption_capability = - OGS_EPC_PRE_EMPTION_DISABLED; - } - - ret = fd_avp_search_avp(avpch1, - ogs_diam_gx_pre_emption_vulnerability, &avpch2); - ogs_assert(ret == 0); - if (avpch2) { - ret = fd_msg_avp_hdr(avpch2, &hdr); - ogs_assert(ret == 0); - gx_message->session_data. - session.qos.arp.pre_emption_vulnerability = - hdr->avp_value->u32; - } else { - gx_message->session_data. - session.qos.arp.pre_emption_vulnerability = - OGS_EPC_PRE_EMPTION_ENABLED; - } - } - } - - ret = fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL); - ogs_assert(ret == 0); - while (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - switch (hdr->avp_code) { - case AC_SESSION_ID: - case AC_ORIGIN_HOST: - case AC_ORIGIN_REALM: - case AC_DESTINATION_REALM: - case AC_RESULT_CODE: - case AC_ROUTE_RECORD: - case AC_PROXY_INFO: - case AC_AUTH_APPLICATION_ID: - break; - case OGS_DIAM_GX_AVP_CODE_CC_REQUEST_TYPE: - case OGS_DIAM_GX_AVP_CODE_CC_REQUEST_NUMBER: - case OGS_DIAM_GX_AVP_CODE_SUPPORTED_FEATURES: - break; - case OGS_DIAM_GX_AVP_CODE_QOS_INFORMATION: - case OGS_DIAM_GX_AVP_CODE_DEFAULT_EPS_BEARER_QOS: - break; - case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_INSTALL: - ret = fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &avpch1, NULL); - ogs_assert(ret == 0); - while (avpch1) { - ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - switch (hdr->avp_code) { - case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_DEFINITION: - pcc_rule = &gx_message->session_data.pcc_rule - [gx_message->session_data.num_of_pcc_rule]; - - rv = decode_pcc_rule_definition(pcc_rule, avpch1, &error); - ogs_assert(rv == OGS_OK); - - pcc_rule->type = OGS_PCC_RULE_TYPE_INSTALL; - gx_message->session_data.num_of_pcc_rule++; - break; - default: - ogs_error("Not supported(%d)", hdr->avp_code); - break; - } - fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL); - } - break; - default: - ogs_warn("Not supported(%d)", hdr->avp_code); - break; - } - fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL); - } - -out: - if (!error) { - e = smf_event_new(SMF_EVT_GX_MESSAGE); - ogs_assert(e); - - e->sess = sess; - e->pkbuf = gxbuf; - e->gtp_xact = xact; - rv = ogs_queue_push(ogs_app()->queue, e); - if (rv != OGS_OK) { - ogs_warn("ogs_queue_push() failed:%d", (int)rv); - ogs_session_data_free(&gx_message->session_data); - ogs_pkbuf_free(e->pkbuf); - smf_event_free(e); - } else { - ogs_pollset_notify(ogs_app()->pollset); - } - } else { - ogs_session_data_free(&gx_message->session_data); - ogs_pkbuf_free(gxbuf); - } - - /* Free the message */ - ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); - dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) + - ((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); - if (ogs_diam_logger_self()->stats.nb_recv) { - /* Ponderate in the avg */ - ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg * - ogs_diam_logger_self()->stats.nb_recv + dur) / - (ogs_diam_logger_self()->stats.nb_recv + 1); - /* Min, max */ - if (dur < ogs_diam_logger_self()->stats.shortest) - ogs_diam_logger_self()->stats.shortest = dur; - if (dur > ogs_diam_logger_self()->stats.longest) - ogs_diam_logger_self()->stats.longest = dur; - } else { - ogs_diam_logger_self()->stats.shortest = dur; - ogs_diam_logger_self()->stats.longest = dur; - ogs_diam_logger_self()->stats.avg = dur; - } - if (error) - ogs_diam_logger_self()->stats.nb_errs++; - else - ogs_diam_logger_self()->stats.nb_recv++; - - ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); - - /* Display how long it took */ - if (ts.tv_nsec > sess_data->ts.tv_nsec) - ogs_trace("in %d.%06ld sec", - (int)(ts.tv_sec - sess_data->ts.tv_sec), - (long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); - else - ogs_trace("in %d.%06ld sec", - (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), - (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); - - ogs_debug(" CC-Request-Type[%d] Number[%d] in Session Data", - sess_data->cc_request_type, sess_data->cc_request_number); - ogs_debug(" Current CC-Request-Number[%d]", cc_request_number); - if (sess_data->cc_request_type == - OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST && - sess_data->cc_request_number <= cc_request_number) { - ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gx_sid); - state_cleanup(sess_data, NULL, NULL); - } else { - ogs_debug(" fd_sess_state_store(): [%s]", sess_data->gx_sid); - ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data == NULL); - } - - ret = fd_msg_free(*msg); - ogs_assert(ret == 0); - *msg = NULL; - - return; -} - -static int smf_gx_fb_cb(struct msg **msg, struct avp *avp, - struct session *sess, void *opaque, enum disp_action *act) -{ - /* This CB should never be called */ - ogs_warn("Unexpected message received!"); - - return ENOTSUP; -} - -static int smf_gx_rar_cb( struct msg **msg, struct avp *avp, - struct session *session, void *opaque, enum disp_action *act) -{ - int rv; - int ret; - - struct msg *ans, *qry; - struct avp *avpch1; - struct avp_hdr *hdr; - union avp_value val; - struct sess_state *sess_data = NULL; - - smf_event_t *e = NULL; - uint16_t gxbuf_len = 0; - ogs_pkbuf_t *gxbuf = NULL; - smf_sess_t *sess = NULL; - ogs_diam_gx_message_t *gx_message = NULL; - ogs_pcc_rule_t *pcc_rule = NULL; - - uint32_t result_code = OGS_DIAM_UNKNOWN_SESSION_ID; - - ogs_assert(msg); - - ogs_debug("Re-Auth-Request"); - - gxbuf_len = sizeof(ogs_diam_gx_message_t); - ogs_assert(gxbuf_len < 8192); - gxbuf = ogs_pkbuf_alloc(NULL, gxbuf_len); - ogs_assert(gxbuf); - ogs_pkbuf_put(gxbuf, gxbuf_len); - gx_message = (ogs_diam_gx_message_t *)gxbuf->data; - ogs_assert(gx_message); - - /* Set Credit Control Command */ - memset(gx_message, 0, gxbuf_len); - gx_message->cmd_code = OGS_DIAM_GX_CMD_RE_AUTH; - - /* Create answer header */ - qry = *msg; - ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0); - ogs_assert(ret == 0); - ans = *msg; - - ret = fd_sess_state_retrieve(smf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); - if (!sess_data) { - ogs_error("No Session Data"); - goto out; - } - - /* Get Session Information */ - sess = sess_data->sess; - ogs_assert(sess); - - ret = fd_msg_browse(qry, MSG_BRW_FIRST_CHILD, &avp, NULL); - ogs_assert(ret == 0); - while (avp) { - ret = fd_msg_avp_hdr(avp, &hdr); - ogs_assert(ret == 0); - switch(hdr->avp_code) { - case AC_SESSION_ID: - case AC_ORIGIN_HOST: - case AC_ORIGIN_REALM: - case AC_DESTINATION_REALM: - case AC_DESTINATION_HOST: - case AC_ROUTE_RECORD: - case AC_PROXY_INFO: - case AC_AUTH_APPLICATION_ID: - break; - case OGS_DIAM_GX_AVP_CODE_RE_AUTH_REQUEST_TYPE: - break; - case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_INSTALL: - ret = fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &avpch1, NULL); - ogs_assert(ret == 0); - while(avpch1) { - ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - switch(hdr->avp_code) { - case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_DEFINITION: - pcc_rule = &gx_message->session_data.pcc_rule - [gx_message->session_data.num_of_pcc_rule]; - - rv = decode_pcc_rule_definition(pcc_rule, avpch1, NULL); - ogs_assert(rv == OGS_OK); - - pcc_rule->type = OGS_PCC_RULE_TYPE_INSTALL; - gx_message->session_data.num_of_pcc_rule++; - break; - default: - ogs_error("Not supported(%d)", hdr->avp_code); - break; - } - fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL); - } - break; - case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_REMOVE: - ret = fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &avpch1, NULL); - ogs_assert(ret == 0); - while (avpch1) { - ret = fd_msg_avp_hdr(avpch1, &hdr); - ogs_assert(ret == 0); - switch (hdr->avp_code) { - case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_NAME: - pcc_rule = &gx_message->session_data.pcc_rule - [gx_message->session_data.num_of_pcc_rule]; - - pcc_rule->name = ogs_strdup((char*)hdr->avp_value->os.data); - ogs_assert(pcc_rule->name); - - pcc_rule->type = OGS_PCC_RULE_TYPE_REMOVE; - gx_message->session_data.num_of_pcc_rule++; - break; - default: - ogs_error("Not supported(%d)", hdr->avp_code); - break; - } - fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL); - } - break; - default: - ogs_warn("Not supported(%d)", hdr->avp_code); - break; - } - fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL); - } - - /* Send Gx Event to SMF State Machine */ - e = smf_event_new(SMF_EVT_GX_MESSAGE); - ogs_assert(e); - - e->sess = sess; - e->pkbuf = gxbuf; - rv = ogs_queue_push(ogs_app()->queue, e); - if (rv != OGS_OK) { - ogs_warn("ogs_queue_push() failed:%d", (int)rv); - ogs_session_data_free(&gx_message->session_data); - ogs_pkbuf_free(e->pkbuf); - smf_event_free(e); - } else { - ogs_pollset_notify(ogs_app()->pollset); - } - - /* Set the Auth-Application-Id AVP */ - ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp); - ogs_assert(ret == 0); - val.i32 = OGS_DIAM_GX_APPLICATION_ID; - ret = fd_msg_avp_setvalue(avp, &val); - ogs_assert(ret == 0); - ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); - - /* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */ - ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); - ogs_assert(ret == 0); - - /* Store this value in the session */ - ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data == NULL); - - /* Send the answer */ - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - ogs_debug("Re-Auth-Answer"); - - /* Add this value to the stats */ - ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); - ogs_diam_logger_self()->stats.nb_echoed++; - ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); - - return 0; - -out: - if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) { - ret = fd_msg_rescode_set(ans, - (char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1); - ogs_assert(ret == 0); - } else { - ret = ogs_diam_message_experimental_rescode_set(ans, result_code); - ogs_assert(ret == 0); - } - - /* Store this value in the session */ - ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); - ogs_assert(ret == 0); - ogs_assert(sess_data == NULL); - - ret = fd_msg_send(msg, NULL, NULL); - ogs_assert(ret == 0); - - ogs_session_data_free(&gx_message->session_data); - ogs_pkbuf_free(gxbuf); - - return 0; -} - int smf_fd_init(void) { - int ret; - struct disp_when data; + int rv; if (smf_self()->diam_conf_path == NULL && (smf_self()->diam_config->cnf_diamid == NULL || @@ -1065,241 +31,28 @@ int smf_fd_init(void) return OGS_OK; } - ogs_thread_mutex_init(&sess_state_mutex); - ogs_pool_init(&sess_state_pool, ogs_app()->pool.sess); - - ret = ogs_diam_init(FD_MODE_CLIENT|FD_MODE_SERVER, + rv = ogs_diam_init(FD_MODE_CLIENT|FD_MODE_SERVER, smf_self()->diam_conf_path, smf_self()->diam_config); - ogs_assert(ret == 0); + ogs_assert(rv == 0); - /* Install objects definitions for this application */ - ret = ogs_diam_gx_init(); - ogs_assert(ret == 0); + rv = smf_gx_init(); + ogs_assert(rv == OGS_OK); - /* Create handler for sessions */ - ret = fd_sess_handler_create(&smf_gx_reg, state_cleanup, NULL, NULL); - ogs_assert(ret == 0); + rv = ogs_diam_rx_init(); + ogs_assert(rv == 0); + rv = smf_s6b_init(); + ogs_assert(rv == OGS_OK); - memset(&data, 0, sizeof(data)); - data.app = ogs_diam_gx_application; - - ret = fd_disp_register(smf_gx_fb_cb, DISP_HOW_APPID, &data, NULL, - &hdl_gx_fb); - ogs_assert(ret == 0); - - data.command = ogs_diam_gx_cmd_rar; - ret = fd_disp_register(smf_gx_rar_cb, DISP_HOW_CC, &data, NULL, - &hdl_gx_rar); - ogs_assert(ret == 0); - - /* Advertise the support for the application in the peer */ - ret = fd_disp_app_support(ogs_diam_gx_application, ogs_diam_vendor, 1, 0); - ogs_assert(ret == 0); + rv = ogs_diam_start(); + ogs_assert(rv == 0); return OGS_OK; } void smf_fd_final(void) { - int ret; - - if (smf_self()->diam_conf_path == NULL && - (smf_self()->diam_config->cnf_diamid == NULL || - smf_self()->diam_config->cnf_diamrlm == NULL || - smf_self()->diam_config->cnf_addr == NULL)) { - return; - } - - ret = fd_sess_handler_destroy(&smf_gx_reg, NULL); - ogs_assert(ret == 0); - - if (hdl_gx_fb) - (void) fd_disp_unregister(&hdl_gx_fb, NULL); - if (hdl_gx_rar) - (void) fd_disp_unregister(&hdl_gx_rar, NULL); + smf_gx_final(); + smf_s6b_final(); ogs_diam_final(); - - ogs_pool_final(&sess_state_pool); - ogs_thread_mutex_destroy(&sess_state_mutex); -} - -static int decode_pcc_rule_definition( - ogs_pcc_rule_t *pcc_rule, struct avp *avpch1, int *perror) -{ - int ret = 0, error = 0; - struct avp *avpch2, *avpch3, *avpch4; - struct avp_hdr *hdr; - - ogs_assert(pcc_rule); - ogs_assert(avpch1); - - ret = fd_msg_browse(avpch1, MSG_BRW_FIRST_CHILD, &avpch2, NULL); - ogs_assert(ret == 0); - while (avpch2) { - ogs_flow_t *flow = NULL; - - ret = fd_msg_avp_hdr(avpch2, &hdr); - ogs_assert(ret == 0); - switch (hdr->avp_code) { - case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_NAME: - if (pcc_rule->name) { - ogs_error("PCC Rule Name has already been defined"); - ogs_free(pcc_rule->name); - } - pcc_rule->name = ogs_strdup((char*)hdr->avp_value->os.data); - ogs_assert(pcc_rule->name); - break; - case OGS_DIAM_GX_AVP_CODE_FLOW_INFORMATION: - flow = &pcc_rule->flow[pcc_rule->num_of_flow]; - - ret = fd_avp_search_avp( - avpch2, ogs_diam_gx_flow_direction, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_msg_avp_hdr( avpch3, &hdr); - ogs_assert(ret == 0); - flow->direction = hdr->avp_value->i32; - } - - ret = fd_avp_search_avp( - avpch2, ogs_diam_gx_flow_description, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_msg_avp_hdr(avpch3, &hdr); - ogs_assert(ret == 0); - flow->description = ogs_malloc(hdr->avp_value->os.len+1); - ogs_assert(flow->description); - ogs_cpystrn(flow->description, - (char*)hdr->avp_value->os.data, - hdr->avp_value->os.len+1); - } - - pcc_rule->num_of_flow++; - break; - case OGS_DIAM_GX_AVP_CODE_FLOW_STATUS: - pcc_rule->flow_status = hdr->avp_value->i32; - break; - case OGS_DIAM_GX_AVP_CODE_QOS_INFORMATION: - ret = fd_avp_search_avp(avpch2, - ogs_diam_gx_qos_class_identifier, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_msg_avp_hdr(avpch3, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.index = hdr->avp_value->u32; - } else { - ogs_error("no_QCI"); - error++; - } - - ret = fd_avp_search_avp(avpch2, - ogs_diam_gx_allocation_retention_priority, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_avp_search_avp( - avpch3, ogs_diam_gx_priority_level, &avpch4); - ogs_assert(ret == 0); - if (avpch4) { - ret = fd_msg_avp_hdr(avpch4, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.arp.priority_level = hdr->avp_value->u32; - } else { - ogs_error("no_Priority-Level"); - error++; - } - - /* - * Ch 7.3.40 Allocation-Retenion-Proirty in TS 29.272 V15.9.0 - * - * If the Pre-emption-Capability AVP is not present in the - * Allocation-Retention-Priority AVP, the default value shall be - * PRE-EMPTION_CAPABILITY_DISABLED (1). - * - * If the Pre-emption-Vulnerability AVP is not present in the - * Allocation-Retention-Priority AVP, the default value shall be - * PRE-EMPTION_VULNERABILITY_ENABLED (0). - * - * However, to easily set up VoLTE service, - * enable Pre-emption Capability/Vulnerablility - * in Default Bearer - */ - ret = fd_avp_search_avp(avpch3, - ogs_diam_gx_pre_emption_capability, &avpch4); - ogs_assert(ret == 0); - if (avpch4) { - ret = fd_msg_avp_hdr(avpch4, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.arp.pre_emption_capability = - hdr->avp_value->u32; - } else { - pcc_rule->qos.arp.pre_emption_capability = - OGS_EPC_PRE_EMPTION_DISABLED; - } - - ret = fd_avp_search_avp(avpch3, - ogs_diam_gx_pre_emption_vulnerability, &avpch4); - ogs_assert(ret == 0); - if (avpch4) { - ret = fd_msg_avp_hdr(avpch4, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.arp.pre_emption_vulnerability = - hdr->avp_value->u32; - } else { - pcc_rule->qos.arp.pre_emption_vulnerability = - OGS_EPC_PRE_EMPTION_ENABLED; - - } - } else { - ogs_error("no_ARP"); - error++; - } - - ret = fd_avp_search_avp(avpch2, - ogs_diam_gx_max_requested_bandwidth_ul, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_msg_avp_hdr(avpch3, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.mbr.uplink = hdr->avp_value->u32; - } - ret = fd_avp_search_avp(avpch2, - ogs_diam_gx_max_requested_bandwidth_dl, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_msg_avp_hdr(avpch3, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.mbr.downlink = hdr->avp_value->u32; - } - ret = fd_avp_search_avp(avpch2, - ogs_diam_gx_guaranteed_bitrate_ul, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_msg_avp_hdr(avpch3, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.gbr.uplink = hdr->avp_value->u32; - } - ret = fd_avp_search_avp(avpch2, - ogs_diam_gx_guaranteed_bitrate_dl, &avpch3); - ogs_assert(ret == 0); - if (avpch3) { - ret = fd_msg_avp_hdr(avpch3, &hdr); - ogs_assert(ret == 0); - pcc_rule->qos.gbr.downlink = hdr->avp_value->u32; - } - break; - case OGS_DIAM_GX_AVP_CODE_PRECEDENCE: - pcc_rule->precedence = hdr->avp_value->i32; - break; - default: - ogs_error("Not implemented(%d)", hdr->avp_code); - break; - } - fd_msg_browse(avpch2, MSG_BRW_NEXT, &avpch2, NULL); - } - - if (perror) - *perror = error; - - return OGS_OK; } diff --git a/src/smf/fd-path.h b/src/smf/fd-path.h index 0f5000e64..77c810458 100644 --- a/src/smf/fd-path.h +++ b/src/smf/fd-path.h @@ -31,9 +31,17 @@ typedef struct gtp_xact_s gtp_xact_t; int smf_fd_init(void); void smf_fd_final(void); +int smf_gx_init(void); +void smf_gx_final(void); +int smf_s6b_init(void); +void smf_s6b_final(void); + void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, uint32_t cc_request_type); +void smf_s6b_send_aar(smf_sess_t *sess, ogs_gtp_xact_t *xact); +void smf_s6b_send_str(smf_sess_t *sess, ogs_gtp_xact_t *xact, uint32_t cause); + #ifdef __cplusplus } #endif diff --git a/src/smf/gtp-path.c b/src/smf/gtp-path.c index b0a8bd623..895da1970 100644 --- a/src/smf/gtp-path.c +++ b/src/smf/gtp-path.c @@ -37,11 +37,14 @@ #include "event.h" #include "gtp-path.h" +#include "pfcp-path.h" #include "s5c-build.h" static bool check_if_router_solicit(ogs_pkbuf_t *pkbuf); static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst); +static void bearer_timeout(ogs_gtp_xact_t *xact, void *data); + static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data) { smf_event_t *e = NULL; @@ -326,6 +329,39 @@ int smf_gtp_send_delete_session_response( return rv; } +int smf_gtp_send_delete_bearer_request( + smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value) +{ + int rv; + + ogs_gtp_xact_t *xact = NULL; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + + smf_sess_t *sess = NULL; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_DELETE_BEARER_REQUEST_TYPE; + h.teid = sess->sgw_s5c_teid; + + pkbuf = smf_s5c_build_delete_bearer_request( + h.type, bearer, pti, cause_value); + ogs_expect_or_return_val(pkbuf, OGS_ERROR); + + xact = ogs_gtp_xact_local_create( + sess->gnode, &h, pkbuf, bearer_timeout, bearer); + ogs_expect_or_return_val(xact, OGS_ERROR); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + static bool check_if_router_solicit(ogs_pkbuf_t *pkbuf) { struct ip *ip_h = NULL; @@ -448,3 +484,37 @@ static void send_router_advertisement(smf_sess_t *sess, uint8_t *ip6_dst) ogs_pkbuf_free(pkbuf); } + +static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) +{ + smf_bearer_t *bearer = data; + smf_sess_t *sess = NULL; + smf_ue_t *smf_ue = NULL; + uint8_t type = 0; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + type = xact->seq[0].type; + + switch (type) { + case OGS_GTP_DELETE_BEARER_REQUEST_TYPE: + ogs_error("[%s] No Delete Bearer Response", smf_ue->imsi_bcd); + if (!smf_bearer_cycle(bearer)) { + ogs_warn("[%s] Bearer has already been removed", smf_ue->imsi_bcd); + break; + } + + ogs_assert(OGS_OK == + smf_epc_pfcp_send_bearer_modification_request( + bearer, OGS_PFCP_MODIFY_REMOVE)); + break; + default: + ogs_error("GTP Timeout : IMSI[%s] Message-Type[%d]", + smf_ue->imsi_bcd, type); + break; + } +} diff --git a/src/smf/gtp-path.h b/src/smf/gtp-path.h index f1740b545..f91046277 100644 --- a/src/smf/gtp-path.h +++ b/src/smf/gtp-path.h @@ -34,6 +34,9 @@ int smf_gtp_send_create_session_response( int smf_gtp_send_delete_session_response( smf_sess_t *sess, ogs_gtp_xact_t *xact); +int smf_gtp_send_delete_bearer_request( + smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value); + #ifdef __cplusplus } #endif diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index 250e35593..53acc8af1 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -283,6 +283,12 @@ void smf_gx_handle_cca_termination_request( ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); + /* + * << 'gtp_xact' is NOT NULL >> + * + * 1. MME sends Delete Session Request to SGW/SMF. + * 2. SMF sends Delete Session Response to SGW/MME. + */ ogs_assert(OGS_OK == smf_epc_pfcp_send_session_deletion_request(sess, gtp_xact)); } diff --git a/src/smf/gx-path.c b/src/smf/gx-path.c new file mode 100644 index 000000000..7fb69e83f --- /dev/null +++ b/src/smf/gx-path.c @@ -0,0 +1,1420 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "fd-path.h" + +static struct session_handler *smf_gx_reg = NULL; +static struct disp_hdl *hdl_gx_fb = NULL; +static struct disp_hdl *hdl_gx_rar = NULL; + +struct sess_state { + os0_t gx_sid; /* Gx Session-Id */ + +#define MAX_CC_REQUEST_NUMBER 32 + smf_sess_t *sess; + ogs_gtp_xact_t *xact[MAX_CC_REQUEST_NUMBER]; + + uint32_t cc_request_type; + uint32_t cc_request_number; + + struct timespec ts; /* Time of sending the message */ +}; + +static OGS_POOL(sess_state_pool, struct sess_state); +static ogs_thread_mutex_t sess_state_mutex; + +static int decode_pcc_rule_definition( + ogs_pcc_rule_t *pcc_rule, struct avp *avpch1, int *perror); +static void smf_gx_cca_cb(void *data, struct msg **msg); + +static __inline__ struct sess_state *new_state(os0_t sid) +{ + struct sess_state *new = NULL; + + ogs_thread_mutex_lock(&sess_state_mutex); + ogs_pool_alloc(&sess_state_pool, &new); + ogs_expect_or_return_val(new, NULL); + ogs_thread_mutex_unlock(&sess_state_mutex); + + new->gx_sid = (os0_t)ogs_strdup((char *)sid); + ogs_expect_or_return_val(new->gx_sid, NULL); + + return new; +} + +static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) +{ + if (sess_data->gx_sid) + ogs_free(sess_data->gx_sid); + + ogs_thread_mutex_lock(&sess_state_mutex); + ogs_pool_free(&sess_state_pool, sess_data); + ogs_thread_mutex_unlock(&sess_state_mutex); +} + +void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, + uint32_t cc_request_type) +{ + int ret; + smf_ue_t *smf_ue = NULL; + + struct msg *req = NULL; + struct avp *avp; + struct avp *avpch1, *avpch2; + union avp_value val; + struct sess_state *sess_data = NULL, *svg; + struct session *session = NULL; + int new; + ogs_paa_t paa; /* For changing Framed-IPv6-Prefix Length to 128 */ + char buf[OGS_PLMNIDSTRLEN]; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + uint32_t charing_id; + + ogs_assert(xact); + ogs_assert(sess); + + ogs_assert(sess->ipv4 || sess->ipv6); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + ogs_debug("[Credit-Control-Request]"); + + /* Create the request */ + ret = fd_msg_new(ogs_diam_gx_cmd_ccr, MSGFL_ALLOC_ETEID, &req); + ogs_assert(ret == 0); + + /* Find Diameter Gx Session */ + if (sess->gx_sid) { + /* Retrieve session by Session-Id */ + size_t sidlen = strlen(sess->gx_sid); + ret = fd_sess_fromsid_msg((os0_t)sess->gx_sid, sidlen, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + ogs_debug(" Found GX Session-Id: [%s]", sess->gx_sid); + + /* Add Session-Id to the message */ + ret = ogs_diam_message_session_id_set(req, (os0_t)sess->gx_sid, sidlen); + ogs_assert(ret == 0); + /* Save the session associated with the message */ + ret = fd_msg_sess_set(req, session); + } else { + /* Create a new session */ + #define OGS_DIAM_GX_APP_SID_OPT "app_gx" + ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_GX_APP_SID_OPT, + CONSTSTRLEN(OGS_DIAM_GX_APP_SID_OPT)); + ogs_assert(ret == 0); + ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL); + ogs_assert(ret == 0); + ogs_debug(" Create a New Session"); + } + + /* Retrieve session state in this session */ + ret = fd_sess_state_retrieve(smf_gx_reg, session, &sess_data); + if (!sess_data) { + os0_t sid; + size_t sidlen; + + ret = fd_sess_getsid(session, &sid, &sidlen); + ogs_assert(ret == 0); + + /* Allocate new session state memory */ + sess_data = new_state(sid); + ogs_assert(sess_data); + + ogs_debug(" Allocate new session: [%s]", sess_data->gx_sid); + + /* Save Session-Id to SMF Session Context */ + sess->gx_sid = (char *)sess_data->gx_sid; + } else + ogs_debug(" Retrieve session: [%s]", sess_data->gx_sid); + + /* + * 8.2. CC-Request-Number AVP + * + * The CC-Request-Number AVP (AVP Code 415) is of type Unsigned32 and + * identifies this request within one session. As Session-Id AVPs are + * globally unique, the combination of Session-Id and CC-Request-Number + * AVPs is also globally unique and can be used in matching credit- + * control messages with confirmations. An easy way to produce unique + * numbers is to set the value to 0 for a credit-control request of type + * INITIAL_REQUEST and EVENT_REQUEST and to set the value to 1 for the + * first UPDATE_REQUEST, to 2 for the second, and so on until the value + * for TERMINATION_REQUEST is one more than for the last UPDATE_REQUEST. + */ + + sess_data->cc_request_type = cc_request_type; + if (cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST || + cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_EVENT_REQUEST) + sess_data->cc_request_number = 0; + else + sess_data->cc_request_number++; + + ogs_debug(" CC Request Type[%d] Number[%d]", + sess_data->cc_request_type, sess_data->cc_request_number); + ogs_assert(sess_data->cc_request_number <= MAX_CC_REQUEST_NUMBER); + + /* Update session state */ + sess_data->sess = sess; + sess_data->xact[sess_data->cc_request_number] = xact; + + /* Set Origin-Host & Origin-Realm */ + ret = fd_msg_add_origin(req, 0); + ogs_assert(ret == 0); + + /* Set the Destination-Realm AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); + val.os.len = strlen(fd_g_config->cnf_diamrlm); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Auth-Application-Id AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_GX_APPLICATION_ID; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set CC-Request-Type, CC-Request-Number */ + ret = fd_msg_avp_new(ogs_diam_gx_cc_request_type, 0, &avp); + ogs_assert(ret == 0); + val.i32 = sess_data->cc_request_type; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_cc_request_number, 0, &avp); + ogs_assert(ret == 0); + val.i32 = sess_data->cc_request_number; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Subscription-Id */ + ret = fd_msg_avp_new(ogs_diam_subscription_id, 0, &avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_subscription_id_type, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_SUBSCRIPTION_ID_TYPE_END_USER_IMSI; + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_subscription_id_data, 0, &avpch1); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)smf_ue->imsi_bcd; + val.os.len = strlen(smf_ue->imsi_bcd); + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + if (cc_request_type != OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { + /* Set Supported-Features */ + ret = fd_msg_avp_new(ogs_diam_gx_supported_features, 0, &avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_feature_list_id, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 1; + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_feature_list, 0, &avpch1); + ogs_assert(ret == 0); + val.u32 = 0x0000000b; + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Network-Request-Support */ + ret = fd_msg_avp_new(ogs_diam_gx_network_request_support, 0, &avp); + ogs_assert(ret == 0); + val.i32 = 1; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Framed-IP-Address */ + if (sess->ipv4) { + ret = fd_msg_avp_new(ogs_diam_gx_framed_ip_address, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t*)&sess->ipv4->addr; + val.os.len = OGS_IPV4_LEN; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + /* Set Framed-IPv6-Prefix */ + if (sess->ipv6) { + ret = fd_msg_avp_new(ogs_diam_gx_framed_ipv6_prefix, 0, &avp); + ogs_assert(ret == 0); + memcpy(&paa, &sess->session.paa, OGS_PAA_IPV6_LEN); +#define FRAMED_IPV6_PREFIX_LENGTH 128 /* from spec document */ + paa.len = FRAMED_IPV6_PREFIX_LENGTH; + val.os.data = (uint8_t*)&paa; + val.os.len = OGS_PAA_IPV6_LEN; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + /* Set IP-Can-Type */ + ret = fd_msg_avp_new(ogs_diam_gx_ip_can_type, 0, &avp); + ogs_assert(ret == 0); + + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + val.i32 = OGS_DIAM_GX_IP_CAN_TYPE_3GPP_EPS; + break; + case OGS_GTP_RAT_TYPE_WLAN: + val.i32 = OGS_DIAM_GX_IP_CAN_TYPE_NON_3GPP_EPS; + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } + + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set RAT-Type */ + ret = fd_msg_avp_new(ogs_diam_rat_type, 0, &avp); + ogs_assert(ret == 0); + + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + val.i32 = OGS_DIAM_RAT_TYPE_EUTRAN; + break; + case OGS_GTP_RAT_TYPE_WLAN: + val.i32 = OGS_DIAM_RAT_TYPE_WLAN; + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } + + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set QoS-Information */ + if (sess->session.ambr.downlink || sess->session.ambr.uplink) { + ret = fd_msg_avp_new(ogs_diam_gx_qos_information, 0, &avp); + ogs_assert(ret == 0); + + if (sess->session.ambr.uplink) { + ret = fd_msg_avp_new(ogs_diam_gx_apn_aggregate_max_bitrate_ul, + 0, &avpch1); + ogs_assert(ret == 0); + val.u32 = sess->session.ambr.uplink; + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + } + + if (sess->session.ambr.downlink) { + ret = fd_msg_avp_new( + ogs_diam_gx_apn_aggregate_max_bitrate_dl, 0, &avpch1); + ogs_assert(ret == 0); + val.u32 = sess->session.ambr.downlink; + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + } + + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + /* Set Default-EPS-Bearer-QoS */ + ret = fd_msg_avp_new(ogs_diam_gx_default_eps_bearer_qos, 0, &avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_qos_class_identifier, 0, &avpch1); + ogs_assert(ret == 0); + val.u32 = sess->session.qos.index; + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new( + ogs_diam_gx_allocation_retention_priority, 0, &avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_priority_level, 0, &avpch2); + ogs_assert(ret == 0); + val.u32 = sess->session.qos.arp.priority_level; + ret = fd_msg_avp_setvalue (avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_pre_emption_capability, 0, &avpch2); + ogs_assert(ret == 0); + val.u32 = sess->session.qos.arp.pre_emption_capability; + ret = fd_msg_avp_setvalue (avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_pre_emption_vulnerability, 0, &avpch2); + ogs_assert(ret == 0); + val.u32 = sess->session.qos.arp.pre_emption_vulnerability; + ret = fd_msg_avp_setvalue (avpch2, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avpch1, MSG_BRW_LAST_CHILD, avpch2); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set 3GPP-User-Location-Info */ + if (sess->gtp.user_location_information.presence) { + ogs_gtp_uli_t uli; + int16_t uli_len; + + uint8_t uli_buf[OGS_GTP_MAX_ULI_LEN]; + + uli_len = ogs_gtp_parse_uli( + &uli, &sess->gtp.user_location_information); + ogs_assert(sess->gtp.user_location_information.len == uli_len); + + ogs_assert(sess->gtp.user_location_information.data); + ogs_assert(sess->gtp.user_location_information.len); + memcpy(&uli_buf, sess->gtp.user_location_information.data, + sess->gtp.user_location_information.len); + + /* Update Gx ULI Type */ + if (uli.flags.tai && uli.flags.e_cgi) + uli_buf[0] = + OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI; + else if (uli.flags.tai) + uli_buf[0] = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI; + else if (uli.flags.e_cgi) + uli_buf[0] = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_ECGI; + + if (uli_buf[0]) { + ret = fd_msg_avp_new( + ogs_diam_gx_3gpp_user_location_info, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)&uli_buf; + val.os.len = sess->gtp.user_location_information.len; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + } + + /* Set 3GPP-MS-Timezone */ + if (sess->gtp.ue_timezone.presence && + sess->gtp.ue_timezone.len && sess->gtp.ue_timezone.data) { + ret = fd_msg_avp_new(ogs_diam_gx_3gpp_ms_timezone, 0, &avp); + ogs_assert(ret == 0); + val.os.data = sess->gtp.ue_timezone.data; + val.os.len = sess->gtp.ue_timezone.len; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + /* Set 3GPP-SGSN-MCC-MNC */ + ret = fd_msg_avp_new(ogs_diam_gx_3gpp_sgsn_mcc_mnc, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)ogs_plmn_id_to_string(&sess->plmn_id, buf); + val.os.len = strlen(buf); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set AN-GW-Address - Upto 2 address */ + if (sess->sgw_s5c_ip.ipv4) { + ret = fd_msg_avp_new(ogs_diam_gx_an_gw_address, 0, &avp); + ogs_assert(ret == 0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = sess->sgw_s5c_ip.addr; + ret = fd_msg_avp_value_encode(&sin, avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + if (sess->sgw_s5c_ip.ipv6) { + ret = fd_msg_avp_new(ogs_diam_gx_an_gw_address, 0, &avp); + ogs_assert(ret == 0); + sin6.sin6_family = AF_INET6; + memcpy(sin6.sin6_addr.s6_addr, + sess->sgw_s5c_ip.addr6, OGS_IPV6_LEN); + ret = fd_msg_avp_value_encode(&sin6, avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + } + + /* Set Called-Station-Id */ + ret = fd_msg_avp_new(ogs_diam_gx_called_station_id, 0, &avp); + ogs_assert(ret == 0); + ogs_assert(sess->session.name); + val.os.data = (uint8_t*)sess->session.name; + val.os.len = strlen(sess->session.name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + if (cc_request_type != OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { + /* Set Online to DISABLE */ + ret = fd_msg_avp_new(ogs_diam_gx_online, 0, &avp); + ogs_assert(ret == 0); + val.u32 = OGS_DIAM_GX_DISABLE_ONLINE; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Offline to ENABLE */ + ret = fd_msg_avp_new(ogs_diam_gx_offline, 0, &avp); + ogs_assert(ret == 0); + val.u32 = OGS_DIAM_GX_ENABLE_OFFLINE; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Access-Network-Charging-Address - Only 1 address */ + if (ogs_gtp_self()->gtpc_addr) { + ret = fd_msg_avp_new( + ogs_diam_gx_access_network_charging_address, 0, &avp); + ogs_assert(ret == 0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = + ogs_gtp_self()->gtpc_addr->sin.sin_addr.s_addr; + ret = fd_msg_avp_value_encode(&sin, avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } else if (ogs_gtp_self()->gtpc_addr6) { + ret = fd_msg_avp_new( + ogs_diam_gx_access_network_charging_address, 0, &avp); + ogs_assert(ret == 0); + sin6.sin6_family = AF_INET6; + memcpy(sin6.sin6_addr.s6_addr, + ogs_gtp_self()->gtpc_addr6->sin6.sin6_addr.s6_addr, + OGS_IPV6_LEN); + ret = fd_msg_avp_value_encode(&sin6, avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + /* Set Access-Network-Charging-Identitifer-Gx */ + ret = fd_msg_avp_new( + ogs_diam_gx_access_network_charging_identifier_gx, 0, &avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new( + ogs_diam_gx_access_network_charging_identifier_value, 0, + &avpch1); + ogs_assert(ret == 0); + charing_id = htobe32(sess->charging.id); + val.os.data = (uint8_t *)&charing_id; + val.os.len = sizeof(charing_id); + ret = fd_msg_avp_setvalue (avpch1, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_gx_an_trusted, 0, &avp); + ogs_assert(ret == 0); + val.u32 = OGS_DIAM_GX_AN_UNTRUSTED; + ret = fd_msg_avp_setvalue (avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts); + + /* Keep a pointer to the session data for debug purpose, + * in real life we would not need it */ + svg = sess_data; + + /* Store this value in the session */ + ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the request */ + ret = fd_msg_send(&req, smf_gx_cca_cb, svg); + ogs_assert(ret == 0); + + /* Increment the counter */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_sent++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); +} + +static void smf_gx_cca_cb(void *data, struct msg **msg) +{ + int rv; + int ret; + + struct sess_state *sess_data = NULL; + struct timespec ts; + struct session *session; + struct avp *avp, *avpch1, *avpch2; + struct avp_hdr *hdr; + unsigned long dur; + int error = 0; + int new; + + smf_event_t *e = NULL; + ogs_gtp_xact_t *xact = NULL; + smf_sess_t *sess = NULL; + ogs_pcc_rule_t *pcc_rule = NULL; + ogs_pkbuf_t *gxbuf = NULL; + ogs_diam_gx_message_t *gx_message = NULL; + uint16_t gxbuf_len = 0; + uint32_t cc_request_number = 0; + + ogs_debug("[Credit-Control-Answer]"); + + ret = clock_gettime(CLOCK_REALTIME, &ts); + ogs_assert(ret == 0); + + /* Search the session, retrieve its data */ + ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + ogs_debug(" Search the session"); + + ret = fd_sess_state_retrieve(smf_gx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data); + ogs_assert((void *)sess_data == data); + + ogs_debug(" Retrieve its data: [%s]", sess_data->gx_sid); + + /* Value of CC-Request-Number */ + ret = fd_msg_search_avp(*msg, ogs_diam_gx_cc_request_number, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + cc_request_number = hdr->avp_value->i32; + } else { + ogs_error("no_CC-Request-Number"); + ogs_assert_if_reached(); + } + + ogs_debug(" CC-Request-Number[%d]", cc_request_number); + + xact = sess_data->xact[cc_request_number]; + ogs_assert(xact); + sess = sess_data->sess; + ogs_assert(sess); + + gxbuf_len = sizeof(ogs_diam_gx_message_t); + ogs_assert(gxbuf_len < 8192); + gxbuf = ogs_pkbuf_alloc(NULL, gxbuf_len); + ogs_assert(gxbuf); + ogs_pkbuf_put(gxbuf, gxbuf_len); + gx_message = (ogs_diam_gx_message_t *)gxbuf->data; + ogs_assert(gx_message); + + /* Set Credit Control Command */ + memset(gx_message, 0, gxbuf_len); + gx_message->cmd_code = OGS_DIAM_GX_CMD_CODE_CREDIT_CONTROL; + + /* Value of Result Code */ + ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + gx_message->result_code = hdr->avp_value->i32; + gx_message->err = &gx_message->result_code; + ogs_debug(" Result Code: %d", hdr->avp_value->i32); + } else { + ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp( + avp, ogs_diam_experimental_result_code, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + gx_message->result_code = hdr->avp_value->i32; + gx_message->exp_err = &gx_message->result_code; + ogs_debug(" Experimental Result Code: %d", + gx_message->result_code); + } + } else { + ogs_error("no Result-Code"); + error++; + } + } + + /* Value of Origin-Host */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_host, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug(" From '%.*s'", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Host"); + error++; + } + + /* Value of Origin-Realm */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_realm, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug(" ('%.*s')", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Realm"); + error++; + } + + /* Value of CC-Request-Type */ + ret = fd_msg_search_avp(*msg, ogs_diam_gx_cc_request_type, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + gx_message->cc_request_type = hdr->avp_value->i32; + } else { + ogs_error("no_CC-Request-Type"); + error++; + } + + if (gx_message->result_code != ER_DIAMETER_SUCCESS) { + ogs_warn("ERROR DIAMETER Result Code(%d)", gx_message->result_code); + goto out; + } + + ret = fd_msg_search_avp(*msg, ogs_diam_gx_qos_information, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp( + avp, ogs_diam_gx_apn_aggregate_max_bitrate_ul, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + gx_message->session_data.session.ambr.uplink = hdr->avp_value->u32; + } + ret = fd_avp_search_avp( + avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + gx_message->session_data.session.ambr.downlink = + hdr->avp_value->u32; + } + } + + ret = fd_msg_search_avp(*msg, ogs_diam_gx_default_eps_bearer_qos, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp(avp, ogs_diam_gx_qos_class_identifier, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + gx_message->session_data.session.qos.index = hdr->avp_value->u32; + } + + ret = fd_avp_search_avp( + avp, ogs_diam_gx_allocation_retention_priority, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_avp_search_avp( + avpch1, ogs_diam_gx_priority_level, &avpch2); + ogs_assert(ret == 0); + if (avpch2) { + ret = fd_msg_avp_hdr(avpch2, &hdr); + ogs_assert(ret == 0); + gx_message->session_data.session.qos.arp.priority_level = + hdr->avp_value->u32; + } + + /* + * Ch 7.3.40 Allocation-Retenion-Proirty in TS 29.272 V15.9.0 + * + * If the Pre-emption-Capability AVP is not present in the + * Allocation-Retention-Priority AVP, the default value shall be + * PRE-EMPTION_CAPABILITY_DISABLED (1). + * + * If the Pre-emption-Vulnerability AVP is not present in the + * Allocation-Retention-Priority AVP, the default value shall be + * PRE-EMPTION_VULNERABILITY_ENABLED (0). + * + * However, to easily set up VoLTE service, + * enable Pre-emption Capability/Vulnerablility + * in Default Bearer + */ + ret = fd_avp_search_avp( + avpch1, ogs_diam_gx_pre_emption_capability, &avpch2); + ogs_assert(ret == 0); + if (avpch2) { + ret = fd_msg_avp_hdr(avpch2, &hdr); + ogs_assert(ret == 0); + gx_message->session_data. + session.qos.arp.pre_emption_capability = + hdr->avp_value->u32; + } else { + gx_message->session_data. + session.qos.arp.pre_emption_capability = + OGS_EPC_PRE_EMPTION_DISABLED; + } + + ret = fd_avp_search_avp(avpch1, + ogs_diam_gx_pre_emption_vulnerability, &avpch2); + ogs_assert(ret == 0); + if (avpch2) { + ret = fd_msg_avp_hdr(avpch2, &hdr); + ogs_assert(ret == 0); + gx_message->session_data. + session.qos.arp.pre_emption_vulnerability = + hdr->avp_value->u32; + } else { + gx_message->session_data. + session.qos.arp.pre_emption_vulnerability = + OGS_EPC_PRE_EMPTION_ENABLED; + } + } + } + + ret = fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL); + ogs_assert(ret == 0); + while (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + switch (hdr->avp_code) { + case AC_SESSION_ID: + case AC_ORIGIN_HOST: + case AC_ORIGIN_REALM: + case AC_DESTINATION_REALM: + case AC_RESULT_CODE: + case AC_ROUTE_RECORD: + case AC_PROXY_INFO: + case AC_AUTH_APPLICATION_ID: + break; + case OGS_DIAM_GX_AVP_CODE_CC_REQUEST_TYPE: + case OGS_DIAM_GX_AVP_CODE_CC_REQUEST_NUMBER: + case OGS_DIAM_GX_AVP_CODE_SUPPORTED_FEATURES: + break; + case OGS_DIAM_GX_AVP_CODE_QOS_INFORMATION: + case OGS_DIAM_GX_AVP_CODE_DEFAULT_EPS_BEARER_QOS: + break; + case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_INSTALL: + ret = fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &avpch1, NULL); + ogs_assert(ret == 0); + while (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + switch (hdr->avp_code) { + case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_DEFINITION: + pcc_rule = &gx_message->session_data.pcc_rule + [gx_message->session_data.num_of_pcc_rule]; + + rv = decode_pcc_rule_definition(pcc_rule, avpch1, &error); + ogs_assert(rv == OGS_OK); + + pcc_rule->type = OGS_PCC_RULE_TYPE_INSTALL; + gx_message->session_data.num_of_pcc_rule++; + break; + default: + ogs_error("Not supported(%d)", hdr->avp_code); + break; + } + fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL); + } + break; + default: + ogs_warn("Not supported(%d)", hdr->avp_code); + break; + } + fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL); + } + +out: + if (!error) { + e = smf_event_new(SMF_EVT_GX_MESSAGE); + ogs_assert(e); + + e->sess = sess; + e->pkbuf = gxbuf; + e->gtp_xact = xact; + rv = ogs_queue_push(ogs_app()->queue, e); + if (rv != OGS_OK) { + ogs_warn("ogs_queue_push() failed:%d", (int)rv); + ogs_session_data_free(&gx_message->session_data); + ogs_pkbuf_free(e->pkbuf); + smf_event_free(e); + } else { + ogs_pollset_notify(ogs_app()->pollset); + } + } else { + ogs_session_data_free(&gx_message->session_data); + ogs_pkbuf_free(gxbuf); + } + + /* Free the message */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) + + ((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + if (ogs_diam_logger_self()->stats.nb_recv) { + /* Ponderate in the avg */ + ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg * + ogs_diam_logger_self()->stats.nb_recv + dur) / + (ogs_diam_logger_self()->stats.nb_recv + 1); + /* Min, max */ + if (dur < ogs_diam_logger_self()->stats.shortest) + ogs_diam_logger_self()->stats.shortest = dur; + if (dur > ogs_diam_logger_self()->stats.longest) + ogs_diam_logger_self()->stats.longest = dur; + } else { + ogs_diam_logger_self()->stats.shortest = dur; + ogs_diam_logger_self()->stats.longest = dur; + ogs_diam_logger_self()->stats.avg = dur; + } + if (error) + ogs_diam_logger_self()->stats.nb_errs++; + else + ogs_diam_logger_self()->stats.nb_recv++; + + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + /* Display how long it took */ + if (ts.tv_nsec > sess_data->ts.tv_nsec) + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec - sess_data->ts.tv_sec), + (long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + else + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), + (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + + ogs_debug(" CC-Request-Type[%d] Number[%d] in Session Data", + sess_data->cc_request_type, sess_data->cc_request_number); + ogs_debug(" Current CC-Request-Number[%d]", cc_request_number); + if (sess_data->cc_request_type == + OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST && + sess_data->cc_request_number <= cc_request_number) { + ogs_debug(" [LAST] state_cleanup(): [%s]", sess_data->gx_sid); + state_cleanup(sess_data, NULL, NULL); + } else { + ogs_debug(" fd_sess_state_store(): [%s]", sess_data->gx_sid); + ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + } + + ret = fd_msg_free(*msg); + ogs_assert(ret == 0); + *msg = NULL; + + return; +} + +static int smf_gx_fb_cb(struct msg **msg, struct avp *avp, + struct session *sess, void *opaque, enum disp_action *act) +{ + /* This CB should never be called */ + ogs_warn("Unexpected message received!"); + + return ENOTSUP; +} + +static int smf_gx_rar_cb( struct msg **msg, struct avp *avp, + struct session *session, void *opaque, enum disp_action *act) +{ + int rv; + int ret; + + struct msg *ans, *qry; + struct avp *avpch1; + struct avp_hdr *hdr; + union avp_value val; + struct sess_state *sess_data = NULL; + + smf_event_t *e = NULL; + uint16_t gxbuf_len = 0; + ogs_pkbuf_t *gxbuf = NULL; + smf_sess_t *sess = NULL; + ogs_diam_gx_message_t *gx_message = NULL; + ogs_pcc_rule_t *pcc_rule = NULL; + + uint32_t result_code = OGS_DIAM_UNKNOWN_SESSION_ID; + + ogs_assert(msg); + + ogs_debug("Re-Auth-Request"); + + gxbuf_len = sizeof(ogs_diam_gx_message_t); + ogs_assert(gxbuf_len < 8192); + gxbuf = ogs_pkbuf_alloc(NULL, gxbuf_len); + ogs_assert(gxbuf); + ogs_pkbuf_put(gxbuf, gxbuf_len); + gx_message = (ogs_diam_gx_message_t *)gxbuf->data; + ogs_assert(gx_message); + + /* Set Credit Control Command */ + memset(gx_message, 0, gxbuf_len); + gx_message->cmd_code = OGS_DIAM_GX_CMD_RE_AUTH; + + /* Create answer header */ + qry = *msg; + ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0); + ogs_assert(ret == 0); + ans = *msg; + + ret = fd_sess_state_retrieve(smf_gx_reg, session, &sess_data); + ogs_assert(ret == 0); + if (!sess_data) { + ogs_error("No Session Data"); + goto out; + } + + /* Get Session Information */ + sess = sess_data->sess; + ogs_assert(sess); + + ret = fd_msg_browse(qry, MSG_BRW_FIRST_CHILD, &avp, NULL); + ogs_assert(ret == 0); + while (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + switch(hdr->avp_code) { + case AC_SESSION_ID: + case AC_ORIGIN_HOST: + case AC_ORIGIN_REALM: + case AC_DESTINATION_REALM: + case AC_DESTINATION_HOST: + case AC_ROUTE_RECORD: + case AC_PROXY_INFO: + case AC_AUTH_APPLICATION_ID: + break; + case OGS_DIAM_GX_AVP_CODE_RE_AUTH_REQUEST_TYPE: + break; + case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_INSTALL: + ret = fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &avpch1, NULL); + ogs_assert(ret == 0); + while(avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + switch(hdr->avp_code) { + case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_DEFINITION: + pcc_rule = &gx_message->session_data.pcc_rule + [gx_message->session_data.num_of_pcc_rule]; + + rv = decode_pcc_rule_definition(pcc_rule, avpch1, NULL); + ogs_assert(rv == OGS_OK); + + pcc_rule->type = OGS_PCC_RULE_TYPE_INSTALL; + gx_message->session_data.num_of_pcc_rule++; + break; + default: + ogs_error("Not supported(%d)", hdr->avp_code); + break; + } + fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL); + } + break; + case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_REMOVE: + ret = fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &avpch1, NULL); + ogs_assert(ret == 0); + while (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + switch (hdr->avp_code) { + case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_NAME: + pcc_rule = &gx_message->session_data.pcc_rule + [gx_message->session_data.num_of_pcc_rule]; + + pcc_rule->name = ogs_strdup((char*)hdr->avp_value->os.data); + ogs_assert(pcc_rule->name); + + pcc_rule->type = OGS_PCC_RULE_TYPE_REMOVE; + gx_message->session_data.num_of_pcc_rule++; + break; + default: + ogs_error("Not supported(%d)", hdr->avp_code); + break; + } + fd_msg_browse(avpch1, MSG_BRW_NEXT, &avpch1, NULL); + } + break; + default: + ogs_warn("Not supported(%d)", hdr->avp_code); + break; + } + fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL); + } + + /* Send Gx Event to SMF State Machine */ + e = smf_event_new(SMF_EVT_GX_MESSAGE); + ogs_assert(e); + + e->sess = sess; + e->pkbuf = gxbuf; + rv = ogs_queue_push(ogs_app()->queue, e); + if (rv != OGS_OK) { + ogs_warn("ogs_queue_push() failed:%d", (int)rv); + ogs_session_data_free(&gx_message->session_data); + ogs_pkbuf_free(e->pkbuf); + smf_event_free(e); + } else { + ogs_pollset_notify(ogs_app()->pollset); + } + + /* Set the Auth-Application-Id AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_GX_APPLICATION_ID; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); + ogs_assert(ret == 0); + + /* Store this value in the session */ + ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + ogs_debug("Re-Auth-Answer"); + + /* Add this value to the stats */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_echoed++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + return 0; + +out: + if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1); + ogs_assert(ret == 0); + } else { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + ogs_assert(ret == 0); + } + + /* Store this value in the session */ + ret = fd_sess_state_store(smf_gx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + ogs_session_data_free(&gx_message->session_data); + ogs_pkbuf_free(gxbuf); + + return 0; +} + +int smf_gx_init(void) +{ + int ret; + struct disp_when data; + + ogs_thread_mutex_init(&sess_state_mutex); + ogs_pool_init(&sess_state_pool, ogs_app()->pool.sess); + + /* Install objects definitions for this application */ + ret = ogs_diam_gx_init(); + ogs_assert(ret == 0); + + /* Create handler for sessions */ + ret = fd_sess_handler_create(&smf_gx_reg, state_cleanup, NULL, NULL); + ogs_assert(ret == 0); + + memset(&data, 0, sizeof(data)); + data.app = ogs_diam_gx_application; + + ret = fd_disp_register(smf_gx_fb_cb, DISP_HOW_APPID, &data, NULL, + &hdl_gx_fb); + ogs_assert(ret == 0); + + data.command = ogs_diam_gx_cmd_rar; + ret = fd_disp_register(smf_gx_rar_cb, DISP_HOW_CC, &data, NULL, + &hdl_gx_rar); + ogs_assert(ret == 0); + + /* Advertise the support for the application in the peer */ + ret = fd_disp_app_support(ogs_diam_gx_application, ogs_diam_vendor, 1, 0); + ogs_assert(ret == 0); + + return OGS_OK; +} + +void smf_gx_final(void) +{ + int ret; + + ret = fd_sess_handler_destroy(&smf_gx_reg, NULL); + ogs_assert(ret == 0); + + if (hdl_gx_fb) + (void) fd_disp_unregister(&hdl_gx_fb, NULL); + if (hdl_gx_rar) + (void) fd_disp_unregister(&hdl_gx_rar, NULL); + + ogs_pool_final(&sess_state_pool); + ogs_thread_mutex_destroy(&sess_state_mutex); +} + +static int decode_pcc_rule_definition( + ogs_pcc_rule_t *pcc_rule, struct avp *avpch1, int *perror) +{ + int ret = 0, error = 0; + struct avp *avpch2, *avpch3, *avpch4; + struct avp_hdr *hdr; + + ogs_assert(pcc_rule); + ogs_assert(avpch1); + + ret = fd_msg_browse(avpch1, MSG_BRW_FIRST_CHILD, &avpch2, NULL); + ogs_assert(ret == 0); + while (avpch2) { + ogs_flow_t *flow = NULL; + + ret = fd_msg_avp_hdr(avpch2, &hdr); + ogs_assert(ret == 0); + switch (hdr->avp_code) { + case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_NAME: + if (pcc_rule->name) { + ogs_error("PCC Rule Name has already been defined"); + ogs_free(pcc_rule->name); + } + pcc_rule->name = ogs_strdup((char*)hdr->avp_value->os.data); + ogs_assert(pcc_rule->name); + break; + case OGS_DIAM_GX_AVP_CODE_FLOW_INFORMATION: + flow = &pcc_rule->flow[pcc_rule->num_of_flow]; + + ret = fd_avp_search_avp( + avpch2, ogs_diam_gx_flow_direction, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr( avpch3, &hdr); + ogs_assert(ret == 0); + flow->direction = hdr->avp_value->i32; + } + + ret = fd_avp_search_avp( + avpch2, ogs_diam_gx_flow_description, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr(avpch3, &hdr); + ogs_assert(ret == 0); + flow->description = ogs_malloc(hdr->avp_value->os.len+1); + ogs_assert(flow->description); + ogs_cpystrn(flow->description, + (char*)hdr->avp_value->os.data, + hdr->avp_value->os.len+1); + } + + pcc_rule->num_of_flow++; + break; + case OGS_DIAM_GX_AVP_CODE_FLOW_STATUS: + pcc_rule->flow_status = hdr->avp_value->i32; + break; + case OGS_DIAM_GX_AVP_CODE_QOS_INFORMATION: + ret = fd_avp_search_avp(avpch2, + ogs_diam_gx_qos_class_identifier, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr(avpch3, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.index = hdr->avp_value->u32; + } else { + ogs_error("no_QCI"); + error++; + } + + ret = fd_avp_search_avp(avpch2, + ogs_diam_gx_allocation_retention_priority, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_avp_search_avp( + avpch3, ogs_diam_gx_priority_level, &avpch4); + ogs_assert(ret == 0); + if (avpch4) { + ret = fd_msg_avp_hdr(avpch4, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.arp.priority_level = hdr->avp_value->u32; + } else { + ogs_error("no_Priority-Level"); + error++; + } + + /* + * Ch 7.3.40 Allocation-Retenion-Proirty in TS 29.272 V15.9.0 + * + * If the Pre-emption-Capability AVP is not present in the + * Allocation-Retention-Priority AVP, the default value shall be + * PRE-EMPTION_CAPABILITY_DISABLED (1). + * + * If the Pre-emption-Vulnerability AVP is not present in the + * Allocation-Retention-Priority AVP, the default value shall be + * PRE-EMPTION_VULNERABILITY_ENABLED (0). + * + * However, to easily set up VoLTE service, + * enable Pre-emption Capability/Vulnerablility + * in Default Bearer + */ + ret = fd_avp_search_avp(avpch3, + ogs_diam_gx_pre_emption_capability, &avpch4); + ogs_assert(ret == 0); + if (avpch4) { + ret = fd_msg_avp_hdr(avpch4, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.arp.pre_emption_capability = + hdr->avp_value->u32; + } else { + pcc_rule->qos.arp.pre_emption_capability = + OGS_EPC_PRE_EMPTION_DISABLED; + } + + ret = fd_avp_search_avp(avpch3, + ogs_diam_gx_pre_emption_vulnerability, &avpch4); + ogs_assert(ret == 0); + if (avpch4) { + ret = fd_msg_avp_hdr(avpch4, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.arp.pre_emption_vulnerability = + hdr->avp_value->u32; + } else { + pcc_rule->qos.arp.pre_emption_vulnerability = + OGS_EPC_PRE_EMPTION_ENABLED; + + } + } else { + ogs_error("no_ARP"); + error++; + } + + ret = fd_avp_search_avp(avpch2, + ogs_diam_gx_max_requested_bandwidth_ul, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr(avpch3, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.mbr.uplink = hdr->avp_value->u32; + } + ret = fd_avp_search_avp(avpch2, + ogs_diam_gx_max_requested_bandwidth_dl, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr(avpch3, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.mbr.downlink = hdr->avp_value->u32; + } + ret = fd_avp_search_avp(avpch2, + ogs_diam_gx_guaranteed_bitrate_ul, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr(avpch3, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.gbr.uplink = hdr->avp_value->u32; + } + ret = fd_avp_search_avp(avpch2, + ogs_diam_gx_guaranteed_bitrate_dl, &avpch3); + ogs_assert(ret == 0); + if (avpch3) { + ret = fd_msg_avp_hdr(avpch3, &hdr); + ogs_assert(ret == 0); + pcc_rule->qos.gbr.downlink = hdr->avp_value->u32; + } + break; + case OGS_DIAM_GX_AVP_CODE_PRECEDENCE: + pcc_rule->precedence = hdr->avp_value->i32; + break; + default: + ogs_error("Not implemented(%d)", hdr->avp_code); + break; + } + fd_msg_browse(avpch2, MSG_BRW_NEXT, &avpch2, NULL); + } + + if (perror) + *perror = error; + + return OGS_OK; +} diff --git a/src/smf/meson.build b/src/smf/meson.build index 718c80429..803c5553f 100644 --- a/src/smf/meson.build +++ b/src/smf/meson.build @@ -77,6 +77,8 @@ libsmf_sources = files(''' s5c-build.c s5c-handler.c fd-path.c + gx-path.c + s6b-path.c gx-handler.c pfcp-path.c n4-build.c @@ -107,6 +109,7 @@ libsmf = static_library('smf', libngap_dep, libnas_5gs_dep, libdiameter_gx_dep, + libdiameter_s6b_dep, libgtp_dep, libpfcp_dep], install : false) @@ -118,6 +121,7 @@ libsmf_dep = declare_dependency( libngap_dep, libnas_5gs_dep, libdiameter_gx_dep, + libdiameter_s6b_dep, libgtp_dep, libpfcp_dep]) diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index 3c94f0d76..ce709b82d 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -628,8 +628,30 @@ void smf_epc_n4_handle_session_establishment_response( ogs_assert(up_f_seid); sess->upf_n4_seid = be64toh(up_f_seid->seid); - ogs_assert(OGS_OK == - smf_gtp_send_create_session_response(sess, gtp_xact)); + ogs_assert(OGS_OK == smf_gtp_send_create_session_response(sess, gtp_xact)); + + if (sess->gtp_rat_type == OGS_GTP_RAT_TYPE_WLAN) { + smf_ue_t *smf_ue = NULL; + smf_sess_t *eutran_sess = NULL; + + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + ogs_assert(sess->session.name); + eutran_sess = smf_sess_find_by_apn( + smf_ue, sess->session.name, OGS_GTP_RAT_TYPE_EUTRAN); + if (eutran_sess) { + smf_bearer_t *eutran_linked_bearer = + ogs_list_first(&eutran_sess->bearer_list); + ogs_assert(eutran_linked_bearer); + + ogs_assert(OGS_OK == + smf_gtp_send_delete_bearer_request( + eutran_linked_bearer, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP)); + } + } smf_bearer_binding(sess); } @@ -738,7 +760,6 @@ void smf_epc_n4_handle_session_deletion_response( ogs_assert(rsp); gtp_xact = xact->assoc_xact; - ogs_assert(gtp_xact); ogs_pfcp_xact_commit(xact); @@ -760,15 +781,36 @@ void smf_epc_n4_handle_session_deletion_response( } if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - ogs_gtp_send_error_message(gtp_xact, sess ? sess->sgw_s5c_teid : 0, - OGS_GTP_DELETE_SESSION_RESPONSE_TYPE, cause_value); + if (gtp_xact) + ogs_gtp_send_error_message(gtp_xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_DELETE_SESSION_RESPONSE_TYPE, cause_value); return; } ogs_assert(sess); - ogs_assert(OGS_OK == - smf_gtp_send_delete_session_response(sess, gtp_xact)); + if (gtp_xact) { + /* + * 1. MME sends Delete Session Request to SGW/SMF. + * 2. SMF sends Delete Session Response to SGW/MME. + */ + ogs_assert(OGS_OK == + smf_gtp_send_delete_session_response(sess, gtp_xact)); + } else { + /* + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + * + * Note that the following messages are not processed here. + * - Bearer Resource Command + * - Delete Bearer Request/Response with DEDICATED BEARER. + */ + } SMF_SESS_CLEAR(sess); } diff --git a/src/smf/nsmf-handler.c b/src/smf/nsmf-handler.c index c5ab8b3d7..92f9cb396 100644 --- a/src/smf/nsmf-handler.c +++ b/src/smf/nsmf-handler.c @@ -155,7 +155,7 @@ bool smf_nsmf_handle_create_sm_context( ogs_sbi_parse_plmn_id_nid(&sess->plmn_id, servingNetwork); - sess->rat_type = SmContextCreateData->rat_type; + sess->sbi_rat_type = SmContextCreateData->rat_type; ogs_sbi_parse_nr_location(&sess->nr_tai, &sess->nr_cgi, NrLocation); if (NrLocation->ue_location_timestamp) diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index c932e177d..07e6ee407 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -507,6 +507,28 @@ int smf_epc_pfcp_send_session_deletion_request( ogs_expect_or_return_val(xact, OGS_ERROR); xact->epc = true; /* EPC PFCP transaction */ + + /* + * << 'gtp_xact' is NOT NULL >> + * + * 1. MME sends Delete Session Request to SGW/SMF. + * 2. SMF sends Delete Session Response to SGW/MME. + * + * + * << 'gtp_xact' should be NULL >> + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + * + * Note that the following messages are not processed here. + * - Bearer Resource Command + * - Delete Bearer Request/Response with DEDICATED BEARER. + */ xact->assoc_xact = gtp_xact; rv = ogs_pfcp_xact_commit(xact); diff --git a/src/smf/s5c-build.c b/src/smf/s5c-build.c index 666053b75..0e60bd1d0 100644 --- a/src/smf/s5c-build.c +++ b/src/smf/s5c-build.c @@ -63,7 +63,17 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( /* Control Plane(UL) : SMF-S5C */ memset(&smf_s5c_teid, 0, sizeof(ogs_gtp_f_teid_t)); - smf_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_C; + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + smf_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_C; + break; + case OGS_GTP_RAT_TYPE_WLAN: + smf_s5c_teid.interface_type = OGS_GTP_F_TEID_S2B_PGW_GTP_C; + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } smf_s5c_teid.teid = htobe32(sess->smf_n4_teid); rv = ogs_gtp_sockaddr_to_f_teid( ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6, @@ -89,8 +99,17 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( rsp->pdn_address_allocation.presence = 1; /* APN Restriction */ - rsp->apn_restriction.presence = 1; - rsp->apn_restriction.u8 = OGS_GTP_APN_NO_RESTRICTION; + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + rsp->apn_restriction.presence = 1; + rsp->apn_restriction.u8 = OGS_GTP_APN_NO_RESTRICTION; + break; + case OGS_GTP_RAT_TYPE_WLAN: + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } /* APN-AMBR * if PCRF changes APN-AMBR, this should be included. */ @@ -140,17 +159,35 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( &bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN); } + /* Bearer Charging ID */ + rsp->bearer_contexts_created.charging_id.presence = 1; + rsp->bearer_contexts_created.charging_id.u32 = sess->charging.id; + /* Data Plane(UL) : SMF-S5U */ memset(&pgw_s5u_teid, 0, sizeof(ogs_gtp_f_teid_t)); - pgw_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; pgw_s5u_teid.teid = htobe32(bearer->pgw_s5u_teid); ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6); rv = ogs_gtp_sockaddr_to_f_teid( bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6, &pgw_s5u_teid, &len); ogs_expect_or_return_val(rv == OGS_OK, NULL); - rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence = 1; - rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &pgw_s5u_teid; - rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.len = len; + + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + pgw_s5u_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; + rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence = 1; + rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &pgw_s5u_teid; + rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.len = len; + break; + case OGS_GTP_RAT_TYPE_WLAN: + pgw_s5u_teid.interface_type = OGS_GTP_F_TEID_S2B_U_PGW_GTP_U; + rsp->bearer_contexts_created.s12_rnc_f_teid.presence = 1; + rsp->bearer_contexts_created.s12_rnc_f_teid.data = &pgw_s5u_teid; + rsp->bearer_contexts_created.s12_rnc_f_teid.len = len; + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } gtp_message.h.type = type; return ogs_gtp_build_msg(>p_message); @@ -198,6 +235,47 @@ ogs_pkbuf_t *smf_s5c_build_delete_session_response( return ogs_gtp_build_msg(>p_message); } +ogs_pkbuf_t *smf_s5c_build_modify_bearer_response( + uint8_t type, smf_sess_t *sess, + ogs_gtp_modify_bearer_request_t *req) +{ + ogs_gtp_message_t gtp_message; + ogs_gtp_modify_bearer_response_t *rsp = NULL; + + ogs_gtp_cause_t cause; + + ogs_assert(sess); + ogs_assert(req); + + rsp = >p_message.modify_bearer_response; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + memset(&cause, 0, sizeof(cause)); + cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + rsp->cause.presence = 1; + rsp->cause.data = &cause; + rsp->cause.len = sizeof(cause); + + rsp->bearer_contexts_modified.presence = 1; + rsp->bearer_contexts_modified.eps_bearer_id.presence = 1; + rsp->bearer_contexts_modified.eps_bearer_id.u8 = + req->bearer_contexts_to_be_modified.eps_bearer_id.u8; + rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.presence = 1; + rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.data = + req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.data; + rsp->bearer_contexts_modified.s1_u_enodeb_f_teid.len = + req->bearer_contexts_to_be_modified.s1_u_enodeb_f_teid.len; + + rsp->bearer_contexts_modified.cause.presence = 1; + rsp->bearer_contexts_modified.cause.len = sizeof(cause); + rsp->bearer_contexts_modified.cause.data = &cause; + + /* build */ + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + ogs_pkbuf_t *smf_s5c_build_create_bearer_request( uint8_t type, smf_bearer_t *bearer, ogs_gtp_tft_t *tft) { @@ -358,7 +436,7 @@ ogs_pkbuf_t *smf_s5c_build_update_bearer_request( } ogs_pkbuf_t *smf_s5c_build_delete_bearer_request( - uint8_t type, smf_bearer_t *bearer, uint8_t pti) + uint8_t type, smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value) { smf_sess_t *sess = NULL; smf_bearer_t *linked_bearer = NULL; @@ -366,6 +444,8 @@ ogs_pkbuf_t *smf_s5c_build_delete_bearer_request( ogs_gtp_message_t gtp_message; ogs_gtp_delete_bearer_request_t *req = NULL; + ogs_gtp_cause_t cause; + ogs_assert(bearer); sess = bearer->sess; ogs_assert(sess); @@ -379,11 +459,32 @@ ogs_pkbuf_t *smf_s5c_build_delete_bearer_request( memset(>p_message, 0, sizeof(ogs_gtp_message_t)); if (bearer->ebi == linked_bearer->ebi) { - /* Linked EBI */ + /* + * << Linked EPS Bearer ID >> + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + */ req->linked_eps_bearer_id.presence = 1; req->linked_eps_bearer_id.u8 = bearer->ebi; } else { - /* Bearer EBI */ + /* + * << EPS Bearer IDs >> + * + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ req->eps_bearer_ids.presence = 1; req->eps_bearer_ids.u8 = bearer->ebi; } @@ -393,6 +494,14 @@ ogs_pkbuf_t *smf_s5c_build_delete_bearer_request( req->procedure_transaction_id.u8 = pti; } + if (cause_value != OGS_GTP_CAUSE_UNDEFINED_VALUE) { + memset(&cause, 0, sizeof(cause)); + cause.value = cause_value; + req->cause.presence = 1; + req->cause.len = sizeof(cause); + req->cause.data = &cause; + } + gtp_message.h.type = type; return ogs_gtp_build_msg(>p_message); } diff --git a/src/smf/s5c-build.h b/src/smf/s5c-build.h index 4fd54f973..4497630cf 100644 --- a/src/smf/s5c-build.h +++ b/src/smf/s5c-build.h @@ -31,13 +31,17 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( ogs_pkbuf_t *smf_s5c_build_delete_session_response( uint8_t type, smf_sess_t *sess); +ogs_pkbuf_t *smf_s5c_build_modify_bearer_response( + uint8_t type, smf_sess_t *sess, + ogs_gtp_modify_bearer_request_t *req); + ogs_pkbuf_t *smf_s5c_build_create_bearer_request( uint8_t type, smf_bearer_t *bearer, ogs_gtp_tft_t *tft); ogs_pkbuf_t *smf_s5c_build_update_bearer_request( uint8_t type, smf_bearer_t *bearer, uint8_t pti, ogs_gtp_tft_t *tft, int qos_presence); ogs_pkbuf_t *smf_s5c_build_delete_bearer_request( - uint8_t type, smf_bearer_t *bearer, uint8_t pti); + uint8_t type, smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value); #ifdef __cplusplus } #endif diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c index 2ddba2d65..f3db22f7f 100644 --- a/src/smf/s5c-handler.c +++ b/src/smf/s5c-handler.c @@ -60,6 +60,7 @@ void smf_s5c_handle_create_session_request( smf_ue_t *smf_ue = NULL; ogs_gtp_f_teid_t *sgw_s5c_teid, *sgw_s5u_teid; + ogs_paa_t *paa = NULL; smf_bearer_t *bearer = NULL; ogs_gtp_bearer_qos_t bearer_qos; ogs_gtp_ambr_t *ambr = NULL; @@ -92,14 +93,6 @@ void smf_s5c_handle_create_session_request( ogs_error("No EPS Bearer QoS"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } - if (req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.presence == 0) { - ogs_error("No TEID"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; - } - if (req->pdn_type.presence == 0) { - ogs_error("No PDN Type"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; - } if (req->pdn_address_allocation.presence == 0) { ogs_error("No PAA"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; @@ -108,15 +101,55 @@ void smf_s5c_handle_create_session_request( ogs_error("No UE Location Information"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + if (req->serving_network.presence == 0) { + ogs_error("No Serving Network"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (req->serving_network.data == NULL) { + ogs_error("No Data in Serving Network"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (req->serving_network.len != OGS_PLMN_ID_LEN) { + ogs_error("Invalid Len[%d] in Serving Network", + req->serving_network.len); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + if (req->bearer_contexts_to_be_created. + s5_s8_u_sgw_f_teid.presence == 0) { + ogs_error("No S5/S8 SGW GTP-U TEID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + break; + case OGS_GTP_RAT_TYPE_WLAN: + if (req->bearer_contexts_to_be_created. + s2b_u_epdg_f_teid_5.presence == 0) { + ogs_error("No S2b ePDG GTP-U TEID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + break; + default: + ogs_error("Unknown RAT Type [%d]", req->rat_type.u8); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } if (!sess) { ogs_error("No Context"); cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; - } + } else { + if (!ogs_diam_app_connected(OGS_DIAM_GX_APPLICATION_ID)) { + ogs_warn("No Gx Diameter Peer"); + cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + } - if (!ogs_diam_peer_connected()) { - ogs_warn("No Diameter Peer"); - cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + if (sess->gtp_rat_type == OGS_GTP_RAT_TYPE_WLAN) { + if (!ogs_diam_app_connected(OGS_DIAM_S6B_APPLICATION_ID)) { + ogs_warn("No S6b Diameter Peer"); + cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + } + } } if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { @@ -129,11 +162,41 @@ void smf_s5c_handle_create_session_request( smf_ue = sess->smf_ue; ogs_assert(smf_ue); - /* UE Location Inforamtion*/ + /* Even after handover to WLAN, + * there must be at least one EUTRAN session */ + if (sess->gtp_rat_type == OGS_GTP_RAT_TYPE_WLAN) { + smf_sess_t *eutran_sess = smf_sess_find_by_apn( + smf_ue, sess->session.name, OGS_GTP_RAT_TYPE_EUTRAN); + if (eutran_sess) { + /* Need to check handover is possible */ + int eutran_session_count = 0; + ogs_list_for_each(&smf_ue->sess_list, eutran_sess) { + if (eutran_sess->gtp_rat_type != OGS_GTP_RAT_TYPE_EUTRAN) + continue; + if (strcmp(eutran_sess->session.name, sess->session.name) == 0) + continue; + + eutran_session_count++; + } + + if (eutran_session_count < 1) { + ogs_error("Cannot handover to WLAN"); + ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, + OGS_GTP_CAUSE_MULTIPLE_ACCESSES_TO_A_PDN_CONNECTION_NOT_ALLOWED); + return; + } + } + } + + /* UE Location Inforamtion */ ogs_gtp_parse_uli(&uli, &req->user_location_information); memcpy(&sess->e_tai, &uli.tai, sizeof(sess->e_tai)); memcpy(&sess->e_cgi, &uli.e_cgi, sizeof(sess->e_cgi)); + /* Serving Network */ + ogs_nas_to_plmn_id(&sess->plmn_id, req->serving_network.data); + /* Select PGW based on UE Location Information */ smf_sess_select_upf(sess); @@ -147,11 +210,10 @@ void smf_s5c_handle_create_session_request( } /* UE IP Address */ - ogs_assert(req->pdn_address_allocation.data); - sess->session.session_type = req->pdn_type.u8; - rv = ogs_gtp_paa_to_ip( - (ogs_paa_t *)req->pdn_address_allocation.data, - &sess->session.ue_ip); + paa = req->pdn_address_allocation.data; + ogs_assert(paa); + sess->session.session_type = paa->session_type; + rv = ogs_gtp_paa_to_ip(paa, &sess->session.ue_ip); ogs_assert(rv == OGS_OK); smf_sess_set_ue_ip(sess); @@ -176,16 +238,34 @@ void smf_s5c_handle_create_session_request( sgw_s5c_teid = req->sender_f_teid_for_control_plane.data; ogs_assert(sgw_s5c_teid); sess->sgw_s5c_teid = be32toh(sgw_s5c_teid->teid); - - /* Data Plane(DL) : SGW-S5U */ - sgw_s5u_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data; - ogs_assert(sgw_s5u_teid); - bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); - rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); + rv = ogs_gtp_f_teid_to_ip(sgw_s5c_teid, &sess->sgw_s5c_ip); ogs_assert(rv == OGS_OK); ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); + + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + sgw_s5u_teid = req->bearer_contexts_to_be_created. + s5_s8_u_sgw_f_teid.data; + ogs_assert(sgw_s5u_teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); + rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); + ogs_assert(rv == OGS_OK); + break; + case OGS_GTP_RAT_TYPE_WLAN: + sgw_s5u_teid = req->bearer_contexts_to_be_created. + s2b_u_epdg_f_teid_5.data; + ogs_assert(sgw_s5u_teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); + rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); + ogs_assert(rv == OGS_OK); + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } + ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); @@ -232,8 +312,18 @@ void smf_s5c_handle_create_session_request( OGS_TLV_STORE_DATA(&sess->gtp.ue_timezone, &req->ue_time_zone); } - smf_gx_send_ccr(sess, xact, - OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST); + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + smf_gx_send_ccr(sess, xact, + OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST); + break; + case OGS_GTP_RAT_TYPE_WLAN: + smf_s6b_send_aar(sess, xact); + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } } void smf_s5c_handle_delete_session_request( @@ -252,11 +342,18 @@ void smf_s5c_handle_delete_session_request( if (!sess) { ogs_warn("No Context"); cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; - } + } else { + if (!ogs_diam_app_connected(OGS_DIAM_GX_APPLICATION_ID)) { + ogs_warn("No Gx Diameter Peer"); + cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + } - if (!ogs_diam_peer_connected()) { - ogs_error("No Diameter Peer"); - cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + if (sess->gtp_rat_type == OGS_GTP_RAT_TYPE_WLAN) { + if (!ogs_diam_app_connected(OGS_DIAM_S6B_APPLICATION_ID)) { + ogs_warn("No S6b Diameter Peer"); + cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + } + } } if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { @@ -268,8 +365,91 @@ void smf_s5c_handle_delete_session_request( ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); - smf_gx_send_ccr(sess, xact, - OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST); + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + smf_gx_send_ccr(sess, xact, + OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST); + break; + case OGS_GTP_RAT_TYPE_WLAN: + smf_s6b_send_str(sess, xact, + OGS_DIAM_RX_TERMINATION_CAUSE_DIAMETER_LOGOUT); + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } +} + +void smf_s5c_handle_modify_bearer_request( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_modify_bearer_request_t *req) +{ + int rv; + uint8_t cause_value = 0; + ogs_gtp_indication_t *indication = NULL; + + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + + smf_ue_t *smf_ue = NULL; + smf_sess_t *wlan_sess = NULL; + + ogs_debug("Modify Bearer Request"); + + ogs_assert(xact); + ogs_assert(req); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_warn("No Context"); + cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; + } + + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE, cause_value); + return; + } + + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_MODIFY_BEARER_RESPONSE_TYPE; + h.teid = sess->sgw_s5c_teid; + + pkbuf = smf_s5c_build_modify_bearer_response(h.type, sess, req); + ogs_expect_or_return(pkbuf); + + rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + if (req->indication_flags.presence && + req->indication_flags.data && req->indication_flags.len) { + indication = req->indication_flags.data; + } + + if (indication && indication->hi) { + ogs_assert(sess->session.name); + wlan_sess = smf_sess_find_by_apn( + smf_ue, sess->session.name, OGS_GTP_RAT_TYPE_WLAN); + ogs_expect_or_return(wlan_sess); + ogs_expect_or_return(ogs_list_first(&wlan_sess->bearer_list)); + + ogs_assert(OGS_OK == + smf_gtp_send_delete_bearer_request( + ogs_list_first(&wlan_sess->bearer_list), + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP)); + } } void smf_s5c_handle_create_bearer_response( @@ -300,11 +480,28 @@ void smf_s5c_handle_create_bearer_response( ogs_error("No EPS Bearer ID"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } - if (rsp->bearer_contexts.s5_s8_u_pgw_f_teid.presence == 0) { - ogs_error("No SMF TEID"); + + if (rsp->bearer_contexts.s5_s8_u_pgw_f_teid.presence && + rsp->bearer_contexts.s5_s8_u_sgw_f_teid.presence) { + if (rsp->bearer_contexts.s5_s8_u_pgw_f_teid.presence) + pgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_pgw_f_teid.data; + if (rsp->bearer_contexts.s5_s8_u_sgw_f_teid.presence) + sgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data; + } + + if (rsp->bearer_contexts.s2b_u_pgw_f_teid.presence && + rsp->bearer_contexts.s2b_u_epdg_f_teid_8.presence) { + if (rsp->bearer_contexts.s2b_u_pgw_f_teid.presence) + pgw_s5u_teid = rsp->bearer_contexts.s2b_u_pgw_f_teid.data; + if (rsp->bearer_contexts.s2b_u_epdg_f_teid_8.presence) + sgw_s5u_teid = rsp->bearer_contexts.s2b_u_epdg_f_teid_8.data; + } + + if (!pgw_s5u_teid) { + ogs_error("No PGW TEID"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } - if (rsp->bearer_contexts.s5_s8_u_sgw_f_teid.presence == 0) { + if (!sgw_s5u_teid) { ogs_error("No SGW TEID"); cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } @@ -351,11 +548,8 @@ void smf_s5c_handle_create_bearer_response( return; } - /* Correlate with PGW-S5U-TEID */ - pgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_pgw_f_teid.data; - ogs_expect_or_return(pgw_s5u_teid); - /* Find the Bearer by PGW-S5U-TEID */ + ogs_assert(pgw_s5u_teid); bearer = smf_bearer_find_by_pgw_s5u_teid(sess, be32toh(pgw_s5u_teid->teid)); ogs_expect_or_return(bearer); @@ -363,7 +557,6 @@ void smf_s5c_handle_create_bearer_response( bearer->ebi = rsp->bearer_contexts.eps_bearer_id.u8; /* Data Plane(DL) : SGW-S5U */ - sgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data; ogs_assert(sgw_s5u_teid); bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); rv = ogs_gtp_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); @@ -531,21 +724,12 @@ void smf_s5c_handle_delete_bearer_response( cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; - rv = ogs_gtp_xact_commit(xact); - ogs_expect(rv == OGS_OK); - - if (rsp->bearer_contexts.presence == 0) { - ogs_error("No Bearer"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; - } - if (rsp->bearer_contexts.eps_bearer_id.presence == 0) { - ogs_error("No EPS Bearer ID"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; - } - bearer = xact->data; ogs_assert(bearer); + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + if (!sess) { ogs_warn("No Context in TEID"); @@ -555,38 +739,87 @@ void smf_s5c_handle_delete_bearer_response( cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; } - if (rsp->cause.presence) { - ogs_gtp_cause_t *cause = rsp->cause.data; - ogs_assert(cause); + if (rsp->linked_eps_bearer_id.presence) { + /* + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + */ + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); - cause_value = cause->value; - if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { - if (rsp->bearer_contexts.cause.presence) { - cause = rsp->bearer_contexts.cause.data; - ogs_assert(cause); - - cause_value = cause->value; + cause_value = cause->value; + if (cause->value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { } else { - ogs_error("No Cause"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + ogs_error("GTP Failed [CAUSE:%d]", cause_value); } } else { - ogs_warn("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("No Cause"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } + + ogs_assert(OGS_OK == + smf_epc_pfcp_send_session_deletion_request( + sess, NULL)); + } else { - ogs_error("No Cause"); - cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + /* + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF + */ + if (rsp->bearer_contexts.presence == 0) { + ogs_error("No Bearer"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (rsp->bearer_contexts.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + cause_value = cause->value; + if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + if (rsp->bearer_contexts.cause.presence) { + cause = rsp->bearer_contexts.cause.data; + ogs_assert(cause); + + cause_value = cause->value; + } else { + ogs_error("No Cause"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + } else { + ogs_warn("GTP Failed [CAUSE:%d]", cause_value); + } + } else { + ogs_error("No Cause"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + ogs_debug("Delete Bearer Response : SGW[0x%x] --> SMF[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + ogs_assert(OGS_OK == + smf_epc_pfcp_send_bearer_modification_request( + bearer, OGS_PFCP_MODIFY_REMOVE)); } - - ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", - sess->sgw_s5c_teid, sess->smf_n4_teid); - - ogs_debug("Delete Bearer Response : SGW[0x%x] --> SMF[0x%x]", - sess->sgw_s5c_teid, sess->smf_n4_teid); - - ogs_assert(OGS_OK == - smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_REMOVE)); } static int reconfigure_packet_filter(smf_pf_t *pf, ogs_gtp_tft_t *tft, int i) @@ -936,7 +1169,8 @@ void smf_s5c_handle_bearer_resource_command( if (tft_delete) { h.type = OGS_GTP_DELETE_BEARER_REQUEST_TYPE; pkbuf = smf_s5c_build_delete_bearer_request( - h.type, bearer, cmd->procedure_transaction_id.u8); + h.type, bearer, cmd->procedure_transaction_id.u8, + OGS_GTP_CAUSE_UNDEFINED_VALUE); ogs_expect_or_return(pkbuf); rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); diff --git a/src/smf/s5c-handler.h b/src/smf/s5c-handler.h index e321665c7..4d046ea93 100644 --- a/src/smf/s5c-handler.h +++ b/src/smf/s5c-handler.h @@ -37,6 +37,9 @@ void smf_s5c_handle_create_session_request( void smf_s5c_handle_delete_session_request( smf_sess_t *sess, ogs_gtp_xact_t *xact, ogs_gtp_delete_session_request_t *req); +void smf_s5c_handle_modify_bearer_request( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_modify_bearer_request_t *req); void smf_s5c_handle_create_bearer_response( smf_sess_t *sess, ogs_gtp_xact_t *xact, ogs_gtp_create_bearer_response_t *req); diff --git a/src/smf/s6b-path.c b/src/smf/s6b-path.c new file mode 100644 index 000000000..d3dfefd12 --- /dev/null +++ b/src/smf/s6b-path.c @@ -0,0 +1,796 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "fd-path.h" + +static struct session_handler *smf_s6b_reg = NULL; +static struct disp_hdl *hdl_s6b_fb = NULL; + +struct sess_state { + smf_sess_t *sess; + os0_t s6b_sid; /* S6B Session-Id */ + + ogs_gtp_xact_t *xact; + + struct timespec ts; /* Time of sending the message */ +}; + +static OGS_POOL(sess_state_pool, struct sess_state); +static ogs_thread_mutex_t sess_state_mutex; + +static void smf_s6b_aaa_cb(void *data, struct msg **msg); +static void smf_s6b_sta_cb(void *data, struct msg **msg); + +static __inline__ struct sess_state *new_state(os0_t sid) +{ + struct sess_state *new = NULL; + + ogs_thread_mutex_lock(&sess_state_mutex); + ogs_pool_alloc(&sess_state_pool, &new); + ogs_expect_or_return_val(new, NULL); + ogs_thread_mutex_unlock(&sess_state_mutex); + + new->s6b_sid = (os0_t)ogs_strdup((char *)sid); + ogs_expect_or_return_val(new->s6b_sid, NULL); + + return new; +} + +static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) +{ + if (sess_data->s6b_sid) + ogs_free(sess_data->s6b_sid); + + ogs_thread_mutex_lock(&sess_state_mutex); + ogs_pool_free(&sess_state_pool, sess_data); + ogs_thread_mutex_unlock(&sess_state_mutex); +} + +static int smf_s6b_fb_cb(struct msg **msg, struct avp *avp, + struct session *sess, void *opaque, enum disp_action *act) +{ + /* This CB should never be called */ + ogs_warn("Unexpected message received!"); + + return ENOTSUP; +} + +void smf_s6b_send_aar(smf_sess_t *sess, ogs_gtp_xact_t *xact) +{ + int ret; + + struct msg *req = NULL; + struct avp *avp; + union avp_value val; + struct sess_state *sess_data = NULL, *svg; + struct session *session = NULL; + int new; + + smf_ue_t *smf_ue = NULL; + char *user_name = NULL; + char *visited_network_identifier = NULL; + + struct avp *mip6_agent_info, *mip_home_agent_address; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + + ogs_assert(xact); + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + ogs_debug("[AA-Request]"); + + /* Create the request */ + ret = fd_msg_new(ogs_diam_rx_cmd_aar, MSGFL_ALLOC_ETEID, &req); + ogs_assert(ret == 0); + { + struct msg_hdr * h; + ret = fd_msg_hdr( req, &h ); + ogs_assert(ret == 0); + h->msg_appl = OGS_DIAM_S6B_APPLICATION_ID; + } + + /* Find Diameter S6b Session */ + if (sess->s6b_sid) { + /* Retrieve session by Session-Id */ + size_t sidlen = strlen(sess->s6b_sid); + ret = fd_sess_fromsid_msg((os0_t)sess->s6b_sid, sidlen, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + ogs_debug(" Found S6b Session-Id: [%s]", sess->s6b_sid); + + /* Add Session-Id to the message */ + ret = ogs_diam_message_session_id_set( + req, (os0_t)sess->s6b_sid, sidlen); + ogs_assert(ret == 0); + /* Save the session associated with the message */ + ret = fd_msg_sess_set(req, session); + } else { + /* Create a new session */ + #define OGS_DIAM_S6B_APP_SID_OPT "app_s6b" + ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_S6B_APP_SID_OPT, + CONSTSTRLEN(OGS_DIAM_S6B_APP_SID_OPT)); + ogs_assert(ret == 0); + ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL); + ogs_assert(ret == 0); + } + + /* Retrieve session state in this session */ + ret = fd_sess_state_retrieve(smf_s6b_reg, session, &sess_data); + if (!sess_data) { + os0_t sid; + size_t sidlen; + + ret = fd_sess_getsid(session, &sid, &sidlen); + ogs_assert(ret == 0); + + /* Allocate new session state memory */ + sess_data = new_state(sid); + ogs_assert(sess_data); + + ogs_debug(" Allocate new session: [%s]", sess_data->s6b_sid); + + /* Save Session-Id to SMF Session Context */ + sess->s6b_sid = (char *)sess_data->s6b_sid; + } else + ogs_debug(" Retrieve session: [%s]", sess_data->s6b_sid); + + /* Update session state */ + sess_data->sess = sess; + sess_data->xact = xact; + + /* Set Origin-Host & Origin-Realm */ + ret = fd_msg_add_origin(req, 0); + ogs_assert(ret == 0); + + /* Set the Destination-Realm AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); + val.os.len = strlen(fd_g_config->cnf_diamrlm); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Auth-Application-Id AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_S6B_APPLICATION_ID; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Auth-Request-Type AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_request_type, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHORIZE_ONLY; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set RAT-Type */ + ret = fd_msg_avp_new(ogs_diam_rat_type, 0, &avp); + ogs_assert(ret == 0); + + switch (sess->gtp_rat_type) { + case OGS_GTP_RAT_TYPE_EUTRAN: + val.i32 = OGS_DIAM_RAT_TYPE_EUTRAN; + break; + case OGS_GTP_RAT_TYPE_WLAN: + val.i32 = OGS_DIAM_RAT_TYPE_WLAN; + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } + + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the User-Name AVP */ + user_name = ogs_msprintf("%s@nai.epc.mnc%03d.mcc%03d.3gppnetwork.org", + smf_ue->imsi_bcd, + ogs_plmn_id_mnc(&sess->plmn_id), + ogs_plmn_id_mcc(&sess->plmn_id)); + ogs_assert(user_name); + + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set MIP6-Feature-Vector */ + ret = fd_msg_avp_new(ogs_diam_s6b_mip6_feature_vector, 0, &avp); + ogs_assert(ret == 0); + val.u64 = 0x0000400000000000LL; /* GTPv2_SUPPORTED: Set */ + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set MIP6-Agent-Info */ + ret = fd_msg_avp_new(ogs_diam_mip6_agent_info, 0, &mip6_agent_info); + ogs_assert(ret == 0); + + if (ogs_gtp_self()->gtpc_addr) { + ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0, + &mip_home_agent_address); + ogs_assert(ret == 0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = + ogs_gtp_self()->gtpc_addr->sin.sin_addr.s_addr; + ret = fd_msg_avp_value_encode ( + &sin, mip_home_agent_address ); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(mip6_agent_info, + MSG_BRW_LAST_CHILD, mip_home_agent_address); + ogs_assert(ret == 0); + } + + if (ogs_gtp_self()->gtpc_addr6) { + ret = fd_msg_avp_new(ogs_diam_mip_home_agent_address, 0, + &mip_home_agent_address); + ogs_assert(ret == 0); + sin6.sin6_family = AF_INET6; + memcpy(sin6.sin6_addr.s6_addr, + ogs_gtp_self()->gtpc_addr6->sin6.sin6_addr.s6_addr, + OGS_IPV6_LEN); + ret = fd_msg_avp_value_encode ( + &sin6, mip_home_agent_address ); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(mip6_agent_info, + MSG_BRW_LAST_CHILD, mip_home_agent_address); + ogs_assert(ret == 0); + } + + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, mip6_agent_info); + ogs_assert(ret == 0); + + /* Set the Visited-Network-Identifier AVP */ + visited_network_identifier = + ogs_msprintf("mnc%03d.mcc%03d.3gppnetwork.org", + ogs_plmn_id_mnc(&sess->plmn_id), + ogs_plmn_id_mcc(&sess->plmn_id)); + ogs_assert(visited_network_identifier); + + ret = fd_msg_avp_new(ogs_diam_visited_network_identifier, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (unsigned char *)(visited_network_identifier); + val.os.len = strlen(visited_network_identifier); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Service-Selection */ + ret = fd_msg_avp_new(ogs_diam_service_selection, 0, &avp); + ogs_assert(ret == 0); + ogs_assert(sess->session.name); + val.os.data = (uint8_t*)sess->session.name; + val.os.len = strlen(sess->session.name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Keep a pointer to the session data for debug purpose, + * in real life we would not need it */ + svg = sess_data; + + /* Store this value in the session */ + ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the request */ + ret = fd_msg_send(&req, smf_s6b_aaa_cb, svg); + ogs_assert(ret == 0); + + /* Increment the counter */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_sent++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + ogs_free(user_name); + ogs_free(visited_network_identifier); +} + +static void smf_s6b_aaa_cb(void *data, struct msg **msg) +{ + int ret; + + struct sess_state *sess_data = NULL; + struct timespec ts; + struct session *session; + struct avp *avp, *avpch1; + struct avp_hdr *hdr; + unsigned long dur; + int error = 0; + int new; + int result_code = 0; + int exp_result_code = 0; + + smf_sess_t *sess = NULL; + ogs_gtp_xact_t *xact = NULL; + + ogs_debug("[AA-Answer]"); + + ret = clock_gettime(CLOCK_REALTIME, &ts); + ogs_assert(ret == 0); + + /* Search the session, retrieve its data */ + ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + ogs_debug(" Search the session"); + + ret = fd_sess_state_retrieve(smf_s6b_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data); + ogs_assert((void *)sess_data == data); + + ogs_debug(" Retrieve its data: [%s]", sess_data->s6b_sid); + + sess = sess_data->sess; + ogs_assert(sess); + xact = sess_data->xact; + ogs_assert(xact); + + /* Value of Result Code */ + ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + result_code = hdr->avp_value->i32; + if (result_code != ER_DIAMETER_SUCCESS) { + ogs_error("Result Code: %d", result_code); + error++; + } + } else { + error++; + + ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp( + avp, ogs_diam_experimental_result_code, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + exp_result_code = hdr->avp_value->i32; + ogs_error("Experimental Result Code: %d", exp_result_code); + } + } else { + ogs_error("no Result-Code"); + } + } + + /* Value of Origin-Host */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_host, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug("From '%.*s' ", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Host "); + error++; + } + + /* Value of Origin-Realm */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_realm, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug("('%.*s') ", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Realm "); + error++; + } + + if (!error) { + smf_gx_send_ccr(sess, xact, + OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST); + } + + /* Free the message */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) + + ((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + if (ogs_diam_logger_self()->stats.nb_recv) { + /* Ponderate in the avg */ + ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg * + ogs_diam_logger_self()->stats.nb_recv + dur) / + (ogs_diam_logger_self()->stats.nb_recv + 1); + /* Min, max */ + if (dur < ogs_diam_logger_self()->stats.shortest) + ogs_diam_logger_self()->stats.shortest = dur; + if (dur > ogs_diam_logger_self()->stats.longest) + ogs_diam_logger_self()->stats.longest = dur; + } else { + ogs_diam_logger_self()->stats.shortest = dur; + ogs_diam_logger_self()->stats.longest = dur; + ogs_diam_logger_self()->stats.avg = dur; + } + if (error) + ogs_diam_logger_self()->stats.nb_errs++; + else + ogs_diam_logger_self()->stats.nb_recv++; + + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + /* Display how long it took */ + if (ts.tv_nsec > sess_data->ts.tv_nsec) + ogs_debug("in %d.%06ld sec", + (int)(ts.tv_sec - sess_data->ts.tv_sec), + (long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + else + ogs_debug("in %d.%06ld sec", + (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), + (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + + ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + ret = fd_msg_free(*msg); + ogs_assert(ret == 0); + *msg = NULL; + + return; +} + +void smf_s6b_send_str(smf_sess_t *sess, ogs_gtp_xact_t *xact, uint32_t cause) +{ + int ret; + + struct msg *req = NULL; + struct avp *avp; + union avp_value val; + struct sess_state *sess_data = NULL, *svg; + struct session *session = NULL; + int new; + size_t sidlen; + + smf_ue_t *smf_ue = NULL; + char *user_name = NULL; + + ogs_assert(xact); + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + ogs_debug("[Session-Termination-Request]"); + + /* Create the request */ + ret = fd_msg_new(ogs_diam_rx_cmd_str, MSGFL_ALLOC_ETEID, &req); + ogs_assert(ret == 0); + { + struct msg_hdr * h; + ret = fd_msg_hdr( req, &h ); + ogs_assert(ret == 0); + h->msg_appl = OGS_DIAM_S6B_APPLICATION_ID; + } + + ogs_assert(sess->s6b_sid); + + /* Retrieve session by Session-Id */ + sidlen = strlen(sess->s6b_sid); + ret = fd_sess_fromsid_msg((os0_t)sess->s6b_sid, sidlen, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + ogs_debug(" Found S6b Session-Id: [%s]", sess->s6b_sid); + + /* Add Session-Id to the message */ + ret = ogs_diam_message_session_id_set(req, (os0_t)sess->s6b_sid, sidlen); + ogs_assert(ret == 0); + /* Save the session associated with the message */ + ret = fd_msg_sess_set(req, session); + + /* Retrieve session state in this session */ + ret = fd_sess_state_retrieve(smf_s6b_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data); + ogs_debug(" Retrieve session: [%s]", sess_data->s6b_sid); + + /* Update session state */ + sess_data->sess = sess; + sess_data->xact = xact; + + /* Set Origin-Host & Origin-Realm */ + ret = fd_msg_add_origin(req, 0); + ogs_assert(ret == 0); + + /* Set the Destination-Realm AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); + val.os.len = strlen(fd_g_config->cnf_diamrlm); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Auth-Application-Id AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_S6B_APPLICATION_ID; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Termination-Cause AVP */ + ret = fd_msg_avp_new(ogs_diam_rx_termination_cause, 0, &avp); + ogs_assert(ret == 0); + val.i32 = cause; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the User-Name AVP */ + user_name = ogs_msprintf("%s@nai.epc.mnc%03d.mcc%03d.3gppnetwork.org", + smf_ue->imsi_bcd, + ogs_plmn_id_mnc(&sess->plmn_id), + ogs_plmn_id_mcc(&sess->plmn_id)); + ogs_assert(user_name); + + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)user_name; + val.os.len = strlen(user_name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Keep a pointer to the session data for debug purpose, + * in real life we would not need it */ + svg = sess_data; + + /* Store this value in the session */ + ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the request */ + ret = fd_msg_send(&req, smf_s6b_sta_cb, svg); + ogs_assert(ret == 0); + + /* Increment the counter */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_sent++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + ogs_free(user_name); +} + +static void smf_s6b_sta_cb(void *data, struct msg **msg) +{ + int ret; + + struct sess_state *sess_data = NULL; + struct timespec ts; + struct session *session; + struct avp *avp, *avpch1; + struct avp_hdr *hdr; + unsigned long dur; + int error = 0; + int new; + int result_code = 0; + int exp_result_code = 0; + + smf_sess_t *sess = NULL; + ogs_gtp_xact_t *xact = NULL; + + ogs_debug("[Session-Termination-Answer]"); + + ret = clock_gettime(CLOCK_REALTIME, &ts); + ogs_assert(ret == 0); + + /* Search the session, retrieve its data */ + ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + ogs_debug(" Search the session"); + + ret = fd_sess_state_retrieve(smf_s6b_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data); + ogs_assert((void *)sess_data == data); + + ogs_debug(" Retrieve its data: [%s]", sess_data->s6b_sid); + + sess = sess_data->sess; + ogs_assert(sess); + xact = sess_data->xact; + ogs_assert(xact); + + /* Value of Result Code */ + ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + result_code = hdr->avp_value->i32; + if (result_code != ER_DIAMETER_SUCCESS) { + ogs_error("Result Code: %d", result_code); + error++; + } + } else { + error++; + + ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp( + avp, ogs_diam_experimental_result_code, &avpch1); + ogs_assert(ret == 0); + if (avpch1) { + ret = fd_msg_avp_hdr(avpch1, &hdr); + ogs_assert(ret == 0); + exp_result_code = hdr->avp_value->i32; + ogs_error("Experimental Result Code: %d", exp_result_code); + } + } else { + ogs_error("no Result-Code"); + } + } + + /* Value of Origin-Host */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_host, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug("From '%.*s' ", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Host "); + error++; + } + + /* Value of Origin-Realm */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_realm, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug("('%.*s') ", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Realm "); + error++; + } + + if (!error) { + smf_gx_send_ccr(sess, xact, + OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST); + } + + /* Free the message */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) + + ((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + if (ogs_diam_logger_self()->stats.nb_recv) { + /* Ponderate in the avg */ + ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg * + ogs_diam_logger_self()->stats.nb_recv + dur) / + (ogs_diam_logger_self()->stats.nb_recv + 1); + /* Min, max */ + if (dur < ogs_diam_logger_self()->stats.shortest) + ogs_diam_logger_self()->stats.shortest = dur; + if (dur > ogs_diam_logger_self()->stats.longest) + ogs_diam_logger_self()->stats.longest = dur; + } else { + ogs_diam_logger_self()->stats.shortest = dur; + ogs_diam_logger_self()->stats.longest = dur; + ogs_diam_logger_self()->stats.avg = dur; + } + if (error) + ogs_diam_logger_self()->stats.nb_errs++; + else + ogs_diam_logger_self()->stats.nb_recv++; + + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + /* Display how long it took */ + if (ts.tv_nsec > sess_data->ts.tv_nsec) + ogs_debug("in %d.%06ld sec", + (int)(ts.tv_sec - sess_data->ts.tv_sec), + (long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + else + ogs_debug("in %d.%06ld sec", + (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), + (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + + ret = fd_sess_state_store(smf_s6b_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + ret = fd_msg_free(*msg); + ogs_assert(ret == 0); + *msg = NULL; + + return; +} + +int smf_s6b_init(void) +{ + int ret; + struct disp_when data; + + ogs_thread_mutex_init(&sess_state_mutex); + ogs_pool_init(&sess_state_pool, ogs_app()->pool.sess); + + /* Install objects definitions for this application */ + ret = ogs_diam_s6b_init(); + ogs_assert(ret == 0); + + /* Create handler for sessions */ + ret = fd_sess_handler_create(&smf_s6b_reg, state_cleanup, NULL, NULL); + ogs_assert(ret == 0); + + memset(&data, 0, sizeof(data)); + data.app = ogs_diam_s6b_application; + + ret = fd_disp_register(smf_s6b_fb_cb, DISP_HOW_APPID, &data, NULL, + &hdl_s6b_fb); + ogs_assert(ret == 0); + + /* Advertise the support for the application in the peer */ + ret = fd_disp_app_support(ogs_diam_s6b_application, ogs_diam_vendor, 1, 0); + ogs_assert(ret == 0); + + return OGS_OK; +} + +void smf_s6b_final(void) +{ + int ret; + + ret = fd_sess_handler_destroy(&smf_s6b_reg, NULL); + ogs_assert(ret == 0); + + if (hdl_s6b_fb) + (void) fd_disp_unregister(&hdl_s6b_fb, NULL); + + ogs_pool_final(&sess_state_pool); + ogs_thread_mutex_destroy(&sess_state_mutex); +} diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c index e7cfa361d..792a79a56 100644 --- a/src/smf/smf-sm.c +++ b/src/smf/smf-sm.c @@ -135,6 +135,10 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) smf_s5c_handle_delete_session_request( sess, gtp_xact, >p_message.delete_session_request); break; + case OGS_GTP_MODIFY_BEARER_REQUEST_TYPE: + smf_s5c_handle_modify_bearer_request( + sess, gtp_xact, >p_message.modify_bearer_request); + break; case OGS_GTP_CREATE_BEARER_RESPONSE_TYPE: smf_s5c_handle_create_bearer_response( sess, gtp_xact, >p_message.create_bearer_response); diff --git a/tests/310014/epc-test.c b/tests/310014/epc-test.c index 9c16228c9..c41f47fd6 100644 --- a/tests/310014/epc-test.c +++ b/tests/310014/epc-test.c @@ -64,7 +64,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "INTERNET"); + sess = test_sess_add_by_apn(test_ue, "INTERNET", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -98,6 +98,8 @@ static void test1_func(abts_case *tc, void *data) /* Send Attach Request */ sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/attach/auth-test.c b/tests/attach/auth-test.c index e01dfbb0c..5152cea4f 100644 --- a/tests/attach/auth-test.c +++ b/tests/attach/auth-test.c @@ -67,7 +67,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -100,6 +100,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -201,6 +203,8 @@ static void test1_func(abts_case *tc, void *data) /* Send Attach Request */ sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -273,6 +277,8 @@ static void test1_func(abts_case *tc, void *data) /* Send Attach Request - No Integrity */ sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -344,6 +350,8 @@ static void test1_func(abts_case *tc, void *data) /* Send Attach Request - No Integrity */ sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/attach/emm-status-test.c b/tests/attach/emm-status-test.c index f2eb44168..c4de71d01 100644 --- a/tests/attach/emm-status-test.c +++ b/tests/attach/emm-status-test.c @@ -64,7 +64,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -94,6 +94,8 @@ static void test1_func(abts_case *tc, void *data) /* Send Attach Request */ sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/attach/guti-test.c b/tests/attach/guti-test.c index fbfb9195c..0651c5695 100644 --- a/tests/attach/guti-test.c +++ b/tests/attach/guti-test.c @@ -67,7 +67,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -233,6 +235,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -372,6 +376,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -491,7 +497,7 @@ static void test2_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -524,6 +530,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -625,6 +633,8 @@ static void test2_func(abts_case *tc, void *data) /* Send Attach Request - No Integrity */ sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -740,6 +750,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -905,7 +917,7 @@ static void test3_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -938,6 +950,8 @@ static void test3_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1241,7 +1255,7 @@ static void test4_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -1274,6 +1288,8 @@ static void test4_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit_no_required = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1356,6 +1372,8 @@ static void test4_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit_no_required = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1463,6 +1481,8 @@ static void test4_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/attach/idle-test.c b/tests/attach/idle-test.c index 55b9551de..c0bf85fbb 100644 --- a/tests/attach/idle-test.c +++ b/tests/attach/idle-test.c @@ -67,7 +67,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -100,6 +100,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -402,7 +404,7 @@ static void test2_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -435,6 +437,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -691,7 +695,7 @@ static void test3_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -724,6 +728,8 @@ static void test3_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/attach/reset-test.c b/tests/attach/reset-test.c index 87cb820a0..d02e141a4 100644 --- a/tests/attach/reset-test.c +++ b/tests/attach/reset-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -124,6 +124,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -344,7 +346,8 @@ static void test2_func(abts_case *tc, void *data) test_ue[i]->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue[i]->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue[i], "internet"); + sess = test_sess_add_by_apn( + test_ue[i], "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /********** Insert Subscriber in Database */ @@ -354,7 +357,8 @@ static void test2_func(abts_case *tc, void *data) } for (i = 0; i < NUM_OF_TEST_UE; i++) { - sess = test_sess_find_by_apn(test_ue[i], "internet"); + sess = test_sess_find_by_apn( + test_ue[i], "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* Send Attach Request */ @@ -362,6 +366,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -567,7 +573,8 @@ static void test3_func(abts_case *tc, void *data) test_ue[i]->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue[i]->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue[i], "internet"); + sess = test_sess_add_by_apn( + test_ue[i], "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /********** Insert Subscriber in Database */ @@ -577,7 +584,8 @@ static void test3_func(abts_case *tc, void *data) } for (i = 0; i < NUM_OF_TEST_UE; i++) { - sess = test_sess_find_by_apn(test_ue[i], "internet"); + sess = test_sess_find_by_apn( + test_ue[i], "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* Send Attach Request */ @@ -585,6 +593,8 @@ static void test3_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/attach/ue-context-test.c b/tests/attach/ue-context-test.c index 984f8e4b3..17848408c 100644 --- a/tests/attach/ue-context-test.c +++ b/tests/attach/ue-context-test.c @@ -64,7 +64,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -96,6 +96,8 @@ static void test1_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -230,7 +232,7 @@ static void test2_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -263,6 +265,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit_no_required = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -345,6 +349,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit_no_required = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -512,7 +518,7 @@ static void test3_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -545,6 +551,8 @@ static void test3_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit_no_required = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -627,6 +635,8 @@ static void test3_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit_no_required = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/common/context.c b/tests/common/context.c index e22d31801..f21826cff 100644 --- a/tests/common/context.c +++ b/tests/common/context.c @@ -803,6 +803,8 @@ void test_ue_set_mobile_identity_suci(test_ue_t *test_ue, ogs_free(test_ue->imsi); test_ue->imsi = ogs_id_get_value(test_ue->supi); ogs_assert(test_ue->imsi); + + ogs_bcd_to_buffer(test_ue->imsi, test_ue->imsi_buf, &test_ue->imsi_len); } static void test_ue_set_mobile_identity_imsi(test_ue_t *test_ue) @@ -949,7 +951,8 @@ void test_ue_remove_all(void) test_ue_remove(test_ue); } -test_sess_t *test_sess_add_by_apn(test_ue_t *test_ue, char *apn) +test_sess_t *test_sess_add_by_apn( + test_ue_t *test_ue, char *apn, uint8_t rat_type) { test_sess_t *sess = NULL; @@ -960,10 +963,17 @@ test_sess_t *test_sess_add_by_apn(test_ue_t *test_ue, char *apn) ogs_assert(sess); memset(sess, 0, sizeof *sess); + sess->index = ogs_pool_index(&test_sess_pool, sess); + sess->apn = ogs_strdup(apn); ogs_assert(sess->apn); + sess->gtp_rat_type = rat_type; + ogs_assert(sess->gtp_rat_type); + sess->pti = 1; /* Default PTI : 1 */ + sess->epdg_s2b_c_teid = sess->index; + sess->test_ue = test_ue; ogs_list_add(&test_ue->sess_list, sess); @@ -1031,7 +1041,8 @@ void test_sess_remove_all(test_ue_t *test_ue) test_sess_remove(sess); } -test_sess_t *test_sess_find_by_apn(test_ue_t *test_ue, char *apn) +test_sess_t *test_sess_find_by_apn( + test_ue_t *test_ue, char *apn, uint8_t rat_type) { test_sess_t *sess = NULL; @@ -1039,7 +1050,9 @@ test_sess_t *test_sess_find_by_apn(test_ue_t *test_ue, char *apn) ogs_assert(apn); ogs_list_for_each(&test_ue->sess_list, sess) - if (ogs_strcasecmp(sess->apn, apn) == 0) return sess; + if (ogs_strcasecmp(sess->apn, apn) == 0 && + sess->gtp_rat_type == rat_type) + return sess; return NULL; } @@ -1140,6 +1153,9 @@ test_bearer_t *test_bearer_find_by_ue_ebi(test_ue_t *test_ue, uint8_t ebi) ogs_assert(test_ue); ogs_list_for_each(&test_ue->sess_list, sess) { + if (sess->gtp_rat_type != OGS_GTP_RAT_TYPE_EUTRAN) + continue; + bearer = test_bearer_find_by_sess_ebi(sess, ebi); if (bearer) return bearer; @@ -2051,3 +2067,157 @@ bson_t *test_db_new_slice(test_ue_t *test_ue) return doc; } + +bson_t *test_db_new_non3gpp(test_ue_t *test_ue) +{ + bson_t *doc = NULL; + + ogs_assert(test_ue); + + doc = BCON_NEW( + "imsi", BCON_UTF8(test_ue->imsi), + "msisdn", "[", + BCON_UTF8(TEST_MSISDN), + BCON_UTF8(TEST_ADDITIONAL_MSISDN), + "]", + "ambr", "{", + "downlink", "{", + "value", BCON_INT32(1), + "unit", BCON_INT32(3), + "}", + "uplink", "{", + "value", BCON_INT32(1), + "unit", BCON_INT32(3), + "}", + "}", + "slice", "[", "{", + "sst", BCON_INT32(1), + "default_indicator", BCON_BOOL(true), + "session", "[", + "{", + "name", BCON_UTF8("internet"), + "type", BCON_INT32(3), + "ambr", "{", + "downlink", "{", + "value", BCON_INT32(1), + "unit", BCON_INT32(3), + "}", + "uplink", "{", + "value", BCON_INT32(1), + "unit", BCON_INT32(3), + "}", + "}", + "qos", "{", + "index", BCON_INT32(9), + "arp", "{", + "priority_level", BCON_INT32(8), + "pre_emption_vulnerability", BCON_INT32(1), + "pre_emption_capability", BCON_INT32(1), + "}", + "}", + "smf", "{", + "addr", BCON_UTF8("127.0.0.4"), + "addr6", BCON_UTF8("::1"), + "}", + "}", + "{", + "name", BCON_UTF8("wlan"), + "type", BCON_INT32(3), + "ambr", "{", + "downlink", "{", + "value", BCON_INT32(1), + "unit", BCON_INT32(3), + "}", + "uplink", "{", + "value", BCON_INT32(1), + "unit", BCON_INT32(3), + "}", + "}", + "qos", "{", + "index", BCON_INT32(5), + "arp", "{", + "priority_level", BCON_INT32(1), + "pre_emption_vulnerability", BCON_INT32(1), + "pre_emption_capability", BCON_INT32(1), + "}", + "}", + "pcc_rule", "[", + "{", + "qos", "{", + "index", BCON_INT32(1), + "arp", "{", + "priority_level", BCON_INT32(3), + "pre_emption_vulnerability", BCON_INT32(2), + "pre_emption_capability", BCON_INT32(2), + "}", + "mbr", "{", + "downlink", "{", + "value", BCON_INT32(82), + "unit", BCON_INT32(1), + "}", + "uplink", "{", + "value", BCON_INT32(82), + "unit", BCON_INT32(1), + "}", + "}", + "gbr", "{", + "downlink", "{", + "value", BCON_INT32(82), + "unit", BCON_INT32(1), + "}", + "uplink", "{", + "value", BCON_INT32(82), + "unit", BCON_INT32(1), + "}", + "}", + "}", + "}", + "{", + "qos", "{", + "index", BCON_INT32(2), + "arp", "{", + "priority_level", BCON_INT32(4), + "pre_emption_vulnerability", BCON_INT32(2), + "pre_emption_capability", BCON_INT32(2), + "}", + "mbr", "{", + "downlink", "{", + "value", BCON_INT32(802), + "unit", BCON_INT32(1), + "}", + "uplink", "{", + "value", BCON_INT32(802), + "unit", BCON_INT32(1), + "}", + "}", + "gbr", "{", + "downlink", "{", + "value", BCON_INT32(802), + "unit", BCON_INT32(1), + "}", + "uplink", "{", + "value", BCON_INT32(802), + "unit", BCON_INT32(1), + "}", + "}", + "}", + "}", + "]", + "}", + "]", + "}", "]", + "security", "{", + "k", BCON_UTF8(test_ue->k_string), + "opc", BCON_UTF8(test_ue->opc_string), + "amf", BCON_UTF8("8000"), + "sqn", BCON_INT64(64), + "}", + "subscribed_rau_tau_timer", BCON_INT32(12), + "network_access_mode", BCON_INT32(2), + "subscriber_status", BCON_INT32(0), + "access_restriction_data", BCON_INT32(32) + ); + ogs_assert(doc); + + return doc; +} diff --git a/tests/common/context.h b/tests/common/context.h index 64cb712f1..589df9e8d 100644 --- a/tests/common/context.h +++ b/tests/common/context.h @@ -32,8 +32,6 @@ extern "C" { #define TEST_ENB_IPV4 "127.0.0.5" #define TEST_AMF_IPV4 TEST_MME_IPV4 #define TEST_GNB_IPV4 TEST_ENB_IPV4 -#define TEST_UPF_IPV4 "127.0.0.4" -#define TEST_SGWU_IPV4 "127.0.0.7" #define TEST_PING_IPV4 "10.45.0.1" #define TEST_PING_IPV6 "2001:230:cafe::1" @@ -43,6 +41,10 @@ extern "C" { #define TEST_MSISDN "491725670014" #define TEST_ADDITIONAL_MSISDN "491725670015" +#define TEST_HSS_IDENTITY "hss.localdomain" +#define TEST_PCRF_IDENTITY "pcrf.localdomain" +#define TEST_SMF_IDENTITY "smf.localdomain" + typedef struct test_context_s { uint16_t ngap_port; /* Default NGAP Port */ ogs_list_t ngap_list; /* AMF NGAP IPv4 Server List */ @@ -53,14 +55,17 @@ typedef struct test_context_s { uint16_t s1ap_port; /* Default S1AP Port */ ogs_list_t s1ap_list; /* MME S1AP IPv4 Server List */ ogs_list_t s1ap_list6; /* MME S1AP IPv6 Server List */ - ogs_sockaddr_t *s1ap_addr; /* MME GTPC IPv4 Address */ - ogs_sockaddr_t *s1ap_addr6; /* MME GTPC IPv6 Address */ + ogs_sockaddr_t *s1ap_addr; /* MME S1AP IPv4 Address */ + ogs_sockaddr_t *s1ap_addr6; /* MME S1AP IPv6 Address */ ogs_sockaddr_t *gnb1_addr; ogs_sockaddr_t *gnb1_addr6; ogs_sockaddr_t *gnb2_addr; ogs_sockaddr_t *gnb2_addr6; + uint32_t gtpc_port; /* SMF GTPC local port */ + ogs_list_t gtpc_list; /* SMF GTPC Client List */ + /* 5G PLMN Support */ uint8_t num_of_plmn_support; struct { @@ -264,14 +269,12 @@ typedef struct test_pdu_session_establishment_param_s { typedef struct test_pdn_connectivity_param_s { union { struct { - ED8(uint8_t eit:1;, + ED6(uint8_t eit:1;, uint8_t eit_no_required:1;, uint8_t apn:1;, uint8_t pco:1;, uint8_t integrity_protected:1;, - uint8_t ciphered:1;, - uint8_t spare6:1;, - uint8_t spare7:1;) + uint8_t request_type:3;) }; uint8_t value; }; @@ -305,6 +308,9 @@ typedef struct test_ue_s { char *suci; /* TS33.501 : SUCI */ char *supi; /* TS33.501 : SUPI */ + uint8_t imsi_buf[OGS_MAX_IMSI_LEN]; + int imsi_len; + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; ogs_nas_mobile_identity_imeisv_t mobile_identity_imeisv; bool mobile_identity_imeisv_presence; @@ -432,6 +438,10 @@ typedef struct test_sess_s { char *apn; }; + /* RAT Type */ + uint8_t gtp_rat_type; + OpenAPI_rat_type_e sbi_rat_type; + ogs_ip_t ue_ip; ogs_ip_t upf_n3_ip; /* UPF-N3 IPv4/IPv6 */ @@ -454,6 +464,11 @@ typedef struct test_sess_s { ogs_ip_t upf_dl_ip; } handover; + /* ePDG */ + uint32_t epdg_s2b_c_teid; + uint32_t smf_s2b_c_teid; + ogs_gtp_node_t *gnode; + ogs_list_t bearer_list; test_ue_t *test_ue; @@ -494,11 +509,13 @@ void test_ue_remove_all(void); test_sess_t *test_sess_add_by_dnn_and_psi( test_ue_t *test_ue, char *dnn, uint8_t psi); -test_sess_t *test_sess_add_by_apn(test_ue_t *test_ue, char *apn); +test_sess_t *test_sess_add_by_apn( + test_ue_t *test_ue, char *apn, uint8_t rat_type); void test_sess_remove(test_sess_t *sess); void test_sess_remove_all(test_ue_t *test_ue); -test_sess_t *test_sess_find_by_apn(test_ue_t *test_ue, char *apn); +test_sess_t *test_sess_find_by_apn( + test_ue_t *test_ue, char *apn, uint8_t rat_type); test_sess_t *test_sess_find_by_psi(test_ue_t *test_ue, uint8_t psi); test_bearer_t *test_bearer_add(test_sess_t *sess, uint8_t ebi); @@ -519,6 +536,7 @@ bson_t *test_db_new_qos_flow(test_ue_t *test_ue); bson_t *test_db_new_session(test_ue_t *test_ue); bson_t *test_db_new_ims(test_ue_t *test_ue); bson_t *test_db_new_slice(test_ue_t *test_ue); +bson_t *test_db_new_non3gpp(test_ue_t *test_ue); #ifdef __cplusplus } diff --git a/tests/common/esm-build.c b/tests/common/esm-build.c index 1e0e56ead..26ffb3951 100644 --- a/tests/common/esm-build.c +++ b/tests/common/esm-build.c @@ -55,12 +55,8 @@ ogs_pkbuf_t *testesm_build_pdn_connectivity_request(test_sess_t *sess) memset(&message, 0, sizeof(message)); if (sess->pdn_connectivity_param.integrity_protected) { - if (sess->pdn_connectivity_param.ciphered) - message.h.security_header_type = - OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED; - else - message.h.security_header_type = - OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED; + message.h.security_header_type = + OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED; message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM; } @@ -69,7 +65,8 @@ ogs_pkbuf_t *testesm_build_pdn_connectivity_request(test_sess_t *sess) message.esm.h.message_type = OGS_NAS_EPS_PDN_CONNECTIVITY_REQUEST; request_type->type = OGS_NAS_EPS_PDN_TYPE_IPV4V6; - request_type->value = OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + request_type->value = sess->pdn_connectivity_param.request_type; + ogs_assert(request_type->value); if (sess->pdn_connectivity_param.apn) { pdn_connectivity_request->presencemask |= diff --git a/tests/common/esm-handler.c b/tests/common/esm-handler.c index dab807bca..f15db8506 100644 --- a/tests/common/esm-handler.c +++ b/tests/common/esm-handler.c @@ -40,7 +40,8 @@ void testesm_handle_activate_default_eps_bearer_context_request( access_point_name = &activate_default_eps_bearer_context_request->access_point_name; - sess = test_sess_find_by_apn(test_ue, access_point_name->apn); + sess = test_sess_find_by_apn( + test_ue, access_point_name->apn, OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); bearer = test_bearer_find_by_sess_ebi( sess, message->esm.h.eps_bearer_identity); diff --git a/tests/common/meson.build b/tests/common/meson.build index 6fa69f731..b670aff25 100644 --- a/tests/common/meson.build +++ b/tests/common/meson.build @@ -69,6 +69,8 @@ libtestcommon = static_library('testcomon', libnas_5gs_dep, libdiameter_rx_dep, libdiameter_cx_dep, + libdiameter_swx_dep, + libdiameter_s6b_dep, libaf_dep], install : false) @@ -87,4 +89,6 @@ libtestcommon_dep = declare_dependency( libnas_5gs_dep, libdiameter_rx_dep, libdiameter_cx_dep, + libdiameter_swx_dep, + libdiameter_s6b_dep, libaf_dep]) diff --git a/tests/common/test-common.h b/tests/common/test-common.h index 4df3ff075..7e443ad85 100644 --- a/tests/common/test-common.h +++ b/tests/common/test-common.h @@ -38,6 +38,8 @@ extern "C" { #include "ogs-s1ap.h" #pragma GCC diagnostic pop +#include "ogs-sbi.h" + #include "core/abts.h" #define OGS_TEST_INSIDE diff --git a/tests/csfb/crash-test.c b/tests/csfb/crash-test.c index 66e8b9d18..df79965f1 100644 --- a/tests/csfb/crash-test.c +++ b/tests/csfb/crash-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/csfb/mo-active-test.c b/tests/csfb/mo-active-test.c index b7f739090..6d64478ed 100644 --- a/tests/csfb/mo-active-test.c +++ b/tests/csfb/mo-active-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/csfb/mo-idle-test.c b/tests/csfb/mo-idle-test.c index fc6fd5d8a..9afb6a895 100644 --- a/tests/csfb/mo-idle-test.c +++ b/tests/csfb/mo-idle-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -354,7 +356,7 @@ static void test2_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -387,6 +389,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -553,7 +557,7 @@ static void test3_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -586,6 +590,8 @@ static void test3_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -838,7 +844,7 @@ static void test4_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -871,6 +877,8 @@ static void test4_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/csfb/mo-sms-test.c b/tests/csfb/mo-sms-test.c index 21d4053a2..9c7ce42eb 100644 --- a/tests/csfb/mo-sms-test.c +++ b/tests/csfb/mo-sms-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/csfb/mt-active-test.c b/tests/csfb/mt-active-test.c index 6188329dd..b259c289f 100644 --- a/tests/csfb/mt-active-test.c +++ b/tests/csfb/mt-active-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/csfb/mt-idle-test.c b/tests/csfb/mt-idle-test.c index 149a2f6a4..761dd11e1 100644 --- a/tests/csfb/mt-idle-test.c +++ b/tests/csfb/mt-idle-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/csfb/mt-sms-test.c b/tests/csfb/mt-sms-test.c index d0b900958..2e9c5b503 100644 --- a/tests/csfb/mt-sms-test.c +++ b/tests/csfb/mt-sms-test.c @@ -66,7 +66,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -99,6 +99,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/handover/epc-s1-test.c b/tests/handover/epc-s1-test.c index a5445ca20..a0ff90288 100644 --- a/tests/handover/epc-s1-test.c +++ b/tests/handover/epc-s1-test.c @@ -67,7 +67,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* Two eNB connects to MME */ @@ -116,6 +116,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -637,7 +639,7 @@ static void test2_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* Two eNB connects to MME */ @@ -686,6 +688,8 @@ static void test2_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -963,7 +967,7 @@ static void test3_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* Two eNB connects to MME */ @@ -1012,6 +1016,8 @@ static void test3_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/handover/epc-x2-test.c b/tests/handover/epc-x2-test.c index 84a4a01d8..c8cc51cc1 100644 --- a/tests/handover/epc-x2-test.c +++ b/tests/handover/epc-x2-test.c @@ -64,7 +64,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* Two eNB connects to MME */ @@ -113,6 +113,8 @@ static void test1_func(abts_case *tc, void *data) 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/meson.build b/tests/meson.build index 4f0422754..60acfd4ef 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -32,3 +32,4 @@ subdir('volte') subdir('csfb') subdir('310014') subdir('handover') +subdir('non3gpp') diff --git a/tests/non3gpp/abts-main.c b/tests/non3gpp/abts-main.c new file mode 100644 index 000000000..c20b44252 --- /dev/null +++ b/tests/non3gpp/abts-main.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test-app.h" +#include "test-fd-path.h" + +int parse_config(void); + +abts_suite *test_epdg(abts_suite *suite); + +const struct testlist { + abts_suite *(*func)(abts_suite *suite); +} alltests[] = { + {test_epdg}, + {NULL}, +}; + +static void terminate(void) +{ + ogs_msleep(50); + + test_child_terminate(); + app_terminate(); + + test_fd_final(); + + test_epc_final(); + + ogs_gtp_node_remove_all(&test_self()->gtpc_list); + ogs_gtp_context_final(); + ogs_gtp_xact_final(); + + ogs_app_terminate(); +} + +static void initialize(const char *const argv[]) +{ + int rv; + + rv = ogs_app_initialize(NULL, NULL, argv); + ogs_assert(rv == OGS_OK); + + ogs_gtp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE); + rv = ogs_gtp_xact_init(); + ogs_assert(rv == OGS_OK); + + test_epc_init(); + + rv = test_fd_init(); + ogs_assert(rv == OGS_OK); + + rv = app_initialize(argv); + ogs_assert(rv == OGS_OK); +} + +int main(int argc, const char *const argv[]) +{ + int i; + int rc; + abts_suite *suite = NULL; + + atexit(terminate); + test_app_run(argc, argv, "non3gpp.yaml", initialize); + + parse_config(); + + for (i = 0; alltests[i].func; i++) + suite = alltests[i].func(suite); + + return abts_report(suite); +} + +static int prepare(void) +{ + test_self()->gtpc_port = OGS_GTPV2_C_UDP_PORT; + + return OGS_OK; +} + +static int validation(void) +{ + return OGS_OK; +} + +int parse_config(void) +{ + int rv; + yaml_document_t *document = NULL; + ogs_yaml_iter_t root_iter; + + document = ogs_app()->document; + ogs_assert(document); + + rv = prepare(); + if (rv != OGS_OK) return rv; + + ogs_yaml_iter_init(&root_iter, document); + while (ogs_yaml_iter_next(&root_iter)) { + const char *root_key = ogs_yaml_iter_key(&root_iter); + ogs_assert(root_key); + if (!strcmp(root_key, "smf")) { + ogs_yaml_iter_t smf_iter; + ogs_yaml_iter_recurse(&root_iter, &smf_iter); + while (ogs_yaml_iter_next(&smf_iter)) { + const char *smf_key = ogs_yaml_iter_key(&smf_iter); + ogs_assert(smf_key); + if (!strcmp(smf_key, "gtpc")) { + ogs_yaml_iter_t gtpc_array, gtpc_iter; + ogs_yaml_iter_recurse(&smf_iter, >pc_array); + do { + int family = AF_UNSPEC; + int i, num = 0; + const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; + uint16_t port = test_self()->gtpc_port; + ogs_sockaddr_t *addr = NULL; + + if (ogs_yaml_iter_type(>pc_array) == + YAML_MAPPING_NODE) { + memcpy(>pc_iter, >pc_array, + sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type(>pc_array) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(>pc_array)) + break; + ogs_yaml_iter_recurse(>pc_array, >pc_iter); + } else if (ogs_yaml_iter_type(>pc_array) == + YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + while (ogs_yaml_iter_next(>pc_iter)) { + const char *gtpc_key = + ogs_yaml_iter_key(>pc_iter); + ogs_assert(gtpc_key); + if (!strcmp(gtpc_key, "family")) { + const char *v = ogs_yaml_iter_value(>pc_iter); + if (v) family = atoi(v); + if (family != AF_UNSPEC && + family != AF_INET && family != AF_INET6) { + ogs_warn("Ignore family(%d) : " + "AF_UNSPEC(%d), " + "AF_INET(%d), AF_INET6(%d) ", + family, AF_UNSPEC, AF_INET, AF_INET6); + family = AF_UNSPEC; + } + } else if (!strcmp(gtpc_key, "addr") || + !strcmp(gtpc_key, "name")) { + ogs_yaml_iter_t hostname_iter; + ogs_yaml_iter_recurse(>pc_iter, + &hostname_iter); + ogs_assert(ogs_yaml_iter_type(&hostname_iter) != + YAML_MAPPING_NODE); + + do { + if (ogs_yaml_iter_type(&hostname_iter) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&hostname_iter)) + break; + } + + ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME); + hostname[num++] = + ogs_yaml_iter_value(&hostname_iter); + } while ( + ogs_yaml_iter_type(&hostname_iter) == + YAML_SEQUENCE_NODE); + } else if (!strcmp(gtpc_key, "port")) { + const char *v = ogs_yaml_iter_value(>pc_iter); + if (v) port = atoi(v); + } else + ogs_warn("unknown key `%s`", gtpc_key); + } + + addr = NULL; + for (i = 0; i < num; i++) { + rv = ogs_addaddrinfo(&addr, + family, hostname[i], port, 0); + ogs_assert(rv == OGS_OK); + } + + ogs_filter_ip_version(&addr, + ogs_app()->parameter.no_ipv4, +#if 0 /* Only IPv4 is supporeted in Test-GTPv2C */ + ogs_app()->parameter.no_ipv6, +#else + 1, +#endif + ogs_app()->parameter.prefer_ipv4); + + if (addr == NULL) continue; + + ogs_gtp_node_add_by_addr(&test_self()->gtpc_list, addr); + + ogs_freeaddrinfo(addr); + + } while (ogs_yaml_iter_type(>pc_array) == + YAML_SEQUENCE_NODE); + } + } + } + } + + rv = validation(); + if (rv != OGS_OK) return rv; + + return OGS_OK; +} diff --git a/tests/non3gpp/diameter-s6b-path.c b/tests/non3gpp/diameter-s6b-path.c new file mode 100644 index 000000000..c63a286ba --- /dev/null +++ b/tests/non3gpp/diameter-s6b-path.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ogs-diameter-s6b.h" + +#include "test-common.h" +#include "test-fd-path.h" + +struct sess_state { + os0_t sid; /* S6B Session-Id */ + + struct timespec ts; /* Time of sending the message */ +}; + +static OGS_POOL(sess_state_pool, struct sess_state); +static ogs_thread_mutex_t sess_state_mutex; + +static struct session_handler *test_s6b_reg = NULL; +static struct disp_hdl *hdl_s6b_fb = NULL; +static struct disp_hdl *hdl_s6b_aar = NULL; +static struct disp_hdl *hdl_s6b_str = NULL; + +static __inline__ struct sess_state *new_state(os0_t sid) +{ + struct sess_state *new = NULL; + + ogs_assert(sid); + + ogs_thread_mutex_lock(&sess_state_mutex); + ogs_pool_alloc(&sess_state_pool, &new); + ogs_expect_or_return_val(new, NULL); + memset(new, 0, sizeof(*new)); + ogs_thread_mutex_unlock(&sess_state_mutex); + + new->sid = (os0_t)ogs_strdup((char *)sid); + ogs_expect_or_return_val(new->sid, NULL); + + return new; +} + +static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) +{ + ogs_assert(sess_data); + + if (sess_data->sid) + ogs_free(sess_data->sid); + + ogs_thread_mutex_lock(&sess_state_mutex); + ogs_pool_free(&sess_state_pool, sess_data); + ogs_thread_mutex_unlock(&sess_state_mutex); +} + +static int test_s6b_fb_cb(struct msg **msg, struct avp *avp, + struct session *sess, void *opaque, enum disp_action *act) +{ + /* This CB should never be called */ + ogs_warn("Unexpected message received!"); + + return ENOTSUP; +} + +static int test_s6b_aar_cb( struct msg **msg, struct avp *avp, + struct session *sess, void *opaque, enum disp_action *act) +{ + int rv; + int ret = 0, i; + + struct msg *ans, *qry; + struct avp *avpch1, *avpch2; + struct avp_hdr *hdr; + union avp_value val; + struct sess_state *sess_data = NULL; + + uint32_t result_code = OGS_DIAM_MISSING_AVP; + + ogs_assert(msg); + + /* Create answer header */ + qry = *msg; + ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0); + ogs_assert(ret == 0); + ans = *msg; + + /* Set the Auth-Application-Id AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_application_id, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_S6B_APPLICATION_ID; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Auth-Request-Type AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_request_type, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHORIZE_ONLY; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Find Session */ + ret = fd_sess_state_retrieve(test_s6b_reg, sess, &sess_data); + ogs_assert(ret == 0); + + if (!sess_data) { + os0_t sid; + size_t sidlen; + + ret = fd_sess_getsid(sess, &sid, &sidlen); + ogs_assert(ret == 0); + + sess_data = new_state(sid); + ogs_assert(sess_data); + } + + /* Get Origin-Host */ + ret = fd_msg_search_avp(qry, ogs_diam_origin_host, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + } else { + ogs_error("no_CC-Request-Type "); + result_code = OGS_DIAM_MISSING_AVP; + goto out; + } + + /* Set the Session-Timeout AVP */ + ret = fd_msg_avp_new(ogs_diam_session_timeout, 0, &avp); + ogs_assert(ret == 0); + val.i32 = 7200; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); + ogs_assert(ret == 0); + + /* Store this value in the session */ + ret = fd_sess_state_store(test_s6b_reg, sess, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + /* Add this value to the stats */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_echoed++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) ==0); + + return 0; + +out: + /* Set the Result-Code */ + if (result_code == OGS_DIAM_AVP_UNSUPPORTED) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_AVP_UNSUPPORTED", NULL, NULL, 1); + ogs_assert(ret == 0); + } else if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1); + ogs_assert(ret == 0); + } else if (result_code == OGS_DIAM_MISSING_AVP) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1); + ogs_assert(ret == 0); + } else { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + ogs_assert(ret == 0); + } + + if (sess_data) { + /* Store this value in the session */ + ret = fd_sess_state_store(test_s6b_reg, sess, &sess_data); + ogs_assert(sess_data == NULL); + } + + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + return 0; +} + +static int test_s6b_str_cb( struct msg **msg, struct avp *avp, + struct session *sess, void *opaque, enum disp_action *act) +{ + int rv; + int ret = 0, i; + + struct msg *ans, *qry; + struct avp *avpch1, *avpch2; + struct avp_hdr *hdr; + union avp_value val; + struct sess_state *sess_data = NULL; + + uint32_t result_code = OGS_DIAM_MISSING_AVP; + + ogs_assert(msg); + + /* Create answer header */ + qry = *msg; + ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0); + ogs_assert(ret == 0); + ans = *msg; + + /* Find Session */ + ret = fd_sess_state_retrieve(test_s6b_reg, sess, &sess_data); + ogs_assert(ret == 0); + + if (!sess_data) { + os0_t sid; + size_t sidlen; + + ret = fd_sess_getsid(sess, &sid, &sidlen); + ogs_assert(ret == 0); + + sess_data = new_state(sid); + ogs_assert(sess_data); + } + + /* Get Origin-Host */ + ret = fd_msg_search_avp(qry, ogs_diam_origin_host, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + } else { + ogs_error("no_CC-Request-Type "); + result_code = OGS_DIAM_MISSING_AVP; + goto out; + } + + /* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char *)"DIAMETER_SUCCESS", NULL, NULL, 1); + ogs_assert(ret == 0); + + /* Store this value in the session */ + ret = fd_sess_state_store(test_s6b_reg, sess, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + /* Add this value to the stats */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_echoed++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) ==0); + + return 0; + +out: + /* Set the Result-Code */ + if (result_code == OGS_DIAM_AVP_UNSUPPORTED) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_AVP_UNSUPPORTED", NULL, NULL, 1); + ogs_assert(ret == 0); + } else if (result_code == OGS_DIAM_UNKNOWN_SESSION_ID) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_UNKNOWN_SESSION_ID", NULL, NULL, 1); + ogs_assert(ret == 0); + } else if (result_code == OGS_DIAM_MISSING_AVP) { + ret = fd_msg_rescode_set(ans, + (char *)"DIAMETER_MISSING_AVP", NULL, NULL, 1); + ogs_assert(ret == 0); + } else { + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + ogs_assert(ret == 0); + } + + if (sess_data) { + /* Store this value in the session */ + ret = fd_sess_state_store(test_s6b_reg, sess, &sess_data); + ogs_assert(sess_data == NULL); + } + + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + return 0; +} + +int test_s6b_init(void) +{ + int ret; + struct disp_when data; + + ogs_thread_mutex_init(&sess_state_mutex); + ogs_pool_init(&sess_state_pool, ogs_app()->pool.sess); + + /* Install objects definitions for this application */ + ret = ogs_diam_s6b_init(); + ogs_assert(ret == 0); + + /* Create handler for sessions */ + ret = fd_sess_handler_create(&test_s6b_reg, &state_cleanup, NULL, NULL); + ogs_assert(ret == 0); + + /* Fallback CB if command != unexpected message received */ + memset(&data, 0, sizeof(data)); + data.app = ogs_diam_s6b_application; + + ret = fd_disp_register(test_s6b_fb_cb, DISP_HOW_APPID, &data, NULL, + &hdl_s6b_fb); + ogs_assert(ret == 0); + + data.command = ogs_diam_rx_cmd_aar; + ret = fd_disp_register(test_s6b_aar_cb, DISP_HOW_CC, &data, NULL, + &hdl_s6b_aar); + ogs_assert(ret == 0); + + data.command = ogs_diam_rx_cmd_str; + ret = fd_disp_register(test_s6b_str_cb, DISP_HOW_CC, &data, NULL, + &hdl_s6b_str); + ogs_assert(ret == 0); + + /* Advertise the support for the application in the peer */ + ret = fd_disp_app_support(ogs_diam_s6b_application, ogs_diam_vendor, 1, 0); + ogs_assert(ret == 0); + + return 0; +} + +void test_s6b_final(void) +{ + int ret; + + ret = fd_sess_handler_destroy(&test_s6b_reg, NULL); + ogs_assert(ret == OGS_OK); + + if (hdl_s6b_fb) + (void) fd_disp_unregister(&hdl_s6b_fb, NULL); + if (hdl_s6b_aar) + (void) fd_disp_unregister(&hdl_s6b_aar, NULL); + if (hdl_s6b_str) + (void) fd_disp_unregister(&hdl_s6b_str, NULL); + + ogs_pool_final(&sess_state_pool); + ogs_thread_mutex_destroy(&sess_state_mutex); +} diff --git a/tests/non3gpp/diameter-swx-path.c b/tests/non3gpp/diameter-swx-path.c new file mode 100644 index 000000000..ec9049ca8 --- /dev/null +++ b/tests/non3gpp/diameter-swx-path.c @@ -0,0 +1,666 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ogs-diameter-swx.h" + +#include "test-common.h" +#include "test-fd-path.h" + +static struct session_handler *test_swx_reg = NULL; + +struct sess_state { + test_sess_t *sess; + bool handover_ind; + int (*gtp_send)(test_sess_t *sess, bool handover_ind); + + char *user_name; + + bool resync; + + int server_assignment_type; + + struct timespec ts; /* Time of sending the message */ +}; + +static struct disp_hdl *hdl_swx_fb = NULL; + +static void test_swx_send_mar(struct sess_state *sess_data); +static void test_swx_maa_cb(void *data, struct msg **msg); + +static void test_swx_send_sar(struct sess_state *sess_data); +static void test_swx_saa_cb(void *data, struct msg **msg); + +static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) +{ + if (sess_data->user_name) + ogs_free(sess_data->user_name); + + ogs_free(sess_data); +} + +static int test_swx_fb_cb(struct msg **msg, struct avp *avp, + struct session *sess, void *opaque, enum disp_action *act) +{ + /* This CB should never be called */ + ogs_warn("Unexpected message received!"); + + return ENOTSUP; +} + +void test_swx_send(test_sess_t *sess, bool handover_ind, + int (*gtp_send)(test_sess_t *sess, bool handover_ind)) +{ + struct sess_state *sess_data = NULL; + + ogs_assert(sess); + ogs_assert(gtp_send); + + /* Create the random value to store with the session */ + sess_data = ogs_calloc(1, sizeof (*sess_data)); + ogs_assert(sess_data); + + sess_data->sess = sess; + sess_data->gtp_send = gtp_send; + sess_data->handover_ind = handover_ind; + + test_swx_send_mar(sess_data); +} + +static void test_swx_send_mar(struct sess_state *sess_data) +{ + int ret; + + struct msg *req = NULL; + + struct msg_hdr *msg_header = NULL; + + struct session *session = NULL; + struct sess_state *svg; + + struct avp *avp = NULL, *avpch = NULL; + union avp_value val; + + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + + uint8_t resync[OGS_AUTS_LEN + OGS_RAND_LEN]; + + ogs_assert(sess_data); + sess = sess_data->sess; + ogs_assert(sess); + test_ue = sess->test_ue; + ogs_assert(test_ue); + + ogs_debug("Multimedia-Auth-Request"); + + /* Create the request */ + ret = fd_msg_new(ogs_diam_cx_cmd_mar, MSGFL_ALLOC_ETEID, &req); + ogs_assert(ret == 0); + + ret = fd_msg_hdr(req, &msg_header); + ogs_assert(ret == 0); + msg_header->msg_appl = OGS_DIAM_SWX_APPLICATION_ID; + + #define OGS_DIAM_SWX_APP_SID_OPT "app_swx" + ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_SWX_APP_SID_OPT, + CONSTSTRLEN(OGS_DIAM_SWX_APP_SID_OPT)); + ogs_assert(ret == 0); + ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL); + ogs_assert(ret == 0); + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + req, OGS_DIAM_SWX_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Origin-Host & Origin-Realm */ + ret = fd_msg_add_origin(req, 0); + ogs_assert(ret == 0); + + /* Set the Destination-Host AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp); + ogs_assert(ret == 0); + val.os.data = TEST_HSS_IDENTITY; + val.os.len = strlen(TEST_HSS_IDENTITY); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Destination-Realm AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); + val.os.len = strlen(fd_g_config->cnf_diamrlm); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the User-Name AVP */ + if (sess_data->user_name) + ogs_free(sess_data->user_name); + sess_data->user_name = + ogs_msprintf("%s@%s", test_ue->imsi, fd_g_config->cnf_diamrlm); + ogs_assert(sess_data->user_name); + + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)sess_data->user_name; + val.os.len = strlen(sess_data->user_name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the RAT-Type AVP */ + ret = fd_msg_avp_new(ogs_diam_rat_type, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_RAT_TYPE_WLAN; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the SIP-Auth-Data-Item AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_auth_data_item, 0, &avp); + ogs_assert(ret == 0); + + if (sess_data->resync == true) { + uint8_t ak[OGS_AK_LEN]; + uint8_t sqn[OGS_SQN_LEN]; + uint8_t mac_s[OGS_MAC_S_LEN]; + uint8_t amf[2] = { 0, 0 }; + uint8_t auts[OGS_AUTS_LEN]; + + uint64_t sqn_ms; + int i; + + OGS_HEX(test_ue->k_string, strlen(test_ue->k_string), test_ue->k); + OGS_HEX(test_ue->opc_string, strlen(test_ue->opc_string), test_ue->opc); + + milenage_f2345(test_ue->opc, test_ue->k, test_ue->rand, + NULL, NULL, NULL, NULL, ak); + + sqn_ms = 0x11223344; + ogs_uint64_to_buffer(sqn_ms, 6, sqn); + milenage_f1(test_ue->opc, test_ue->k, test_ue->rand, + sqn, amf, NULL, auts + OGS_SQN_LEN); + for (i = 0; i < OGS_SQN_LEN; i++) + auts[i] = sqn[i] ^ ak[i]; + + memset(resync, 0, sizeof resync); + memcpy(resync, test_ue->rand, OGS_RAND_LEN); + memcpy(resync+OGS_RAND_LEN, auts, OGS_AUTS_LEN); + + ret = fd_msg_avp_new(ogs_diam_cx_sip_authorization, 0, &avpch); + ogs_assert(ret == 0); + val.os.len = OGS_RAND_LEN+OGS_AUTS_LEN; + val.os.data = resync; + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + } else { + ret = fd_msg_avp_new(ogs_diam_cx_sip_authentication_scheme, 0, &avpch); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA; + val.os.len = strlen(OGS_DIAM_SWX_AUTH_SCHEME_EAP_AKA); + ret = fd_msg_avp_setvalue(avpch, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avpch); + ogs_assert(ret == 0); + } + + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the SIP-Number-Auth-Items AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_sip_number_auth_items, 0, &avp); + ogs_assert(ret == 0); + val.i32 = 1; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts); + ogs_assert(ret == 0); + + /* Keep a pointer to the session data for debug purpose, + * in real life we would not need it */ + svg = sess_data; + + /* Store this value in the session */ + ret = fd_sess_state_store(test_swx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == 0); + + /* Send the request */ + ret = fd_msg_send(&req, test_swx_maa_cb, svg); + ogs_assert(ret == 0); + + /* Increment the counter */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_sent++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); +} + +/* Callback for incoming Multimedia-Auth-Answer messages */ +static void test_swx_maa_cb(void *data, struct msg **msg) +{ + int ret, new; + + struct avp *avp, *avpch; + struct avp_hdr *hdr; + + unsigned long dur; + int error = 0; + + struct sess_state *sess_data = NULL; + struct timespec ts; + struct session *session; + + uint32_t result_code; + uint32_t *err = NULL, *exp_err = NULL; + + ogs_debug("Multimedia-Auth-Answer"); + + ret = clock_gettime(CLOCK_REALTIME, &ts); + ogs_assert(ret == 0); + + /* Search the session, retrieve its data */ + ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); + ogs_expect_or_return(ret == 0); + ogs_expect_or_return(new == 0); + + ret = fd_sess_state_retrieve(test_swx_reg, session, &sess_data); + ogs_expect_or_return(ret == 0); + ogs_expect_or_return(sess_data); + ogs_expect_or_return((void *)sess_data == data); + + /* Value of Result Code */ + ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + result_code = hdr->avp_value->i32; + err = &result_code; + ogs_debug(" Result Code: %d", hdr->avp_value->i32); + } else { + ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp(avp, + ogs_diam_experimental_result_code, &avpch); + ogs_assert(ret == 0); + if (avpch) { + ret = fd_msg_avp_hdr(avpch, &hdr); + ogs_assert(ret == 0); + result_code = hdr->avp_value->i32; + exp_err = &result_code; + ogs_debug(" Experimental Result Code: %d", result_code); + } + } else { + ogs_error("no Result-Code"); + error++; + } + } + + ogs_assert(err && !exp_err && result_code == ER_DIAMETER_SUCCESS); + + /* Free the message */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) + + ((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + if (ogs_diam_logger_self()->stats.nb_recv) { + /* Ponderate in the avg */ + ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg * + ogs_diam_logger_self()->stats.nb_recv + dur) / + (ogs_diam_logger_self()->stats.nb_recv + 1); + /* Min, max */ + if (dur < ogs_diam_logger_self()->stats.shortest) + ogs_diam_logger_self()->stats.shortest = dur; + if (dur > ogs_diam_logger_self()->stats.longest) + ogs_diam_logger_self()->stats.longest = dur; + } else { + ogs_diam_logger_self()->stats.shortest = dur; + ogs_diam_logger_self()->stats.longest = dur; + ogs_diam_logger_self()->stats.avg = dur; + } + if (error) + ogs_diam_logger_self()->stats.nb_errs++; + else + ogs_diam_logger_self()->stats.nb_recv++; + + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + /* Display how long it took */ + if (ts.tv_nsec > sess_data->ts.tv_nsec) + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec - sess_data->ts.tv_sec), + (long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + else + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), + (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + + ret = fd_msg_free(*msg); + ogs_assert(ret == 0); + *msg = NULL; + + if (sess_data->resync == true) { + sess_data->server_assignment_type = + OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION; + test_swx_send_sar(sess_data); + } else { + sess_data->resync = true; + test_swx_send_mar(sess_data); + } + return; +} + +static void test_swx_send_sar(struct sess_state *sess_data) +{ + int ret; + + struct msg *req = NULL; + + struct msg_hdr *msg_header = NULL; + + struct session *session = NULL; + struct sess_state *svg; + + struct avp *avp = NULL, *avpch = NULL; + union avp_value val; + + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + + ogs_assert(sess_data); + sess = sess_data->sess; + ogs_assert(sess); + test_ue = sess->test_ue; + ogs_assert(test_ue); + + ogs_debug("Server-Assignment-Request"); + + /* Create the request */ + ret = fd_msg_new(ogs_diam_cx_cmd_sar, MSGFL_ALLOC_ETEID, &req); + ogs_assert(ret == 0); + + ret = fd_msg_hdr(req, &msg_header); + ogs_assert(ret == 0); + msg_header->msg_appl = OGS_DIAM_SWX_APPLICATION_ID; + + #define OGS_DIAM_SWX_APP_SID_OPT "app_swx" + ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_SWX_APP_SID_OPT, + CONSTSTRLEN(OGS_DIAM_SWX_APP_SID_OPT)); + ogs_assert(ret == 0); + ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL); + ogs_assert(ret == 0); + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + req, OGS_DIAM_SWX_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Origin-Host & Origin-Realm */ + ret = fd_msg_add_origin(req, 0); + ogs_assert(ret == 0); + + /* Set the Destination-Host AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_host, 0, &avp); + ogs_assert(ret == 0); + val.os.data = TEST_HSS_IDENTITY; + val.os.len = strlen(TEST_HSS_IDENTITY); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the Destination-Realm AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); + val.os.len = strlen(fd_g_config->cnf_diamrlm); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + if (sess_data->server_assignment_type == + OGS_DIAM_CX_SERVER_ASSIGNMENT_REGISTRATION) { + /* Set the User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)sess_data->user_name; + val.os.len = strlen(sess_data->user_name); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } + + /* Set the Server-Assignment-Type AVP */ + ret = fd_msg_avp_new(ogs_diam_cx_server_assignment_type, 0, &avp); + ogs_assert(ret == 0); + val.i32 = sess_data->server_assignment_type; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts); + ogs_assert(ret == 0); + + /* Keep a pointer to the session data for debug purpose, + * in real life we would not need it */ + svg = sess_data; + + /* Store this value in the session */ + ret = fd_sess_state_store(test_swx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == 0); + + /* Send the request */ + ret = fd_msg_send(&req, test_swx_saa_cb, svg); + ogs_assert(ret == 0); + + /* Increment the counter */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_sent++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); +} + +/* Callback for incoming Server-Assignment-Answer messages */ +static void test_swx_saa_cb(void *data, struct msg **msg) +{ + int rv, ret, new; + + struct avp *avp, *avpch; + struct avp_hdr *hdr; + + unsigned long dur; + int error = 0; + + struct sess_state *sess_data = NULL; + struct timespec ts; + struct session *session; + + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + + uint32_t result_code; + uint32_t *err = NULL, *exp_err = NULL; + + ogs_debug("Server-Assignment-Answer"); + + ret = clock_gettime(CLOCK_REALTIME, &ts); + ogs_assert(ret == 0); + + /* Search the session, retrieve its data */ + ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); + ogs_expect_or_return(ret == 0); + ogs_expect_or_return(new == 0); + + ret = fd_sess_state_retrieve(test_swx_reg, session, &sess_data); + ogs_expect_or_return(ret == 0); + ogs_expect_or_return(sess_data); + ogs_expect_or_return((void *)sess_data == data); + + sess = sess_data->sess; + ogs_assert(sess); + test_ue = sess->test_ue; + ogs_assert(test_ue); + + /* Value of Result Code */ + ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + result_code = hdr->avp_value->i32; + err = &result_code; + ogs_debug(" Result Code: %d", hdr->avp_value->i32); + } else { + ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp(avp, + ogs_diam_experimental_result_code, &avpch); + ogs_assert(ret == 0); + if (avpch) { + ret = fd_msg_avp_hdr(avpch, &hdr); + ogs_assert(ret == 0); + result_code = hdr->avp_value->i32; + exp_err = &result_code; + ogs_debug(" Experimental Result Code: %d", result_code); + } + } else { + ogs_error("no Result-Code"); + error++; + } + } + + ogs_assert(err && !exp_err && result_code == ER_DIAMETER_SUCCESS); + + /* Free the message */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) + + ((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + if (ogs_diam_logger_self()->stats.nb_recv) { + /* Ponderate in the avg */ + ogs_diam_logger_self()->stats.avg = (ogs_diam_logger_self()->stats.avg * + ogs_diam_logger_self()->stats.nb_recv + dur) / + (ogs_diam_logger_self()->stats.nb_recv + 1); + /* Min, max */ + if (dur < ogs_diam_logger_self()->stats.shortest) + ogs_diam_logger_self()->stats.shortest = dur; + if (dur > ogs_diam_logger_self()->stats.longest) + ogs_diam_logger_self()->stats.longest = dur; + } else { + ogs_diam_logger_self()->stats.shortest = dur; + ogs_diam_logger_self()->stats.longest = dur; + ogs_diam_logger_self()->stats.avg = dur; + } + if (error) + ogs_diam_logger_self()->stats.nb_errs++; + else + ogs_diam_logger_self()->stats.nb_recv++; + + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + /* Display how long it took */ + if (ts.tv_nsec > sess_data->ts.tv_nsec) + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec - sess_data->ts.tv_sec), + (long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + else + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), + (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + + ret = fd_msg_free(*msg); + ogs_assert(ret == 0); + *msg = NULL; + + rv = sess_data->gtp_send(sess, sess_data->handover_ind); + ogs_assert(rv == OGS_OK); + + state_cleanup(sess_data, NULL, NULL); +} + +int test_swx_init(void) +{ + int ret; + struct disp_when data; + + /* Install objects definitions for this application */ + ret = ogs_diam_swx_init(); + ogs_assert(ret == 0); + + /* Create handler for sessions */ + ret = fd_sess_handler_create(&test_swx_reg, &state_cleanup, NULL, NULL); + ogs_assert(ret == 0); + + /* Fallback CB if command != unexpected message received */ + memset(&data, 0, sizeof(data)); + data.app = ogs_diam_swx_application; + + ret = fd_disp_register(test_swx_fb_cb, DISP_HOW_APPID, &data, NULL, + &hdl_swx_fb); + ogs_assert(ret == 0); + + /* Advertise the support for the application in the peer */ + ret = fd_disp_app_support(ogs_diam_swx_application, ogs_diam_vendor, 1, 0); + ogs_assert(ret == 0); + + return 0; +} + +void test_swx_final(void) +{ + int ret; + + ret = fd_sess_handler_destroy(&test_swx_reg, NULL); + ogs_assert(ret == OGS_OK); + + if (hdl_swx_fb) + (void) fd_disp_unregister(&hdl_swx_fb, NULL); +} diff --git a/tests/non3gpp/epdg-test.c b/tests/non3gpp/epdg-test.c new file mode 100644 index 000000000..698e87de6 --- /dev/null +++ b/tests/non3gpp/epdg-test.c @@ -0,0 +1,754 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test-common.h" +#include "test-fd-path.h" +#include "gtp-path.h" + +static void test1_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_socknode_t *epdg_c; + ogs_socknode_t *epdg_u; + ogs_gtp_node_t *gnode; + ogs_pkbuf_t *emmbuf; + ogs_pkbuf_t *esmbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_s1ap_message_t message; + + uint8_t *rx_sid = NULL; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *bearer = NULL; + + uint32_t enb_ue_s1ap_id; + uint64_t mme_ue_s1ap_id; + + bson_t *doc = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_NAS_5GS_NULL_SCHEME; + mobile_identity_suci.home_network_pki_value = 0; + mobile_identity_suci.scheme_output[0] = 0x10; + mobile_identity_suci.scheme_output[1] = 0x32; + mobile_identity_suci.scheme_output[2] = 0x54; + mobile_identity_suci.scheme_output[3] = 0x86; + mobile_identity_suci.scheme_output[4] = 0x91; + + test_ue = test_ue_add_by_suci(&mobile_identity_suci, 13); + ogs_assert(test_ue); + + test_ue->e_cgi.cell_id = 0x1079baf; + test_ue->nas.ksi = 0; + test_ue->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* eNB connects to MME */ + s1ap = tests1ap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* ePDG GTPv2-C */ + epdg_c = test_epdg_server(OGS_GTPV2_C_UDP_PORT); + ABTS_PTR_NOTNULL(tc, epdg_c); + + gnode = ogs_list_first(&test_self()->gtpc_list); + ogs_assert(gnode); + + ABTS_PTR_NOTNULL(tc, epdg_c->sock); + rv = ogs_gtp_connect(epdg_c->sock, NULL, gnode); + ogs_assert(rv == OGS_OK); + + /* ePDG GTP-U */ + epdg_u = test_epdg_server(OGS_GTPV1_U_UDP_PORT); + ABTS_PTR_NOTNULL(tc, epdg_u); + + /* Send S1-Setup Reqeust */ + sendbuf = test_s1ap_build_s1_setup_request( + S1AP_ENB_ID_PR_macroENB_ID, 0x54f64); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S1-Setup Response */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(NULL, recvbuf); + + /********** Insert Subscriber in Database */ + doc = test_db_new_non3gpp(test_ue); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc)); + + /* Setup WLAN Session */ + sess = test_sess_add_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_WLAN); + ogs_assert(sess); + + OGS_SETUP_GTP_NODE(sess, ogs_list_first(&test_self()->gtpc_list)); + + /* Send SWx MAR */ + test_swx_send(sess, false, test_s2b_send_create_session_request); + + /* Receive S2b Create Session Response */ + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + /* Send GTP-U ICMP Packet */ + bearer = test_bearer_find_by_sess_ebi(sess, 5); + ogs_assert(bearer); + + rv = test_gtpu_send_ping(epdg_u, bearer, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = test_epdg_read(epdg_u); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send S2b Delete Session Request */ + rv = test_s2b_send_delete_session_request(sess); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S2b Delete Session Response */ + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue)); + + /* eNB disconnect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disconnect from SGW */ + test_gtpu_close(gtpu); + + /* ePDG diconnect */ + test_epdg_close(epdg_c); + test_epdg_close(epdg_u); + + test_ue_remove(test_ue); +} + +static void test2_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_socknode_t *epdg_c; + ogs_socknode_t *epdg_u; + ogs_gtp_node_t *gnode; + ogs_pkbuf_t *emmbuf; + ogs_pkbuf_t *esmbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_s1ap_message_t message; + + uint8_t *rx_sid = NULL; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *bearer = NULL; + + uint32_t enb_ue_s1ap_id; + uint64_t mme_ue_s1ap_id; + + bson_t *doc = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_NAS_5GS_NULL_SCHEME; + mobile_identity_suci.home_network_pki_value = 0; + mobile_identity_suci.scheme_output[0] = 0x10; + mobile_identity_suci.scheme_output[1] = 0x32; + mobile_identity_suci.scheme_output[2] = 0x54; + mobile_identity_suci.scheme_output[3] = 0x86; + mobile_identity_suci.scheme_output[4] = 0x91; + + test_ue = test_ue_add_by_suci(&mobile_identity_suci, 13); + ogs_assert(test_ue); + + test_ue->e_cgi.cell_id = 0x1079baf; + test_ue->nas.ksi = 0; + test_ue->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* eNB connects to MME */ + s1ap = tests1ap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* ePDG GTPv2-C */ + epdg_c = test_epdg_server(OGS_GTPV2_C_UDP_PORT); + ABTS_PTR_NOTNULL(tc, epdg_c); + + gnode = ogs_list_first(&test_self()->gtpc_list); + ogs_assert(gnode); + + ABTS_PTR_NOTNULL(tc, epdg_c->sock); + rv = ogs_gtp_connect(epdg_c->sock, NULL, gnode); + ogs_assert(rv == OGS_OK); + + /* ePDG GTP-U */ + epdg_u = test_epdg_server(OGS_GTPV1_U_UDP_PORT); + ABTS_PTR_NOTNULL(tc, epdg_u); + + /* Send S1-Setup Reqeust */ + sendbuf = test_s1ap_build_s1_setup_request( + S1AP_ENB_ID_PR_macroENB_ID, 0x54f64); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S1-Setup Response */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(NULL, recvbuf); + + /********** Insert Subscriber in Database */ + doc = test_db_new_session(test_ue); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc)); + + /* Setup WLAN Session */ + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_WLAN); + ogs_assert(sess); + + OGS_SETUP_GTP_NODE(sess, ogs_list_first(&test_self()->gtpc_list)); + + /* Send SWx MAR */ + test_swx_send(sess, false, test_s2b_send_create_session_request); + + /* Receive S2b Create Session Response */ + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + /* Receive S2b Create Bearer Request */ + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + /* Send GTP-U ICMP Packet */ + bearer = test_bearer_find_by_sess_ebi(sess, 6); + ogs_assert(bearer); + + rv = test_gtpu_send_ping(epdg_u, bearer, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = test_epdg_read(epdg_u); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send S2b Delete Session Request */ + rv = test_s2b_send_delete_session_request(sess); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S2b Delete Session Response */ + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue)); + + /* eNB disconnect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disconnect from SGW */ + test_gtpu_close(gtpu); + + /* ePDG diconnect */ + test_epdg_close(epdg_c); + test_epdg_close(epdg_u); + + test_ue_remove(test_ue); +} + +static void test3_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_socknode_t *epdg_c; + ogs_socknode_t *epdg_u; + ogs_gtp_node_t *gnode; + ogs_pkbuf_t *emmbuf; + ogs_pkbuf_t *esmbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_s1ap_message_t message; + + uint8_t *rx_sid = NULL; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *bearer = NULL; + + uint32_t enb_ue_s1ap_id; + uint64_t mme_ue_s1ap_id; + + bson_t *doc = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_NAS_5GS_NULL_SCHEME; + mobile_identity_suci.home_network_pki_value = 0; + mobile_identity_suci.scheme_output[0] = 0x10; + mobile_identity_suci.scheme_output[1] = 0x32; + mobile_identity_suci.scheme_output[2] = 0x54; + mobile_identity_suci.scheme_output[3] = 0x86; + mobile_identity_suci.scheme_output[4] = 0x91; + + test_ue = test_ue_add_by_suci(&mobile_identity_suci, 13); + ogs_assert(test_ue); + + test_ue->e_cgi.cell_id = 0x1079baf; + test_ue->nas.ksi = 0; + test_ue->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* eNB connects to MME */ + s1ap = tests1ap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* ePDG GTPv2-C */ + epdg_c = test_epdg_server(OGS_GTPV2_C_UDP_PORT); + ABTS_PTR_NOTNULL(tc, epdg_c); + + gnode = ogs_list_first(&test_self()->gtpc_list); + ogs_assert(gnode); + + ABTS_PTR_NOTNULL(tc, epdg_c->sock); + rv = ogs_gtp_connect(epdg_c->sock, NULL, gnode); + ogs_assert(rv == OGS_OK); + + /* ePDG GTP-U */ + epdg_u = test_epdg_server(OGS_GTPV1_U_UDP_PORT); + ABTS_PTR_NOTNULL(tc, epdg_u); + + /* Send S1-Setup Reqeust */ + sendbuf = test_s1ap_build_s1_setup_request( + S1AP_ENB_ID_PR_macroENB_ID, 0x54f64); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S1-Setup Response */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(NULL, recvbuf); + + /********** Insert Subscriber in Database */ + doc = test_db_new_non3gpp(test_ue); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc)); + + /* Setup WLAN Session */ + sess = test_sess_add_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_WLAN); + ogs_assert(sess); + + OGS_SETUP_GTP_NODE(sess, ogs_list_first(&test_self()->gtpc_list)); + + /* Send SWx MAR */ + test_swx_send(sess, false, test_s2b_send_create_session_request); + + /* Receive S2b Create Session Response */ + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + bearer = test_bearer_find_by_sess_ebi(sess, 5); + ogs_assert(bearer); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(epdg_u, bearer, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = test_epdg_read(epdg_u); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Setup EUTRAN Session */ + sess = test_sess_add_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_EUTRAN); + ogs_assert(sess); + + /* Send Attach Request */ + memset(&sess->pdn_connectivity_param, + 0, sizeof(sess->pdn_connectivity_param)); + sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_HANDOVER; + esmbuf = testesm_build_pdn_connectivity_request(sess); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue->attach_request_param, + 0, sizeof(test_ue->attach_request_param)); + test_ue->attach_request_param.drx_parameter = 1; + test_ue->attach_request_param.tmsi_status = 1; + test_ue->attach_request_param.mobile_station_classmark_2 = 1; + test_ue->attach_request_param.additional_update_type = 1; + test_ue->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue->initial_ue_param, 0, sizeof(test_ue->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + test_ue->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + + /* Send ESM Information Response */ + esmbuf = testesm_build_esm_information_response(sess); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + test_ue->nr_cgi.cell_id = 0x1234502; + bearer = test_bearer_find_by_ue_ebi(test_ue, 5); + ogs_assert(bearer); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = test_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive S2b Delete Session Response */ + sess = test_sess_find_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_WLAN); + ogs_assert(sess); + + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + /* Send PDN Connectivity Request */ + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); + ogs_assert(sess); + sess->pti = 5; + + sess->pdn_connectivity_param.integrity_protected = 1; + sess->pdn_connectivity_param.apn = 1; + sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request(sess); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RABSetupRequest + + * Activate default EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_E_RABSetup, + test_ue->s1ap_procedure_code); + + /* Send E-RABSetupResponse */ + bearer = test_bearer_find_by_ue_ebi(test_ue, 6); + ogs_assert(bearer); + sendbuf = test_s1ap_build_e_rab_setup_response(bearer); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Activate default EPS bearer context accept */ + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer, true); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Setup WLAN Session */ + sess = test_sess_add_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_WLAN); + ogs_assert(sess); + + OGS_SETUP_GTP_NODE(sess, ogs_list_first(&test_self()->gtpc_list)); + + /* Send SWx MAR */ + test_swx_send(sess, true, test_s2b_send_create_session_request); + + /* Receive S2b Create Session Response */ + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + /* Send GTP-U ICMP Packet */ + bearer = test_bearer_find_by_sess_ebi(sess, 5); + ogs_assert(bearer); + + rv = test_gtpu_send_ping(epdg_u, bearer, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = test_epdg_read(epdg_u); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive E-RABReleaseCommand + + * Deactivate EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_E_RABRelease, + test_ue->s1ap_procedure_code); + + /* Send E-RABReleaseResponse */ + sess = test_sess_find_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_EUTRAN); + ogs_assert(sess); + + bearer = test_bearer_find_by_sess_ebi(sess, 5); + ogs_assert(bearer); + sendbuf = test_s1ap_build_e_rab_release_response(bearer); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Deactivate EPS bearer context accept */ + esmbuf = testesm_build_deactivate_eps_bearer_context_accept(bearer); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Remove EUTRAN Session */ + test_sess_remove(sess); + + ogs_msleep(300); + + /* Setup EUTRAN Session */ + sess = test_sess_add_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_EUTRAN); + ogs_assert(sess); + + sess->pdn_connectivity_param.integrity_protected = 1; + sess->pdn_connectivity_param.apn = 1; + sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_HANDOVER; + esmbuf = testesm_build_pdn_connectivity_request(sess); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RABSetupRequest + + * Activate default EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_E_RABSetup, + test_ue->s1ap_procedure_code); + + /* Send E-RABSetupResponse */ + bearer = test_bearer_find_by_ue_ebi(test_ue, 7); + ogs_assert(bearer); + sendbuf = test_s1ap_build_e_rab_setup_response(bearer); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Activate default EPS bearer context accept */ + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer, true); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, bearer, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = test_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive S2b Delete Session Response */ + sess = test_sess_find_by_apn(test_ue, "wlan", OGS_GTP_RAT_TYPE_WLAN); + ogs_assert(sess); + + recvbuf = test_epdg_read(epdg_c); + ABTS_PTR_NOTNULL(tc, recvbuf); + test_s2b_recv(sess, recvbuf); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue)); + + /* eNB disconnect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disconnect from SGW */ + test_gtpu_close(gtpu); + + /* ePDG diconnect */ + test_epdg_close(epdg_c); + test_epdg_close(epdg_u); + + test_ue_remove(test_ue); +} + +abts_suite *test_epdg(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test1_func, NULL); + abts_run_test(suite, test2_func, NULL); + abts_run_test(suite, test3_func, NULL); + + return suite; +} diff --git a/tests/non3gpp/gtp-path.c b/tests/non3gpp/gtp-path.c new file mode 100644 index 000000000..d6e8a4693 --- /dev/null +++ b/tests/non3gpp/gtp-path.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test-common.h" +#include "s2b-build.h" +#include "s2b-handler.h" + +ogs_socknode_t *test_epdg_server(uint16_t port) +{ + int rv; + ogs_sockaddr_t *addr = NULL; + ogs_socknode_t *node = NULL; + ogs_sock_t *sock = NULL; + + ogs_assert(port); + +#define TEST_EPDG_IPV4 "127.0.0.5" + + rv = ogs_getaddrinfo(&addr, AF_UNSPEC, TEST_EPDG_IPV4, port, 0); + ogs_assert(rv == OGS_OK); + + node = ogs_socknode_new(addr); + ogs_assert(node); + + sock = ogs_udp_server(node); + ogs_assert(sock); + + return node; +} + +void test_epdg_close(ogs_socknode_t *node) +{ + ogs_socknode_free(node); +} + +ogs_pkbuf_t *test_epdg_read(ogs_socknode_t *node) +{ + int rc = 0; + ogs_sockaddr_t from; + ogs_pkbuf_t *recvbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_assert(recvbuf); + ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN); + + ogs_assert(node); + ogs_assert(node->sock); + + while (1) { + rc = ogs_recvfrom( + node->sock->fd, recvbuf->data, recvbuf->len, 0, &from); + if (rc <= 0) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "ogs_recvfrom() failed"); + } + break; + } + recvbuf->len = rc; + + return recvbuf; +} + +void test_s2b_recv(test_sess_t *sess, ogs_pkbuf_t *pkbuf) +{ + int rv; + ogs_gtp_message_t gtp_message; + ogs_gtp_xact_t *xact = NULL; + + ogs_assert(sess); + ogs_assert(sess->gnode); + ogs_assert(pkbuf); + + if (ogs_gtp_parse_msg(>p_message, pkbuf) != OGS_OK) { + ogs_error("ogs_gtp_parse_msg() failed"); + ogs_pkbuf_free(pkbuf); + return; + } + + rv = ogs_gtp_xact_receive(sess->gnode, >p_message.h, &xact); + if (rv != OGS_OK) { + ogs_error("ogs_gtp_xact_receive() failed"); + ogs_pkbuf_free(pkbuf); + return; + } + + switch (gtp_message.h.type) { + case OGS_GTP_CREATE_SESSION_RESPONSE_TYPE: + test_s2b_handle_create_session_response( + xact, sess, >p_message.create_session_response); + break; + case OGS_GTP_DELETE_SESSION_RESPONSE_TYPE: + test_s2b_handle_delete_session_response( + xact, sess, >p_message.delete_session_response); + break; + case OGS_GTP_CREATE_BEARER_REQUEST_TYPE: + test_s2b_handle_create_bearer_request( + xact, sess, >p_message.create_bearer_request); + break; + case OGS_GTP_DELETE_BEARER_REQUEST_TYPE: + test_s2b_handle_delete_bearer_request( + xact, sess, >p_message.delete_bearer_request); + break; + default: + ogs_error("Not implmeneted(type:%d)", gtp_message.h.type); + break; + } + + ogs_pkbuf_free(pkbuf); +} + +int test_s2b_send_create_session_request(test_sess_t *sess, bool handover_ind) +{ + int rv; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + ogs_gtp_xact_t *xact = NULL; + + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_CREATE_SESSION_REQUEST_TYPE; + h.teid = sess->smf_s2b_c_teid; + + pkbuf = test_s2b_build_create_session_request(h.type, sess, handover_ind); + ogs_expect_or_return_val(pkbuf, OGS_ERROR); + + xact = ogs_gtp_xact_local_create(sess->gnode, &h, pkbuf, NULL, sess); + ogs_expect_or_return_val(xact, OGS_ERROR); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + +int test_s2b_send_delete_session_request(test_sess_t *sess) +{ + int rv; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + ogs_gtp_xact_t *xact = NULL; + + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_DELETE_SESSION_REQUEST_TYPE; + h.teid = sess->smf_s2b_c_teid; + + pkbuf = test_s2b_build_delete_session_request(h.type, sess); + ogs_expect_or_return_val(pkbuf, OGS_ERROR); + + xact = ogs_gtp_xact_local_create(sess->gnode, &h, pkbuf, NULL, sess); + ogs_expect_or_return_val(xact, OGS_ERROR); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + +int test_s2b_send_create_bearer_response( + test_bearer_t *bearer, ogs_gtp_xact_t *xact) +{ + int rv; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + test_sess_t *sess = NULL; + + ogs_assert(xact); + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_CREATE_BEARER_RESPONSE_TYPE; + h.teid = sess->smf_s2b_c_teid; + + pkbuf = test_s2b_build_create_bearer_response(h.type, bearer); + ogs_expect_or_return_val(pkbuf, OGS_ERROR); + + rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); + ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + +int test_s2b_send_delete_bearer_response( + test_bearer_t *bearer, ogs_gtp_xact_t *xact) +{ + int rv; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + test_sess_t *sess = NULL; + + ogs_assert(xact); + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_DELETE_BEARER_RESPONSE_TYPE; + h.teid = sess->smf_s2b_c_teid; + + pkbuf = test_s2b_build_delete_bearer_response(h.type, bearer); + ogs_expect_or_return_val(pkbuf, OGS_ERROR); + + rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); + ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} diff --git a/tests/non3gpp/gtp-path.h b/tests/non3gpp/gtp-path.h new file mode 100644 index 000000000..182238584 --- /dev/null +++ b/tests/non3gpp/gtp-path.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TEST_NON3GPP_GTP_PATH_H +#define TEST_NON3GPP_GTP_PATH_H + +#include "test-common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ogs_socknode_t *test_epdg_server(uint16_t port); +void test_epdg_close(ogs_socknode_t *node); + +ogs_pkbuf_t *test_epdg_read(ogs_socknode_t *node); + +void test_s2b_recv(test_sess_t *sess, ogs_pkbuf_t *pkbuf); + +int test_s2b_send_create_session_request(test_sess_t *sess, bool handover_ind); +int test_s2b_send_delete_session_request(test_sess_t *sess); + +int test_s2b_send_create_bearer_response( + test_bearer_t *bearer, ogs_gtp_xact_t *xact); +int test_s2b_send_delete_bearer_response( + test_bearer_t *bearer, ogs_gtp_xact_t *xact); + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_NON3GPP_GTP_PATH_H */ diff --git a/tests/non3gpp/meson.build b/tests/non3gpp/meson.build new file mode 100644 index 000000000..e58e63753 --- /dev/null +++ b/tests/non3gpp/meson.build @@ -0,0 +1,38 @@ +# Copyright (C) 2019 by Sukchan Lee + +# This file is part of Open5GS. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +testapp_non3gpp_sources = files(''' + test-fd-path.h + test-fd-path.c + diameter-swx-path.c + diameter-s6b-path.c + gtp-path.c + + s2b-build.c + s2b-handler.c + + abts-main.c + epdg-test.c +'''.split()) + +testapp_non3gpp_exe = executable('non3gpp', + sources : testapp_non3gpp_sources, + c_args : [testunit_core_cc_flags, + '-DFD_EXT_DIR="@0@"'.format(freediameter_extensions_builddir)], + dependencies : libtestepc_dep) + +test('non3gpp', testapp_non3gpp_exe, is_parallel : false, suite: 'epc') diff --git a/tests/non3gpp/s2b-build.c b/tests/non3gpp/s2b-build.c new file mode 100644 index 000000000..0d286f13d --- /dev/null +++ b/tests/non3gpp/s2b-build.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test-common.h" + +ogs_pkbuf_t *test_s2b_build_create_session_request( + uint8_t type, test_sess_t *sess, bool handover_ind) +{ + int rv; + ogs_session_t *session = NULL; + test_ue_t *test_ue = NULL; + test_bearer_t *bearer = NULL; + ogs_gtp_message_t gtp_message; + ogs_gtp_create_session_request_t *req = >p_message.create_session_request; + + uint8_t msisdn_buf[OGS_MAX_MSISDN_LEN]; + int msisdn_len; + + ogs_gtp_uli_t uli; + char uli_buf[OGS_GTP_MAX_ULI_LEN]; + ogs_gtp_f_teid_t test_s2b_c_teid, test_s2b_u_teid; + int len; + ogs_paa_t paa; + + ogs_gtp_ambr_t ambr; + ogs_gtp_bearer_qos_t bearer_qos; + char bearer_qos_buf[GTP_BEARER_QOS_LEN]; + char apn[OGS_MAX_APN_LEN]; + + ogs_gtp_indication_t indication; + + ogs_assert(sess); + test_ue = sess->test_ue; + ogs_assert(test_ue); + + ogs_assert(0 == ogs_list_count(&sess->bearer_list)); + + bearer = test_bearer_add(sess, 5); + ogs_assert(bearer); + + ogs_debug("Create Session Request"); + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + if (handover_ind == true) { + memset(&indication, 0, sizeof(ogs_gtp_indication_t)); + indication.hi = 1; + req->indication_flags.presence = 1; + req->indication_flags.data = &indication; + req->indication_flags.len = sizeof(ogs_gtp_indication_t); + } + + ogs_assert(test_ue->imsi_len); + req->imsi.presence = 1; + req->imsi.data = test_ue->imsi_buf; + req->imsi.len = test_ue->imsi_len; + + ogs_bcd_to_buffer(TEST_MSISDN, msisdn_buf, &msisdn_len); + + req->msisdn.presence = 1; + req->msisdn.data = msisdn_buf; + req->msisdn.len = msisdn_len; + + memset(&uli, 0, sizeof(ogs_gtp_uli_t)); + uli.flags.e_cgi = 1; + uli.flags.tai = 1; + ogs_nas_from_plmn_id(&uli.tai.nas_plmn_id, &test_ue->e_tai.plmn_id); + uli.tai.tac = test_ue->e_tai.tac; + ogs_nas_from_plmn_id(&uli.e_cgi.nas_plmn_id, &test_ue->e_cgi.plmn_id); + uli.e_cgi.cell_id = test_ue->e_cgi.cell_id; + req->user_location_information.presence = 1; + ogs_gtp_build_uli(&req->user_location_information, &uli, + uli_buf, OGS_GTP_MAX_ULI_LEN); + + req->serving_network.presence = 1; + req->serving_network.data = &uli.tai.nas_plmn_id; + req->serving_network.len = sizeof(uli.tai.nas_plmn_id); + + req->rat_type.presence = 1; + req->rat_type.u8 = OGS_GTP_RAT_TYPE_WLAN; + + memset(&test_s2b_c_teid, 0, sizeof(ogs_gtp_f_teid_t)); + test_s2b_c_teid.interface_type = OGS_GTP_F_TEID_S2B_EPDG_GTP_C; + test_s2b_c_teid.teid = htobe32(sess->epdg_s2b_c_teid); + ogs_assert(sess->gnode->sock); + rv = ogs_gtp_sockaddr_to_f_teid( + &sess->gnode->sock->local_addr, NULL, &test_s2b_c_teid, &len); + ogs_assert(rv == OGS_OK); + req->sender_f_teid_for_control_plane.presence = 1; + req->sender_f_teid_for_control_plane.data = &test_s2b_c_teid; + req->sender_f_teid_for_control_plane.len = len; + + req->access_point_name.presence = 1; + req->access_point_name.len = ogs_fqdn_build( + apn, sess->apn, strlen(sess->apn)); + req->access_point_name.data = apn; + + req->selection_mode.presence = 1; + req->selection_mode.u8 = + OGS_GTP_SELECTION_MODE_MS_OR_NETWORK_PROVIDED_APN; + + memset(&paa, 0, sizeof(paa)); + paa.session_type = OGS_PDU_SESSION_TYPE_IPV4V6; + + req->pdn_address_allocation.presence = 1; + req->pdn_address_allocation.data = &paa; + req->pdn_address_allocation.len = OGS_PAA_IPV4V6_LEN; + + memset(&ambr, 0, sizeof(ogs_gtp_ambr_t)); + ambr.uplink = htobe32(50000); + ambr.downlink = htobe32(150000); + req->aggregate_maximum_bit_rate.presence = 1; + req->aggregate_maximum_bit_rate.data = &ambr; + req->aggregate_maximum_bit_rate.len = sizeof(ambr); + + req->bearer_contexts_to_be_created.presence = 1; + req->bearer_contexts_to_be_created.eps_bearer_id.presence = 1; + req->bearer_contexts_to_be_created.eps_bearer_id.u8 = bearer->ebi; + + memset(&test_s2b_u_teid, 0, sizeof(ogs_gtp_f_teid_t)); + test_s2b_u_teid.teid = htobe32(bearer->enb_s1u_teid); + test_s2b_u_teid.interface_type = OGS_GTP_F_TEID_S2B_U_EPDG_GTP_U; + ogs_assert(sess->gnode->sock); + rv = ogs_gtp_sockaddr_to_f_teid( + &sess->gnode->sock->local_addr, NULL, &test_s2b_u_teid, &len); + + req->bearer_contexts_to_be_created.s2b_u_epdg_f_teid_5.presence = 1; + req->bearer_contexts_to_be_created.s2b_u_epdg_f_teid_5.data = + &test_s2b_u_teid; + req->bearer_contexts_to_be_created.s2b_u_epdg_f_teid_5.len = len; + + memset(&bearer_qos, 0, sizeof(bearer_qos)); + bearer_qos.qci = 8; + bearer_qos.priority_level = 1; + bearer_qos.pre_emption_capability = 0; + bearer_qos.pre_emption_vulnerability = 0; + req->bearer_contexts_to_be_created.bearer_level_qos.presence = 1; + ogs_gtp_build_bearer_qos( + &req->bearer_contexts_to_be_created.bearer_level_qos, + &bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN); + + req->recovery.presence = 1; + req->recovery.u8 = 66; + + req->additional_protocol_configuration_options.presence = 1; + req->additional_protocol_configuration_options.data = + (uint8_t *)"\x80\x00\x0d\x00"; + req->additional_protocol_configuration_options.len = 4; + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + +ogs_pkbuf_t *test_s2b_build_delete_session_request( + uint8_t type, test_sess_t *sess) +{ + int rv; + test_bearer_t *bearer = NULL; + + ogs_gtp_message_t gtp_message; + ogs_gtp_delete_session_request_t *req = >p_message.delete_session_request; + + ogs_assert(sess); + bearer = ogs_list_first(&sess->bearer_list); + ogs_assert(bearer); + + ogs_debug("Delete Session Request"); + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + req->linked_eps_bearer_id.presence = 1; + req->linked_eps_bearer_id.u8 = bearer->ebi; + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + +ogs_pkbuf_t *test_s2b_build_create_bearer_response( + uint8_t type, test_bearer_t *bearer) +{ + int rv; + ogs_session_t *session = NULL; + ogs_gtp_message_t gtp_message; + ogs_gtp_create_bearer_response_t *rsp = NULL; + + test_sess_t *sess = NULL; + + ogs_gtp_cause_t cause; + ogs_gtp_f_teid_t epdg_s2b_u_teid, smf_s2b_u_teid; + int len; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + ogs_debug("Create Bearer Response"); + rsp = >p_message.create_bearer_response; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + memset(&cause, 0, sizeof(cause)); + cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + rsp->cause.presence = 1; + rsp->cause.data = &cause; + rsp->cause.len = sizeof(cause); + + /* Bearer Context : EBI */ + rsp->bearer_contexts.presence = 1; + rsp->bearer_contexts.eps_bearer_id.presence = 1; + rsp->bearer_contexts.eps_bearer_id.u8 = bearer->ebi; + + /* Data Plane(DL) : ePDG-S2B-U */ + memset(&epdg_s2b_u_teid, 0, sizeof(ogs_gtp_f_teid_t)); + epdg_s2b_u_teid.interface_type = OGS_GTP_F_TEID_S2B_U_EPDG_GTP_U; + epdg_s2b_u_teid.teid = htobe32(bearer->enb_s1u_teid); + ogs_assert(sess->gnode->sock); + rv = ogs_gtp_sockaddr_to_f_teid( + &sess->gnode->sock->local_addr, NULL, &epdg_s2b_u_teid, &len); + ogs_expect_or_return_val(rv == OGS_OK, NULL); + rsp->bearer_contexts.s2b_u_epdg_f_teid_8.presence = 1; + rsp->bearer_contexts.s2b_u_epdg_f_teid_8.data = &epdg_s2b_u_teid; + rsp->bearer_contexts.s2b_u_epdg_f_teid_8.len = len; + + /* Data Plane(UL) : SMF-S2B-U */ + memset(&smf_s2b_u_teid, 0, sizeof(ogs_gtp_f_teid_t)); + smf_s2b_u_teid.interface_type = OGS_GTP_F_TEID_S2B_U_PGW_GTP_U; + smf_s2b_u_teid.teid = htobe32(bearer->sgw_s1u_teid); + rv = ogs_gtp_ip_to_f_teid(&bearer->sgw_s1u_ip, &smf_s2b_u_teid, &len); + ogs_expect_or_return_val(rv == OGS_OK, NULL); + rsp->bearer_contexts.s2b_u_pgw_f_teid.presence = 1; + rsp->bearer_contexts.s2b_u_pgw_f_teid.data = &smf_s2b_u_teid; + rsp->bearer_contexts.s2b_u_pgw_f_teid.len = OGS_GTP_F_TEID_IPV4_LEN; + + /* Bearer Context : Cause */ + rsp->bearer_contexts.cause.presence = 1; + rsp->bearer_contexts.cause.len = sizeof(cause); + rsp->bearer_contexts.cause.data = &cause; + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + +ogs_pkbuf_t *test_s2b_build_delete_bearer_response( + uint8_t type, test_bearer_t *bearer) +{ + int rv; + ogs_session_t *session = NULL; + ogs_gtp_message_t gtp_message; + ogs_gtp_delete_bearer_response_t *rsp = NULL; + + ogs_gtp_cause_t cause; + + ogs_assert(bearer); + + ogs_debug("Delete Bearer Response"); + rsp = >p_message.delete_bearer_response; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + memset(&cause, 0, sizeof(cause)); + cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + rsp->cause.presence = 1; + rsp->cause.data = &cause; + rsp->cause.len = sizeof(cause); + + rsp->linked_eps_bearer_id.presence = 1; + rsp->linked_eps_bearer_id.u8 = bearer->ebi; + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} diff --git a/tests/non3gpp/s2b-build.h b/tests/non3gpp/s2b-build.h new file mode 100644 index 000000000..a47fa4775 --- /dev/null +++ b/tests/non3gpp/s2b-build.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TEST_S2B_BUILD_H +#define TEST_S2B_BUILD_H + +#ifdef __cplusplus +extern "C" { +#endif + +ogs_pkbuf_t *test_s2b_build_create_session_request( + uint8_t type, test_sess_t *sess, bool handover_ind); +ogs_pkbuf_t *test_s2b_build_delete_session_request( + uint8_t type, test_sess_t *sess); + +ogs_pkbuf_t *test_s2b_build_create_bearer_response( + uint8_t type, test_bearer_t *bearer); +ogs_pkbuf_t *test_s2b_build_delete_bearer_response( + uint8_t type, test_bearer_t *bearer); + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_S2B_BUILD_H */ diff --git a/tests/non3gpp/s2b-handler.c b/tests/non3gpp/s2b-handler.c new file mode 100644 index 000000000..871ead03c --- /dev/null +++ b/tests/non3gpp/s2b-handler.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "s2b-handler.h" +#include "gtp-path.h" + +void test_s2b_handle_create_session_response( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_create_session_response_t *rsp) +{ + int rv; + uint8_t cause_value; + + test_bearer_t *bearer = NULL; + ogs_gtp_f_teid_t *smf_s2b_c_teid = NULL; + ogs_gtp_f_teid_t *smf_s2b_u_teid = NULL; + ogs_paa_t paa; + + ogs_assert(xact); + ogs_assert(sess); + ogs_assert(rsp); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + cause_value = cause->value; + if (cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + } else { + ogs_error("GTP Failed [CAUSE:%d]", cause_value); + return; + } + } else { + ogs_error("No Cause"); + return; + } + + if (rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.presence == 0) { + ogs_error("No S5/S8 TEID"); + return; + } + if (rsp->bearer_contexts_created.presence == 0) { + ogs_error("No Bearer Context"); + return; + } + if (rsp->bearer_contexts_created.eps_bearer_id.presence == 0) { + ogs_error("No EBI"); + return; + } + if (rsp->bearer_contexts_created.s12_rnc_f_teid.presence == 0) { + ogs_error("No S1U TEID"); + return; + } + if (rsp->pdn_address_allocation.presence == 0) { + ogs_error("No PDN Address Allocation"); + return; + } + + ogs_expect( + rsp->pdn_address_allocation.data && rsp->pdn_address_allocation.len); + + bearer = test_bearer_find_by_sess_ebi( + sess, rsp->bearer_contexts_created.eps_bearer_id.u8); + ogs_assert(bearer); + + smf_s2b_c_teid = rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.data; + ogs_assert(smf_s2b_c_teid); + + sess->smf_s2b_c_teid = be32toh(smf_s2b_c_teid->teid); + + smf_s2b_u_teid = rsp->bearer_contexts_created.s12_rnc_f_teid.data; + ogs_assert(smf_s2b_u_teid); + + bearer->sgw_s1u_teid = be32toh(smf_s2b_u_teid->teid); + ogs_assert(OGS_OK == + ogs_gtp_f_teid_to_ip(smf_s2b_u_teid, &bearer->sgw_s1u_ip)); + + memcpy(&paa, + rsp->pdn_address_allocation.data, rsp->pdn_address_allocation.len); + + switch (paa.session_type) { + case OGS_PDU_SESSION_TYPE_IPV4: + sess->ue_ip.ipv4 = 1; + sess->ue_ip.addr = paa.addr; + break; + case OGS_PDU_SESSION_TYPE_IPV6: + sess->ue_ip.ipv6 = 1; + memset(sess->ue_ip.addr6, 0, 8); + memcpy(sess->ue_ip.addr6+8, paa.addr6, 8); + break; + case OGS_PDU_SESSION_TYPE_IPV4V6: + sess->ue_ip.ipv4 = 1; + sess->ue_ip.addr = paa.both.addr; + sess->ue_ip.ipv6 = 1; + memset(sess->ue_ip.addr6, 0, 8); + memcpy(sess->ue_ip.addr6+8, paa.both.addr6, 8); + break; + default: + ogs_fatal("Invalid PDU Address Type [%d]", paa.session_type); + ogs_assert_if_reached(); + } +} + +void test_s2b_handle_delete_session_response( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_delete_session_response_t *rsp) +{ + int rv; + uint8_t cause_value; + + ogs_assert(xact); + ogs_assert(sess); + ogs_assert(rsp); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + cause_value = cause->value; + ogs_assert(cause_value == OGS_GTP_CAUSE_REQUEST_ACCEPTED); + } + + test_sess_remove(sess); +} + +void test_s2b_handle_create_bearer_request( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_create_bearer_request_t *req) +{ + int rv; + test_bearer_t *linked_bearer = NULL; + test_bearer_t *bearer = NULL; + ogs_gtp_f_teid_t *smf_s2b_u_teid = NULL; + + ogs_assert(xact); + ogs_assert(sess); + ogs_assert(req); + + if (req->linked_eps_bearer_id.presence == 0) { + ogs_error("No Linked EBI"); + return; + } + if (req->bearer_contexts.presence == 0) { + ogs_error("No Bearer"); + return; + } + if (req->bearer_contexts.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + return; + } + if (req->bearer_contexts.s5_s8_u_sgw_f_teid.presence == 0) { + ogs_error("No GTP TEID"); + return; + } + if (req->bearer_contexts.bearer_level_qos.presence == 0) { + ogs_error("No QoS"); + return; + } + if (req->bearer_contexts.tft.presence == 0) { + ogs_error("No TFT"); + return; + } + + linked_bearer = + test_bearer_find_by_sess_ebi(sess, req->linked_eps_bearer_id.u8); + ogs_assert(linked_bearer); + ogs_assert(linked_bearer->sess == sess); + + bearer = test_bearer_add(sess, + linked_bearer->ebi + ogs_list_count(&sess->bearer_list)); + ogs_assert(bearer); + + /* Receive Data Plane(UL) : SMF-S2B-U */ + smf_s2b_u_teid = req->bearer_contexts.s5_s8_u_sgw_f_teid.data; + ogs_assert(smf_s2b_u_teid); + bearer->sgw_s1u_teid = be32toh(smf_s2b_u_teid->teid); + rv = ogs_gtp_f_teid_to_ip(smf_s2b_u_teid, &bearer->sgw_s1u_ip); + ogs_assert(rv == OGS_OK); + + ogs_assert(OGS_OK == test_s2b_send_create_bearer_response(bearer, xact)); +} + +void test_s2b_handle_delete_bearer_request( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_delete_bearer_request_t *req) +{ + test_bearer_t *bearer = NULL; + ogs_gtp_cause_t *cause = NULL; + + ogs_assert(xact); + ogs_assert(sess); + ogs_assert(req); + + ogs_assert(req->cause.presence); + cause = req->cause.data; + ogs_assert(cause); + + ogs_assert(cause->value == + OGS_GTP_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP); + + ogs_assert(req->linked_eps_bearer_id.presence); + bearer = test_bearer_find_by_sess_ebi(sess, req->linked_eps_bearer_id.u8); + ogs_assert(bearer); + + ogs_assert(OGS_OK == test_s2b_send_delete_bearer_response(bearer, xact)); + + test_sess_remove(sess); +} diff --git a/tests/non3gpp/s2b-handler.h b/tests/non3gpp/s2b-handler.h new file mode 100644 index 000000000..e5dd1a893 --- /dev/null +++ b/tests/non3gpp/s2b-handler.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TEST_NON3GPP_GTP_HANDLE_H +#define TEST_NON3GPP_GTP_HANDLE_H + +#include "test-common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void test_s2b_handle_create_session_response( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_create_session_response_t *rsp); +void test_s2b_handle_delete_session_response( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_delete_session_response_t *rsp); + +void test_s2b_handle_create_bearer_request( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_create_bearer_request_t *req); +void test_s2b_handle_delete_bearer_request( + ogs_gtp_xact_t *xact, test_sess_t *sess, + ogs_gtp_delete_bearer_request_t *req); + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_NON3GPP_GTP_HANDLE_H */ diff --git a/tests/non3gpp/test-fd-path.c b/tests/non3gpp/test-fd-path.c new file mode 100644 index 000000000..d5a850315 --- /dev/null +++ b/tests/non3gpp/test-fd-path.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test-common.h" +#include "test-fd-path.h" + +static ogs_diam_config_t diam_config; + +static void test_diam_config(void) +{ + memset(&diam_config, 0, sizeof(ogs_diam_config_t)); + + diam_config.cnf_diamid = "aaa.localdomain"; + diam_config.cnf_diamrlm = "localdomain"; + diam_config.cnf_port = DIAMETER_PORT; + diam_config.cnf_port_tls = DIAMETER_SECURE_PORT; + diam_config.cnf_flags.no_sctp = 1; + diam_config.cnf_flags.no_fwd = 1; + diam_config.cnf_addr = "127.0.0.1"; + + diam_config.ext[diam_config.num_of_ext].module = + FD_EXT_DIR OGS_DIR_SEPARATOR_S "dbg_msg_dumps.fdx"; + diam_config.ext[diam_config.num_of_ext].conf = "0x8888"; + diam_config.num_of_ext++; + diam_config.ext[diam_config.num_of_ext].module = + FD_EXT_DIR OGS_DIR_SEPARATOR_S "dict_rfc5777.fdx"; + diam_config.num_of_ext++; + diam_config.ext[diam_config.num_of_ext].module = + FD_EXT_DIR OGS_DIR_SEPARATOR_S "dict_mip6i.fdx"; + diam_config.num_of_ext++; + diam_config.ext[diam_config.num_of_ext].module = + FD_EXT_DIR OGS_DIR_SEPARATOR_S "dict_nasreq.fdx"; + diam_config.num_of_ext++; + diam_config.ext[diam_config.num_of_ext].module = + FD_EXT_DIR OGS_DIR_SEPARATOR_S "dict_nas_mipv6.fdx"; + diam_config.num_of_ext++; + diam_config.ext[diam_config.num_of_ext].module = + FD_EXT_DIR OGS_DIR_SEPARATOR_S "dict_dcca.fdx"; + diam_config.num_of_ext++; + diam_config.ext[diam_config.num_of_ext].module = + FD_EXT_DIR OGS_DIR_SEPARATOR_S "dict_dcca_3gpp.fdx"; + diam_config.num_of_ext++; + + diam_config.conn[diam_config.num_of_conn].identity = TEST_HSS_IDENTITY; + diam_config.conn[diam_config.num_of_conn].addr = "127.0.0.8"; + diam_config.num_of_conn++; + diam_config.conn[diam_config.num_of_conn].identity = TEST_SMF_IDENTITY; + diam_config.conn[diam_config.num_of_conn].addr = "127.0.0.4"; + diam_config.num_of_conn++; +} + +int test_fd_init(void) +{ + int ret; + struct disp_when data; + + test_diam_config(); + + ret = ogs_diam_init(FD_MODE_CLIENT, NULL, &diam_config); + ogs_assert(ret == 0); + + ret = ogs_diam_s6a_init(); + ogs_assert(ret == 0); + ret = ogs_diam_cx_init(); + ogs_assert(ret == 0); + ret = ogs_diam_rx_init(); + ogs_assert(ret == 0); + + test_swx_init(); + test_s6b_init(); + + ret = ogs_diam_start(); + ogs_assert(ret == 0); + + return 0; +} + +void test_fd_final(void) +{ + test_swx_final(); + test_s6b_final(); + + ogs_diam_final(); +} diff --git a/tests/non3gpp/test-fd-path.h b/tests/non3gpp/test-fd-path.h new file mode 100644 index 000000000..3df0d3b6a --- /dev/null +++ b/tests/non3gpp/test-fd-path.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TEST_FD_PATH_H +#define TEST_FD_PATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ogs-diameter-cx.h" +#include "ogs-diameter-s6a.h" +#include "ogs-diameter-swx.h" + +#include "ogs-diameter-rx.h" +#include "ogs-diameter-s6b.h" + +int test_fd_init(void); +void test_fd_final(void); + +int test_swx_init(void); +void test_swx_final(void); + +void test_swx_send(test_sess_t *sess, bool handover_ind, + int (*gtp_send)(test_sess_t *sess, bool handover_ind)); + +int test_s6b_init(void); +void test_s6b_final(void); + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_FD_PATH_H */ + diff --git a/tests/volte/bearer-test.c b/tests/volte/bearer-test.c index 1d16d7412..34df4c5a8 100644 --- a/tests/volte/bearer-test.c +++ b/tests/volte/bearer-test.c @@ -64,7 +64,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -96,6 +96,8 @@ static void test1_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); diff --git a/tests/volte/cx-test.c b/tests/volte/cx-test.c index cc21e19a1..3a149db9b 100644 --- a/tests/volte/cx-test.c +++ b/tests/volte/cx-test.c @@ -75,7 +75,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; #endif - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -107,6 +107,8 @@ static void test1_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -217,14 +219,15 @@ static void test1_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 5; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); diff --git a/tests/volte/diameter-cx-path.c b/tests/volte/diameter-cx-path.c index b0ccaead7..97e9e98c9 100644 --- a/tests/volte/diameter-cx-path.c +++ b/tests/volte/diameter-cx-path.c @@ -179,7 +179,7 @@ void test_cx_send_uar(test_ue_t *test_ue, int id_type) ogs_assert(ret == 0); /* Set the Visited-Network-Identifier AVP */ - ret = fd_msg_avp_new(ogs_diam_cx_visited_network_identifier, 0, &avp); + ret = fd_msg_avp_new(ogs_diam_visited_network_identifier, 0, &avp); ogs_assert(ret == 0); val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); val.os.len = strlen(fd_g_config->cnf_diamrlm); diff --git a/tests/volte/diameter-rx-path.c b/tests/volte/diameter-rx-path.c index 3320c35fc..569902a30 100644 --- a/tests/volte/diameter-rx-path.c +++ b/tests/volte/diameter-rx-path.c @@ -1822,7 +1822,7 @@ static int pcscf_rx_asr_cb( struct msg **msg, struct avp *avp, /* Set the Auth-Request-Type AVP */ ret = fd_msg_avp_new(ogs_diam_auth_request_type, 0, &avp); ogs_assert(ret == 0); - val.i32 = 1; + val.i32 = OGS_DIAM_AUTH_REQUEST_TYPE_AUTHENTICATE_ONLY; ret = fd_msg_avp_setvalue(avp, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); @@ -1876,6 +1876,7 @@ void test_rx_send_str(uint8_t *rx_sid) struct sess_state *sess_data = NULL, *svg; struct session *session = NULL; int new; + size_t sidlen; ogs_assert(rx_sid); @@ -1890,7 +1891,7 @@ void test_rx_send_str(uint8_t *rx_sid) } /* Retrieve session by Session-Id */ - size_t sidlen = strlen((char*)rx_sid); + sidlen = strlen((char*)rx_sid); ret = fd_sess_fromsid_msg(rx_sid, sidlen, &session, &new); ogs_assert(ret == 0); ogs_assert(new == 0); diff --git a/tests/volte/rx-test.c b/tests/volte/rx-test.c index 13d50531d..a8c69f40a 100644 --- a/tests/volte/rx-test.c +++ b/tests/volte/rx-test.c @@ -70,7 +70,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -102,6 +102,8 @@ static void test1_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -212,14 +214,15 @@ static void test1_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 5; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -584,7 +587,7 @@ static void test2_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -616,6 +619,8 @@ static void test2_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -717,14 +722,15 @@ static void test2_func(abts_case *tc, void *data) tests1ap_recv(test_ue, recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 5; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -934,7 +940,7 @@ static void test3_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -966,6 +972,8 @@ static void test3_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1076,14 +1084,15 @@ static void test3_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 37; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -1161,14 +1170,15 @@ static void test3_func(abts_case *tc, void *data) test_ue->s1ap_procedure_code); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 39; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -1310,7 +1320,7 @@ static void test4_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -1342,6 +1352,8 @@ static void test4_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1452,14 +1464,15 @@ static void test4_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 7; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -1497,7 +1510,7 @@ static void test4_func(abts_case *tc, void *data) ogs_msleep(100); /* Send PDN disconnectivity request */ - sess = test_sess_find_by_apn(test_ue, "internet"); + sess = test_sess_find_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); sess->pti = 8; esmbuf = testesm_build_pdn_disconnect_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1535,14 +1548,15 @@ static void test4_func(abts_case *tc, void *data) test_sess_remove(sess); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 9; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -1580,7 +1594,7 @@ static void test4_func(abts_case *tc, void *data) ogs_msleep(100); /* Send AA-Request */ - sess = test_sess_find_by_apn(test_ue, "ims"); + sess = test_sess_find_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); test_rx_send_aar_audio(&rx_sid, sess, OGS_DIAM_RX_SUBSCRIPTION_ID_TYPE_END_USER_IMSI, 1, 1); @@ -1663,20 +1677,22 @@ static void test4_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, OGS_OK, rv); /* Test Session Remove */ - sess = test_sess_find_by_apn(test_ue, "internet"); + sess = test_sess_find_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); test_sess_remove(sess); - sess = test_sess_find_by_apn(test_ue, "ims"); + sess = test_sess_find_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); test_sess_remove(sess); /* Send Attach Request */ - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1837,7 +1853,7 @@ static void test5_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -1869,6 +1885,8 @@ static void test5_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -1979,14 +1997,15 @@ static void test5_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 7; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -2342,7 +2361,7 @@ static void test6_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -2374,6 +2393,8 @@ static void test6_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -2484,14 +2505,15 @@ static void test6_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 5; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); diff --git a/tests/volte/session-test.c b/tests/volte/session-test.c index 8adafb6e0..4dd1f86d4 100644 --- a/tests/volte/session-test.c +++ b/tests/volte/session-test.c @@ -64,7 +64,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -96,6 +96,8 @@ static void test1_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -197,14 +199,15 @@ static void test1_func(abts_case *tc, void *data) tests1ap_recv(test_ue, recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 5; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); @@ -313,14 +316,15 @@ static void test1_func(abts_case *tc, void *data) test_sess_remove(sess); /* Send INVALID PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims2"); + sess = test_sess_add_by_apn(test_ue, "ims2", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 9; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf); diff --git a/tests/volte/test-fd-path.c b/tests/volte/test-fd-path.c index 1267bd5be..c1fd5a896 100644 --- a/tests/volte/test-fd-path.c +++ b/tests/volte/test-fd-path.c @@ -31,6 +31,7 @@ static void test_diam_config(void) diam_config.cnf_port = DIAMETER_PORT; diam_config.cnf_port_tls = DIAMETER_SECURE_PORT; diam_config.cnf_flags.no_sctp = 1; + diam_config.cnf_flags.no_fwd = 1; diam_config.cnf_addr = "127.0.0.1"; diam_config.ext[diam_config.num_of_ext].module = @@ -77,6 +78,9 @@ int test_fd_init(void) test_rx_init(); test_cx_init(); + ret = ogs_diam_start(); + ogs_assert(ret == 0); + return 0; } diff --git a/tests/volte/test-fd-path.h b/tests/volte/test-fd-path.h index 2184ae055..74d26066a 100644 --- a/tests/volte/test-fd-path.h +++ b/tests/volte/test-fd-path.h @@ -26,9 +26,6 @@ extern "C" { #include "ogs-diameter-rx.h" -#define TEST_HSS_IDENTITY "hss.localdomain" -#define TEST_PCRF_IDENTITY "pcrf.localdomain" - int test_fd_init(void); void test_fd_final(void); diff --git a/tests/volte/video-test.c b/tests/volte/video-test.c index 07145a50b..67abe5c3a 100644 --- a/tests/volte/video-test.c +++ b/tests/volte/video-test.c @@ -68,7 +68,7 @@ static void test1_func(abts_case *tc, void *data) test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; - sess = test_sess_add_by_apn(test_ue, "internet"); + sess = test_sess_add_by_apn(test_ue, "internet", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); /* eNB connects to MME */ @@ -100,6 +100,8 @@ static void test1_func(abts_case *tc, void *data) memset(&sess->pdn_connectivity_param, 0, sizeof(sess->pdn_connectivity_param)); sess->pdn_connectivity_param.eit = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); @@ -210,14 +212,15 @@ static void test1_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send PDN Connectivity Request */ - sess = test_sess_add_by_apn(test_ue, "ims"); + sess = test_sess_add_by_apn(test_ue, "ims", OGS_GTP_RAT_TYPE_EUTRAN); ogs_assert(sess); sess->pti = 5; sess->pdn_connectivity_param.integrity_protected = 1; - sess->pdn_connectivity_param.ciphered = 1; sess->pdn_connectivity_param.apn = 1; sess->pdn_connectivity_param.pco = 1; + sess->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; esmbuf = testesm_build_pdn_connectivity_request(sess); ABTS_PTR_NOTNULL(tc, esmbuf); sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, esmbuf);