From ae75f43a882c94ad2fffe9c06dc664ae2ff43ade Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sun, 26 Apr 2020 15:36:05 -0400 Subject: [PATCH] Initial proposal CUPS using PFCP --- configs/csfb.yaml.in | 2 +- configs/cups.yaml.in | 128 ++ configs/installed.yaml.in | 532 +----- configs/meson.build | 1 + configs/mnc3.yaml.in | 2 +- configs/open5gs/hss.yaml.in | 90 +- configs/open5gs/meson.build | 3 + configs/open5gs/mme.yaml.in | 367 +++- configs/open5gs/pcrf.yaml.in | 89 +- configs/open5gs/pgw.yaml.in | 216 ++- configs/open5gs/sgw.yaml.in | 127 +- configs/open5gs/smf.yaml.in | 241 +++ configs/open5gs/upf.yaml.in | 149 ++ configs/simple.yaml.in | 2 +- configs/split.yaml.in | 2 +- configs/srslte.yaml.in | 2 +- configs/volte.yaml.in | 2 +- docs/_docs/tutorial/03-VoLTE-dockerized.md | 15 + lib/app/ogs-app.h | 6 + lib/app/ogs-config.c | 5 + lib/app/ogs-config.h | 3 + lib/core/meson.build | 2 + lib/core/ogs-3gpp-types.c | 49 +- lib/core/ogs-3gpp-types.h | 54 +- lib/core/ogs-core.h | 1 + lib/core/ogs-list.h | 117 +- lib/core/ogs-log.c | 3 - lib/core/ogs-macros.h | 4 + lib/core/ogs-memory.h | 16 + lib/core/ogs-rbtree.h | 3 +- lib/core/ogs-sockaddr.c | 31 +- lib/core/ogs-sockaddr.h | 5 + lib/core/ogs-timer.c | 1 - lib/core/ogs-tlv-msg.c | 25 +- lib/core/ogs-tlv-msg.h | 3 +- {src/pgw => lib/core}/ogs-tun.c | 2 - {src/pgw => lib/core}/ogs-tun.h | 0 lib/gtp/conv.c | 6 +- lib/gtp/message.c | 2 +- lib/gtp/message.h | 4 +- lib/gtp/node.c | 54 +- lib/gtp/node.h | 13 +- lib/gtp/path.c | 8 +- lib/gtp/support/gtp-tlv.py | 6 +- lib/gtp/xact.c | 64 +- {src/pgw => lib}/ipfw/dummynet.c | 0 {src/pgw => lib}/ipfw/expand_number.c | 0 {src/pgw => lib}/ipfw/glue.c | 0 {src/pgw => lib}/ipfw/glue.h | 0 {src/pgw => lib}/ipfw/humanize_number.c | 0 {src/pgw => lib}/ipfw/ipfw2.c | 0 {src/pgw => lib}/ipfw/ipfw2.h | 0 {src/pgw => lib}/ipfw/ipv6.c | 0 {src/pgw => lib}/ipfw/meson.build | 18 +- {src/pgw => lib}/ipfw/missing.h | 0 .../pgw => lib}/ipfw/objs/include_e/libutil.h | 0 .../ipfw/objs/include_e/net/if_var.h | 0 .../ipfw/objs/include_e/netinet/ip_dummynet.h | 0 .../ipfw/objs/include_e/netinet/ip_fw.h | 0 .../ipfw/objs/include_e/sys/sockio.h | 0 .../ipfw/objs/include_e/timeconv.h | 0 lib/ipfw/ogs-ipfw.c | 176 ++ lib/ipfw/ogs-ipfw.h | 68 + {src/pgw => lib}/ipfw/tables.c | 0 lib/meson.build | 1 + lib/nas/ies.c | 48 +- lib/nas/support/nas-message.py | 4 +- lib/nas/support/type-list.py | 36 +- lib/nas/types.c | 28 +- lib/pfcp/context.c | 1371 +++++++++++++++ lib/pfcp/context.h | 305 ++++ lib/pfcp/conv.c | 262 ++- lib/pfcp/conv.h | 22 +- lib/pfcp/meson.build | 10 +- lib/pfcp/message.c | 1546 ++++++++--------- lib/pfcp/message.h | 551 +++--- lib/pfcp/n4-build.c | 54 + lib/pfcp/n4-build.h | 34 + lib/pfcp/node.c | 171 -- lib/pfcp/node.h | 84 - lib/pfcp/ogs-pfcp.h | 12 +- lib/pfcp/path.c | 138 +- lib/pfcp/path.h | 12 +- lib/pfcp/support/README.md | 2 +- lib/pfcp/support/cache/tlv-group-list.py | 545 +++--- lib/pfcp/support/cache/tlv-msg-1.py | 2 +- lib/pfcp/support/cache/tlv-msg-10.py | 4 +- lib/pfcp/support/cache/tlv-msg-12.py | 6 +- lib/pfcp/support/cache/tlv-msg-13.py | 6 +- lib/pfcp/support/cache/tlv-msg-14.py | 10 +- lib/pfcp/support/cache/tlv-msg-15.py | 6 +- lib/pfcp/support/cache/tlv-msg-2.py | 2 +- lib/pfcp/support/cache/tlv-msg-3.py | 2 +- lib/pfcp/support/cache/tlv-msg-4.py | 4 +- lib/pfcp/support/cache/tlv-msg-5.py | 17 +- lib/pfcp/support/cache/tlv-msg-50.py | 36 +- lib/pfcp/support/cache/tlv-msg-51.py | 22 +- lib/pfcp/support/cache/tlv-msg-52.py | 80 +- lib/pfcp/support/cache/tlv-msg-53.py | 18 +- lib/pfcp/support/cache/tlv-msg-55.py | 10 +- lib/pfcp/support/cache/tlv-msg-56.py | 18 +- lib/pfcp/support/cache/tlv-msg-57.py | 14 +- lib/pfcp/support/cache/tlv-msg-6.py | 14 +- lib/pfcp/support/cache/tlv-msg-7.py | 16 +- lib/pfcp/support/cache/tlv-msg-8.py | 8 +- lib/pfcp/support/cache/tlv-msg-9.py | 2 +- lib/pfcp/support/cache/tlv-type-list.py | 362 ++-- lib/pfcp/support/pfcp-tlv.py | 246 ++- lib/pfcp/types.c | 335 +++- lib/pfcp/types.h | 594 +++++-- lib/pfcp/xact.c | 157 +- lib/pfcp/xact.h | 16 +- lib/s1ap/message.h | 3 +- lib/sctp/ogs-lksctp.c | 4 +- lib/sctp/ogs-usrsctp.c | 4 +- src/meson.build | 3 + src/mme/mme-context.c | 4 +- src/mme/mme-sm.c | 8 +- src/mme/s1ap-path.c | 2 +- src/pcrf/pcrf-context.c | 13 +- src/pcrf/pcrf-gx-path.c | 46 +- src/pgw/meson.build | 9 +- src/pgw/pgw-context.c | 111 +- src/pgw/pgw-context.h | 14 +- src/pgw/pgw-event.h | 3 +- src/pgw/pgw-fd-path.c | 145 +- src/pgw/pgw-fd-path.h | 2 +- src/pgw/pgw-gtp-path.c | 22 +- src/pgw/pgw-gx-handler.c | 13 +- src/pgw/pgw-gx-handler.h | 4 +- src/pgw/pgw-ipfw.c | 60 +- src/pgw/pgw-s5c-build.c | 25 +- src/pgw/pgw-s5c-build.h | 7 +- src/pgw/pgw-s5c-handler.c | 66 +- src/pgw/pgw-s5c-handler.h | 4 +- src/pgw/pgw-sm.c | 84 +- src/sgw/sgw-context.h | 1 - src/sgw/sgw-gtp-path.c | 8 +- src/sgw/sgw-s11-handler.c | 21 +- src/sgw/sgw-s5c-handler.c | 8 +- src/sgw/sgw-sm.c | 19 +- src/smf/app.c | 40 + src/smf/bearer-binding.c | 349 ++++ src/smf/bearer-binding.h | 35 + src/smf/context.c | 1081 ++++++++++++ src/smf/context.h | 236 +++ src/smf/event.c | 100 ++ src/smf/event.h | 79 + src/smf/fd-path.c | 1232 +++++++++++++ src/smf/fd-path.h | 42 + src/smf/gtp-path.c | 156 ++ src/smf/gtp-path.h | 42 + src/smf/gx-handler.c | 119 ++ src/smf/gx-handler.h | 42 + src/smf/init.c | 145 ++ src/smf/meson.build | 90 + src/smf/n4-build.c | 534 ++++++ src/smf/n4-build.h | 44 + src/smf/n4-handler.c | 257 +++ src/smf/n4-handler.h | 56 + src/smf/pfcp-path.c | 305 ++++ src/smf/pfcp-path.h | 47 + src/smf/pfcp-sm.c | 268 +++ src/smf/s5c-build.c | 535 ++++++ src/smf/s5c-build.h | 45 + src/smf/s5c-handler.c | 689 ++++++++ src/smf/s5c-handler.h | 57 + src/smf/smf-sm.c | 255 +++ src/smf/smf-sm.h | 47 + src/smf/timer.c | 76 + src/smf/timer.h | 56 + src/upf/app.c | 40 + src/upf/context.c | 685 ++++++++ src/upf/context.h | 127 ++ src/upf/event.c | 96 + src/upf/event.h | 69 + src/upf/gtp-path.c | 501 ++++++ src/upf/gtp-path.h | 37 + src/upf/init.c | 134 ++ src/upf/meson.build | 90 + src/upf/n4-build.c | 228 +++ src/upf/n4-build.h | 44 + src/upf/n4-handler.c | 640 +++++++ src/upf/n4-handler.h | 56 + src/upf/pfcp-path.c | 301 ++++ src/upf/pfcp-path.h | 50 + src/upf/pfcp-sm.c | 273 +++ src/upf/rule-match.c | 320 ++++ src/upf/rule-match.h | 35 + src/upf/timer.c | 76 + src/upf/timer.h | 56 + src/upf/upf-sm.c | 128 ++ src/upf/upf-sm.h | 47 + tests/app/test-packet.c | 51 +- tests/app/test-packet.h | 4 +- tests/core/list-test.c | 258 ++- tests/cups/abts-main.c | 96 + tests/cups/cups-test.c | 1314 ++++++++++++++ tests/cups/meson.build | 32 + tests/cups/pcscf-fd-path.c | 948 ++++++++++ tests/cups/pcscf-fd-path.h | 39 + tests/meson.build | 1 + tests/mnc3/mnc3-test.c | 2 +- tests/simple/attach-test.c | 4 +- tests/simple/volte-test.c | 4 +- tests/volte/abts-main.c | 2 + 206 files changed, 21116 insertions(+), 3406 deletions(-) create mode 100644 configs/cups.yaml.in create mode 100644 configs/open5gs/smf.yaml.in create mode 100644 configs/open5gs/upf.yaml.in rename {src/pgw => lib/core}/ogs-tun.c (99%) rename {src/pgw => lib/core}/ogs-tun.h (100%) rename {src/pgw => lib}/ipfw/dummynet.c (100%) rename {src/pgw => lib}/ipfw/expand_number.c (100%) rename {src/pgw => lib}/ipfw/glue.c (100%) rename {src/pgw => lib}/ipfw/glue.h (100%) rename {src/pgw => lib}/ipfw/humanize_number.c (100%) rename {src/pgw => lib}/ipfw/ipfw2.c (100%) rename {src/pgw => lib}/ipfw/ipfw2.h (100%) rename {src/pgw => lib}/ipfw/ipv6.c (100%) rename {src/pgw => lib}/ipfw/meson.build (87%) rename {src/pgw => lib}/ipfw/missing.h (100%) rename {src/pgw => lib}/ipfw/objs/include_e/libutil.h (100%) rename {src/pgw => lib}/ipfw/objs/include_e/net/if_var.h (100%) rename {src/pgw => lib}/ipfw/objs/include_e/netinet/ip_dummynet.h (100%) rename {src/pgw => lib}/ipfw/objs/include_e/netinet/ip_fw.h (100%) rename {src/pgw => lib}/ipfw/objs/include_e/sys/sockio.h (100%) rename {src/pgw => lib}/ipfw/objs/include_e/timeconv.h (100%) create mode 100644 lib/ipfw/ogs-ipfw.c create mode 100644 lib/ipfw/ogs-ipfw.h rename {src/pgw => lib}/ipfw/tables.c (100%) create mode 100644 lib/pfcp/context.c create mode 100644 lib/pfcp/context.h create mode 100644 lib/pfcp/n4-build.c create mode 100644 lib/pfcp/n4-build.h delete mode 100644 lib/pfcp/node.c delete mode 100644 lib/pfcp/node.h create mode 100644 src/smf/app.c create mode 100644 src/smf/bearer-binding.c create mode 100644 src/smf/bearer-binding.h create mode 100644 src/smf/context.c create mode 100644 src/smf/context.h create mode 100644 src/smf/event.c create mode 100644 src/smf/event.h create mode 100644 src/smf/fd-path.c create mode 100644 src/smf/fd-path.h create mode 100644 src/smf/gtp-path.c create mode 100644 src/smf/gtp-path.h create mode 100644 src/smf/gx-handler.c create mode 100644 src/smf/gx-handler.h create mode 100644 src/smf/init.c create mode 100644 src/smf/meson.build create mode 100644 src/smf/n4-build.c create mode 100644 src/smf/n4-build.h create mode 100644 src/smf/n4-handler.c create mode 100644 src/smf/n4-handler.h create mode 100644 src/smf/pfcp-path.c create mode 100644 src/smf/pfcp-path.h create mode 100644 src/smf/pfcp-sm.c create mode 100644 src/smf/s5c-build.c create mode 100644 src/smf/s5c-build.h create mode 100644 src/smf/s5c-handler.c create mode 100644 src/smf/s5c-handler.h create mode 100644 src/smf/smf-sm.c create mode 100644 src/smf/smf-sm.h create mode 100644 src/smf/timer.c create mode 100644 src/smf/timer.h create mode 100644 src/upf/app.c create mode 100644 src/upf/context.c create mode 100644 src/upf/context.h create mode 100644 src/upf/event.c create mode 100644 src/upf/event.h create mode 100644 src/upf/gtp-path.c create mode 100644 src/upf/gtp-path.h create mode 100644 src/upf/init.c create mode 100644 src/upf/meson.build create mode 100644 src/upf/n4-build.c create mode 100644 src/upf/n4-build.h create mode 100644 src/upf/n4-handler.c create mode 100644 src/upf/n4-handler.h create mode 100644 src/upf/pfcp-path.c create mode 100644 src/upf/pfcp-path.h create mode 100644 src/upf/pfcp-sm.c create mode 100644 src/upf/rule-match.c create mode 100644 src/upf/rule-match.h create mode 100644 src/upf/timer.c create mode 100644 src/upf/timer.h create mode 100644 src/upf/upf-sm.c create mode 100644 src/upf/upf-sm.h create mode 100644 tests/cups/abts-main.c create mode 100644 tests/cups/cups-test.c create mode 100644 tests/cups/meson.build create mode 100644 tests/cups/pcscf-fd-path.c create mode 100644 tests/cups/pcscf-fd-path.h diff --git a/configs/csfb.yaml.in b/configs/csfb.yaml.in index 2c2909bd7..ec57f96b0 100644 --- a/configs/csfb.yaml.in +++ b/configs/csfb.yaml.in @@ -128,7 +128,7 @@ pgw: gtpu: - addr: 127.0.0.3 - addr: ::1 - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 dns: diff --git a/configs/cups.yaml.in b/configs/cups.yaml.in new file mode 100644 index 000000000..73663658d --- /dev/null +++ b/configs/cups.yaml.in @@ -0,0 +1,128 @@ +db_uri: mongodb://localhost/open5gs + +logger: + +parameter: + +mme: + freeDiameter: + identity: mme.open-ims.test + realm: open-ims.test + listen_on: 127.0.0.2 + 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.open-ims.test + addr: 127.0.0.4 + + s1ap: + addr: 127.0.0.1 + gtpc: + addr: 127.0.0.1 + gummei: + plmn_id: + mcc: 001 + mnc: 01 + mme_gid: 2 + mme_code: 1 + tai: + plmn_id: + mcc: 001 + mnc: 01 + tac: 12345 + security: + integrity_order : [ EIA1, EIA2, EIA0 ] + ciphering_order : [ EEA0, EEA1, EEA2 ] + +hss: + freeDiameter: + identity: hss.open-ims.test + realm: open-ims.test + listen_on: 127.0.0.4 + 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.open-ims.test + addr: 127.0.0.2 + +sgw: + gtpc: + addr: 127.0.0.2 + gtpu: + addr: 127.0.0.2 + +smf: + freeDiameter: + identity: pgw.open-ims.test + realm: open-ims.test + listen_on: 127.0.0.3 + load_extension: + - module: @freediameter_extensions_builddir@/dbg_msg_dumps.fdx + conf: 0x8888 + - module: @freediameter_extensions_builddir@/dict_rfc5777.fdx + - module: @freediameter_extensions_builddir@/dict_mip6i.fdx + - module: @freediameter_extensions_builddir@/dict_nasreq.fdx + - module: @freediameter_extensions_builddir@/dict_nas_mipv6.fdx + - module: @freediameter_extensions_builddir@/dict_dcca.fdx + - module: @freediameter_extensions_builddir@/dict_dcca_3gpp.fdx + connect: + - identity: pcrf.open-ims.test + addr: 127.0.0.5 + + gtpc: + - addr: 127.0.0.3 + - addr: ::1 + pfcp: + - addr: 127.0.0.3 + pdn: + - addr: 10.45.0.1/16 + - addr: cafe::1/64 + dns: + - 8.8.8.8 + - 8.8.4.4 + - 2001:4860:4860::8888 + - 2001:4860:4860::8844 + mtu: 1400 + +upf: + pfcp: + addr: 127.0.0.2 + gtpu: + - addr: + - 127.0.0.3 + - ::1 + pdn: + +pcrf: + freeDiameter: + identity: pcrf.open-ims.test + realm: open-ims.test + listen_on: 127.0.0.5 + 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: pgw.open-ims.test + addr: 127.0.0.3 + - identity: pcscf.open-ims.test + addr: 127.0.0.1 diff --git a/configs/installed.yaml.in b/configs/installed.yaml.in index 7aeaab577..f86fad320 100644 --- a/configs/installed.yaml.in +++ b/configs/installed.yaml.in @@ -2,294 +2,21 @@ db_uri: mongodb://localhost/open5gs logger: file: @localstatedir@/log/open5gs/open5gs.log -# -# o Set OGS_LOG_INFO to all domain level -# - If `level` is omitted, the default level is OGS_LOG_INFO) -# - If `domain` is omitted, the all domain level is set from 'level' -# (Nothing is needed) -# -# o Set OGS_LOG_ERROR to all domain level -# - `level` can be set with none, fatal, error, warn, info, debug, trace -# level: error -# -# o Set OGS_LOG_DEBUG to mme/emm domain level -# level: debug -# domain: mme,emm -# -# o Set OGS_LOG_TRACE to all domain level -# level: trace -# domain: core,s1ap,nas,fd,gtp,mme,emm,esm,sgw,pgw,hss,pcrf,event,tlv,mem,sock -# -# -# parameter: -# -# o Number of output streams per SCTP associations. -# sctp_streams: 30 -# -# o Disable use of IPv4 addresses (only IPv6) -# no_ipv4: true -# -# o Disable use of IPv6 addresses (only IPv4) -# no_ipv6: true -# -# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. -# prefer_ipv4: true -# -# o Enable Multicast traffic to the UE -# multicast: true -# -# o Disable Stateless Address Autoconfiguration for IPv6 -# no_slaac: true -# -# parameter: no_ipv6: true -# -# sctp: -# -# o heartbit_interval : 5000 (5secs) -# o rto_initial : 3000 (3secs) -# o rto_min : 1000 (1sec) -# o rto_max : 5000 (5secs) -# o max_num_of_ostreams : 30 -# o max_num_of_istreams : 65535 -# o max_attempts : 4 -# o max_initial_timeout : 8000(8secs) -# o usrsctp_udp_port : 9899 -sctp: - -# -# max: -# -# o Maximum Number of SGW per MME -# sgw: 32 -# o Maximum Number of PGW per MME -# pgw: 32 -# o Maximum Number of VLR per MME -# vlr: 32 -# o Maximum Number of eNodeB per MME -# enb: 32 -# o Maximum Number of UE per eNodeB -# ue: 128 -# -max: - -# -# pool: -# -# o The Number of Default Memory Pool Size -# -# - Pool-size 128 => 8192 Number -# - Pool-size 256 => 4096 Number -# - Pool-size 512 => 2048 Number -# - Pool-size 1024 => 1024 Number -# - Pool-size 2048 => 512 Number -# - Pool-size 8192 => 128 Number -# - Pool-size 1024*1024 => 8 Number -# -# 128: 8192 -# 256: 4096 -# 512: 2048 -# 1024: 1024 -# 2048: 512 -# 8192: 128 -# big: 8 -# -# o Memory of Packet Buffering in SGW -# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW -# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes -# -# packet: 65536 -pool: - mme: freeDiameter: @sysconfdir@/freeDiameter/mme.conf - -# -# > -# -# o S1AP Server(all address avaiable) -# s1ap: -# -# o S1AP Server(0.0.0.0:36412) -# s1ap: -# addr: 0.0.0.0 -# -# o S1AP Server(127.0.0.1:36412, [::1]:36412) -# s1ap: -# - addr: 127.0.0.1 -# - addr: ::1 - -# o S1AP Server(different port) -# s1ap: -# - addr: 127.0.0.1 -# port: 36413 -# -# o S1AP Server(address avaiable in `eth0` interface) -# s1ap: -# dev: eth0 -# s1ap: - -# -# > -# -# o GTP-C Server(all address avaiable) -# gtpc: -# -# o GTP-C Server(127.0.0.1:2123, [::1]:2123) -# gtpc: -# - addr: 127.0.0.1 -# - addr: ::1 -# gtpc: - -# -# -# -# o Single MSC/VLR(127.0.0.2) -# sgsap: -# addr: 127.0.0.2 -# map: -# tai: -# plmn_id: -# mcc: 001 -# mnc: 01 -# tac: 4130 -# lai: -# plmn_id: -# mcc: 001 -# mnc: 01 -# lac: 43690 -# map: -# tai: -# plmn_id: -# mcc: 002 -# mnc: 02 -# tac: 4132 -# lai: -# plmn_id: -# mcc: 002 -# mnc: 02 -# lac: 43692 -# -# o Multiple MSC/VLR -# sgsap: -# - addr: 127.0.0.2 -# port: 29119 -# map: -# tai: -# plmn_id: -# mcc: 001 -# mnc: 01 -# tac: 4131 -# lai: -# plmn_id: -# mcc: 001 -# mnc: 01 -# lac: 43691 -# map: -# tai: -# plmn_id: -# mcc: 002 -# mnc: 02 -# tac: 4132 -# lai: -# plmn_id: -# mcc: 002 -# mnc: 02 -# lac: 43692 -# - addr -# - 127.0.0.3 -# - fe80::2%@loopback_devname@ -# map: -# tai: -# plmn_id: -# mcc: 001 -# mnc: 01 -# tac: 4132 -# lai: -# plmn_id: -# mcc: 002 -# mnc: 02 -# lac: 43692 -# - name: msc.open5gs.org -# map: -# tai: -# plmn_id: -# mcc: 001 -# mnc: 01 -# tac: 4133 -# lai: -# plmn_id: -# mcc: 002 -# mnc: 02 -# lac: 43693 -# sgsap: - - -# -# -# -# o Multiple GUMMEI -# gummei: -# - plmn_id: -# mcc: 001 -# mnc: 01 -# mme_gid: 2 -# mme_code: 1 -# - plmn_id: -# - mcc: 002 -# mnc: 02 -# - mcc: 003 -# mnc: 03 -# mme_gid: [3, 4] -# mme_code: -# - 2 -# - 3 -# - gummei: + gummei: plmn_id: mcc: 001 mnc: 01 mme_gid: 2 mme_code: 1 - -# -# -# -# o Multiple TAI -# tai: -# - plmn_id: -# mcc: 001 -# mnc: 01 -# tac: [1, 2, 3] -# tai: -# - plmn_id: -# mcc: 002 -# mnc: 02 -# tac: 4 -# - plmn_id: -# mcc: 003 -# mnc: 03 -# tac: 5 -# tai: -# - plmn_id: -# mcc: 004 -# mnc: 04 -# tac: [6, 7] -# - plmn_id: -# mcc: 005 -# mnc: 05 -# tac: 8 -# - plmn_id: -# mcc: 006 -# mnc: 06 -# tac: [9, 10] -# tai: plmn_id: mcc: 001 @@ -299,14 +26,6 @@ mme: security: integrity_order : [ EIA1, EIA2, EIA0 ] ciphering_order : [ EEA0, EEA1, EEA2 ] - -# -# -# network_name: -# full: Open5GS -# short: Next -# - network_name: full: Open5GS @@ -314,276 +33,29 @@ hss: freeDiameter: @sysconfdir@/freeDiameter/hss.conf sgw: -# -# ------------------------ MME -------------------------- -# -# o Specify SGW addresses the GTP-C must connect to -# -# o One SGW is defined. If prefer_ipv4 is not true, [fe80::2%@loopback_devname@] is selected. -# gtpc: -# addr: -# - 127.0.0.2 -# - fe80::2%@loopback_devname@ -# -# o Two SGW are defined. MME selects SGW with round-robin manner per UE -# gtpc: -# - addr: 127.0.0.2 -# - addr: fe80::2%@loopback_devname@ -# -# o Three SGW are defined. MME selects SGW with round-robin manner per UE -# gtpc: -# - addr -# - 127.0.0.2 -# - fe80::2%@loopback_devname@ -# - addr -# - 127.0.0.12 -# - fe80::12%@loopback_devname@ -# - name: sgw3.open5gs.org -# -# ------------------------ SGW -------------------------- -# -# o GTP-C Server(127.0.0.2:2123, [fe80::2%@loopback_devname@]:2123) -# gtpc: -# addr: -# - 127.0.0.2 -# - fe80::2%@loopback_devname@ -# -# o On SGW, Same Configuration(127.0.0.2:2123, [fe80::2%@loopback_devname@]:2123) as below. -# gtpc: -# - addr: 127.0.0.2 -# - addr: fe80::2%@loopback_devname@ -# gtpc: addr: 127.0.0.2 - -# -# -# -# o Round-Robin -# (If `selection_mode` is omitted, the default mode is Round-Robin) -# -# selection_mode: rr -# gtpc: -# addr: 127.0.0.2 -# addr: 127.0.2.2 -# addr: 127.0.4.2 -# -# o SGW selection by eNodeB TAC -# -# selection_mode: tac -# gtpc: -# - addr: 127.0.0.2 -# tac: 26000 -# - addr: 127.0.2.2 -# tac: [25000, 27000, 28000] -# - -# -# -# -# o GTP-U Server(all address avaiable) -# gtpu: -# -# o Provide custom SGW GTP-U address to be advertised inside S1AP messages -# gtpu: -# addr: 10.4.128.21 -# advertise_addr: 172.24.15.30 -# -# gtpu: -# addr: 10.4.128.21 -# advertise_name: sgw1.epc.mnc001.mcc001.3gppnetwork.org -# -# gtpu: -# dev: ens3 -# advertise_name: sgw1.epc.mnc001.mcc001.3gppnetwork.org -# gtpu: pgw: freeDiameter: @sysconfdir@/freeDiameter/pgw.conf - -# -# ------------------------ MME -------------------------- -# -# o By default, the PGW uses the first PGW node. -# - To use a different APN for each PGW, specify gtpc.apn as the APN name. -# - If the HSS uses WebUI to set the PGW IP for eacho UE, -# you can use a specific PGW node for each UE. -# -# o Two PGW are defined. 127.0.0.3:2123 is used. -# [fe80::3%@loopback_devname@]:2123 is ignored. -# gtpc: -# - addr: 127.0.0.3 -# - addr: fe80::3%@loopback_devname@ -# -# o One PGW is defined. if prefer_ipv4 is not true, -# [fe80::3%@loopback_devname@] is selected. -# gtpc: -# - addr: -# - 127.0.0.3 -# - fe80::3%@loopback_devname@ -# -# o Two PGW are defined with a different APN. -# - Note that if PGW IP for UE is configured in HSS, -# the following configurion for this UE is ignored. -# gtpc: -# - addr: 127.0.0.3 -# apn: internet -# - addr: 127.0.0.5 -# apn: volte -# -# o If APN is omitted, the default APN uses the first PGW node. -# gtpc: -# - addr: 127.0.0.3 -# - addr: 127.0.0.5 -# apn: volte -# ------------------------ PGW -------------------------- -# -# o GTP-C Server(127.0.0.3:2123, [fe80::3%@loopback_devname@]:2123) -# gtpc: -# addr: -# - 127.0.0.3 -# - fe80::3%@loopback_devname@ -# -# o On PGW, Same configuration(127.0.0.3:2123, [fe80::3%@loopback_devname@]:2123). -# gtpc: -# - addr: 127.0.0.3 -# - addr: fe80::3%@loopback_devname@ -# gtpc: addr: - 127.0.0.3 - ::1 - -# -# > -# -# o GTP-U Server(127.0.0.3:2152, [::1]:2152) -# gtpu: -# - addr: 127.0.0.3 -# - addr: ::1 -# -# o Same configuration(127.0.0.3:2152, [::1]:2152) as below. -# gtpu: -# name: localhost -# gtpu: - addr: 127.0.0.3 - addr: ::1 - -# -# -# -# o IPv4 Pool -# $ sudo ip addr add 10.45.0.1/16 dev ogstun -# -# ue_pool: -# addr: 10.45.0.1/16 -# -# o IPv4/IPv6 Pool -# $ sudo ip addr add 10.45.0.1/16 dev ogstun -# $ sudo ip addr add cafe:1::1/64 dev ogstun -# -# ue_pool: -# - addr: 10.45.0.1/16 -# - addr: cafe:1::1/64 -# -# -# o Specific APN(e.g 'volte') uses 10.46.0.1/16, cafe:2::1/64 -# All other APNs use 10.45.0.1/16, cafe:1::1/64 -# $ sudo ip addr add 10.45.0.1/16 dev ogstun -# $ sudo ip addr add 10.46.0.1/16 dev ogstun -# $ sudo ip addr add cafe:1::1/64 dev ogstun -# $ sudo ip addr add cafe:2::1/64 dev ogstun -# -# ue_pool: -# - addr: 10.45.0.1/16 -# - addr: cafe:1::1/64 -# - addr: 10.46.0.1/16 -# apn: volte -# - addr: cafe:2::1/64 -# apn: volte -# -# o Multiple Devices (default: ogstun) -# $ sudo ip addr add 10.45.0.1/16 dev ogstun -# $ sudo ip addr add cafe:1::1/64 dev ogstun2 -# $ sudo ip addr add 10.46.0.1/16 dev ogstun3 -# $ sudo ip addr add cafe:2::1/64 dev ogstun3 -# -# ue_pool: -# - addr: 10.45.0.1/16 -# - addr: cafe:1::1/64 -# dev: ogstun2 -# - addr: 10.46.0.1/16 -# apn: volte -# dev: ogstun3 -# - addr: cafe:2::1/64 -# apn: volte -# dev: ogstun3 -# -# o Pool Range Sample -# ue_pool: -# - addr: 10.45.0.1/24 -# range: 10.45.0.100-10.45.0.200 -# -# ue_pool: -# - addr: 10.45.0.1/24 -# range: -# - 10.45.0.5-10.45.0.50 -# - 10.45.0.100- -# -# ue_pool: -# - addr: 10.45.0.1/24 -# range: -# - -10.45.0.200 -# - 10.45.0.210-10.45.0.220 -# -# ue_pool: -# - addr: 10.45.0.1/16 -# range: -# - 10.45.0.100-10.45.0.200 -# - 10.45.1.100-10.45.1.200 -# - addr: cafe::1/64 -# range: -# - cafe::a0-cafe:b0 -# - cafe::c0-cafe:d0 -# -# - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 -# -# -# -# o Primary/Secondary can be configured. Others are ignored. -# dns: - 8.8.8.8 - 8.8.4.4 - 2001:4860:4860::8888 - 2001:4860:4860::8844 - -# -# -# -# o Provisioning a limit on the size of the packets sent by the MS -# to avoid packet fragmentation in the backbone network -# between the MS and the GGSN/PGW and/or across the (S)Gi reference point) -# when some of the backbone links does not support -# packets larger then 1500 octets -# mtu: 1400 -# -# -# -# o Proxy Call Session Control Function -# -# p-cscf: -# - 127.0.0.1 -# - ::1 -# - pcrf: freeDiameter: @sysconfdir@/freeDiameter/pcrf.conf diff --git a/configs/meson.build b/configs/meson.build index ba0a9a6af..5176b5b88 100644 --- a/configs/meson.build +++ b/configs/meson.build @@ -41,6 +41,7 @@ example_conf = ''' csfb.yaml volte.yaml srslte.yaml + cups.yaml '''.split() foreach file : example_conf diff --git a/configs/mnc3.yaml.in b/configs/mnc3.yaml.in index 7cb8acf25..3cf77fa7c 100644 --- a/configs/mnc3.yaml.in +++ b/configs/mnc3.yaml.in @@ -98,7 +98,7 @@ pgw: gtpu: - addr: 127.0.0.3 - addr: ::1 - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 dns: diff --git a/configs/open5gs/hss.yaml.in b/configs/open5gs/hss.yaml.in index 61e08efd1..4de7f2958 100644 --- a/configs/open5gs/hss.yaml.in +++ b/configs/open5gs/hss.yaml.in @@ -1,9 +1,95 @@ db_uri: mongodb://localhost/open5gs +# +# logger: +# +# o Set OGS_LOG_INFO to all domain level +# - If `level` is omitted, the default level is OGS_LOG_INFO) +# - If `domain` is omitted, the all domain level is set from 'level' +# (Nothing is needed) +# +# o Set OGS_LOG_ERROR to all domain level +# - `level` can be set with none, fatal, error, warn, info, debug, trace +# level: error +# +# o Set OGS_LOG_DEBUG to mme/emm domain level +# level: debug +# domain: mme,emm +# +# o Set OGS_LOG_TRACE to all domain level +# level: trace +# domain: core,fd,hss,event,mem,sock +# logger: file: @localstatedir@/log/open5gs/hss.log -parameter: - hss: freeDiameter: @sysconfdir@/freeDiameter/hss.conf + +# +# parameter: +# +# o Number of output streams per SCTP associations. +# sctp_streams: 30 +# +# o Disable use of IPv4 addresses (only IPv6) +# no_ipv4: true +# +# o Disable use of IPv6 addresses (only IPv4) +# no_ipv6: true +# +# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. +# prefer_ipv4: true +# +# o Enable Multicast traffic to the UE +# multicast: true +# +# o Disable Stateless Address Autoconfiguration for IPv6 +# no_slaac: true +# +# +parameter: + +# +# max: +# +# o Maximum Number of SGW per MME +# sgw: 32 +# o Maximum Number of PGW per MME +# pgw: 32 +# o Maximum Number of VLR per MME +# vlr: 32 +# o Maximum Number of eNodeB per MME +# enb: 32 +# o Maximum Number of UE per eNodeB +# ue: 128 +# +max: + +# +# pool: +# +# o The Number of Default Memory Pool Size +# +# - Pool-size 128 => 8192 Number +# - Pool-size 256 => 4096 Number +# - Pool-size 512 => 2048 Number +# - Pool-size 1024 => 1024 Number +# - Pool-size 2048 => 512 Number +# - Pool-size 8192 => 128 Number +# - Pool-size 1024*1024 => 8 Number +# +# 128: 8192 +# 256: 4096 +# 512: 2048 +# 1024: 1024 +# 2048: 512 +# 8192: 128 +# big: 8 +# +# o Memory of Packet Buffering in SGW +# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW +# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes +# +# packet: 65536 +pool: diff --git a/configs/open5gs/meson.build b/configs/open5gs/meson.build index 377a21ab3..9874cdfd8 100644 --- a/configs/open5gs/meson.build +++ b/configs/open5gs/meson.build @@ -25,6 +25,9 @@ open5gs_conf = ''' sgw.yaml pgw.yaml pcrf.yaml + + smf.yaml + upf.yaml '''.split() foreach file : open5gs_conf diff --git a/configs/open5gs/mme.yaml.in b/configs/open5gs/mme.yaml.in index e74fa70f7..854ccd705 100644 --- a/configs/open5gs/mme.yaml.in +++ b/configs/open5gs/mme.yaml.in @@ -1,8 +1,202 @@ +# +# logger: +# +# o Set OGS_LOG_INFO to all domain level +# - If `level` is omitted, the default level is OGS_LOG_INFO) +# - If `domain` is omitted, the all domain level is set from 'level' +# (Nothing is needed) +# +# o Set OGS_LOG_ERROR to all domain level +# - `level` can be set with none, fatal, error, warn, info, debug, trace +# level: error +# +# o Set OGS_LOG_DEBUG to mme/emm domain level +# level: debug +# domain: mme,emm +# +# o Set OGS_LOG_TRACE to all domain level +# level: trace +# domain: core,s1ap,nas,fd,gtp,mme,emm,esm,event,tlv,mem,sock +# logger: file: @localstatedir@/log/open5gs/mme.log -parameter: - +# +# mme: +# +# > +# +# o S1AP Server(all address avaiable) +# s1ap: +# +# o S1AP Server(0.0.0.0:36412) +# s1ap: +# addr: 0.0.0.0 +# +# o S1AP Server(127.0.0.1:36412, [::1]:36412) +# s1ap: +# - addr: 127.0.0.1 +# - addr: ::1 +# +# o S1AP Server(different port) +# s1ap: +# - addr: 127.0.0.1 +# port: 36413 +# +# o S1AP Server(address avaiable in `eth0` interface) +# s1ap: +# dev: eth0 +# +# > +# +# o GTP-C Server(all address avaiable) +# gtpc: +# +# o GTP-C Server(127.0.0.1:2123, [::1]:2123) +# gtpc: +# - addr: 127.0.0.1 +# - addr: ::1 +# +# +# +# o Single MSC/VLR(127.0.0.2) +# sgsap: +# addr: 127.0.0.2 +# map: +# tai: +# plmn_id: +# mcc: 001 +# mnc: 01 +# tac: 4130 +# lai: +# plmn_id: +# mcc: 001 +# mnc: 01 +# lac: 43690 +# map: +# tai: +# plmn_id: +# mcc: 002 +# mnc: 02 +# tac: 4132 +# lai: +# plmn_id: +# mcc: 002 +# mnc: 02 +# lac: 43692 +# +# o Multiple MSC/VLR +# sgsap: +# - addr: 127.0.0.2 +# port: 29119 +# map: +# tai: +# plmn_id: +# mcc: 001 +# mnc: 01 +# tac: 4131 +# lai: +# plmn_id: +# mcc: 001 +# mnc: 01 +# lac: 43691 +# map: +# tai: +# plmn_id: +# mcc: 002 +# mnc: 02 +# tac: 4132 +# lai: +# plmn_id: +# mcc: 002 +# mnc: 02 +# lac: 43692 +# - addr +# - 127.0.0.3 +# - fe80::2%@loopback_devname@ +# map: +# tai: +# plmn_id: +# mcc: 001 +# mnc: 01 +# tac: 4132 +# lai: +# plmn_id: +# mcc: 002 +# mnc: 02 +# lac: 43692 +# - name: msc.open5gs.org +# map: +# tai: +# plmn_id: +# mcc: 001 +# mnc: 01 +# tac: 4133 +# lai: +# plmn_id: +# mcc: 002 +# mnc: 02 +# lac: 43693 +# +# +# +# +# o Multiple GUMMEI +# gummei: +# - plmn_id: +# mcc: 001 +# mnc: 01 +# mme_gid: 2 +# mme_code: 1 +# - plmn_id: +# - mcc: 002 +# mnc: 02 +# - mcc: 003 +# mnc: 03 +# mme_gid: [3, 4] +# mme_code: +# - 2 +# - 3 +# +# +# +# +# o Multiple TAI +# tai: +# - plmn_id: +# mcc: 001 +# mnc: 01 +# tac: [1, 2, 3] +# tai: +# - plmn_id: +# mcc: 002 +# mnc: 02 +# tac: 4 +# - plmn_id: +# mcc: 003 +# mnc: 03 +# tac: 5 +# tai: +# - plmn_id: +# mcc: 004 +# mnc: 04 +# tac: [6, 7] +# - plmn_id: +# mcc: 005 +# mnc: 05 +# tac: 8 +# - plmn_id: +# mcc: 006 +# mnc: 06 +# tac: [9, 10] +# +# +# +# +# network_name: +# full: Open5GS +# short: Next +# mme: freeDiameter: @sysconfdir@/freeDiameter/mme.conf s1ap: @@ -24,12 +218,181 @@ mme: network_name: full: Open5GS +# +# sgw: +# +# +# +# o Specify SGW addresses the GTP-C must connect to +# +# o One SGW is defined. +# If prefer_ipv4 is not true, [fe80::2%@loopback_devname@] is selected. +# gtpc: +# addr: +# - 127.0.0.2 +# - fe80::2%@loopback_devname@ +# +# o Two SGW are defined. MME selects SGW with round-robin manner per UE +# gtpc: +# - addr: 127.0.0.2 +# - addr: fe80::2%@loopback_devname@ +# +# o Three SGW are defined. MME selects SGW with round-robin manner per UE +# gtpc: +# - addr +# - 127.0.0.2 +# - fe80::2%@loopback_devname@ +# - addr +# - 127.0.0.12 +# - fe80::12%@loopback_devname@ +# - name: sgw3.open5gs.org +# +# +# +# o Round-Robin +# (If `selection_mode` is omitted, the default mode is Round-Robin) +# +# selection_mode: rr +# gtpc: +# addr: 127.0.0.2 +# addr: 127.0.2.2 +# addr: 127.0.4.2 +# +# o SGW selection by eNodeB TAC +# +# selection_mode: tac +# gtpc: +# - addr: 127.0.0.2 +# tac: 26000 +# - addr: 127.0.2.2 +# tac: [25000, 27000, 28000] +# +# sgw: gtpc: addr: 127.0.0.2 +# +# pgw: +# +# +# +# o By default, the PGW uses the first PGW node. +# - To use a different APN for each PGW, specify gtpc.apn as the APN name. +# - If the HSS uses WebUI to set the PGW IP for eacho UE, +# you can use a specific PGW node for each UE. +# +# o Two PGW are defined. 127.0.0.3:2123 is used. +# [fe80::3%@loopback_devname@]:2123 is ignored. +# gtpc: +# - addr: 127.0.0.3 +# - addr: fe80::3%@loopback_devname@ +# +# o One PGW is defined. if prefer_ipv4 is not true, +# [fe80::3%@loopback_devname@] is selected. +# gtpc: +# - addr: +# - 127.0.0.3 +# - fe80::3%@loopback_devname@ +# +# o Two PGW are defined with a different APN. +# - Note that if PGW IP for UE is configured in HSS, +# the following configurion for this UE is ignored. +# gtpc: +# - addr: 127.0.0.3 +# apn: internet +# - addr: 127.0.0.5 +# apn: volte +# +# o If APN is omitted, the default APN uses the first PGW node. +# gtpc: +# - addr: 127.0.0.3 +# - addr: 127.0.0.5 +# apn: volte pgw: gtpc: addr: - 127.0.0.3 - ::1 + +# +# parameter: +# +# o Number of output streams per SCTP associations. +# sctp_streams: 30 +# +# o Disable use of IPv4 addresses (only IPv6) +# no_ipv4: true +# +# o Disable use of IPv6 addresses (only IPv4) +# no_ipv6: true +# +# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. +# prefer_ipv4: true +# +# o Enable Multicast traffic to the UE +# multicast: true +# +# o Disable Stateless Address Autoconfiguration for IPv6 +# no_slaac: true +# +# +parameter: + +# +# max: +# +# o Maximum Number of SGW per MME +# sgw: 32 +# o Maximum Number of PGW per MME +# pgw: 32 +# o Maximum Number of VLR per MME +# vlr: 32 +# o Maximum Number of eNodeB per MME +# enb: 32 +# o Maximum Number of UE per eNodeB +# ue: 128 +# +max: + +# +# pool: +# +# o The Number of Default Memory Pool Size +# +# - Pool-size 128 => 8192 Number +# - Pool-size 256 => 4096 Number +# - Pool-size 512 => 2048 Number +# - Pool-size 1024 => 1024 Number +# - Pool-size 2048 => 512 Number +# - Pool-size 8192 => 128 Number +# - Pool-size 1024*1024 => 8 Number +# +# 128: 8192 +# 256: 4096 +# 512: 2048 +# 1024: 1024 +# 2048: 512 +# 8192: 128 +# big: 8 +# +# o Memory of Packet Buffering in SGW +# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW +# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes +# +# packet: 65536 +pool: + +# +# sctp: +# +# o heartbit_interval : 5000 (5secs) +# o rto_initial : 3000 (3secs) +# o rto_min : 1000 (1sec) +# o rto_max : 5000 (5secs) +# o max_num_of_ostreams : 30 +# o max_num_of_istreams : 65535 +# o max_attempts : 4 +# o max_initial_timeout : 8000(8secs) +# o usrsctp_udp_port : 9899 +sctp: diff --git a/configs/open5gs/pcrf.yaml.in b/configs/open5gs/pcrf.yaml.in index 349b3b47f..724e5f376 100644 --- a/configs/open5gs/pcrf.yaml.in +++ b/configs/open5gs/pcrf.yaml.in @@ -1,9 +1,94 @@ db_uri: mongodb://localhost/open5gs +# +# logger: +# +# o Set OGS_LOG_INFO to all domain level +# - If `level` is omitted, the default level is OGS_LOG_INFO) +# - If `domain` is omitted, the all domain level is set from 'level' +# (Nothing is needed) +# +# o Set OGS_LOG_ERROR to all domain level +# - `level` can be set with none, fatal, error, warn, info, debug, trace +# level: error +# +# o Set OGS_LOG_DEBUG to mme/emm domain level +# level: debug +# domain: mme,emm +# +# o Set OGS_LOG_TRACE to all domain level +# level: trace +# domain: core,fd,pcrf,event,mem,sock logger: file: @localstatedir@/log/open5gs/pcrf.log -parameter: - pcrf: freeDiameter: @sysconfdir@/freeDiameter/pcrf.conf + +# +# parameter: +# +# o Number of output streams per SCTP associations. +# sctp_streams: 30 +# +# o Disable use of IPv4 addresses (only IPv6) +# no_ipv4: true +# +# o Disable use of IPv6 addresses (only IPv4) +# no_ipv6: true +# +# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. +# prefer_ipv4: true +# +# o Enable Multicast traffic to the UE +# multicast: true +# +# o Disable Stateless Address Autoconfiguration for IPv6 +# no_slaac: true +# +# +parameter: + +# +# max: +# +# o Maximum Number of SGW per MME +# sgw: 32 +# o Maximum Number of PGW per MME +# pgw: 32 +# o Maximum Number of VLR per MME +# vlr: 32 +# o Maximum Number of eNodeB per MME +# enb: 32 +# o Maximum Number of UE per eNodeB +# ue: 128 +# +max: + +# +# pool: +# +# o The Number of Default Memory Pool Size +# +# - Pool-size 128 => 8192 Number +# - Pool-size 256 => 4096 Number +# - Pool-size 512 => 2048 Number +# - Pool-size 1024 => 1024 Number +# - Pool-size 2048 => 512 Number +# - Pool-size 8192 => 128 Number +# - Pool-size 1024*1024 => 8 Number +# +# 128: 8192 +# 256: 4096 +# 512: 2048 +# 1024: 1024 +# 2048: 512 +# 8192: 128 +# big: 8 +# +# o Memory of Packet Buffering in SGW +# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW +# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes +# +# packet: 65536 +pool: diff --git a/configs/open5gs/pgw.yaml.in b/configs/open5gs/pgw.yaml.in index 9f90360fe..cc4d96ec4 100644 --- a/configs/open5gs/pgw.yaml.in +++ b/configs/open5gs/pgw.yaml.in @@ -1,8 +1,152 @@ +# +# logger: +# +# o Set OGS_LOG_INFO to all domain level +# - If `level` is omitted, the default level is OGS_LOG_INFO) +# - If `domain` is omitted, the all domain level is set from 'level' +# (Nothing is needed) +# +# o Set OGS_LOG_ERROR to all domain level +# - `level` can be set with none, fatal, error, warn, info, debug, trace +# level: error +# +# o Set OGS_LOG_DEBUG to mme/emm domain level +# level: debug +# domain: mme,emm +# +# o Set OGS_LOG_TRACE to all domain level +# level: trace +# domain: core,fd,gtp,pgw,event,tlv,mem,sock +# logger: file: @localstatedir@/log/open5gs/pgw.log -parameter: +# +# pgw: +# +# +# +# o GTP-C Server(127.0.0.3:2123, [fe80::3%@loopback_devname@]:2123) +# gtpc: +# addr: +# - 127.0.0.3 +# - fe80::3%@loopback_devname@ +# +# o On PGW, Same configuration +# (127.0.0.3:2123, [fe80::3%@loopback_devname@]:2123). +# gtpc: +# - addr: 127.0.0.3 +# - addr: fe80::3%@loopback_devname@ +# +# +# > +# +# o GTP-U Server(127.0.0.3:2152, [::1]:2152) +# gtpu: +# - addr: 127.0.0.3 +# - addr: ::1 +# +# o Same configuration(127.0.0.3:2152, [::1]:2152) as below. +# gtpu: +# name: localhost +# +# +# +# o IPv4 Pool +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# +# pdn: +# addr: 10.45.0.1/16 +# +# o IPv4/IPv6 Pool +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# $ sudo ip addr add cafe:1::1/64 dev ogstun +# +# pdn: +# - addr: 10.45.0.1/16 +# - addr: cafe:1::1/64 +# +# +# o Specific APN(e.g 'volte') uses 10.46.0.1/16, cafe:2::1/64 +# All other APNs use 10.45.0.1/16, cafe:1::1/64 +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# $ sudo ip addr add 10.46.0.1/16 dev ogstun +# $ sudo ip addr add cafe:1::1/64 dev ogstun +# $ sudo ip addr add cafe:2::1/64 dev ogstun +# +# pdn: +# - addr: 10.45.0.1/16 +# - addr: cafe:1::1/64 +# - addr: 10.46.0.1/16 +# apn: volte +# - addr: cafe:2::1/64 +# apn: volte +# +# o Multiple Devices (default: ogstun) +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# $ sudo ip addr add cafe:1::1/64 dev ogstun2 +# $ sudo ip addr add 10.46.0.1/16 dev ogstun3 +# $ sudo ip addr add cafe:2::1/64 dev ogstun3 +# +# pdn: +# - addr: 10.45.0.1/16 +# - addr: cafe:1::1/64 +# dev: ogstun2 +# - addr: 10.46.0.1/16 +# apn: volte +# dev: ogstun3 +# - addr: cafe:2::1/64 +# apn: volte +# dev: ogstun3 +# +# o Pool Range Sample +# pdn: +# - addr: 10.45.0.1/24 +# range: 10.45.0.100-10.45.0.200 +# +# pdn: +# - addr: 10.45.0.1/24 +# range: +# - 10.45.0.5-10.45.0.50 +# - 10.45.0.100- +# +# pdn: +# - addr: 10.45.0.1/24 +# range: +# - -10.45.0.200 +# - 10.45.0.210-10.45.0.220 +# +# pdn: +# - addr: 10.45.0.1/16 +# range: +# - 10.45.0.100-10.45.0.200 +# - 10.45.1.100-10.45.1.200 +# - addr: cafe::1/64 +# range: +# - cafe::a0-cafe:b0 +# - cafe::c0-cafe:d0 +# +# +# +# o Primary/Secondary can be configured. Others are ignored. +# +# +# +# o Provisioning a limit on the size of the packets sent by the MS +# to avoid packet fragmentation in the backbone network +# between the MS and the GGSN/PGW and/or across the (S)Gi reference point) +# when some of the backbone links does not support +# packets larger then 1500 octets +# +# +# +# o Proxy Call Session Control Function +# +# p-cscf: +# - 127.0.0.1 +# - ::1 +# pgw: freeDiameter: @sysconfdir@/freeDiameter/pgw.conf gtpc: @@ -11,7 +155,7 @@ pgw: gtpu: - addr: 127.0.0.3 - addr: ::1 - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 dns: @@ -20,3 +164,71 @@ pgw: - 2001:4860:4860::8888 - 2001:4860:4860::8844 mtu: 1400 + +# +# parameter: +# +# o Number of output streams per SCTP associations. +# sctp_streams: 30 +# +# o Disable use of IPv4 addresses (only IPv6) +# no_ipv4: true +# +# o Disable use of IPv6 addresses (only IPv4) +# no_ipv6: true +# +# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. +# prefer_ipv4: true +# +# o Enable Multicast traffic to the UE +# multicast: true +# +# o Disable Stateless Address Autoconfiguration for IPv6 +# no_slaac: true +# +# +parameter: + +# +# max: +# +# o Maximum Number of SGW per MME +# sgw: 32 +# o Maximum Number of PGW per MME +# pgw: 32 +# o Maximum Number of VLR per MME +# vlr: 32 +# o Maximum Number of eNodeB per MME +# enb: 32 +# o Maximum Number of UE per eNodeB +# ue: 128 +# +max: + +# +# pool: +# +# o The Number of Default Memory Pool Size +# +# - Pool-size 128 => 8192 Number +# - Pool-size 256 => 4096 Number +# - Pool-size 512 => 2048 Number +# - Pool-size 1024 => 1024 Number +# - Pool-size 2048 => 512 Number +# - Pool-size 8192 => 128 Number +# - Pool-size 1024*1024 => 8 Number +# +# 128: 8192 +# 256: 4096 +# 512: 2048 +# 1024: 1024 +# 2048: 512 +# 8192: 128 +# big: 8 +# +# o Memory of Packet Buffering in SGW +# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW +# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes +# +# packet: 65536 +pool: diff --git a/configs/open5gs/sgw.yaml.in b/configs/open5gs/sgw.yaml.in index b76ac9cbc..1e642be4f 100644 --- a/configs/open5gs/sgw.yaml.in +++ b/configs/open5gs/sgw.yaml.in @@ -1,10 +1,131 @@ +# +# logger: +# +# o Set OGS_LOG_INFO to all domain level +# - If `level` is omitted, the default level is OGS_LOG_INFO) +# - If `domain` is omitted, the all domain level is set from 'level' +# (Nothing is needed) +# +# o Set OGS_LOG_ERROR to all domain level +# - `level` can be set with none, fatal, error, warn, info, debug, trace +# level: error +# +# o Set OGS_LOG_DEBUG to mme/emm domain level +# level: debug +# domain: mme,emm +# +# o Set OGS_LOG_TRACE to all domain level +# level: trace +# domain: core,gtp,sgw,event,tlv,mem,sock +# logger: file: @localstatedir@/log/open5gs/sgw.log -parameter: - no_ipv6: true - +# +# sgw: +# +# +# +# o GTP-C Server(127.0.0.2:2123, [fe80::2%@loopback_devname@]:2123) +# gtpc: +# addr: +# - 127.0.0.2 +# - fe80::2%@loopback_devname@ +# +# o On SGW, Same Configuration(127.0.0.2:2123, +# [fe80::2%@loopback_devname@]:2123) as below. +# gtpc: +# - addr: 127.0.0.2 +# - addr: fe80::2%@loopback_devname@ +# +# +# +# o GTP-U Server(all address avaiable) +# gtpu: +# +# o Provide custom SGW GTP-U address to be advertised inside S1AP messages +# gtpu: +# addr: 10.4.128.21 +# advertise_addr: 172.24.15.30 +# +# gtpu: +# addr: 10.4.128.21 +# advertise_name: sgw1.epc.mnc001.mcc001.3gppnetwork.org +# +# gtpu: +# dev: ens3 +# advertise_name: sgw1.epc.mnc001.mcc001.3gppnetwork.org +# sgw: gtpc: addr: 127.0.0.2 gtpu: + +# +# parameter: +# +# o Number of output streams per SCTP associations. +# sctp_streams: 30 +# +# o Disable use of IPv4 addresses (only IPv6) +# no_ipv4: true +# +# o Disable use of IPv6 addresses (only IPv4) +# no_ipv6: true +# +# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. +# prefer_ipv4: true +# +# o Enable Multicast traffic to the UE +# multicast: true +# +# o Disable Stateless Address Autoconfiguration for IPv6 +# no_slaac: true +# +# +parameter: + no_ipv6: true + +# +# max: +# +# o Maximum Number of SGW per MME +# sgw: 32 +# o Maximum Number of PGW per MME +# pgw: 32 +# o Maximum Number of VLR per MME +# vlr: 32 +# o Maximum Number of eNodeB per MME +# enb: 32 +# o Maximum Number of UE per eNodeB +# ue: 128 +# +max: + +# +# pool: +# +# o The Number of Default Memory Pool Size +# +# - Pool-size 128 => 8192 Number +# - Pool-size 256 => 4096 Number +# - Pool-size 512 => 2048 Number +# - Pool-size 1024 => 1024 Number +# - Pool-size 2048 => 512 Number +# - Pool-size 8192 => 128 Number +# - Pool-size 1024*1024 => 8 Number +# +# 128: 8192 +# 256: 4096 +# 512: 2048 +# 1024: 1024 +# 2048: 512 +# 8192: 128 +# big: 8 +# +# o Memory of Packet Buffering in SGW +# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW +# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes +# +# packet: 65536 +pool: diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in new file mode 100644 index 000000000..bff20df5d --- /dev/null +++ b/configs/open5gs/smf.yaml.in @@ -0,0 +1,241 @@ +# +# logger: +# +# o Set OGS_LOG_INFO to all domain level +# - If `level` is omitted, the default level is OGS_LOG_INFO) +# - If `domain` is omitted, the all domain level is set from 'level' +# (Nothing is needed) +# +# o Set OGS_LOG_ERROR to all domain level +# - `level` can be set with none, fatal, error, warn, info, debug, trace +# level: error +# +# o Set OGS_LOG_DEBUG to mme/emm domain level +# level: debug +# domain: mme,emm +# +# o Set OGS_LOG_TRACE to all domain level +# level: trace +# domain: core,pfcp,fd,gtp,smf,event,tlv,mem,sock +# +logger: + file: @localstatedir@/log/open5gs/smf.log +# +# smf: +# +# +# +# o PFCP Server(127.0.0.3:8805, ::1:8805) +# pfcp: +# - addr: 127.0.0.3 +# - addr: ::1 +# +# +# +# o GTP-C Server(127.0.0.3:2123, [fe80::3%@loopback_devname@]:2123) +# gtpc: +# addr: +# - 127.0.0.3 +# - fe80::3%@loopback_devname@ +# +# o On SMF, Same configuration +# (127.0.0.3:2123, [fe80::3%@loopback_devname@]:2123). +# gtpc: +# - addr: 127.0.0.3 +# - addr: fe80::3%@loopback_devname@ +# +# +# +# o IPv4 Pool +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# +# pdn: +# addr: 10.45.0.1/16 +# +# o IPv4/IPv6 Pool +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# $ sudo ip addr add cafe:1::1/64 dev ogstun +# +# pdn: +# - addr: 10.45.0.1/16 +# - addr: cafe:1::1/64 +# +# +# o Specific APN(e.g 'volte') uses 10.46.0.1/16, cafe:2::1/64 +# All other APNs use 10.45.0.1/16, cafe:1::1/64 +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# $ sudo ip addr add 10.46.0.1/16 dev ogstun +# $ sudo ip addr add cafe:1::1/64 dev ogstun +# $ sudo ip addr add cafe:2::1/64 dev ogstun +# +# pdn: +# - addr: 10.45.0.1/16 +# - addr: cafe:1::1/64 +# - addr: 10.46.0.1/16 +# apn: volte +# - addr: cafe:2::1/64 +# apn: volte +# +# o Multiple Devices (default: ogstun) +# $ sudo ip addr add 10.45.0.1/16 dev ogstun +# $ sudo ip addr add cafe:1::1/64 dev ogstun2 +# $ sudo ip addr add 10.46.0.1/16 dev ogstun3 +# $ sudo ip addr add cafe:2::1/64 dev ogstun3 +# +# pdn: +# - addr: 10.45.0.1/16 +# - addr: cafe:1::1/64 +# dev: ogstun2 +# - addr: 10.46.0.1/16 +# apn: volte +# dev: ogstun3 +# - addr: cafe:2::1/64 +# apn: volte +# dev: ogstun3 +# +# o Pool Range Sample +# pdn: +# - addr: 10.45.0.1/24 +# range: 10.45.0.100-10.45.0.200 +# +# pdn: +# - addr: 10.45.0.1/24 +# range: +# - 10.45.0.5-10.45.0.50 +# - 10.45.0.100- +# +# pdn: +# - addr: 10.45.0.1/24 +# range: +# - -10.45.0.200 +# - 10.45.0.210-10.45.0.220 +# +# pdn: +# - addr: 10.45.0.1/16 +# range: +# - 10.45.0.100-10.45.0.200 +# - 10.45.1.100-10.45.1.200 +# - addr: cafe::1/64 +# range: +# - cafe::a0-cafe:b0 +# - cafe::c0-cafe:d0 +# +# +# +# o Primary/Secondary can be configured. Others are ignored. +# +# +# +# o Provisioning a limit on the size of the packets sent by the MS +# to avoid packet fragmentation in the backbone network +# between the MS and the GGSN/PGW and/or across the (S)Gi reference point) +# when some of the backbone links does not support +# packets larger then 1500 octets +# +# +# +# o Proxy Call Session Control Function +# +# p-cscf: +# - 127.0.0.1 +# - ::1 +# +smf: + freeDiameter: @sysconfdir@/freeDiameter/pgw.conf + gtpc: + - addr: 127.0.0.3 + - addr: ::1 + pfcp: + - addr: 127.0.0.3 + - addr: ::1 + pdn: + - addr: 10.45.0.1/16 + - addr: cafe::1/64 + dns: + - 8.8.8.8 + - 8.8.4.4 + - 2001:4860:4860::8888 + - 2001:4860:4860::8844 + mtu: 1400 + +# +# upf: +# +# > +# +# o PFCP Client(127.0.0.2:8805) +# +# pfcp: +# addr: 127.0.0.2 +# +upf: + pfcp: + addr: 127.0.0.2 + +# +# parameter: +# +# o Number of output streams per SCTP associations. +# sctp_streams: 30 +# +# o Disable use of IPv4 addresses (only IPv6) +# no_ipv4: true +# +# o Disable use of IPv6 addresses (only IPv4) +# no_ipv6: true +# +# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. +# prefer_ipv4: true +# +# o Enable Multicast traffic to the UE +# multicast: true +# +# o Disable Stateless Address Autoconfiguration for IPv6 +# no_slaac: true +# +# +parameter: + +# +# max: +# +# o Maximum Number of SGW per MME +# sgw: 32 +# o Maximum Number of PGW per MME +# pgw: 32 +# o Maximum Number of VLR per MME +# vlr: 32 +# o Maximum Number of eNodeB per MME +# enb: 32 +# o Maximum Number of UE per eNodeB +# ue: 128 +# +max: + +# +# pool: +# +# o The Number of Default Memory Pool Size +# +# - Pool-size 128 => 8192 Number +# - Pool-size 256 => 4096 Number +# - Pool-size 512 => 2048 Number +# - Pool-size 1024 => 1024 Number +# - Pool-size 2048 => 512 Number +# - Pool-size 8192 => 128 Number +# - Pool-size 1024*1024 => 8 Number +# +# 128: 8192 +# 256: 4096 +# 512: 2048 +# 1024: 1024 +# 2048: 512 +# 8192: 128 +# big: 8 +# +# o Memory of Packet Buffering in SGW +# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW +# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes +# +# packet: 65536 +pool: diff --git a/configs/open5gs/upf.yaml.in b/configs/open5gs/upf.yaml.in new file mode 100644 index 000000000..ec46c6603 --- /dev/null +++ b/configs/open5gs/upf.yaml.in @@ -0,0 +1,149 @@ +# +# logger: +# +# o Set OGS_LOG_INFO to all domain level +# - If `level` is omitted, the default level is OGS_LOG_INFO) +# - If `domain` is omitted, the all domain level is set from 'level' +# (Nothing is needed) +# +# o Set OGS_LOG_ERROR to all domain level +# - `level` can be set with none, fatal, error, warn, info, debug, trace +# level: error +# +# o Set OGS_LOG_DEBUG to mme/emm domain level +# level: debug +# domain: mme,emm +# +# o Set OGS_LOG_TRACE to all domain level +# level: trace +# domain: core,pfcp,gtp,upf,event,tlv,mem,sock +# +logger: + file: @localstatedir@/log/open5gs/upf.log + +# +# upf: +# +# +# +# o PFCP Server(127.0.0.2:8805) +# pfcp: +# addr: 127.0.0.2 +# +# > +# +# o GTP-U Server(127.0.0.3:2152, [::1]:2152) +# gtpu: +# - addr: +# - 127.0.0.3 +# - ::1 +# +# o Same configuration(127.0.0.3:2152, [::1]:2152) as below. +# gtpu: +# name: localhost +# +# o User Plane IP Resource information +# gtpu: +# - addr: +# - 127.0.0.3 +# - ::1 +# teid_range_indication: 4 +# teid_range: 10 +# network_instance: internet +# source_interface: 0 +# - addr: 127.0.0.4 +# teid_range_indication: 4 +# teid_range: 5 +# network_instance: ims +# source_interface: 1 +# +upf: + pfcp: + addr: 127.0.0.2 + gtpu: + - addr: + - 127.0.0.3 + - ::1 + pdn: + +# +# smf: +# +# > +# +# o PFCP Client(127.0.0.3:8805) +# +# pfcp: +# addr: 127.0.0.3 +# +smf: + pfcp: + addr: 127.0.0.3 + +# +# parameter: +# +# o Number of output streams per SCTP associations. +# sctp_streams: 30 +# +# o Disable use of IPv4 addresses (only IPv6) +# no_ipv4: true +# +# o Disable use of IPv6 addresses (only IPv4) +# no_ipv6: true +# +# o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. +# prefer_ipv4: true +# +# o Enable Multicast traffic to the UE +# multicast: true +# +# o Disable Stateless Address Autoconfiguration for IPv6 +# no_slaac: true +# +# +parameter: + +# +# max: +# +# o Maximum Number of SGW per MME +# sgw: 32 +# o Maximum Number of PGW per MME +# pgw: 32 +# o Maximum Number of VLR per MME +# vlr: 32 +# o Maximum Number of eNodeB per MME +# enb: 32 +# o Maximum Number of UE per eNodeB +# ue: 128 +# +max: + +# +# pool: +# +# o The Number of Default Memory Pool Size +# +# - Pool-size 128 => 8192 Number +# - Pool-size 256 => 4096 Number +# - Pool-size 512 => 2048 Number +# - Pool-size 1024 => 1024 Number +# - Pool-size 2048 => 512 Number +# - Pool-size 8192 => 128 Number +# - Pool-size 1024*1024 => 8 Number +# +# 128: 8192 +# 256: 4096 +# 512: 2048 +# 1024: 1024 +# 2048: 512 +# 8192: 128 +# big: 8 +# +# o Memory of Packet Buffering in SGW +# - Maximum Number of packet(SDU size = 8Kbytes) pool in SGW +# - SGW Memory Usage : 65536 * 8Kbytes = 512Mbytes +# +# packet: 65536 +pool: diff --git a/configs/simple.yaml.in b/configs/simple.yaml.in index 6d5b033a0..6692fb370 100644 --- a/configs/simple.yaml.in +++ b/configs/simple.yaml.in @@ -94,7 +94,7 @@ pgw: gtpu: - addr: 127.0.0.3 - addr: ::1 - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 dns: diff --git a/configs/split.yaml.in b/configs/split.yaml.in index 093c8c9eb..a0ee41cc4 100644 --- a/configs/split.yaml.in +++ b/configs/split.yaml.in @@ -92,7 +92,7 @@ pgw: gtpu: - addr: 127.0.0.3 - addr: ::1 - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 dns: diff --git a/configs/srslte.yaml.in b/configs/srslte.yaml.in index 4589971c2..343779d63 100644 --- a/configs/srslte.yaml.in +++ b/configs/srslte.yaml.in @@ -94,7 +94,7 @@ pgw: gtpu: - addr: 127.0.0.3 - addr: ::1 - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 dns: diff --git a/configs/volte.yaml.in b/configs/volte.yaml.in index 799393b8f..cf88ca92e 100644 --- a/configs/volte.yaml.in +++ b/configs/volte.yaml.in @@ -99,7 +99,7 @@ pgw: gtpu: - addr: 127.0.0.3 - addr: ::1 - ue_pool: + pdn: - addr: 10.45.0.1/16 - addr: cafe::1/64 dns: diff --git a/docs/_docs/tutorial/03-VoLTE-dockerized.md b/docs/_docs/tutorial/03-VoLTE-dockerized.md index 6c57d7ec1..05793bc04 100644 --- a/docs/_docs/tutorial/03-VoLTE-dockerized.md +++ b/docs/_docs/tutorial/03-VoLTE-dockerized.md @@ -122,12 +122,17 @@ Password : 1423 Follow the instructions in [VoLTE Setup](https://open5gs.org/open5gs/docs/tutorial/02-VoLTE-setup/): - Step 18, set IMSI, Ki, OP, SQN and APN of your SIM cards. +<<<<<<< HEAD +- Step 20, add IMS subscriptions to FHoSS. + +======= **Important!** Set the type of both APN to IPv4. Kamailio does not support VoLTE over IPv6 at the moment. (See the screenshot below.) - Step 20, add IMS subscriptions to FHoSS. ![Set both type to IPv4 only](https://raw.githubusercontent.com/miaoski/docker_open5gs/gh-pages/screenshots/subscriber-type-ipv4.png) +>>>>>>> master For already running systems, copy SQN from Open5GS and type it in FHoSS. You can type SQN in decimal. FHoSS will automagically convert it to hex. @@ -135,7 +140,10 @@ Pay special attention to copy/paste. You might have leading or trailing spaces in FHoSS, resulting in failed connections! +<<<<<<< HEAD +======= +>>>>>>> master #### 5. Debugging with Wireshark Thanks to Open5GS, the topology is super similar to [SAE on Wikipedia](https://en.wikipedia.org/wiki/System_Architecture_Evolution#/media/File:Evolved_Packet_Core.svg). @@ -145,6 +153,13 @@ Thanks to Open5GS, the topology is super similar to [SAE on Wikipedia](https://e **APN** +<<<<<<< HEAD +APN Configurations in Open5GS should look like this one. + +![APN Configurations](https://raw.githubusercontent.com/miaoski/docker_open5gs/gh-pages/screenshots/open5gs-subscriber.png) + +======= +>>>>>>> master On your cellphone, there should be *internet* and *ims*. diff --git a/lib/app/ogs-app.h b/lib/app/ogs-app.h index 06b082140..60cf5a302 100644 --- a/lib/app/ogs-app.h +++ b/lib/app/ogs-app.h @@ -57,6 +57,12 @@ void pgw_terminate(void); int pcrf_initialize(void); void pcrf_terminate(void); +int smf_initialize(void); +void smf_terminate(void); + +int upf_initialize(void); +void upf_terminate(void); + #ifdef __cplusplus } #endif diff --git a/lib/app/ogs-config.c b/lib/app/ogs-config.c index db0ad9609..6e837f834 100644 --- a/lib/app/ogs-config.c +++ b/lib/app/ogs-config.c @@ -139,6 +139,7 @@ static void recalculate_pool_size(void) #define MAX_NUM_OF_PF 16 /* Num of PacketFilter per Bearer */ self.pool.ue = self.max.ue * self.max.enb; + self.pool.pfcp = ogs_max(self.max.smf, self.max.upf); self.pool.sess = self.pool.ue * OGS_MAX_NUM_OF_SESS; self.pool.bearer = self.pool.sess * MAX_NUM_OF_BEARER; self.pool.tunnel = self.pool.bearer * MAX_NUM_OF_TUNNEL; @@ -156,12 +157,16 @@ static int config_prepare(void) #define MAX_NUM_OF_CSMAP 128 /* Num of TAI-LAI MAP per MME */ #define MAX_NUM_OF_ENB 32 /* Num of eNodeB per MME */ #define MAX_NUM_OF_UE 128 /* Num of UE per eNodeB */ +#define MAX_NUM_OF_SMF 32 /* Num of SMF per AMF */ +#define MAX_NUM_OF_UPF 32 /* Num of PGW per AMF */ self.max.sgw = MAX_NUM_OF_SGW; self.max.pgw = MAX_NUM_OF_PGW; self.max.vlr = MAX_NUM_OF_VLR; self.max.csmap = MAX_NUM_OF_CSMAP; self.max.enb = MAX_NUM_OF_ENB; self.max.ue = MAX_NUM_OF_UE; + self.max.smf = MAX_NUM_OF_SMF; + self.max.upf = MAX_NUM_OF_UPF; #define MAX_NUM_OF_PACKET_POOL 65536 self.pool.packet = MAX_NUM_OF_PACKET_POOL; diff --git a/lib/app/ogs-config.h b/lib/app/ogs-config.h index db6a4f4e7..5440781c1 100644 --- a/lib/app/ogs-config.h +++ b/lib/app/ogs-config.h @@ -68,6 +68,8 @@ typedef struct ogs_config_s { int csmap; int enb; int ue; + int smf; + int upf; } max; struct { @@ -75,6 +77,7 @@ typedef struct ogs_config_s { int packet; int ue; + int pfcp; int sess; int bearer; int tunnel; diff --git a/lib/core/meson.build b/lib/core/meson.build index 6530635dd..f47f9de01 100644 --- a/lib/core/meson.build +++ b/lib/core/meson.build @@ -244,6 +244,7 @@ libcore_sources = files(''' ogs-socknode.h ogs-udp.h ogs-tcp.h + ogs-tun.h ogs-queue.h ogs-poll.h ogs-notify.h @@ -277,6 +278,7 @@ libcore_sources = files(''' ogs-socknode.c ogs-udp.c ogs-tcp.c + ogs-tun.c ogs-queue.c ogs-select.c ogs-poll.c diff --git a/lib/core/ogs-3gpp-types.c b/lib/core/ogs-3gpp-types.c index f25b5e9d1..a33750d85 100644 --- a/lib/core/ogs-3gpp-types.c +++ b/lib/core/ogs-3gpp-types.c @@ -28,7 +28,7 @@ uint32_t ogs_plmn_id_hexdump(void *plmn_id) uint32_t hex; ogs_assert(plmn_id); memcpy(&hex, plmn_id, sizeof(ogs_plmn_id_t)); - hex = ntohl(hex) >> 8; + hex = be32toh(hex) >> 8; return hex; } @@ -124,7 +124,7 @@ int ogs_pco_parse(ogs_pco_t *pco, unsigned char *data, int data_len) ogs_pco_id_t *id = &pco->ids[i]; ogs_assert(size + sizeof(id->id) <= data_len); memcpy(&id->id, data + size, sizeof(id->id)); - id->id = ntohs(id->id); + id->id = be16toh(id->id); size += sizeof(id->id); ogs_assert(size + sizeof(id->len) <= data_len); @@ -162,7 +162,7 @@ int ogs_pco_build(unsigned char *data, int data_len, ogs_pco_t *pco) ogs_pco_id_t *id = &target.ids[i]; ogs_assert(size + sizeof(id->id) <= data_len); - id->id = htons(id->id); + id->id = htobe16(id->id); memcpy(data + size, &id->id, sizeof(id->id)); size += sizeof(id->id); @@ -177,3 +177,46 @@ int ogs_pco_build(unsigned char *data, int data_len, ogs_pco_t *pco) return size; } + +int ogs_ip_to_sockaddr(ogs_ip_t *ip, uint16_t port, ogs_sockaddr_t **list) +{ + ogs_sockaddr_t *addr = NULL, *addr6 = NULL; + + ogs_assert(ip); + ogs_assert(list); + + addr = ogs_calloc(1, sizeof(ogs_sockaddr_t)); + ogs_assert(addr); + addr->ogs_sa_family = AF_INET; + addr->ogs_sin_port = htobe16(port); + + addr6 = ogs_calloc(1, sizeof(ogs_sockaddr_t)); + ogs_assert(addr6); + addr6->ogs_sa_family = AF_INET6; + addr6->ogs_sin_port = htobe16(port); + + if (ip->ipv4 && ip->ipv6) { + addr->next = addr6; + + addr->sin.sin_addr.s_addr = ip->both.addr; + memcpy(addr6->sin6.sin6_addr.s6_addr, ip->both.addr6, OGS_IPV6_LEN); + + *list = addr; + } else if (ip->ipv4) { + addr->sin.sin_addr.s_addr = ip->addr; + ogs_free(addr6); + + *list = addr; + } else if (ip->ipv6) { + memcpy(addr6->sin6.sin6_addr.s6_addr, ip->addr6, OGS_IPV6_LEN); + ogs_free(addr); + + *list = addr6; + } else { + ogs_free(addr); + ogs_free(addr6); + return OGS_ERROR; + } + + return OGS_OK; +} diff --git a/lib/core/ogs-3gpp-types.h b/lib/core/ogs-3gpp-types.h index 802c22061..f122da77c 100644 --- a/lib/core/ogs-3gpp-types.h +++ b/lib/core/ogs-3gpp-types.h @@ -31,6 +31,7 @@ extern "C" { #define OGS_MAX_FILEPATH_LEN 256 #define OGS_MAX_NUM_OF_SESS 4 /* Num of APN(Session) per UE */ +#define OGS_MAX_NUM_OF_RULE 4 /* Num of Rule per Session */ #define OGS_MAX_SDU_LEN 8192 #define OGS_PLMN_ID_LEN 3 @@ -48,6 +49,7 @@ extern "C" { #define OGS_MAX_APN_LEN 100 #define OGS_MAX_PCO_LEN 251 #define OGS_MAX_FQDN_LEN 256 +#define OGS_MAX_IFNAME_LEN 32 #define OGS_NEXT_ID(__id, __min, __max) \ ((__id) = ((__id) == (__max) ? (__min) : ((__id) + 1))) @@ -114,18 +116,24 @@ ED3(uint8_t ipv4:1;, uint8_t reserved:6;) } ogs_ip_t; +int ogs_ip_to_sockaddr(ogs_ip_t *ip, uint16_t port, ogs_sockaddr_t **list); + /************************************************** * 8.14 PDN Address Allocation (PAA) */ -#define OGS_PAA_IPV4_LEN 5 -#define OGS_PAA_IPV6_LEN 18 -#define OGS_PAA_IPV4V6_LEN 22 +#define OGS_PAA_IPV4_LEN 5 +#define OGS_PAA_IPV6_LEN 18 +#define OGS_PAA_IPV4V6_LEN 22 typedef struct ogs_paa_s { -/* 8.34 PDN Type */ -#define OGS_GTP_PDN_TYPE_IPV4 1 -#define OGS_GTP_PDN_TYPE_IPV6 2 -#define OGS_GTP_PDN_TYPE_IPV4V6 3 -#define OGS_GTP_PDN_TYPE_NON_IP 4 ED2(uint8_t spare:5;, +/* 8.34 PDN Type */ +#define OGS_GTP_PDN_TYPE_IPV4 1 +#define OGS_GTP_PDN_TYPE_IPV6 2 +#define OGS_GTP_PDN_TYPE_IPV4V6 3 +#define OGS_GTP_PDN_TYPE_NON_IP 4 +#define OGS_PFCP_PDN_TYPE_IPV4 OGS_GTP_PDN_TYPE_IPV4 +#define OGS_PFCP_PDN_TYPE_IPV6 OGS_GTP_PDN_TYPE_IPV6 +#define OGS_PFCP_PDN_TYPE_IPV4V6 OGS_GTP_PDN_TYPE_IPV4V6 +#define OGS_PFCP_PDN_TYPE_NONIP OGS_GTP_PDN_TYPE_NONIP uint8_t pdn_type:3;) union { /* GTP_PDN_TYPE_IPV4 */ @@ -241,14 +249,36 @@ typedef struct ogs_pcc_rule_s { ogs_qos_t qos; } ogs_pcc_rule_t; +#define OGS_STORE_PCC_RULE(__dST, __sRC) \ + do { \ + int __iNDEX; \ + ogs_assert((__sRC)); \ + ogs_assert((__dST)); \ + OGS_PCC_RULE_FREE(__dST); \ + (__dST)->type = (__sRC)->type; \ + if ((__sRC)->name) { \ + (__dST)->name = ogs_strdup((__sRC)->name); \ + ogs_assert((__dST)->name); \ + } else \ + ogs_assert_if_reached(); \ + for (__iNDEX = 0; __iNDEX < (__sRC)->num_of_flow; __iNDEX++) { \ + (__dST)->flow[__iNDEX].direction = (__sRC)->flow[__iNDEX].direction; \ + (__dST)->flow[__iNDEX].description = \ + ogs_strdup((__sRC)->flow[__iNDEX].description); \ + ogs_assert((__dST)->flow[__iNDEX].description); \ + } \ + (__dST)->num_of_flow = (__sRC)->num_of_flow; \ + (__dST)->flow_status = (__sRC)->flow_status; \ + (__dST)->precedence = (__sRC)->precedence; \ + memcpy(&(__dST)->qos, &(__sRC)->qos, sizeof(ogs_qos_t)); \ + } while(0) + #define OGS_PCC_RULE_FREE(__pCCrULE) \ do { \ int __pCCrULE_iNDEX; \ ogs_assert((__pCCrULE)); \ - if ((__pCCrULE)->name) { \ + if ((__pCCrULE)->name) \ ogs_free((__pCCrULE)->name); \ - } else \ - ogs_assert_if_reached(); \ for (__pCCrULE_iNDEX = 0; \ __pCCrULE_iNDEX < (__pCCrULE)->num_of_flow; __pCCrULE_iNDEX++) { \ OGS_FLOW_FREE(&((__pCCrULE)->flow[__pCCrULE_iNDEX])); \ @@ -265,7 +295,7 @@ typedef struct ogs_pdn_s { #define OGS_DIAM_PDN_TYPE_IPV6 1 #define OGS_DIAM_PDN_TYPE_IPV4V6 2 #define OGS_DIAM_PDN_TYPE_IPV4_OR_IPV6 3 - int pdn_type; + uint8_t pdn_type; ogs_qos_t qos; ogs_bitrate_t ambr; /* APN-AMBR */ diff --git a/lib/core/ogs-core.h b/lib/core/ogs-core.h index 134991205..0089a2faf 100644 --- a/lib/core/ogs-core.h +++ b/lib/core/ogs-core.h @@ -48,6 +48,7 @@ #include "core/ogs-socknode.h" #include "core/ogs-udp.h" #include "core/ogs-tcp.h" +#include "core/ogs-tun.h" #include "core/ogs-queue.h" #include "core/ogs-poll.h" #include "core/ogs-notify.h" diff --git a/lib/core/ogs-list.h b/lib/core/ogs-list.h index 087ad9b87..14071de29 100644 --- a/lib/core/ogs-list.h +++ b/lib/core/ogs-list.h @@ -35,26 +35,68 @@ typedef struct ogs_list_s ogs_list_t; typedef struct ogs_list_s ogs_lnode_t;; #define OGS_LIST(name) \ - ogs_list_t name = { &(name), &(name) } + ogs_list_t name = { NULL, NULL } #define ogs_list_init(list) do { \ (list)->prev = (NULL); \ (list)->next = (NULL); \ } while (0) +static ogs_inline void *ogs_list_first(const ogs_list_t *list) +{ + return list->next; +} + +static ogs_inline void *ogs_list_last(const ogs_list_t *list) +{ + return list->prev; +} + +static ogs_inline void *ogs_list_next(void *lnode) +{ + ogs_list_t *node = lnode; + return node->next; +} + +static ogs_inline void *ogs_list_prev(void *lnode) +{ + ogs_list_t *node = lnode; + return node->prev; +} + +#define ogs_list_for_each(list, node) \ + for (node = ogs_list_first(list); (node); \ + node = ogs_list_next(node)) + +#define ogs_list_for_each_safe(list, n, node) \ + for (node = ogs_list_first(list); \ + (node) && (n = ogs_list_next(node), 1); \ + node = n) + +static ogs_inline void ogs_list_prepend(ogs_list_t *list, void *lnode) +{ + ogs_list_t *node = lnode; + + node->prev = NULL; + node->next = list->next; + if (list->next) + list->next->prev = node; + else + list->prev = node; + list->next = node; +} + static ogs_inline void ogs_list_add(ogs_list_t *list, void *lnode) { ogs_list_t *node = lnode; - ogs_list_t *head = list; - ogs_list_t *tail = list->prev; - node->prev = tail; + node->prev = list->prev; node->next = NULL; - if (tail) - tail->next = node; + if (list->prev) + list->prev->next = node; else - head->next = node; - head->prev = node; + list->next = node; + list->prev = node; } static ogs_inline void ogs_list_remove(ogs_list_t *list, void *lnode) @@ -74,25 +116,56 @@ static ogs_inline void ogs_list_remove(ogs_list_t *list, void *lnode) list->prev = prev; } -static ogs_inline void *ogs_list_first(const ogs_list_t *list) -{ - return list->next; -} - -static ogs_inline void *ogs_list_next(void *lnode) +static ogs_inline void ogs_list_insert_prev( + ogs_list_t *list, void *lnext, void *lnode) { ogs_list_t *node = lnode; - return node->next; + ogs_list_t *next = lnext; + + node->prev = next->prev; + node->next = next; + if (next->prev) + next->prev->next = node; + else + list->next = node; + next->prev = node; } -#define ogs_list_for_each(list, node) \ - for (node = ogs_list_first(list); (node); \ - node = ogs_list_next(node)) +static ogs_inline void ogs_list_insert_next( + ogs_list_t *list, void *lprev, void *lnode) +{ + ogs_list_t *node = lnode; + ogs_list_t *prev = lprev; -#define ogs_list_for_each_safe(list, n, node) \ - for (node = ogs_list_first(list); \ - (node) && (n = ogs_list_next(node), 1); \ - node = n) + node->prev = prev; + node->next = prev->next; + if (prev->next) + prev->next->prev = node; + else + list->prev = node; + prev->next = node; +} + +typedef int (*ogs_list_compare_f)(ogs_lnode_t *n1, ogs_lnode_t *n2); +#define ogs_list_insert_sorted(__list, __lnode, __compare) \ + __ogs_list_insert_sorted(__list, __lnode, (ogs_list_compare_f)__compare); + +static ogs_inline void __ogs_list_insert_sorted( + ogs_list_t *list, void *lnode, ogs_list_compare_f compare) +{ + ogs_list_t *node = lnode; + ogs_list_t *iter = NULL; + + ogs_list_for_each(list, iter) { + if ((*compare)(node, iter) < 0) { + ogs_list_insert_prev(list, iter, node); + break; + } + } + + if (iter == NULL) + ogs_list_add(list, node); +} static ogs_inline bool ogs_list_empty(const ogs_list_t *list) { diff --git a/lib/core/ogs-log.c b/lib/core/ogs-log.c index ff9d965e9..a89baa869 100644 --- a/lib/core/ogs-log.c +++ b/lib/core/ogs-log.c @@ -114,10 +114,7 @@ static void file_writer( void ogs_log_init(void) { ogs_pool_init(&log_pool, ogs_core()->log.pool); - ogs_list_init(&log_list); - ogs_pool_init(&domain_pool, ogs_core()->log.domain_pool); - ogs_list_init(&domain_list); ogs_log_add_domain("core", ogs_core()->log.level); ogs_log_add_stderr(); diff --git a/lib/core/ogs-macros.h b/lib/core/ogs-macros.h index 0c6d22370..6617e802b 100644 --- a/lib/core/ogs-macros.h +++ b/lib/core/ogs-macros.h @@ -161,6 +161,10 @@ extern "C" { #define OGS_IS_DIR_SEPARATOR(c) ((c) == OGS_DIR_SEPARATOR) #endif +#define ogs_container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type, member) );}) + #ifdef __cplusplus } #endif diff --git a/lib/core/ogs-memory.h b/lib/core/ogs-memory.h index 0f72082c4..e4d6cf2a8 100644 --- a/lib/core/ogs-memory.h +++ b/lib/core/ogs-memory.h @@ -28,6 +28,22 @@ extern "C" { #endif +#define OGS_MEM_CLEAR(__dATA) \ + do { \ + if ((__dATA)) { \ + ogs_free((__dATA)); \ + (__dATA) = NULL; \ + } \ + } while(0) +#define OGS_MEM_STORE(__dST, __sRC) \ + do { \ + ogs_assert((__sRC)); \ + OGS_MEM_CLEAR(__dST); \ + (__dST) = ogs_calloc(sizeof(*(__sRC)), sizeof(uint8_t)); \ + ogs_assert((__dST)); \ + memcpy((__dST), (__sRC), sizeof(*(__sRC))*sizeof(uint8_t)); \ + } while(0) + void *ogs_malloc(size_t size); void ogs_free(void *ptr); void *ogs_calloc(size_t nmemb, size_t size); diff --git a/lib/core/ogs-rbtree.h b/lib/core/ogs-rbtree.h index 1a42bfdc6..ba99ccd7a 100644 --- a/lib/core/ogs-rbtree.h +++ b/lib/core/ogs-rbtree.h @@ -47,8 +47,7 @@ typedef struct ogs_rbtree_s { #define OGS_RBTREE(name) ogs_rbtree_t name = { NULL } -#define ogs_rb_entry(n, type, link) \ - (type *)((u_char *)n - offsetof(type, link)) +#define ogs_rb_entry(ptr, type, member) ogs_container_of(ptr, type, member) static ogs_inline void ogs_rbtree_link_node( void *rb_node, ogs_rbnode_t *parent, ogs_rbnode_t **rb_link) diff --git a/lib/core/ogs-sockaddr.c b/lib/core/ogs-sockaddr.c index bc882c54e..169d954ee 100644 --- a/lib/core/ogs-sockaddr.c +++ b/lib/core/ogs-sockaddr.c @@ -40,6 +40,17 @@ #undef OGS_LOG_DOMAIN #define OGS_LOG_DOMAIN __ogs_sock_domain +int ogs_getnameinfo( + char *hostname, socklen_t hostname_len, ogs_sockaddr_t *addr, int flags) +{ + ogs_assert(hostname); + ogs_assert(addr); + + return getnameinfo(&addr->sa, ogs_sockaddr_len(addr), + hostname, hostname_len, + NULL, 0, flags != 0 ? flags : NI_NAMEREQD); +} + int ogs_getaddrinfo(ogs_sockaddr_t **sa_list, int family, const char *hostname, uint16_t port, int flags) { @@ -54,6 +65,8 @@ int ogs_freeaddrinfo(ogs_sockaddr_t *sa_list) addr = sa_list; while (addr) { next = addr->next; + if (addr->hostname) + ogs_free(addr->hostname); ogs_free(addr); addr = next; } @@ -100,6 +113,8 @@ int ogs_addaddrinfo(ogs_sockaddr_t **sa_list, new = ogs_calloc(1, sizeof(ogs_sockaddr_t)); memcpy(&new->sa, ai->ai_addr, ai->ai_addrlen); new->ogs_sin_port = htobe16(port); + if (hostname) + new->hostname = ogs_strdup(hostname); ogs_trace("addr:%s, port:%d", OGS_ADDR(new, buf), port); if (!prev) @@ -138,6 +153,8 @@ int ogs_filteraddrinfo(ogs_sockaddr_t **sa_list, int family) prev->next = addr->next; else *sa_list = addr->next; + if (addr->hostname) + ogs_free(addr->hostname); ogs_free(addr); } else { @@ -157,13 +174,19 @@ int ogs_copyaddrinfo(ogs_sockaddr_t **dst, const ogs_sockaddr_t *src) for (*dst = d = NULL, s = src; s; s = s->next) { if (!d) { - d = ogs_calloc(1, sizeof *s); - *dst = memcpy(d, s, sizeof *s); + *dst = d = ogs_memdup(s, sizeof *s); } else { - d->next = ogs_calloc(1, sizeof(ogs_sockaddr_t)); - d = memcpy(d->next, s, sizeof *s); + d = d->next = ogs_memdup(s, sizeof *s); + } + if (s->hostname) { + if (s == src || s->hostname != src->hostname) { + d->hostname = ogs_strdup(s->hostname); + } else { + d->hostname = (*dst)->hostname; + } } } + return OGS_OK; } diff --git a/lib/core/ogs-sockaddr.h b/lib/core/ogs-sockaddr.h index a6536729b..2c0028353 100644 --- a/lib/core/ogs-sockaddr.h +++ b/lib/core/ogs-sockaddr.h @@ -50,6 +50,8 @@ struct ogs_sockaddr_s { /* User Area * - Could add your attribute. */ + char *hostname; + ogs_sockaddr_t *next; }; @@ -60,6 +62,9 @@ typedef struct ogs_ipsubnet_s { uint32_t mask[4]; } ogs_ipsubnet_t; +int ogs_getnameinfo( + char *hostname, socklen_t hostname_len, ogs_sockaddr_t *addr, int flags); + int ogs_getaddrinfo(ogs_sockaddr_t **sa_list, int family, const char *hostname, uint16_t port, int flags); int ogs_freeaddrinfo(ogs_sockaddr_t *sa_list); diff --git a/lib/core/ogs-timer.c b/lib/core/ogs-timer.c index 5f8326c23..95ce03dce 100644 --- a/lib/core/ogs-timer.c +++ b/lib/core/ogs-timer.c @@ -175,7 +175,6 @@ void ogs_timer_mgr_expire(ogs_timer_mgr_t *manager) current = ogs_get_monotonic_time(); - ogs_list_init(&list); ogs_rbtree_for_each(&manager->tree, rbnode) { this = ogs_rb_entry(rbnode, ogs_timer_t, rbnode); diff --git a/lib/core/ogs-tlv-msg.c b/lib/core/ogs-tlv-msg.c index f9d77af56..0a41ffdae 100644 --- a/lib/core/ogs-tlv-msg.c +++ b/lib/core/ogs-tlv-msg.c @@ -56,7 +56,7 @@ static ogs_tlv_t *tlv_add_leaf( { ogs_tlv_uint16_t *v = (ogs_tlv_uint16_t *)msg; - v->u16 = htons(v->u16); + v->u16 = htobe16(v->u16); if (parent_tlv) tlv = ogs_tlv_embed(parent_tlv, @@ -72,7 +72,7 @@ static ogs_tlv_t *tlv_add_leaf( ogs_tlv_uint24_t *v = (ogs_tlv_uint24_t *)msg; v->u24 = v->u24 << 8; - v->u24 = htonl(v->u24); + v->u24 = htobe32(v->u24); if (parent_tlv) tlv = ogs_tlv_embed(parent_tlv, @@ -87,7 +87,7 @@ static ogs_tlv_t *tlv_add_leaf( { ogs_tlv_uint32_t *v = (ogs_tlv_uint32_t *)msg; - v->u32 = htonl(v->u32); + v->u32 = htobe32(v->u32); if (parent_tlv) tlv = ogs_tlv_embed(parent_tlv, @@ -263,21 +263,26 @@ ogs_pkbuf_t *ogs_tlv_build_msg(ogs_tlv_desc_t *desc, void *msg, int mode) ogs_assert(msg); ogs_assert(desc->ctype == OGS_TLV_MESSAGE); - ogs_assert(desc->child_descs[0]); - r = tlv_add_compound(&root, NULL, desc, msg, 0); - ogs_assert(r > 0 && root); + if (desc->child_descs[0]) { + r = tlv_add_compound(&root, NULL, desc, msg, 0); + ogs_assert(r > 0 && root); - length = ogs_tlv_calc_length(root, mode); + length = ogs_tlv_calc_length(root, mode); + } else { + length = 0; + } pkbuf = ogs_pkbuf_alloc(NULL, OGS_TLV_MAX_HEADROOM+length); ogs_assert(pkbuf); ogs_pkbuf_reserve(pkbuf, OGS_TLV_MAX_HEADROOM); ogs_pkbuf_put(pkbuf, length); - rendlen = ogs_tlv_render(root, pkbuf->data, length, mode); - ogs_assert(rendlen == length); + if (desc->child_descs[0]) { + rendlen = ogs_tlv_render(root, pkbuf->data, length, mode); + ogs_assert(rendlen == length); - ogs_tlv_free_all(root); + ogs_tlv_free_all(root); + } return pkbuf; } diff --git a/lib/core/ogs-tlv-msg.h b/lib/core/ogs-tlv-msg.h index 4ef7930f8..fd8e3ab3b 100644 --- a/lib/core/ogs-tlv-msg.h +++ b/lib/core/ogs-tlv-msg.h @@ -125,8 +125,7 @@ typedef struct ogs_tlv_int32_s { #define OGS_TLV_CLEAR_DATA(__dATA) \ do { \ ogs_assert((__dATA)); \ - if ((__dATA)->data) \ - { \ + if ((__dATA)->data) { \ ogs_free((__dATA)->data); \ (__dATA)->data = NULL; \ (__dATA)->len = 0; \ diff --git a/src/pgw/ogs-tun.c b/lib/core/ogs-tun.c similarity index 99% rename from src/pgw/ogs-tun.c rename to lib/core/ogs-tun.c index ceecfc571..10a67238a 100644 --- a/src/pgw/ogs-tun.c +++ b/lib/core/ogs-tun.c @@ -378,8 +378,6 @@ int ogs_tun_set_ip(char *ifname, ogs_ipsubnet_t *gw, ogs_ipsubnet_t *sub) rv = tun_set_ipv4(ifname, gw, sub); else if (gw->family == AF_INET6) rv = tun_set_ipv6(ifname, gw, sub); - else - ogs_assert_if_reached(); return rv; } diff --git a/src/pgw/ogs-tun.h b/lib/core/ogs-tun.h similarity index 100% rename from src/pgw/ogs-tun.h rename to lib/core/ogs-tun.h diff --git a/lib/gtp/conv.c b/lib/gtp/conv.c index ff00cf142..6bafbb622 100644 --- a/lib/gtp/conv.c +++ b/lib/gtp/conv.c @@ -65,12 +65,12 @@ int ogs_gtp_f_teid_to_sockaddr( addr = ogs_calloc(1, sizeof(ogs_sockaddr_t)); ogs_assert(addr); addr->ogs_sa_family = AF_INET; - addr->ogs_sin_port = htons(port); + addr->ogs_sin_port = htobe16(port); addr6 = ogs_calloc(1, sizeof(ogs_sockaddr_t)); ogs_assert(addr6); addr6->ogs_sa_family = AF_INET6; - addr6->ogs_sin_port = htons(port); + addr6->ogs_sin_port = htobe16(port); if (f_teid->ipv4 && f_teid->ipv6) { addr->next = addr6; @@ -146,7 +146,7 @@ int ogs_gtp_f_teid_to_ip(ogs_gtp_f_teid_t *f_teid, ogs_ip_t *ip) memcpy(ip->addr6, f_teid->addr6, OGS_IPV6_LEN); ip->len = OGS_IPV6_LEN; } else - ogs_assert_if_reached(); + return OGS_ERROR; return OGS_OK; } diff --git a/lib/gtp/message.c b/lib/gtp/message.c index 3d249690b..3f23d7be6 100644 --- a/lib/gtp/message.c +++ b/lib/gtp/message.c @@ -2827,7 +2827,7 @@ int ogs_gtp_parse_msg(ogs_gtp_message_t *gtp_message, ogs_pkbuf_t *pkbuf) memcpy(>p_message->h, pkbuf->data - size, size); if (h->teid_presence) - gtp_message->h.teid = ntohl(gtp_message->h.teid); + gtp_message->h.teid = be32toh(gtp_message->h.teid); if (pkbuf->len == 0) return OGS_OK; diff --git a/lib/gtp/message.h b/lib/gtp/message.h index 16928e737..fd4483216 100644 --- a/lib/gtp/message.h +++ b/lib/gtp/message.h @@ -58,8 +58,8 @@ typedef struct ogs_gtp_header_s { struct { uint32_t teid; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ -#define OGS_GTP_XID_TO_SQN(__xid) htonl(((__xid) << 8)) -#define OGS_GTP_SQN_TO_XID(__sqn) (ntohl(__sqn) >> 8) +#define OGS_GTP_XID_TO_SQN(__xid) htobe32(((__xid) << 8)) +#define OGS_GTP_SQN_TO_XID(__sqn) (be32toh(__sqn) >> 8) uint32_t sqn; }; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ diff --git a/lib/gtp/node.c b/lib/gtp/node.c index 579780430..cb20b48c2 100644 --- a/lib/gtp/node.c +++ b/lib/gtp/node.c @@ -65,7 +65,8 @@ void ogs_gtp_node_free(ogs_gtp_node_t *node) ogs_pool_free(&pool, node); } -ogs_gtp_node_t *ogs_gtp_node_add(ogs_list_t *list, ogs_gtp_f_teid_t *f_teid, +ogs_gtp_node_t *ogs_gtp_node_add_by_f_teid( + ogs_list_t *list, ogs_gtp_f_teid_t *f_teid, uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4) { int rv; @@ -109,7 +110,7 @@ ogs_gtp_node_t *ogs_gtp_node_add_by_addr( gnode = ogs_gtp_node_new(new); ogs_assert(gnode); - memcpy(&gnode->remote_addr, new, sizeof gnode->remote_addr); + memcpy(&gnode->addr, new, sizeof gnode->addr); ogs_list_add(list, gnode); @@ -142,7 +143,7 @@ ogs_gtp_node_t *ogs_gtp_node_find_by_addr( ogs_assert(addr); ogs_list_for_each(list, node) { - if (ogs_sockaddr_is_equal(&node->remote_addr, addr) == true) + if (ogs_sockaddr_is_equal(&node->addr, addr) == true) break; } @@ -163,7 +164,52 @@ ogs_gtp_node_t *ogs_gtp_node_find_by_f_teid( ogs_assert(rv == OGS_OK); ogs_list_for_each(list, node) { - if (memcmp(&node->ip, &ip, ip.len) == 0) + if (memcmp(&node->ip, &ip, sizeof(ip)) == 0) + break; + } + + return node; +} + +ogs_gtp_node_t *ogs_gtp_node_add_by_ip(ogs_list_t *list, ogs_ip_t *ip, + uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4) +{ + int rv; + ogs_gtp_node_t *node = NULL; + ogs_sockaddr_t *addr = NULL; + + ogs_assert(list); + ogs_assert(ip); + ogs_assert(port); + + rv = ogs_ip_to_sockaddr(ip, port, &addr); + ogs_assert(rv == OGS_OK); + + rv = ogs_filter_ip_version(&addr, no_ipv4, no_ipv6, prefer_ipv4); + ogs_assert(addr); + + rv = ogs_socknode_fill_scope_id_in_local(addr); + ogs_assert(rv == OGS_OK); + + node = ogs_gtp_node_new(addr); + ogs_assert(node); + + memcpy(&node->ip, ip, sizeof(*ip)); + + ogs_list_add(list, node); + + return node; +} + +ogs_gtp_node_t *ogs_gtp_node_find_by_ip(ogs_list_t *list, ogs_ip_t *ip) +{ + ogs_gtp_node_t *node = NULL; + + ogs_assert(list); + ogs_assert(ip); + + ogs_list_for_each(list, node) { + if (node->ip.len == ip->len && memcmp(&node->ip, ip, ip->len) == 0) break; } diff --git a/lib/gtp/node.h b/lib/gtp/node.h index 5904cf6d5..24d53ba55 100644 --- a/lib/gtp/node.h +++ b/lib/gtp/node.h @@ -41,11 +41,12 @@ extern "C" { typedef struct ogs_gtp_node_s { ogs_lnode_t node; /* A node of list_t */ - ogs_sockaddr_t *sa_list; /* Socket Address List */ + ogs_sockaddr_t *sa_list; /* Socket Address List Candidate */ ogs_sock_t *sock; /* Socket Instance */ - ogs_ip_t ip; /* Socket Address */ - ogs_sockaddr_t remote_addr; /* Connected Address */ + ogs_sockaddr_t addr; /* Remote Address */ + + ogs_ip_t ip; /* F-TEID IP Address Duplicate Check */ ogs_list_t local_list; ogs_list_t remote_list; @@ -57,7 +58,7 @@ int ogs_gtp_node_final(void); ogs_gtp_node_t *ogs_gtp_node_new(ogs_sockaddr_t *sa_list); void ogs_gtp_node_free(ogs_gtp_node_t *node); -ogs_gtp_node_t *ogs_gtp_node_add( +ogs_gtp_node_t *ogs_gtp_node_add_by_f_teid( ogs_list_t *list, ogs_gtp_f_teid_t *f_teid, uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4); ogs_gtp_node_t *ogs_gtp_node_add_by_addr( @@ -70,6 +71,10 @@ ogs_gtp_node_t *ogs_gtp_node_find_by_addr( ogs_gtp_node_t *ogs_gtp_node_find_by_f_teid( ogs_list_t *list, ogs_gtp_f_teid_t *f_teid); +ogs_gtp_node_t *ogs_gtp_node_add_by_ip(ogs_list_t *list, ogs_ip_t *ip, + uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4); +ogs_gtp_node_t *ogs_gtp_node_find_by_ip(ogs_list_t *list, ogs_ip_t *ip); + #ifdef __cplusplus } #endif diff --git a/lib/gtp/path.c b/lib/gtp/path.c index ee40958dc..6063cc182 100644 --- a/lib/gtp/path.c +++ b/lib/gtp/path.c @@ -59,7 +59,7 @@ int ogs_gtp_connect(ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_gtp_node_t *gnode) OGS_ADDR(addr, buf), OGS_PORT(addr)); gnode->sock = sock; - memcpy(&gnode->remote_addr, addr, sizeof gnode->remote_addr); + memcpy(&gnode->addr, addr, sizeof gnode->addr); break; } @@ -105,7 +105,7 @@ int ogs_gtp_sendto(ogs_gtp_node_t *gnode, ogs_pkbuf_t *pkbuf) ogs_assert(pkbuf); sock = gnode->sock; ogs_assert(sock); - addr = &gnode->remote_addr; + addr = &gnode->addr; ogs_assert(addr); sent = ogs_sendto(sock->fd, pkbuf->data, pkbuf->len, 0, addr); @@ -148,7 +148,7 @@ ogs_pkbuf_t *ogs_gtp_handle_echo_req(ogs_pkbuf_t *pkb) gtph_resp->flags |= (1 << 4); /* set PT */ gtph_resp->type = OGS_GTPU_MSGTYPE_ECHO_RSP; length = 0; /* length of Recovery IE */ - gtph_resp->length = htons(length); /* to be overwriten */ + gtph_resp->length = htobe16(length); /* to be overwriten */ gtph_resp->teid = 0; idx = 8; @@ -182,7 +182,7 @@ ogs_pkbuf_t *ogs_gtp_handle_echo_req(ogs_pkbuf_t *pkb) *((uint8_t *)pkb_resp->data + idx) = 14; idx++; /* type */ *((uint8_t *)pkb_resp->data + idx) = 0; idx++; /* restart counter */ - gtph_resp->length = htons(length); + gtph_resp->length = htobe16(length); ogs_pkbuf_trim(pkb_resp, idx); /* buffer length */ return pkb_resp; diff --git a/lib/gtp/support/gtp-tlv.py b/lib/gtp/support/gtp-tlv.py index b74515642..0b741027e 100644 --- a/lib/gtp/support/gtp-tlv.py +++ b/lib/gtp/support/gtp-tlv.py @@ -410,8 +410,8 @@ typedef struct ogs_gtp_header_s { struct { uint32_t teid; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ -#define OGS_GTP_XID_TO_SQN(__xid) htonl(((__xid) << 8)) -#define OGS_GTP_SQN_TO_XID(__sqn) (ntohl(__sqn) >> 8) +#define OGS_GTP_XID_TO_SQN(__xid) htobe32(((__xid) << 8)) +#define OGS_GTP_SQN_TO_XID(__sqn) (be32toh(__sqn) >> 8) uint32_t sqn; }; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ @@ -625,7 +625,7 @@ f.write("""int ogs_gtp_parse_msg(ogs_gtp_message_t *gtp_message, ogs_pkbuf_t *pk memcpy(>p_message->h, pkbuf->data - size, size); if (h->teid_presence) - gtp_message->h.teid = ntohl(gtp_message->h.teid); + gtp_message->h.teid = be32toh(gtp_message->h.teid); if (pkbuf->len == 0) return OGS_OK; diff --git a/lib/gtp/xact.c b/lib/gtp/xact.c index caed7011a..79a4aa2ed 100644 --- a/lib/gtp/xact.c +++ b/lib/gtp/xact.c @@ -118,8 +118,8 @@ ogs_gtp_xact_t *ogs_gtp_xact_local_create(ogs_gtp_node_t *gnode, ogs_debug("[%d] %s Create peer [%s]:%d", xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&gnode->remote_addr, buf), - OGS_PORT(&gnode->remote_addr)); + OGS_ADDR(&gnode->addr, buf), + OGS_PORT(&gnode->addr)); return xact; } @@ -154,8 +154,8 @@ ogs_gtp_xact_t *ogs_gtp_xact_remote_create(ogs_gtp_node_t *gnode, uint32_t sqn) ogs_debug("[%d] %s Create peer [%s]:%d", xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&gnode->remote_addr, buf), - OGS_PORT(&gnode->remote_addr)); + OGS_ADDR(&gnode->addr, buf), + OGS_PORT(&gnode->addr)); return xact; } @@ -187,8 +187,8 @@ int ogs_gtp_xact_update_tx(ogs_gtp_xact_t *xact, xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", hdesc->type, - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); stage = ogs_gtp_xact_get_stage(hdesc->type, xact->xid); if (xact->org == OGS_GTP_LOCAL_ORIGINATOR) { @@ -288,8 +288,8 @@ int ogs_gtp_xact_update_rx(ogs_gtp_xact_t *xact, uint8_t type) xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", type, - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); stage = ogs_gtp_xact_get_stage(type, xact->xid); if (xact->org == OGS_GTP_LOCAL_ORIGINATOR) { @@ -320,9 +320,9 @@ int ogs_gtp_xact_update_rx(ogs_gtp_xact_t *xact, uint8_t type) xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->gnode->remote_addr, + OGS_ADDR(&xact->gnode->addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_PORT(&xact->gnode->addr)); rv = ogs_gtp_sendto(xact->gnode, pkbuf); ogs_expect(rv == OGS_OK); } else { @@ -332,9 +332,9 @@ int ogs_gtp_xact_update_rx(ogs_gtp_xact_t *xact, uint8_t type) xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->gnode->remote_addr, + OGS_ADDR(&xact->gnode->addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_PORT(&xact->gnode->addr)); } return OGS_RETRY; @@ -385,9 +385,9 @@ int ogs_gtp_xact_update_rx(ogs_gtp_xact_t *xact, uint8_t type) xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->gnode->remote_addr, + OGS_ADDR(&xact->gnode->addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_PORT(&xact->gnode->addr)); rv = ogs_gtp_sendto(xact->gnode, pkbuf); ogs_expect(rv == OGS_OK); } else { @@ -397,9 +397,9 @@ int ogs_gtp_xact_update_rx(ogs_gtp_xact_t *xact, uint8_t type) xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->gnode->remote_addr, + OGS_ADDR(&xact->gnode->addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_PORT(&xact->gnode->addr)); } return OGS_RETRY; @@ -465,8 +465,8 @@ int ogs_gtp_xact_commit(ogs_gtp_xact_t *xact) ogs_debug("[%d] %s Commit peer [%s]:%d", xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); type = xact->seq[xact->step-1].type; stage = ogs_gtp_xact_get_stage(type, xact->xid); @@ -573,8 +573,8 @@ static void response_timeout(void *data) xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); if (--xact->response_rcount > 0) { ogs_pkbuf_t *pkbuf = NULL; @@ -595,8 +595,8 @@ static void response_timeout(void *data) xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); if (xact->cb) xact->cb(xact, xact->data); @@ -623,8 +623,8 @@ static void holding_timeout(void *data) xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); if (--xact->holding_rcount > 0) { if (xact->tm_holding) @@ -635,8 +635,8 @@ static void holding_timeout(void *data) xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); ogs_gtp_xact_delete(xact); } } @@ -664,8 +664,8 @@ int ogs_gtp_xact_receive( ogs_debug("[%d] %s Receive peer [%s]:%d", new->xid, new->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&gnode->remote_addr, buf), - OGS_PORT(&gnode->remote_addr)); + OGS_ADDR(&gnode->addr, buf), + OGS_PORT(&gnode->addr)); rv = ogs_gtp_xact_update_rx(new, h->type); if (rv == OGS_ERROR) { @@ -778,8 +778,8 @@ ogs_gtp_xact_t *ogs_gtp_xact_find_by_xid( ogs_debug("[%d] %s Find peer [%s]:%d", xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&gnode->remote_addr, buf), - OGS_PORT(&gnode->remote_addr)); + OGS_ADDR(&gnode->addr, buf), + OGS_PORT(&gnode->addr)); break; } } @@ -821,8 +821,8 @@ static int ogs_gtp_xact_delete(ogs_gtp_xact_t *xact) ogs_debug("[%d] %s Delete peer [%s]:%d", xact->xid, xact->org == OGS_GTP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&xact->gnode->remote_addr, buf), - OGS_PORT(&xact->gnode->remote_addr)); + OGS_ADDR(&xact->gnode->addr, buf), + OGS_PORT(&xact->gnode->addr)); if (xact->seq[0].pkbuf) ogs_pkbuf_free(xact->seq[0].pkbuf); diff --git a/src/pgw/ipfw/dummynet.c b/lib/ipfw/dummynet.c similarity index 100% rename from src/pgw/ipfw/dummynet.c rename to lib/ipfw/dummynet.c diff --git a/src/pgw/ipfw/expand_number.c b/lib/ipfw/expand_number.c similarity index 100% rename from src/pgw/ipfw/expand_number.c rename to lib/ipfw/expand_number.c diff --git a/src/pgw/ipfw/glue.c b/lib/ipfw/glue.c similarity index 100% rename from src/pgw/ipfw/glue.c rename to lib/ipfw/glue.c diff --git a/src/pgw/ipfw/glue.h b/lib/ipfw/glue.h similarity index 100% rename from src/pgw/ipfw/glue.h rename to lib/ipfw/glue.h diff --git a/src/pgw/ipfw/humanize_number.c b/lib/ipfw/humanize_number.c similarity index 100% rename from src/pgw/ipfw/humanize_number.c rename to lib/ipfw/humanize_number.c diff --git a/src/pgw/ipfw/ipfw2.c b/lib/ipfw/ipfw2.c similarity index 100% rename from src/pgw/ipfw/ipfw2.c rename to lib/ipfw/ipfw2.c diff --git a/src/pgw/ipfw/ipfw2.h b/lib/ipfw/ipfw2.h similarity index 100% rename from src/pgw/ipfw/ipfw2.h rename to lib/ipfw/ipfw2.h diff --git a/src/pgw/ipfw/ipv6.c b/lib/ipfw/ipv6.c similarity index 100% rename from src/pgw/ipfw/ipv6.c rename to lib/ipfw/ipv6.c diff --git a/src/pgw/ipfw/meson.build b/lib/ipfw/meson.build similarity index 87% rename from src/pgw/ipfw/meson.build rename to lib/ipfw/meson.build index fe029a445..9a35c2e04 100644 --- a/src/pgw/ipfw/meson.build +++ b/lib/ipfw/meson.build @@ -40,9 +40,12 @@ libipfw_sources = files(''' expand_number.c humanize_number.c glue.c + + ogs-ipfw.h + ogs-ipfw.c '''.split()) -ipfwinc = include_directories('objs/include_e') +libipfw_inc = include_directories('objs/include_e') ipfw_cc_flags = ['-D_DEFAULT_SOURCE', '-D_BSD_SOURCE', '-DUSERSPACE', '-D__BSD_VISIBLE', '-DNEED_STRTONUM', '-DNEED_ROUNDUP2' ] @@ -70,8 +73,13 @@ if cc.get_id() == 'gcc' or cc.get_id() == 'clang' ]) endif -libipfw = static_library('ipfw', - sources : [libipfw_sources], +libipfw = library('ogsipfw', + sources : libipfw_sources, + version : libogslib_version, c_args : ['-include', 'glue.h', ipfw_cc_flags], - include_directories : [ipfwinc], - install : false) + include_directories : libipfw_inc, + install : true) + +libipfw_dep = declare_dependency( + link_with : libipfw, + include_directories : libinc) diff --git a/src/pgw/ipfw/missing.h b/lib/ipfw/missing.h similarity index 100% rename from src/pgw/ipfw/missing.h rename to lib/ipfw/missing.h diff --git a/src/pgw/ipfw/objs/include_e/libutil.h b/lib/ipfw/objs/include_e/libutil.h similarity index 100% rename from src/pgw/ipfw/objs/include_e/libutil.h rename to lib/ipfw/objs/include_e/libutil.h diff --git a/src/pgw/ipfw/objs/include_e/net/if_var.h b/lib/ipfw/objs/include_e/net/if_var.h similarity index 100% rename from src/pgw/ipfw/objs/include_e/net/if_var.h rename to lib/ipfw/objs/include_e/net/if_var.h diff --git a/src/pgw/ipfw/objs/include_e/netinet/ip_dummynet.h b/lib/ipfw/objs/include_e/netinet/ip_dummynet.h similarity index 100% rename from src/pgw/ipfw/objs/include_e/netinet/ip_dummynet.h rename to lib/ipfw/objs/include_e/netinet/ip_dummynet.h diff --git a/src/pgw/ipfw/objs/include_e/netinet/ip_fw.h b/lib/ipfw/objs/include_e/netinet/ip_fw.h similarity index 100% rename from src/pgw/ipfw/objs/include_e/netinet/ip_fw.h rename to lib/ipfw/objs/include_e/netinet/ip_fw.h diff --git a/src/pgw/ipfw/objs/include_e/sys/sockio.h b/lib/ipfw/objs/include_e/sys/sockio.h similarity index 100% rename from src/pgw/ipfw/objs/include_e/sys/sockio.h rename to lib/ipfw/objs/include_e/sys/sockio.h diff --git a/src/pgw/ipfw/objs/include_e/timeconv.h b/lib/ipfw/objs/include_e/timeconv.h similarity index 100% rename from src/pgw/ipfw/objs/include_e/timeconv.h rename to lib/ipfw/objs/include_e/timeconv.h diff --git a/lib/ipfw/ogs-ipfw.c b/lib/ipfw/ogs-ipfw.c new file mode 100644 index 000000000..bde585b50 --- /dev/null +++ b/lib/ipfw/ogs-ipfw.c @@ -0,0 +1,176 @@ +/* + * 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 IF_NAMESIZE +#define IF_NAMESIZE 16 +#ifndef IFNAMSIZ +#define IFNAMSIZ IF_NAMESIZE +#endif +#endif + +#ifndef OGS_ERROR +#define OGS_ERROR -1 +#endif + +#ifndef OGS_OK +#define OGS_OK 0 +#endif + +#ifndef OGS_IPV6_LEN +#define OGS_IPV6_LEN 16 +#endif + +#include "ipfw2.h" +#include "objs/include_e/netinet/ip_fw.h" + +#include "ogs-ipfw.h" + +#define MAX_NUM_OF_TOKEN 32 +#define MAX_NUM_OF_RULE_BUFFER 1024 + +void compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, void *tstate); + +int ogs_ipfw_compile_rule(ogs_ipfw_rule_t *ipfw_rule, char *description) +{ + ogs_ipfw_rule_t zero_rule; + char *token, *dir; + char *saveptr; + int i = 2; + + char *av[MAX_NUM_OF_TOKEN]; + uint32_t rulebuf[MAX_NUM_OF_RULE_BUFFER]; + int rbufsize; + struct ip_fw_rule *rule = (struct ip_fw_rule *)rulebuf; + + int l; + ipfw_insn *cmd; + + if (!ipfw_rule) { + fprintf(stderr, "ipfw_rule is NULL\n"); + return OGS_ERROR; + } + + rbufsize = sizeof(rulebuf); + memset(rulebuf, 0, rbufsize); + + av[0] = NULL; + + /* ACTION */ + if (!description) { /* FIXME : OLD gcc generates uninitialized warning */ + fprintf(stderr, "description is NULL\n"); + return OGS_ERROR; + } + token = strtok_r(description, " ", &saveptr); + if (strcmp(token, "permit") != 0) { + fprintf(stderr, "Not begins with reserved keyword : 'permit'"); + return OGS_ERROR; + } + av[1] = token; + + /* Save DIRECTION */ + dir = token = strtok_r(NULL, " ", &saveptr); + if (strcmp(token, "out") != 0) { + fprintf(stderr, "Not begins with reserved keyword : 'permit out'"); + return OGS_ERROR; + } + + /* ADDR */ + token = strtok_r(NULL, " ", &saveptr); + while (token != NULL) { + av[i++] = token; + token = strtok_r(NULL, " ", &saveptr); + } + + /* Add DIRECTION */ + av[i++] = dir; + + av[i] = NULL; + + compile_rule(av, (uint32_t *)rule, &rbufsize, NULL); + + memset(ipfw_rule, 0, sizeof(ogs_ipfw_rule_t)); + for (l = rule->act_ofs, cmd = rule->cmd; + l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { + uint32_t *a = NULL; + uint16_t *p = NULL; + switch (cmd->opcode) { + case O_PROTO: + ipfw_rule->proto = cmd->arg1; + break; + case O_IP_SRC: + case O_IP_SRC_MASK: + a = ((ipfw_insn_u32 *)cmd)->d; + ipfw_rule->ipv4_local = 1; + ipfw_rule->ip.local.addr[0] = a[0]; + if (cmd->opcode == O_IP_SRC_MASK) + ipfw_rule->ip.local.mask[0] = a[1]; + else + ipfw_rule->ip.local.mask[0] = 0xffffffff; + break; + case O_IP_DST: + case O_IP_DST_MASK: + a = ((ipfw_insn_u32 *)cmd)->d; + ipfw_rule->ipv4_remote = 1; + ipfw_rule->ip.remote.addr[0] = a[0]; + if (cmd->opcode == O_IP_DST_MASK) + ipfw_rule->ip.remote.mask[0] = a[1]; + else + ipfw_rule->ip.remote.mask[0] = 0xffffffff; + break; + case O_IP6_SRC: + case O_IP6_SRC_MASK: + a = ((ipfw_insn_u32 *)cmd)->d; + ipfw_rule->ipv6_local = 1; + memcpy(ipfw_rule->ip.local.addr, a, OGS_IPV6_LEN); + if (cmd->opcode == O_IP6_SRC_MASK) + memcpy(ipfw_rule->ip.local.mask, a+4, OGS_IPV6_LEN); + else + n2mask((struct in6_addr *)ipfw_rule->ip.local.mask, 128); + break; + case O_IP6_DST: + case O_IP6_DST_MASK: + a = ((ipfw_insn_u32 *)cmd)->d; + ipfw_rule->ipv6_remote = 1; + memcpy(ipfw_rule->ip.remote.addr, a, OGS_IPV6_LEN); + if (cmd->opcode == O_IP6_DST_MASK) + memcpy(ipfw_rule->ip.remote.mask, a+4, OGS_IPV6_LEN); + else + n2mask((struct in6_addr *)ipfw_rule->ip.remote.mask, 128); + break; + case O_IP_SRCPORT: + p = ((ipfw_insn_u16 *)cmd)->ports; + ipfw_rule->port.local.low = p[0]; + ipfw_rule->port.local.high = p[1]; + break; + case O_IP_DSTPORT: + p = ((ipfw_insn_u16 *)cmd)->ports; + ipfw_rule->port.remote.low = p[0]; + ipfw_rule->port.remote.high = p[1]; + break; + } + } + + memset(&zero_rule, 0, sizeof(ogs_ipfw_rule_t)); + if (memcmp(ipfw_rule, &zero_rule, sizeof(ogs_ipfw_rule_t)) == 0) { + fprintf(stderr, "Cannot find Flow-Description"); + return OGS_ERROR; + } + + return OGS_OK; +} diff --git a/lib/ipfw/ogs-ipfw.h b/lib/ipfw/ogs-ipfw.h new file mode 100644 index 000000000..ce75b783b --- /dev/null +++ b/lib/ipfw/ogs-ipfw.h @@ -0,0 +1,68 @@ +/* + * 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_IPFW_H +#define OGS_IPFW_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ogs_ipfw_rule_s { + uint8_t proto; + + uint8_t ipv4_local; + uint8_t ipv4_remote; + uint8_t ipv6_local; + uint8_t ipv6_remote; + + struct { + struct { + uint32_t addr[4]; + uint32_t mask[4]; + } local; + struct { + uint32_t addr[4]; + uint32_t mask[4]; + } remote; + } ip; + struct { + struct { + uint16_t low; + uint16_t high; + } local; + struct { + uint16_t low; + uint16_t high; + } remote; + } port; + + uint16_t tos_traffic_class; + uint32_t security_parameter_index; + uint32_t flow_label; /* 24bit */ + uint32_t sdf_filter_id; +} ogs_ipfw_rule_t; + +int ogs_ipfw_compile_rule(ogs_ipfw_rule_t *ipfw_rule, char *description); + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_IPFW_H */ diff --git a/src/pgw/ipfw/tables.c b/lib/ipfw/tables.c similarity index 100% rename from src/pgw/ipfw/tables.c rename to lib/ipfw/tables.c diff --git a/lib/meson.build b/lib/meson.build index 7db709954..8a3b7b363 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -17,6 +17,7 @@ libinc = include_directories('.') +subdir('ipfw') subdir('core') subdir('crypt') subdir('sctp') diff --git a/lib/nas/ies.c b/lib/nas/ies.c index d6c581139..ead71f529 100644 --- a/lib/nas/ies.c +++ b/lib/nas/ies.c @@ -179,7 +179,7 @@ int ogs_nas_decode_location_area_identification(ogs_nas_location_area_identifica ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(location_area_identification, pkbuf->data - size, size); - location_area_identification->lac = ntohs(location_area_identification->lac); + location_area_identification->lac = be16toh(location_area_identification->lac); ogs_trace(" LOCATION_AREA_IDENTIFICATION - "); ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size); @@ -193,7 +193,7 @@ int ogs_nas_encode_location_area_identification(ogs_pkbuf_t *pkbuf, ogs_nas_loca ogs_nas_location_area_identification_t target; memcpy(&target, location_area_identification, size); - target.lac = htons(location_area_identification->lac); + target.lac = htobe16(location_area_identification->lac); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(pkbuf->data - size, &target, size); @@ -219,7 +219,7 @@ int ogs_nas_decode_mobile_identity(ogs_nas_mobile_identity_t *mobile_identity, o if (mobile_identity->tmsi.type == OGS_NAS_MOBILE_IDENTITY_TMSI) { - mobile_identity->tmsi.tmsi = ntohl(mobile_identity->tmsi.tmsi); + mobile_identity->tmsi.tmsi = be32toh(mobile_identity->tmsi.tmsi); } ogs_trace(" MOBILE_IDENTITY - "); @@ -236,7 +236,7 @@ int ogs_nas_encode_mobile_identity(ogs_pkbuf_t *pkbuf, ogs_nas_mobile_identity_t memcpy(&target, mobile_identity, sizeof(ogs_nas_mobile_identity_t)); if (mobile_identity->tmsi.type == OGS_NAS_MOBILE_IDENTITY_TMSI) { - target.tmsi.tmsi = htonl(mobile_identity->tmsi.tmsi); + target.tmsi.tmsi = htobe32(mobile_identity->tmsi.tmsi); target.tmsi.spare = 0xf; } @@ -510,8 +510,8 @@ int ogs_nas_decode_eps_mobile_identity(ogs_nas_eps_mobile_identity_t *eps_mobile if (eps_mobile_identity->guti.type == OGS_NAS_EPS_MOBILE_IDENTITY_GUTI) { - eps_mobile_identity->guti.mme_gid = ntohs(eps_mobile_identity->guti.mme_gid); - eps_mobile_identity->guti.m_tmsi = ntohl(eps_mobile_identity->guti.m_tmsi); + eps_mobile_identity->guti.mme_gid = be16toh(eps_mobile_identity->guti.mme_gid); + eps_mobile_identity->guti.m_tmsi = be32toh(eps_mobile_identity->guti.m_tmsi); } ogs_trace(" EPS_MOBILE_IDENTITY - "); @@ -529,8 +529,8 @@ int ogs_nas_encode_eps_mobile_identity(ogs_pkbuf_t *pkbuf, ogs_nas_eps_mobile_id if (target.guti.type == OGS_NAS_EPS_MOBILE_IDENTITY_GUTI) { target.guti.spare = 0xf; - target.guti.mme_gid = htons(eps_mobile_identity->guti.mme_gid); - target.guti.m_tmsi = htonl(eps_mobile_identity->guti.m_tmsi); + target.guti.mme_gid = htobe16(eps_mobile_identity->guti.mme_gid); + target.guti.m_tmsi = htobe32(eps_mobile_identity->guti.m_tmsi); } ogs_assert(ogs_pkbuf_pull(pkbuf, size)); @@ -643,7 +643,7 @@ int ogs_nas_decode_esm_message_container(ogs_nas_esm_message_container_t *esm_me uint16_t size = 0; ogs_nas_esm_message_container_t *source = (ogs_nas_esm_message_container_t *)pkbuf->data; - esm_message_container->length = ntohs(source->length); + esm_message_container->length = be16toh(source->length); size = esm_message_container->length + sizeof(esm_message_container->length); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); @@ -665,7 +665,7 @@ int ogs_nas_encode_esm_message_container(ogs_pkbuf_t *pkbuf, ogs_nas_esm_message size = sizeof(esm_message_container->length); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); - target = htons(esm_message_container->length); + target = htobe16(esm_message_container->length); memcpy(pkbuf->data - size, &target, size); size = esm_message_container->length; @@ -1120,7 +1120,7 @@ int ogs_nas_decode_nonce(ogs_nas_nonce_t *nonce, ogs_pkbuf_t *pkbuf) ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(nonce, pkbuf->data - size, size); - *nonce = ntohl(*nonce); + *nonce = be32toh(*nonce); ogs_trace(" NONCE - "); ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size); @@ -1134,7 +1134,7 @@ int ogs_nas_encode_nonce(ogs_pkbuf_t *pkbuf, ogs_nas_nonce_t *nonce) ogs_nas_nonce_t target; memcpy(&target, nonce, size); - target = htonl(*nonce); + target = htobe32(*nonce); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(pkbuf->data - size, &target, size); @@ -1184,7 +1184,7 @@ int ogs_nas_decode_p_tmsi_signature(ogs_nas_p_tmsi_signature_t *p_tmsi_signature ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(p_tmsi_signature, pkbuf->data - size, size); - *p_tmsi_signature = htonl(*p_tmsi_signature); + *p_tmsi_signature = htobe32(*p_tmsi_signature); ogs_trace(" P_TMSI_SIGNATURE - "); ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size); @@ -1198,7 +1198,7 @@ int ogs_nas_encode_p_tmsi_signature(ogs_pkbuf_t *pkbuf, ogs_nas_p_tmsi_signature ogs_nas_p_tmsi_signature_t target; memcpy(&target, p_tmsi_signature, size); - *p_tmsi_signature = ntohl(*p_tmsi_signature); + *p_tmsi_signature = be32toh(*p_tmsi_signature); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(pkbuf->data - size, &target, size); @@ -1273,7 +1273,7 @@ int ogs_nas_decode_short_mac(ogs_nas_short_mac_t *short_mac, ogs_pkbuf_t *pkbuf) ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(short_mac, pkbuf->data - size, size); - *short_mac = ntohs(*short_mac); + *short_mac = be16toh(*short_mac); ogs_trace(" SHORT_MAC - "); ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size); @@ -1287,7 +1287,7 @@ int ogs_nas_encode_short_mac(ogs_pkbuf_t *pkbuf, ogs_nas_short_mac_t *short_mac) ogs_nas_short_mac_t target; memcpy(&target, short_mac, size); - target = htons(*short_mac); + target = htobe16(*short_mac); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(pkbuf->data - size, &target, size); @@ -1422,7 +1422,7 @@ int ogs_nas_decode_tracking_area_identity(ogs_nas_tracking_area_identity_t *trac ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(tracking_area_identity, pkbuf->data - size, size); - tracking_area_identity->tac = ntohs(tracking_area_identity->tac); + tracking_area_identity->tac = be16toh(tracking_area_identity->tac); ogs_trace(" TRACKING_AREA_IDENTITY - "); ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size); @@ -1436,7 +1436,7 @@ int ogs_nas_encode_tracking_area_identity(ogs_pkbuf_t *pkbuf, ogs_nas_tracking_a ogs_nas_tracking_area_identity_t target; memcpy(&target, tracking_area_identity, size); - target.tac = htons(tracking_area_identity->tac); + target.tac = htobe16(tracking_area_identity->tac); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(pkbuf->data - size, &target, size); @@ -1807,7 +1807,7 @@ int ogs_nas_decode_generic_message_container(ogs_nas_generic_message_container_t uint16_t size = 0; ogs_nas_generic_message_container_t *source = (ogs_nas_generic_message_container_t *)pkbuf->data; - generic_message_container->length = ntohs(source->length); + generic_message_container->length = be16toh(source->length); size = generic_message_container->length + sizeof(generic_message_container->length); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); @@ -1829,7 +1829,7 @@ int ogs_nas_encode_generic_message_container(ogs_pkbuf_t *pkbuf, ogs_nas_generic size = sizeof(generic_message_container->length); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); - target = htons(generic_message_container->length); + target = htobe16(generic_message_container->length); memcpy(pkbuf->data - size, &target, size); size = generic_message_container->length; @@ -2517,7 +2517,7 @@ int ogs_nas_decode_header_compression_configuration(ogs_nas_header_compression_c ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(header_compression_configuration, pkbuf->data - size, size); - header_compression_configuration->max_cid = ntohs(header_compression_configuration->max_cid); + header_compression_configuration->max_cid = be16toh(header_compression_configuration->max_cid); ogs_trace(" HEADER_COMPRESSION_CONFIGURATION - "); ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size); @@ -2531,7 +2531,7 @@ int ogs_nas_encode_header_compression_configuration(ogs_pkbuf_t *pkbuf, ogs_nas_ ogs_nas_header_compression_configuration_t target; memcpy(&target, header_compression_configuration, sizeof(ogs_nas_header_compression_configuration_t)); - target.max_cid = htons(header_compression_configuration->max_cid); + target.max_cid = htobe16(header_compression_configuration->max_cid); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(pkbuf->data - size, &target, size); @@ -2574,7 +2574,7 @@ int ogs_nas_decode_extended_protocol_configuration_options(ogs_nas_extended_prot uint16_t size = 0; ogs_nas_extended_protocol_configuration_options_t *source = (ogs_nas_extended_protocol_configuration_options_t *)pkbuf->data; - extended_protocol_configuration_options->length = ntohs(source->length); + extended_protocol_configuration_options->length = be16toh(source->length); size = extended_protocol_configuration_options->length + sizeof(extended_protocol_configuration_options->length); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); @@ -2596,7 +2596,7 @@ int ogs_nas_encode_extended_protocol_configuration_options(ogs_pkbuf_t *pkbuf, o size = sizeof(extended_protocol_configuration_options->length); ogs_assert(ogs_pkbuf_pull(pkbuf, size)); - target = htons(extended_protocol_configuration_options->length); + target = htobe16(extended_protocol_configuration_options->length); memcpy(pkbuf->data - size, &target, size); size = extended_protocol_configuration_options->length; diff --git a/lib/nas/support/nas-message.py b/lib/nas/support/nas-message.py index 3794f2f56..d9a0b9df5 100644 --- a/lib/nas/support/nas-message.py +++ b/lib/nas/support/nas-message.py @@ -451,7 +451,7 @@ for (k, v) in sorted_type_list: f.write("{\n") f.write(" uint16_t size = 0;\n") f.write(" ogs_nas_%s_t *source = (ogs_nas_%s_t *)pkbuf->data;\n\n" % (v_lower(k), v_lower(k))) - f.write(" %s->length = ntohs(source->length);\n" % v_lower(k)) + f.write(" %s->length = be16toh(source->length);\n" % v_lower(k)) f.write(" size = %s->length + sizeof(%s->length);\n\n" % (v_lower(k), v_lower(k))) f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n") f.write(" %s->buffer = pkbuf->data - size + sizeof(%s->length);\n\n" % (v_lower(k), v_lower(k))) @@ -467,7 +467,7 @@ for (k, v) in sorted_type_list: f.write(" ogs_assert(%s->buffer);\n\n" % v_lower(k)) f.write(" size = sizeof(%s->length);\n" % v_lower(k)) f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n") - f.write(" target = htons(%s->length);\n" % v_lower(k)) + f.write(" target = htobe16(%s->length);\n" % v_lower(k)) f.write(" memcpy(pkbuf->data - size, &target, size);\n\n") f.write(" size = %s->length;\n" % v_lower(k)) f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n") diff --git a/lib/nas/support/type-list.py b/lib/nas/support/type-list.py index 37fecfe03..1f699538f 100644 --- a/lib/nas/support/type-list.py +++ b/lib/nas/support/type-list.py @@ -17,60 +17,60 @@ # along with this program. If not, see . type_list["P-TMSI signature"]["decode"] = \ -" *p_tmsi_signature = htonl(*p_tmsi_signature);\n\n" +" *p_tmsi_signature = htobe32(*p_tmsi_signature);\n\n" type_list["P-TMSI signature"]["encode"] = \ -" *p_tmsi_signature = ntohl(*p_tmsi_signature);\n\n" +" *p_tmsi_signature = be32toh(*p_tmsi_signature);\n\n" type_list["Location area identification"]["decode"] = \ -" location_area_identification->lac = ntohs(location_area_identification->lac);\n\n" +" location_area_identification->lac = be16toh(location_area_identification->lac);\n\n" type_list["Location area identification"]["encode"] = \ -" target.lac = htons(location_area_identification->lac);\n\n" +" target.lac = htobe16(location_area_identification->lac);\n\n" type_list["Tracking area identity"]["decode"] = \ -" tracking_area_identity->tac = ntohs(tracking_area_identity->tac);\n\n" +" tracking_area_identity->tac = be16toh(tracking_area_identity->tac);\n\n" type_list["Tracking area identity"]["encode"] = \ -" target.tac = htons(tracking_area_identity->tac);\n\n" +" target.tac = htobe16(tracking_area_identity->tac);\n\n" type_list["Mobile identity"]["decode"] = \ " if (mobile_identity->tmsi.type == OGS_NAS_MOBILE_IDENTITY_TMSI)\n" \ " {\n" \ -" mobile_identity->tmsi.tmsi = ntohl(mobile_identity->tmsi.tmsi);\n" \ +" mobile_identity->tmsi.tmsi = be32toh(mobile_identity->tmsi.tmsi);\n" \ " }\n\n" type_list["Mobile identity"]["encode"] = \ " if (mobile_identity->tmsi.type == OGS_NAS_MOBILE_IDENTITY_TMSI)\n" \ " {\n" \ -" target.tmsi.tmsi = htonl(mobile_identity->tmsi.tmsi);\n" \ +" target.tmsi.tmsi = htobe32(mobile_identity->tmsi.tmsi);\n" \ " target.tmsi.spare = 0xf;\n" \ " }\n\n" type_list["EPS mobile identity"]["decode"] = \ " if (eps_mobile_identity->guti.type == OGS_NAS_EPS_MOBILE_IDENTITY_GUTI)\n" \ " {\n" \ -" eps_mobile_identity->guti.mme_gid = ntohs(eps_mobile_identity->guti.mme_gid);\n" \ -" eps_mobile_identity->guti.m_tmsi = ntohl(eps_mobile_identity->guti.m_tmsi);\n" \ +" eps_mobile_identity->guti.mme_gid = be16toh(eps_mobile_identity->guti.mme_gid);\n" \ +" eps_mobile_identity->guti.m_tmsi = be32toh(eps_mobile_identity->guti.m_tmsi);\n" \ " }\n\n" type_list["EPS mobile identity"]["encode"] = \ " if (target.guti.type == OGS_NAS_EPS_MOBILE_IDENTITY_GUTI)\n" \ " {\n" \ " target.guti.spare = 0xf;\n" \ -" target.guti.mme_gid = htons(eps_mobile_identity->guti.mme_gid);\n" \ -" target.guti.m_tmsi = htonl(eps_mobile_identity->guti.m_tmsi);\n" \ +" target.guti.mme_gid = htobe16(eps_mobile_identity->guti.mme_gid);\n" \ +" target.guti.m_tmsi = htobe32(eps_mobile_identity->guti.m_tmsi);\n" \ " }\n\n" type_list["Nonce"]["decode"] = \ -" *nonce = ntohl(*nonce);\n\n" +" *nonce = be32toh(*nonce);\n\n" type_list["Nonce"]["encode"] = \ -" target = htonl(*nonce);\n\n" +" target = htobe32(*nonce);\n\n" type_list["Header compression configuration"]["decode"] = \ -" header_compression_configuration->max_cid = ntohs(header_compression_configuration->max_cid);\n\n" +" header_compression_configuration->max_cid = be16toh(header_compression_configuration->max_cid);\n\n" type_list["Header compression configuration"]["encode"] = \ -" target.max_cid = htons(header_compression_configuration->max_cid);\n\n" +" target.max_cid = htobe16(header_compression_configuration->max_cid);\n\n" type_list["Short MAC"]["decode"] = \ -" *short_mac = ntohs(*short_mac);\n\n" +" *short_mac = be16toh(*short_mac);\n\n" type_list["Short MAC"]["encode"] = \ -" target = htons(*short_mac);\n\n" +" target = htobe16(*short_mac);\n\n" type_list["Access point name"]["decode"] = \ " {\n" \ diff --git a/lib/nas/types.c b/lib/nas/types.c index 758f47f35..16b54455b 100644 --- a/lib/nas/types.c +++ b/lib/nas/types.c @@ -24,8 +24,7 @@ int __ogs_nas_domain; void *ogs_nas_from_plmn_id(ogs_nas_plmn_id_t *ogs_nas_plmn_id, ogs_plmn_id_t *plmn_id) { memcpy(ogs_nas_plmn_id, plmn_id, OGS_PLMN_ID_LEN); - if (plmn_id->mnc1 != 0xf) - { + if (plmn_id->mnc1 != 0xf) { ogs_nas_plmn_id->mnc1 = plmn_id->mnc1; ogs_nas_plmn_id->mnc2 = plmn_id->mnc2; ogs_nas_plmn_id->mnc3 = plmn_id->mnc3; @@ -35,8 +34,7 @@ void *ogs_nas_from_plmn_id(ogs_nas_plmn_id_t *ogs_nas_plmn_id, ogs_plmn_id_t *pl void *ogs_nas_to_plmn_id(ogs_plmn_id_t *plmn_id, ogs_nas_plmn_id_t *ogs_nas_plmn_id) { memcpy(plmn_id, ogs_nas_plmn_id, OGS_PLMN_ID_LEN); - if (plmn_id->mnc1 != 0xf) - { + if (plmn_id->mnc1 != 0xf) { plmn_id->mnc1 = ogs_nas_plmn_id->mnc1; plmn_id->mnc2 = ogs_nas_plmn_id->mnc2; plmn_id->mnc3 = ogs_nas_plmn_id->mnc3; @@ -448,8 +446,7 @@ void ogs_nas_tai_list_build( memset(&target0, 0, sizeof(tai0_list_t)); memset(&target2, 0, sizeof(tai2_list_t)); - for (i = 0; source0->tai[i].num; i++) - { + for (i = 0; source0->tai[i].num; i++) { ogs_assert(source0->tai[i].type == TAI0_TYPE); target0.tai[i].type = source0->tai[i].type; @@ -460,14 +457,12 @@ void ogs_nas_tai_list_build( ogs_nas_from_plmn_id(&ogs_nas_plmn_id, &source0->tai[i].plmn_id), OGS_PLMN_ID_LEN); - for (j = 0; j < source0->tai[i].num; j++) - { - target0.tai[i].tac[j] = htons(source0->tai[i].tac[j]); + for (j = 0; j < source0->tai[i].num; j++) { + target0.tai[i].tac[j] = htobe16(source0->tai[i].tac[j]); } size = (1 + 3 + 2 * source0->tai[i].num); - if ((target->length + size) > OGS_NAS_MAX_TAI_LIST_LEN) - { + if ((target->length + size) > OGS_NAS_MAX_TAI_LIST_LEN) { ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)", target->length, size); return; @@ -476,8 +471,7 @@ void ogs_nas_tai_list_build( target->length += size; } - if (source2->num) - { + if (source2->num) { memset(&target2, 0, sizeof(target2)); ogs_assert(source2->type == TAI1_TYPE || source2->type == TAI2_TYPE); @@ -488,18 +482,16 @@ void ogs_nas_tai_list_build( target2.num = source2->num - 1; size = (1 + (3 + 2) * source2->num); - if ((target->length + size) > OGS_NAS_MAX_TAI_LIST_LEN) - { + if ((target->length + size) > OGS_NAS_MAX_TAI_LIST_LEN) { ogs_warn("Overflow: Ignore remained TAI LIST(length:%d, size:%d)", target->length, size); return; } - for (i = 0; i < source2->num; i++) - { + for (i = 0; i < source2->num; i++) { memcpy(&target2.tai[i].plmn_id, ogs_nas_from_plmn_id(&ogs_nas_plmn_id, &source2->tai[i].plmn_id), OGS_PLMN_ID_LEN); - target2.tai[i].tac = htons(source2->tai[i].tac); + target2.tai[i].tac = htobe16(source2->tai[i].tac); } memcpy(target->buffer + target->length, &target2, size); target->length += size; diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c new file mode 100644 index 000000000..31103eee8 --- /dev/null +++ b/lib/pfcp/context.c @@ -0,0 +1,1371 @@ +/* + * 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 "app/ogs-app.h" +#include "ogs-pfcp.h" + +static ogs_pfcp_context_t self; + +static OGS_POOL(ogs_pfcp_node_pool, ogs_pfcp_node_t); +static OGS_POOL(ogs_pfcp_gtpu_resource_pool, ogs_pfcp_gtpu_resource_t); + +static OGS_POOL(ogs_pfcp_sess_pool, ogs_pfcp_sess_t); +static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t); +static OGS_POOL(ogs_pfcp_far_pool, ogs_pfcp_far_t); +static OGS_POOL(ogs_pfcp_urr_pool, ogs_pfcp_urr_t); +static OGS_POOL(ogs_pfcp_qer_pool, ogs_pfcp_qer_t); +static OGS_POOL(ogs_pfcp_bar_pool, ogs_pfcp_bar_t); + +static OGS_POOL(ogs_pfcp_dev_pool, ogs_pfcp_dev_t); +static OGS_POOL(ogs_pfcp_subnet_pool, ogs_pfcp_subnet_t); + +static int context_initiaized = 0; + +void ogs_pfcp_context_init(int num_of_gtpu_resource) +{ + struct timeval tv; + ogs_assert(context_initiaized == 0); + + /* Initialize SMF context */ + memset(&self, 0, sizeof(ogs_pfcp_context_t)); + + /* + * PFCP entity uses NTP timestamp(1900), but Open5GS uses UNIX(1970). + * + * One is the offset between the two epochs. + * Unix uses an epoch located at 1/1/1970-00:00h (UTC) and + * NTP uses 1/1/1900-00:00h. This leads to an offset equivalent + * to 70 years in seconds (there are 17 leap years + * between the two dates so the offset is + * + * (70*365 + 17)*86400 = 2208988800 + * + * to be substracted from NTP time to get Unix struct timeval. + */ + ogs_gettimeofday(&tv); + self.pfcp_started = tv.tv_sec + 2208988800; + + ogs_log_install_domain(&__ogs_pfcp_domain, "pfcp", ogs_core()->log.level); + + ogs_pool_init(&ogs_pfcp_node_pool, ogs_config()->pool.pfcp); + ogs_pool_init(&ogs_pfcp_gtpu_resource_pool, num_of_gtpu_resource); + + ogs_list_init(&self.n4_list); + + ogs_pool_init(&ogs_pfcp_sess_pool, ogs_config()->pool.sess); + + ogs_pool_init(&ogs_pfcp_pdr_pool, + ogs_config()->pool.sess * OGS_MAX_NUM_OF_PDR); + ogs_pool_init(&ogs_pfcp_far_pool, + ogs_config()->pool.sess * OGS_MAX_NUM_OF_FAR); + ogs_pool_init(&ogs_pfcp_urr_pool, + ogs_config()->pool.sess * OGS_MAX_NUM_OF_URR); + ogs_pool_init(&ogs_pfcp_qer_pool, + ogs_config()->pool.sess * OGS_MAX_NUM_OF_QER); + ogs_pool_init(&ogs_pfcp_bar_pool, + ogs_config()->pool.sess * OGS_MAX_NUM_OF_BAR); + + ogs_list_init(&self.dev_list); + ogs_pool_init(&ogs_pfcp_dev_pool, OGS_MAX_NUM_OF_DEV); + ogs_list_init(&self.subnet_list); + ogs_pool_init(&ogs_pfcp_subnet_pool, OGS_MAX_NUM_OF_SUBNET); + + self.pdr_hash = ogs_hash_make(); + + context_initiaized = 1; +} + +void ogs_pfcp_context_final(void) +{ + ogs_assert(context_initiaized == 1); + + ogs_assert(self.pdr_hash); + ogs_hash_destroy(self.pdr_hash); + + ogs_pfcp_dev_remove_all(); + ogs_pfcp_subnet_remove_all(); + + ogs_pool_final(&ogs_pfcp_dev_pool); + ogs_pool_final(&ogs_pfcp_subnet_pool); + + ogs_pool_final(&ogs_pfcp_sess_pool); + ogs_pool_final(&ogs_pfcp_pdr_pool); + ogs_pool_final(&ogs_pfcp_far_pool); + ogs_pool_final(&ogs_pfcp_urr_pool); + ogs_pool_final(&ogs_pfcp_qer_pool); + ogs_pool_final(&ogs_pfcp_bar_pool); + + ogs_pfcp_node_remove_all(&ogs_pfcp_self()->n4_list); + + ogs_pool_final(&ogs_pfcp_node_pool); + ogs_pool_final(&ogs_pfcp_gtpu_resource_pool); + + context_initiaized = 0; +} + +ogs_pfcp_context_t *ogs_pfcp_self(void) +{ + return &self; +} + +static int ogs_pfcp_context_prepare(void) +{ + self.pfcp_port = OGS_PFCP_UDP_PORT; + self.tun_ifname = "ogstun"; + + return OGS_OK; +} + +static int ogs_pfcp_context_validation(const char *local) +{ + if (ogs_list_first(&self.pfcp_list) == NULL && + ogs_list_first(&self.pfcp_list6) == NULL) { + ogs_error("No %s.pfcp: in '%s'", local, ogs_config()->file); + return OGS_ERROR; + } + if (ogs_list_first(&self.subnet_list) == NULL) { + ogs_error("No %s.pdn: in '%s'", local, ogs_config()->file); + return OGS_ERROR; + } + + return OGS_OK; +} + +int ogs_pfcp_context_parse_config(const char *local, const char *remote) +{ + int rv; + yaml_document_t *document = NULL; + ogs_yaml_iter_t root_iter; + + document = ogs_config()->document; + ogs_assert(document); + + rv = ogs_pfcp_context_prepare(); + if (rv != OGS_OK) return rv; + + ogs_yaml_iter_init(&root_iter, document); + while (ogs_yaml_iter_next(&root_iter)) { + const char *root_key = ogs_yaml_iter_key(&root_iter); + ogs_assert(root_key); + if (!strcmp(root_key, local)) { + ogs_yaml_iter_t local_iter; + ogs_yaml_iter_recurse(&root_iter, &local_iter); + while (ogs_yaml_iter_next(&local_iter)) { + const char *local_key = ogs_yaml_iter_key(&local_iter); + ogs_assert(local_key); + if (!strcmp(local_key, "pfcp")) { + ogs_yaml_iter_t pfcp_array, pfcp_iter; + ogs_yaml_iter_recurse(&local_iter, &pfcp_array); + do { + int family = AF_UNSPEC; + int i, num = 0; + const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; + uint16_t port = self.pfcp_port; + const char *dev = NULL; + ogs_sockaddr_t *addr = NULL; + + if (ogs_yaml_iter_type(&pfcp_array) == + YAML_MAPPING_NODE) { + memcpy(&pfcp_iter, &pfcp_array, + sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type(&pfcp_array) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&pfcp_array)) + break; + ogs_yaml_iter_recurse(&pfcp_array, &pfcp_iter); + } else if (ogs_yaml_iter_type(&pfcp_array) == + YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + while (ogs_yaml_iter_next(&pfcp_iter)) { + const char *pfcp_key = + ogs_yaml_iter_key(&pfcp_iter); + ogs_assert(pfcp_key); + if (!strcmp(pfcp_key, "family")) { + const char *v = ogs_yaml_iter_value(&pfcp_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(pfcp_key, "addr") || + !strcmp(pfcp_key, "name")) { + ogs_yaml_iter_t hostname_iter; + ogs_yaml_iter_recurse(&pfcp_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(pfcp_key, "port")) { + const char *v = ogs_yaml_iter_value(&pfcp_iter); + if (v) { + port = atoi(v); + self.pfcp_port = port; + } + } else if (!strcmp(pfcp_key, "dev")) { + dev = ogs_yaml_iter_value(&pfcp_iter); + } else if (!strcmp(pfcp_key, "apn")) { + /* Skip */ + } else + ogs_warn("unknown key `%s`", pfcp_key); + } + + addr = NULL; + for (i = 0; i < num; i++) { + rv = ogs_addaddrinfo(&addr, + family, hostname[i], port, 0); + ogs_assert(rv == OGS_OK); + } + + if (addr) { + if (ogs_config()->parameter.no_ipv4 == 0) + ogs_socknode_add( + &self.pfcp_list, AF_INET, addr); + if (ogs_config()->parameter.no_ipv6 == 0) + ogs_socknode_add( + &self.pfcp_list6, AF_INET6, addr); + ogs_freeaddrinfo(addr); + } + + if (dev) { + rv = ogs_socknode_probe( + ogs_config()->parameter.no_ipv4 ? + NULL : &self.pfcp_list, + ogs_config()->parameter.no_ipv6 ? + NULL : &self.pfcp_list6, + dev, self.pfcp_port); + ogs_assert(rv == OGS_OK); + } + + } while (ogs_yaml_iter_type(&pfcp_array) == + YAML_SEQUENCE_NODE); + + if (ogs_list_first(&self.pfcp_list) == NULL && + ogs_list_first(&self.pfcp_list6) == NULL) { + rv = ogs_socknode_probe( + ogs_config()->parameter.no_ipv4 ? + NULL : &self.pfcp_list, + ogs_config()->parameter.no_ipv6 ? + NULL : &self.pfcp_list6, + NULL, self.pfcp_port); + ogs_assert(rv == OGS_OK); + } + } else if (!strcmp(local_key, "pdn")) { + ogs_yaml_iter_t pdn_array, pdn_iter; + ogs_yaml_iter_recurse(&local_iter, &pdn_array); + + do { + ogs_pfcp_subnet_t *subnet = NULL; + const char *ipstr = NULL; + const char *mask_or_numbits = NULL; + const char *apn = NULL; + const char *dev = self.tun_ifname; + const char *low[MAX_NUM_OF_SUBNET_RANGE]; + const char *high[MAX_NUM_OF_SUBNET_RANGE]; + int i, num = 0; + + if (ogs_yaml_iter_type(&pdn_array) == + YAML_MAPPING_NODE) { + memcpy(&pdn_iter, &pdn_array, + sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type(&pdn_array) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&pdn_array)) + break; + ogs_yaml_iter_recurse(&pdn_array, &pdn_iter); + } else if (ogs_yaml_iter_type(&pdn_array) == + YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + while (ogs_yaml_iter_next(&pdn_iter)) { + const char *pdn_key = ogs_yaml_iter_key(&pdn_iter); + ogs_assert(pdn_key); + if (!strcmp(pdn_key, "addr")) { + char *v = + (char *)ogs_yaml_iter_value(&pdn_iter); + if (v) { + ipstr = (const char *)strsep(&v, "/"); + if (ipstr) { + mask_or_numbits = (const char *)v; + } + } + } else if (!strcmp(pdn_key, "apn")) { + apn = ogs_yaml_iter_value(&pdn_iter); + } else if (!strcmp(pdn_key, "dev")) { + dev = ogs_yaml_iter_value(&pdn_iter); + } else if (!strcmp(pdn_key, "range")) { + ogs_yaml_iter_t range_iter; + ogs_yaml_iter_recurse(&pdn_iter, &range_iter); + ogs_assert(ogs_yaml_iter_type(&range_iter) != + YAML_MAPPING_NODE); + do { + char *v = NULL; + + if (ogs_yaml_iter_type(&range_iter) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&range_iter)) + break; + } + + v = (char *) + ogs_yaml_iter_value(&range_iter); + if (v) { + ogs_assert(num <= + MAX_NUM_OF_SUBNET_RANGE); + low[num] = + (const char *)strsep(&v, "-"); + if (low[num] && strlen(low[num]) == 0) + low[num] = NULL; + + high[num] = (const char *)v; + if (high[num] && strlen(high[num]) == 0) + high[num] = NULL; + } + + if (low[num] || high[num]) num++; + } while ( + ogs_yaml_iter_type(&range_iter) == + YAML_SEQUENCE_NODE); + } else + ogs_warn("unknown key `%s`", pdn_key); + } + + subnet = ogs_pfcp_subnet_add( + ipstr, mask_or_numbits, apn, dev); + ogs_assert(subnet); + + subnet->num_of_range = num; + for (i = 0; i < subnet->num_of_range; i++) { + subnet->range[i].low = low[i]; + subnet->range[i].high = high[i]; + } + + } while (ogs_yaml_iter_type(&pdn_array) == + YAML_SEQUENCE_NODE); + + if (ogs_list_first(&self.subnet_list) == NULL) { + /* The followings are default configuration + * if no PDN configration */ + ogs_pfcp_subnet_t *subnet = NULL; + +#if defined(__linux) + /* + * On Linux, we can use a persitent tun/tap interface + * which has already been setup. As such, + * we do not need to get the IP address + * from configuration. + * + * If there is no APN and TUN mapping, + * the default subnet is added with `ogstun` name + */ + subnet = ogs_pfcp_subnet_add( + NULL, NULL, NULL, self.tun_ifname); + ogs_assert(subnet); +#else + /* + * On MacOSX/FreeBSD, There is no persitent tun/tap + * interface, TUN IP address is required. + * The default configuration is same as below. + * + * pdn: + * - addr: 10.45.0.1/16 + * - addr: cafe::1/64 + */ + subnet = ogs_pfcp_subnet_add( + "10.45.0.1", "16", NULL, self.tun_ifname); + ogs_assert(subnet); + subnet = ogs_pfcp_subnet_add( + "cafe::1", "64", NULL, self.tun_ifname); + ogs_assert(subnet); +#endif + } + } + } + } else if (!strcmp(root_key, remote)) { + ogs_yaml_iter_t remote_iter; + ogs_yaml_iter_recurse(&root_iter, &remote_iter); + while (ogs_yaml_iter_next(&remote_iter)) { + const char *remote_key = ogs_yaml_iter_key(&remote_iter); + ogs_assert(remote_key); + if (!strcmp(remote_key, "pfcp")) { + ogs_yaml_iter_t pfcp_array, pfcp_iter; + ogs_yaml_iter_recurse(&remote_iter, &pfcp_array); + do { + ogs_pfcp_node_t *node = NULL; + ogs_sockaddr_t *addr = NULL; + int family = AF_UNSPEC; + int i, num = 0; + const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; + uint16_t port = self.pfcp_port; + uint16_t tac[OGS_MAX_NUM_OF_TAI] = {0,}; + uint8_t num_of_tac = 0; + + if (ogs_yaml_iter_type(&pfcp_array) == + YAML_MAPPING_NODE) { + memcpy(&pfcp_iter, &pfcp_array, + sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type(&pfcp_array) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&pfcp_array)) + break; + ogs_yaml_iter_recurse(&pfcp_array, &pfcp_iter); + } else if (ogs_yaml_iter_type(&pfcp_array) == + YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + while (ogs_yaml_iter_next(&pfcp_iter)) { + const char *pfcp_key = + ogs_yaml_iter_key(&pfcp_iter); + ogs_assert(pfcp_key); + if (!strcmp(pfcp_key, "family")) { + const char *v = ogs_yaml_iter_value(&pfcp_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(pfcp_key, "addr") || + !strcmp(pfcp_key, "name")) { + ogs_yaml_iter_t hostname_iter; + ogs_yaml_iter_recurse(&pfcp_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(pfcp_key, "port")) { + const char *v = ogs_yaml_iter_value(&pfcp_iter); + if (v) port = atoi(v); + } else if (!strcmp(pfcp_key, "tac")) { + ogs_yaml_iter_t tac_iter; + ogs_yaml_iter_recurse(&pfcp_iter, &tac_iter); + ogs_assert(ogs_yaml_iter_type(&tac_iter) != + YAML_MAPPING_NODE); + + do { + const char *v = NULL; + + ogs_assert(num_of_tac <= + OGS_MAX_NUM_OF_TAI); + if (ogs_yaml_iter_type(&tac_iter) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&tac_iter)) + break; + } + + v = ogs_yaml_iter_value(&tac_iter); + if (v) { + tac[num_of_tac] = atoi(v); + num_of_tac++; + } + } while ( + ogs_yaml_iter_type(&tac_iter) == + YAML_SEQUENCE_NODE); + } else + ogs_warn("unknown key `%s`", pfcp_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_config()->parameter.no_ipv4, + ogs_config()->parameter.no_ipv6, + ogs_config()->parameter.prefer_ipv4); + + node = ogs_pfcp_node_new(addr); + ogs_assert(node); + ogs_list_add(&self.n4_list, node); + + node->num_of_tac = num_of_tac; + if (num_of_tac != 0) + memcpy(node->tac, tac, sizeof(node->tac)); + + } while (ogs_yaml_iter_type(&pfcp_array) == + YAML_SEQUENCE_NODE); + } + } + } + } + + rv = ogs_pfcp_context_validation(local); + if (rv != OGS_OK) return rv; + + return OGS_OK; +} + +ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *sa_list) +{ + ogs_pfcp_node_t *node = NULL; + + ogs_assert(sa_list); + + ogs_pool_alloc(&ogs_pfcp_node_pool, &node); + ogs_assert(node); + memset(node, 0, sizeof(ogs_pfcp_node_t)); + + node->sa_list = sa_list; + + ogs_list_init(&node->local_list); + ogs_list_init(&node->remote_list); + + ogs_list_init(&node->gtpu_resource_list); + + return node; +} + +void ogs_pfcp_node_free(ogs_pfcp_node_t *node) +{ + ogs_assert(node); + + ogs_pfcp_gtpu_resource_remove_all(&node->gtpu_resource_list); + + if (node->sock) + ogs_sock_destroy(node->sock); + + ogs_pfcp_xact_delete_all(node); + + ogs_freeaddrinfo(node->sa_list); + ogs_pool_free(&ogs_pfcp_node_pool, node); +} + +ogs_pfcp_node_t *ogs_pfcp_node_add( + ogs_list_t *list, ogs_sockaddr_t *addr) +{ + ogs_pfcp_node_t *node = NULL; + ogs_sockaddr_t *new = NULL; + + ogs_assert(list); + ogs_assert(addr); + + ogs_copyaddrinfo(&new, addr); + node = ogs_pfcp_node_new(new); + + ogs_assert(node); + memcpy(&node->addr, new, sizeof node->addr); + + ogs_list_add(list, node); + + return node; +} + +ogs_pfcp_node_t *ogs_pfcp_node_find( + ogs_list_t *list, ogs_sockaddr_t *addr) +{ + ogs_pfcp_node_t *node = NULL; + + ogs_assert(list); + ogs_assert(addr); + + ogs_list_for_each(list, node) { + if (ogs_sockaddr_is_equal(&node->addr, addr) == true) + break; + } + + return node; +} + +void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node) +{ + ogs_assert(list); + ogs_assert(node); + + ogs_list_remove(list, node); + ogs_pfcp_node_free(node); +} + +void ogs_pfcp_node_remove_all(ogs_list_t *list) +{ + ogs_pfcp_node_t *node = NULL, *next_node = NULL; + + ogs_assert(list); + + ogs_list_for_each_safe(list, next_node, node) + ogs_pfcp_node_remove(list, node); +} + +ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(ogs_list_t *list, + ogs_pfcp_user_plane_ip_resource_info_t *info) +{ + ogs_pfcp_gtpu_resource_t *resource = NULL; + + ogs_assert(list); + ogs_assert(info); + + ogs_pool_alloc(&ogs_pfcp_gtpu_resource_pool, &resource); + ogs_assert(resource); + + memcpy(&resource->info, info, sizeof(*info)); + + ogs_list_add(list, resource); + + return resource; +} + +ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list, + char *apn, ogs_pfcp_interface_t source_interface) +{ + ogs_pfcp_gtpu_resource_t *resource = NULL; + + ogs_assert(list); + + ogs_list_for_each(list, resource) { + bool match = true; + + if (resource->info.assoni && + strlen(resource->info.network_instance) && + apn && strlen(apn) && + strcmp(apn, resource->info.network_instance) != 0) { + match = false; + } + + if (resource->info.assosi && + resource->info.source_interface <= OGS_PFCP_INTERFACE_LI_FUNCTION && + source_interface <= OGS_PFCP_INTERFACE_LI_FUNCTION && + source_interface != resource->info.source_interface) { + match = false; + } + + if (match == true) return resource; + } + + return NULL; +} + +void ogs_pfcp_gtpu_resource_remove(ogs_list_t *list, + ogs_pfcp_gtpu_resource_t *resource) +{ + ogs_assert(list); + ogs_assert(resource); + + ogs_list_remove(list, resource); + + ogs_pool_free(&ogs_pfcp_gtpu_resource_pool, resource); +} + +void ogs_pfcp_gtpu_resource_remove_all(ogs_list_t *list) +{ + ogs_pfcp_gtpu_resource_t *resource = NULL, *next_resource = NULL; + + ogs_assert(list); + + ogs_list_for_each_safe(list, next_resource, resource) + ogs_pfcp_gtpu_resource_remove(list, resource); +} + +ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr(ogs_pfcp_sess_t *sess) +{ + ogs_assert(sess); + return sess->default_pdr; +} + +void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_pdr_remove_all(sess); + ogs_pfcp_far_remove_all(sess); + ogs_pfcp_urr_remove_all(sess); + ogs_pfcp_qer_remove_all(sess); + if (sess->bar) ogs_pfcp_bar_delete(sess->bar); +} + +static int precedence_compare(ogs_pfcp_pdr_t *pdr1, ogs_pfcp_pdr_t *pdr2) +{ + if (pdr1->precedence == pdr2->precedence) + return 0; + else if (pdr1->precedence < pdr2->precedence) + return -1; + else + return 1; +} + +ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_assert(sess); + + ogs_pool_alloc(&ogs_pfcp_pdr_pool, &pdr); + ogs_assert(pdr); + memset(pdr, 0, sizeof *pdr); + + pdr->sess = sess; + ogs_list_add(&sess->pdr_list, pdr); + + return pdr; +} + +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id) +{ + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->pdr_list, pdr) + if (pdr->id == id) return pdr; + + return NULL; +} + +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid(uint32_t teid) +{ + return (ogs_pfcp_pdr_t *)ogs_hash_get(self.pdr_hash, &teid, sizeof(teid)); +} + +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id) +{ + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_assert(sess); + + pdr = ogs_pfcp_pdr_find(sess, id); + if (!pdr) { + pdr = ogs_pfcp_pdr_add(sess); + ogs_assert(pdr); + pdr->id = id; + } + + return pdr; +} + +void ogs_pfcp_pdr_reorder_by_precedence( + ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence) +{ + ogs_pfcp_sess_t *sess = NULL; + + ogs_assert(pdr); + sess = pdr->sess; + ogs_assert(sess); + + ogs_list_remove(&sess->pdr_list, pdr); + + pdr->precedence = precedence; + ogs_list_insert_sorted(&sess->pdr_list, pdr, precedence_compare); +} + +void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far) +{ + ogs_assert(pdr); + ogs_assert(far); + + pdr->far = far; +} +void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr) +{ + ogs_assert(pdr); + ogs_assert(urr); + + pdr->urr = urr; +} +void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer) +{ + ogs_assert(pdr); + ogs_assert(qer); + + pdr->qer = qer; +} + +void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr) +{ + ogs_assert(pdr); + ogs_assert(pdr->sess); + + ogs_list_remove(&pdr->sess->pdr_list, pdr); + + if (pdr->f_teid.teid) + ogs_hash_set(self.pdr_hash, &pdr->f_teid.teid, + sizeof(pdr->f_teid.teid), NULL); + + ogs_pool_free(&ogs_pfcp_pdr_pool, pdr); +} + +void ogs_pfcp_pdr_remove_all(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_pdr_t *pdr = NULL, *next_pdr = NULL; + + ogs_assert(sess); + ogs_list_for_each_safe(&sess->pdr_list, next_pdr, pdr) + ogs_pfcp_pdr_remove(pdr); +} + +ogs_pfcp_far_t *ogs_pfcp_far_add(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_far_t *far = NULL; + + ogs_assert(sess); + + ogs_pool_alloc(&ogs_pfcp_far_pool, &far); + ogs_assert(far); + memset(far, 0, sizeof *far); + + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + + far->sess = sess; + ogs_list_add(&sess->far_list, far); + + return far; +} + +ogs_pfcp_far_t *ogs_pfcp_far_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id) +{ + ogs_pfcp_far_t *far = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->far_list, far) + if (far->id == id) return far; + + return NULL; +} + +ogs_pfcp_far_t *ogs_pfcp_far_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id) +{ + ogs_pfcp_far_t *far = NULL; + + ogs_assert(sess); + + far = ogs_pfcp_far_find(sess, id); + if (!far) { + far = ogs_pfcp_far_add(sess); + ogs_assert(far); + far->id = id; + } + + return far; +} + +void ogs_pfcp_far_remove(ogs_pfcp_far_t *far) +{ + ogs_pfcp_sess_t *sess = NULL; + + ogs_assert(far); + sess = far->sess; + ogs_assert(sess); + + ogs_list_remove(&sess->far_list, far); + ogs_pool_free(&ogs_pfcp_far_pool, far); +} + +void ogs_pfcp_far_remove_all(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_far_t *far = NULL, *next_far = NULL; + + ogs_assert(sess); + + ogs_list_for_each_safe(&sess->far_list, next_far, far) + ogs_pfcp_far_remove(far); +} + +ogs_pfcp_urr_t *ogs_pfcp_urr_add(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_urr_t *urr = NULL; + + ogs_assert(sess); + + ogs_pool_alloc(&ogs_pfcp_urr_pool, &urr); + ogs_assert(urr); + memset(urr, 0, sizeof *urr); + + urr->sess = sess; + ogs_list_add(&sess->urr_list, urr); + + return urr; +} + +ogs_pfcp_urr_t *ogs_pfcp_urr_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id) +{ + ogs_pfcp_urr_t *urr = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->urr_list, urr) + if (urr->id == id) return urr; + + return NULL; +} + +ogs_pfcp_urr_t *ogs_pfcp_urr_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id) +{ + ogs_pfcp_urr_t *urr = NULL; + + ogs_assert(sess); + + urr = ogs_pfcp_urr_find(sess, id); + if (!urr) { + urr = ogs_pfcp_urr_add(sess); + ogs_assert(urr); + urr->id = id; + } + + return urr; +} + +void ogs_pfcp_urr_remove(ogs_pfcp_urr_t *urr) +{ + ogs_pfcp_sess_t *sess = NULL; + + ogs_assert(urr); + sess = urr->sess; + ogs_assert(sess); + + ogs_list_remove(&sess->urr_list, urr); + ogs_pool_free(&ogs_pfcp_urr_pool, urr); +} + +void ogs_pfcp_urr_remove_all(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_urr_t *urr = NULL, *next_urr = NULL; + + ogs_assert(sess); + + ogs_list_for_each_safe(&sess->urr_list, next_urr, urr) + ogs_pfcp_urr_remove(urr); +} + +ogs_pfcp_qer_t *ogs_pfcp_qer_add(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_qer_t *qer = NULL; + + ogs_assert(sess); + + ogs_pool_alloc(&ogs_pfcp_qer_pool, &qer); + ogs_assert(qer); + memset(qer, 0, sizeof *qer); + + qer->sess = sess; + ogs_list_add(&sess->qer_list, qer); + + return qer; +} + +ogs_pfcp_qer_t *ogs_pfcp_qer_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id) +{ + ogs_pfcp_qer_t *qer = NULL; + + ogs_assert(sess); + + ogs_list_for_each(&sess->qer_list, qer) + if (qer->id == id) return qer; + + return NULL; +} + +ogs_pfcp_qer_t *ogs_pfcp_qer_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id) +{ + ogs_pfcp_qer_t *qer = NULL; + + ogs_assert(sess); + + qer = ogs_pfcp_qer_find(sess, id); + if (!qer) { + qer = ogs_pfcp_qer_add(sess); + ogs_assert(qer); + qer->id = id; + } + + return qer; +} + +void ogs_pfcp_qer_remove(ogs_pfcp_qer_t *qer) +{ + ogs_pfcp_sess_t *sess = NULL; + + ogs_assert(qer); + sess = qer->sess; + ogs_assert(sess); + + ogs_list_remove(&sess->qer_list, qer); + ogs_pool_free(&ogs_pfcp_qer_pool, qer); +} + +void ogs_pfcp_qer_remove_all(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_qer_t *qer = NULL, *next_qer = NULL; + + ogs_assert(sess); + + ogs_list_for_each_safe(&sess->qer_list, next_qer, qer) + ogs_pfcp_qer_remove(qer); +} + +ogs_pfcp_bar_t *ogs_pfcp_bar_new(ogs_pfcp_sess_t *sess) +{ + ogs_pfcp_bar_t *bar = NULL; + + ogs_assert(sess); + ogs_assert(sess->bar == NULL); /* Only One BAR is supported */ + + ogs_pool_alloc(&ogs_pfcp_bar_pool, &bar); + ogs_assert(bar); + memset(bar, 0, sizeof *bar); + + bar->sess = sess; + sess->bar = bar; + + return bar; +} + +void ogs_pfcp_bar_delete(ogs_pfcp_bar_t *bar) +{ + ogs_pfcp_sess_t *sess = NULL; + + ogs_assert(bar); + sess = bar->sess; + ogs_assert(sess); + + bar->sess = NULL; + sess->bar = NULL; + + ogs_pool_free(&ogs_pfcp_bar_pool, bar); +} + +int ogs_pfcp_ue_pool_generate(void) +{ + int i, rv; + ogs_pfcp_subnet_t *subnet = NULL; + + ogs_list_for_each(&self.subnet_list, subnet) { + int maxbytes = 0; + int lastindex = 0; + uint32_t start[4], end[4], broadcast[4]; + int rangeindex, num_of_range; + int poolindex; + int inc; + + if (subnet->family == AF_INET) { + maxbytes = 4; + lastindex = 0; + } else if (subnet->family == AF_INET6) { + maxbytes = 16; + lastindex = 3; + } else { + /* subnet->family might be AF_UNSPEC. So, skip it */ + continue; + } + + for (i = 0; i < 4; i++) { + broadcast[i] = subnet->sub.sub[i] + ~subnet->sub.mask[i]; + } + + num_of_range = subnet->num_of_range; + if (!num_of_range) num_of_range = 1; + + poolindex = 0; + for (rangeindex = 0; rangeindex < num_of_range; rangeindex++) { + + if (subnet->num_of_range && + subnet->range[rangeindex].low) { + ogs_ipsubnet_t low; + rv = ogs_ipsubnet( + &low, subnet->range[rangeindex].low, NULL); + ogs_assert(rv == OGS_OK); + memcpy(start, low.sub, maxbytes); + } else { + memcpy(start, subnet->sub.sub, maxbytes); + } + + if (subnet->num_of_range && + subnet->range[rangeindex].high) { + ogs_ipsubnet_t high; + rv = ogs_ipsubnet( + &high, subnet->range[rangeindex].high, NULL); + ogs_assert(rv == OGS_OK); + high.sub[lastindex] += htobe32(1); + memcpy(end, high.sub, maxbytes); + } else { + memcpy(end, broadcast, maxbytes); + } + + inc = 0; + while(poolindex < ogs_config()->pool.sess) { + ogs_pfcp_ue_ip_t *ue_ip = NULL; + + ue_ip = &subnet->pool.array[poolindex]; + ogs_assert(ue_ip); + memset(ue_ip, 0, sizeof *ue_ip); + ue_ip->subnet = subnet; + + memcpy(ue_ip->addr, start, maxbytes); + ue_ip->addr[lastindex] += htobe32(inc); + inc++; + + if (memcmp(ue_ip->addr, end, maxbytes) == 0) + break; + + /* Exclude Network Address */ + if (memcmp(ue_ip->addr, subnet->sub.sub, maxbytes) == 0) + continue; + + /* Exclude TUN IP Address */ + if (memcmp(ue_ip->addr, subnet->gw.sub, maxbytes) == 0) + continue; + + ogs_trace("[%d] - %x:%x:%x:%x", + poolindex, + ue_ip->addr[0], ue_ip->addr[1], + ue_ip->addr[2], ue_ip->addr[3]); + + poolindex++; + } + } + subnet->pool.size = subnet->pool.avail = poolindex; + } + + return OGS_OK; +} + +static ogs_pfcp_subnet_t *find_subnet(int family, const char *apn) +{ + ogs_pfcp_subnet_t *subnet = NULL; + + ogs_assert(apn); + ogs_assert(family == AF_INET || family == AF_INET6); + + ogs_list_for_each(&self.subnet_list, subnet) { + if ((subnet->family == AF_UNSPEC || subnet->family == family) && + (strlen(subnet->apn) == 0 || + (strlen(subnet->apn) && strcmp(subnet->apn, apn) == 0))) { + return subnet; + } + } + + if (subnet == NULL) + ogs_error("CHECK CONFIGURATION: Cannot find PDN[family:%d, apn:%s]", + family, apn); + + return subnet; +} + +ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc( + int family, const char *apn, uint8_t *addr) +{ + ogs_pfcp_subnet_t *subnet = NULL; + ogs_pfcp_ue_ip_t *ue_ip = NULL; + + uint8_t zero[16]; + size_t maxbytes = 0; + + ogs_assert(apn); + subnet = find_subnet(family, apn); + ogs_assert(subnet); + + memset(zero, 0, sizeof zero); + if (family == AF_INET) { + maxbytes = 4; + } else if (family == AF_INET6) { + maxbytes = 16; + } else { + ogs_fatal("Invalid family[%d]", family); + ogs_assert_if_reached(); + } + + // if assigning a static IP, do so. If not, assign dynamically! + if (memcmp(addr, zero, maxbytes) != 0) { + ue_ip = ogs_calloc(1, sizeof(ogs_pfcp_ue_ip_t)); + + ue_ip->subnet = subnet; + ue_ip->static_ip = true; + memcpy(ue_ip->addr, addr, maxbytes); + } else { + ogs_pool_alloc(&subnet->pool, &ue_ip); + } + + ogs_assert(ue_ip); + return ue_ip; +} + +void ogs_pfcp_ue_ip_free(ogs_pfcp_ue_ip_t *ue_ip) +{ + ogs_pfcp_subnet_t *subnet = NULL; + + ogs_assert(ue_ip); + subnet = ue_ip->subnet; + + ogs_assert(subnet); + + if (ue_ip->static_ip) { + ogs_free(ue_ip); + } else { + ogs_pool_free(&subnet->pool, ue_ip); + } +} + +ogs_pfcp_dev_t *ogs_pfcp_dev_add(const char *ifname) +{ + ogs_pfcp_dev_t *dev = NULL; + + ogs_assert(ifname); + + ogs_pool_alloc(&ogs_pfcp_dev_pool, &dev); + ogs_assert(dev); + memset(dev, 0, sizeof *dev); + + strcpy(dev->ifname, ifname); + + ogs_list_add(&self.dev_list, dev); + + return dev; +} + +void ogs_pfcp_dev_remove(ogs_pfcp_dev_t *dev) +{ + ogs_assert(dev); + + ogs_list_remove(&self.dev_list, dev); + + if (dev->link_local_addr) + ogs_freeaddrinfo(dev->link_local_addr); + + ogs_pool_free(&ogs_pfcp_dev_pool, dev); +} + +void ogs_pfcp_dev_remove_all(void) +{ + ogs_pfcp_dev_t *dev = NULL, *next_dev = NULL; + + ogs_list_for_each_safe(&self.dev_list, next_dev, dev) + ogs_pfcp_dev_remove(dev); +} + +ogs_pfcp_dev_t *ogs_pfcp_dev_find_by_ifname(const char *ifname) +{ + ogs_pfcp_dev_t *dev = NULL; + + ogs_assert(ifname); + + ogs_list_for_each(&ogs_pfcp_self()->dev_list, dev) { + if (strcmp(dev->ifname, ifname) == 0) + return dev; + } + + return OGS_OK; +} + +ogs_pfcp_subnet_t *ogs_pfcp_subnet_add( + const char *ipstr, const char *mask_or_numbits, + const char *apn, const char *ifname) +{ + int rv; + ogs_pfcp_dev_t *dev = NULL; + ogs_pfcp_subnet_t *subnet = NULL; + + ogs_assert(ifname); + + dev = ogs_pfcp_dev_find_by_ifname(ifname); + if (!dev) + dev = ogs_pfcp_dev_add(ifname); + ogs_assert(dev); + + ogs_pool_alloc(&ogs_pfcp_subnet_pool, &subnet); + ogs_assert(subnet); + memset(subnet, 0, sizeof *subnet); + + subnet->family = AF_UNSPEC; + subnet->dev = dev; + + if (ipstr && mask_or_numbits) { + rv = ogs_ipsubnet(&subnet->gw, ipstr, NULL); + ogs_assert(rv == OGS_OK); + + rv = ogs_ipsubnet(&subnet->sub, ipstr, mask_or_numbits); + ogs_assert(rv == OGS_OK); + + subnet->family = subnet->gw.family; + subnet->prefixlen = atoi(mask_or_numbits); + } + + if (apn) + strcpy(subnet->apn, apn); + + ogs_pool_init(&subnet->pool, ogs_config()->pool.sess); + + ogs_list_add(&self.subnet_list, subnet); + + return subnet; +} + +void ogs_pfcp_subnet_remove(ogs_pfcp_subnet_t *subnet) +{ + ogs_assert(subnet); + + ogs_list_remove(&self.subnet_list, subnet); + + ogs_pool_final(&subnet->pool); + + ogs_pool_free(&ogs_pfcp_subnet_pool, subnet); +} + +void ogs_pfcp_subnet_remove_all(void) +{ + ogs_pfcp_subnet_t *subnet = NULL, *next_subnet = NULL; + + ogs_list_for_each_safe(&self.subnet_list, next_subnet, subnet) + ogs_pfcp_subnet_remove(subnet); +} diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h new file mode 100644 index 000000000..c82294362 --- /dev/null +++ b/lib/pfcp/context.h @@ -0,0 +1,305 @@ +/* + * 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_PFCP_INSIDE) && !defined(OGS_PFCP_COMPILATION) +#error "This header cannot be included directly." +#endif + +#ifndef OGS_PFCP_CONTEXT_H +#define OGS_PFCP_CONTEXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define OGS_MAX_NUM_OF_DEV 16 +#define OGS_MAX_NUM_OF_SUBNET 16 + +typedef struct ogs_pfcp_node_s ogs_pfcp_node_t; + +typedef struct ogs_pfcp_context_s { + uint32_t pfcp_port; /* PFCP local port */ + const char *tun_ifname; /* PFCP TUN Interface Name */ + + ogs_list_t pfcp_list; /* PFCP IPv4 Server List */ + ogs_list_t pfcp_list6; /* PFCP IPv6 Server List */ + ogs_sock_t *pfcp_sock; /* PFCP IPv4 Socket */ + ogs_sock_t *pfcp_sock6; /* PFCP IPv6 Socket */ + ogs_sockaddr_t *pfcp_addr; /* PFCP IPv4 Address */ + ogs_sockaddr_t *pfcp_addr6; /* PFCP IPv6 Address */ + + uint32_t pfcp_started; /* UTC time when the PFCP entity started */ + + ogs_list_t n4_list; /* PFCP Node List */ + ogs_pfcp_node_t *node; /* Iterator for Peer round-robin */ + + ogs_list_t dev_list; /* Tun Device List */ + ogs_list_t subnet_list; /* UE Subnet List */ + + ogs_hash_t *pdr_hash; /* hash table (UPF-N3-TEID) */ +} ogs_pfcp_context_t; + +#define OGS_SETUP_PFCP_NODE(__cTX, __pNODE) \ + do { \ + ogs_assert((__cTX)); \ + ogs_assert((__pNODE)); \ + (__cTX)->pfcp_node = __pNODE; \ + } while(0) + +typedef struct ogs_pfcp_node_s { + ogs_lnode_t lnode; /* A node of list_t */ + + ogs_sockaddr_t *sa_list; /* Socket Address List Candidate */ + + ogs_sock_t *sock; /* Socket Instance */ + ogs_sockaddr_t addr; /* Remote Address */ + + ogs_list_t local_list; + ogs_list_t remote_list; + + ogs_fsm_t sm; /* A state machine */ + ogs_timer_t *t_association; /* timer to retry to associate peer node */ + ogs_timer_t *t_heartbeat; /* heartbeat timer to check UPF aliveness */ + + uint16_t tac[OGS_MAX_NUM_OF_TAI]; + uint8_t num_of_tac; + + ogs_list_t gtpu_resource_list; /* User Plane IP Resource Information */ +} ogs_pfcp_node_t; + +typedef struct ogs_pfcp_gtpu_resource_s { + ogs_lnode_t lnode; + + ogs_pfcp_user_plane_ip_resource_info_t info; +} __attribute__ ((packed)) ogs_pfcp_gtpu_resource_t; + +typedef struct ogs_pfcp_pdr_s ogs_pfcp_pdr_t; +typedef struct ogs_pfcp_far_s ogs_pfcp_far_t; +typedef struct ogs_pfcp_urr_s ogs_pfcp_urr_t; +typedef struct ogs_pfcp_qer_s ogs_pfcp_qer_t; +typedef struct ogs_pfcp_bar_s ogs_pfcp_bar_t; + +typedef struct ogs_pfcp_sess_s { + ogs_list_t pdr_list; /* PDR List */ + ogs_list_t far_list; /* FAR List */ + ogs_list_t urr_list; /* URR List */ + ogs_list_t qer_list; /* QER List */ + ogs_pfcp_bar_t *bar; /* BAR Item */ + + /* Related Context */ + ogs_pfcp_pdr_t *default_pdr; /* Used by UPF */ +} ogs_pfcp_sess_t; + +typedef struct ogs_pfcp_pdr_s { + ogs_lnode_t lnode; + + ogs_pfcp_pdr_id_t id; + ogs_pfcp_precedence_t precedence; + ogs_pfcp_interface_t src_if; + + ogs_pfcp_f_teid_t f_teid; + ogs_pfcp_outer_header_removal_t outer_header_removal; + + ogs_pfcp_far_t *far; + ogs_pfcp_urr_t *urr; + ogs_pfcp_qer_t *qer; + + int num_of_flow; + char *flow_description[OGS_MAX_NUM_OF_RULE]; + + /* Related Context */ + ogs_pfcp_sess_t *sess; +} ogs_pfcp_pdr_t; + +typedef struct ogs_pfcp_far_s { + ogs_lnode_t lnode; + + ogs_pfcp_far_id_t id; + ogs_pfcp_apply_action_t apply_action; + ogs_pfcp_interface_t dst_if; + ogs_pfcp_outer_header_creation_t outer_header_creation; + int outer_header_creation_len; + + /* Related Context */ + ogs_pfcp_sess_t *sess; + void *gnode; +} ogs_pfcp_far_t; + +typedef struct ogs_pfcp_urr_s { + ogs_lnode_t lnode; + + ogs_pfcp_urr_id_t id; + + ogs_pfcp_sess_t *sess; +} ogs_pfcp_urr_t; + +typedef struct ogs_pfcp_qer_s { + ogs_lnode_t lnode; + + ogs_pfcp_qer_id_t id; + + ogs_pfcp_gate_status_t gate_status; + ogs_pfcp_bitrate_t mbr; + ogs_pfcp_bitrate_t gbr; + + ogs_pfcp_sess_t *sess; +} ogs_pfcp_qer_t; + +typedef struct ogs_pfcp_bar_s { + ogs_pfcp_bar_id_t id; + + ogs_pfcp_sess_t *sess; +} ogs_pfcp_bar_t; + +typedef struct ogs_pfcp_subnet_s ogs_pfcp_subnet_t; +typedef struct ogs_pfcp_ue_ip_s { + uint32_t addr[4]; + bool static_ip; + + /* Related Context */ + ogs_pfcp_subnet_t *subnet; +} ogs_pfcp_ue_ip_t; + +typedef struct ogs_pfcp_dev_s { + ogs_lnode_t lnode; + + char ifname[OGS_MAX_IFNAME_LEN]; + ogs_socket_t fd; + + ogs_sockaddr_t *link_local_addr; + ogs_poll_t *poll; +} ogs_pfcp_dev_t; + +typedef struct ogs_pfcp_subnet_s { + ogs_lnode_t lnode; + + ogs_ipsubnet_t sub; /* Subnet : cafe::0/64 */ + ogs_ipsubnet_t gw; /* Gateway : cafe::1 */ + char apn[OGS_MAX_APN_LEN]; /* APN : "internet", "volte", .. */ + +#define MAX_NUM_OF_SUBNET_RANGE 16 + struct { + const char *low; + const char *high; + } range[MAX_NUM_OF_SUBNET_RANGE]; + int num_of_range; + + int family; /* AF_INET or AF_INET6 */ + uint8_t prefixlen; /* prefixlen */ + OGS_POOL(pool, ogs_pfcp_ue_ip_t); + + ogs_pfcp_dev_t *dev; /* Related Context */ +} ogs_pfcp_subnet_t; + +void ogs_pfcp_context_init(int num_of_gtpu_resource); +void ogs_pfcp_context_final(void); +ogs_pfcp_context_t *ogs_pfcp_self(void); +int ogs_pfcp_context_parse_config(const char *local, const char *remote); + +ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *sa_list); +void ogs_pfcp_node_free(ogs_pfcp_node_t *node); + +ogs_pfcp_node_t *ogs_pfcp_node_add( + ogs_list_t *list, ogs_sockaddr_t *addr); +ogs_pfcp_node_t *ogs_pfcp_node_find( + ogs_list_t *list, ogs_sockaddr_t *addr); +void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node); +void ogs_pfcp_node_remove_all(ogs_list_t *list); + +ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_add(ogs_list_t *list, + ogs_pfcp_user_plane_ip_resource_info_t *info); +ogs_pfcp_gtpu_resource_t *ogs_pfcp_gtpu_resource_find(ogs_list_t *list, + char *apn, ogs_pfcp_interface_t source_interface); +void ogs_pfcp_gtpu_resource_remove(ogs_list_t *list, + ogs_pfcp_gtpu_resource_t *resource); +void ogs_pfcp_gtpu_resource_remove_all(ogs_list_t *list); + +#define OGS_SETUP_DEFAULT_PDR(__sESS, __pDR) \ + do { \ + ogs_assert((__sESS)); \ + ogs_assert((__pDR)); \ + (__sESS)->default_pdr = __pDR; \ + ogs_assert((__sESS)->default_pdr); \ + } while(0) +ogs_pfcp_pdr_t *ogs_pfcp_sess_default_pdr(ogs_pfcp_sess_t *sess); +void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess); + +ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess); +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id); +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_teid(uint32_t teid); +ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id); +void ogs_pfcp_pdr_reorder_by_precedence( + ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence); +void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far); +void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr); +void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer); +void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr); +void ogs_pfcp_pdr_remove_all(ogs_pfcp_sess_t *sess); + +ogs_pfcp_far_t *ogs_pfcp_far_add(ogs_pfcp_sess_t *sess); +ogs_pfcp_far_t *ogs_pfcp_far_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id); +ogs_pfcp_far_t *ogs_pfcp_far_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id); +void ogs_pfcp_far_remove(ogs_pfcp_far_t *far); +void ogs_pfcp_far_remove_all(ogs_pfcp_sess_t *sess); + +ogs_pfcp_urr_t *ogs_pfcp_urr_add(ogs_pfcp_sess_t *sess); +ogs_pfcp_urr_t *ogs_pfcp_urr_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id); +ogs_pfcp_urr_t *ogs_pfcp_urr_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id); +void ogs_pfcp_urr_remove(ogs_pfcp_urr_t *urr); +void ogs_pfcp_urr_remove_all(ogs_pfcp_sess_t *sess); + +ogs_pfcp_qer_t *ogs_pfcp_qer_add(ogs_pfcp_sess_t *sess); +ogs_pfcp_qer_t *ogs_pfcp_qer_find( + ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id); +ogs_pfcp_qer_t *ogs_pfcp_qer_find_or_add( + ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id); +void ogs_pfcp_qer_remove(ogs_pfcp_qer_t *qer); +void ogs_pfcp_qer_remove_all(ogs_pfcp_sess_t *sess); + +ogs_pfcp_bar_t *ogs_pfcp_bar_new(ogs_pfcp_sess_t *sess); +void ogs_pfcp_bar_delete(ogs_pfcp_bar_t *bar); + +int ogs_pfcp_ue_pool_generate(void); +ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc( + int family, const char *apn, uint8_t *addr); +void ogs_pfcp_ue_ip_free(ogs_pfcp_ue_ip_t *ip); + +ogs_pfcp_dev_t *ogs_pfcp_dev_add(const char *ifname); +void ogs_pfcp_dev_remove(ogs_pfcp_dev_t *dev); +void ogs_pfcp_dev_remove_all(void); +ogs_pfcp_dev_t *ogs_pfcp_dev_find_by_ifname(const char *ifname); + +ogs_pfcp_subnet_t *ogs_pfcp_subnet_add( + const char *ipstr, const char *mask_or_numbits, + const char *apn, const char *ifname); +ogs_pfcp_subnet_t *ogs_pfcp_subnet_next(ogs_pfcp_subnet_t *subnet); +void ogs_pfcp_subnet_remove(ogs_pfcp_subnet_t *subnet); +void ogs_pfcp_subnet_remove_all(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_PFCP_CONTEXT_H */ diff --git a/lib/pfcp/conv.c b/lib/pfcp/conv.c index e98b02724..4d3450dce 100644 --- a/lib/pfcp/conv.c +++ b/lib/pfcp/conv.c @@ -19,15 +19,59 @@ #include "ogs-pfcp.h" -#define OGS_PFCP_F_TEID_HDR_LEN 5 -#define OGS_PFCP_F_TEID_IPV4_LEN (OGS_IPV4_LEN + OGS_PFCP_F_TEID_HDR_LEN) -#define OGS_PFCP_F_TEID_IPV6_LEN (OGS_IPV6_LEN + OGS_PFCP_F_TEID_HDR_LEN) -#define OGS_PFCP_F_TEID_IPV4V6_LEN (OGS_IPV4V6_LEN + OGS_PFCP_F_TEID_HDR_LEN) +int ogs_pfcp_sockaddr_to_node_id( + ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, int prefer_ipv4, + ogs_pfcp_node_id_t *node_id, int *len) +{ + const int hdr_len = 1; + int rv; + char hostname[OGS_MAX_FQDN_LEN]; -#define OGS_PFCP_F_SEID_HDR_LEN 9 -#define OGS_PFCP_F_SEID_IPV4_LEN (OGS_IPV4_LEN + OGS_PFCP_F_SEID_HDR_LEN) -#define OGS_PFCP_F_SEID_IPV6_LEN (OGS_IPV6_LEN + OGS_PFCP_F_SEID_HDR_LEN) -#define OGS_PFCP_F_SEID_IPV4V6_LEN (OGS_IPV4V6_LEN + OGS_PFCP_F_SEID_HDR_LEN) + ogs_assert(node_id); + + memset(node_id, 0, sizeof *node_id); + + if (addr && addr->hostname) { + rv = ogs_getnameinfo(hostname, OGS_MAX_FQDN_LEN, addr, 0); + if (rv == OGS_OK && strcmp(addr->hostname, hostname) == 0) { + node_id->type = OGS_PFCP_NODE_ID_FQDN; + *len = ogs_fqdn_build(node_id->fqdn, + addr->hostname, strlen(addr->hostname)) + hdr_len; + + return OGS_OK; + } + } + + if (addr6 && addr6->hostname) { + rv = ogs_getnameinfo(hostname, OGS_MAX_FQDN_LEN, addr6, 0); + if (rv == OGS_OK && strcmp(addr6->hostname, hostname) == 0) { + node_id->type = OGS_PFCP_NODE_ID_FQDN; + *len = ogs_fqdn_build(node_id->fqdn, + addr6->hostname, strlen(addr6->hostname)) + hdr_len; + + return OGS_OK; + } + } + + if (prefer_ipv4 && addr) { + node_id->type = OGS_PFCP_NODE_ID_IPV4; + node_id->addr = addr->sin.sin_addr.s_addr; + *len = OGS_IPV4_LEN + hdr_len; + } else if (addr6) { + node_id->type = OGS_PFCP_NODE_ID_IPV6; + memcpy(node_id->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN); + *len = OGS_IPV6_LEN + hdr_len; + } else if (addr) { + node_id->type = OGS_PFCP_NODE_ID_IPV4; + node_id->addr = addr->sin.sin_addr.s_addr; + *len = OGS_IPV4_LEN + hdr_len; + } else { + ogs_assert_if_reached(); + return OGS_ERROR; + } + + return OGS_OK; +} int ogs_pfcp_f_seid_to_sockaddr( ogs_pfcp_f_seid_t *f_seid, uint16_t port, ogs_sockaddr_t **list) @@ -40,12 +84,12 @@ int ogs_pfcp_f_seid_to_sockaddr( addr = ogs_calloc(1, sizeof(ogs_sockaddr_t)); ogs_assert(addr); addr->ogs_sa_family = AF_INET; - addr->ogs_sin_port = htons(port); + addr->ogs_sin_port = htobe16(port); addr6 = ogs_calloc(1, sizeof(ogs_sockaddr_t)); ogs_assert(addr6); addr6->ogs_sa_family = AF_INET6; - addr6->ogs_sin_port = htons(port); + addr6->ogs_sin_port = htobe16(port); if (f_seid->ipv4 && f_seid->ipv6) { addr->next = addr6; @@ -77,24 +121,28 @@ int ogs_pfcp_sockaddr_to_f_seid( ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, ogs_pfcp_f_seid_t *f_seid, int *len) { + const int hdr_len = 9; + ogs_assert(f_seid); + memset(f_seid, 0, sizeof *f_seid); + if (addr && addr6) { f_seid->ipv4 = 1; f_seid->both.addr = addr->sin.sin_addr.s_addr; f_seid->ipv6 = 1; memcpy(f_seid->both.addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN); - *len = OGS_PFCP_F_SEID_IPV4V6_LEN; + *len = OGS_IPV4V6_LEN + hdr_len; } else if (addr) { f_seid->ipv4 = 1; f_seid->ipv6 = 0; f_seid->addr = addr->sin.sin_addr.s_addr; - *len = OGS_PFCP_F_SEID_IPV4_LEN; + *len = OGS_IPV4_LEN + hdr_len; } else if (addr6) { f_seid->ipv4 = 0; f_seid->ipv6 = 1; memcpy(f_seid->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN); - *len = OGS_PFCP_F_SEID_IPV6_LEN; + *len = OGS_IPV6_LEN + hdr_len; } else ogs_assert_if_reached(); @@ -106,7 +154,7 @@ int ogs_pfcp_f_seid_to_ip(ogs_pfcp_f_seid_t *f_seid, ogs_ip_t *ip) ogs_assert(ip); ogs_assert(f_seid); - memset(ip, 0, sizeof(ogs_ip_t)); + memset(ip, 0, sizeof *ip); ip->ipv4 = f_seid->ipv4; ip->ipv6 = f_seid->ipv6; @@ -131,52 +179,204 @@ int ogs_pfcp_sockaddr_to_f_teid( ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, ogs_pfcp_f_teid_t *f_teid, int *len) { + const int hdr_len = 5; + + ogs_assert(addr || addr6); ogs_assert(f_teid); + memset(f_teid, 0, sizeof *f_teid); if (addr && addr6) { f_teid->ipv4 = 1; f_teid->both.addr = addr->sin.sin_addr.s_addr; f_teid->ipv6 = 1; memcpy(f_teid->both.addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN); - *len = OGS_PFCP_F_TEID_IPV4V6_LEN; + *len = OGS_IPV4V6_LEN + hdr_len; } else if (addr) { f_teid->ipv4 = 1; f_teid->ipv6 = 0; f_teid->addr = addr->sin.sin_addr.s_addr; - *len = OGS_PFCP_F_TEID_IPV4_LEN; + *len = OGS_IPV4_LEN + hdr_len; } else if (addr6) { f_teid->ipv4 = 0; f_teid->ipv6 = 1; memcpy(f_teid->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN); - *len = OGS_PFCP_F_TEID_IPV6_LEN; + *len = OGS_IPV6_LEN + hdr_len; } else ogs_assert_if_reached(); return OGS_OK; } -int ogs_pfcp_outer_hdr_to_ip(ogs_pfcp_outer_hdr_t *outer_hdr, ogs_ip_t *ip) +int ogs_pfcp_sockaddr_to_user_plane_ip_resource_info( + ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, + ogs_pfcp_user_plane_ip_resource_info_t *info) { + ogs_assert(addr || addr6); + ogs_assert(info); + + if (addr) { + info->v4 = 1; + info->addr = addr->sin.sin_addr.s_addr; + } + if (addr6) { + info->v6 = 1; + memcpy(info->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN); + } + + return OGS_OK; +} + +int ogs_pfcp_user_plane_ip_resource_info_to_sockaddr( + ogs_pfcp_user_plane_ip_resource_info_t *info, + ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6) +{ + ogs_assert(addr && addr6); + ogs_assert(info); + + *addr = NULL; + *addr6 = NULL; + + if (info->v4) { + *addr = ogs_calloc(1, sizeof(**addr)); + (*addr)->sin.sin_addr.s_addr = info->addr; + (*addr)->ogs_sa_family = AF_INET; + } + + if (info->v6) { + *addr6 = ogs_calloc(1, sizeof(**addr6)); + memcpy((*addr6)->sin6.sin6_addr.s6_addr, info->addr6, OGS_IPV6_LEN); + (*addr6)->ogs_sa_family = AF_INET6; + } + + return OGS_OK; +} + +int ogs_pfcp_user_plane_ip_resource_info_to_f_teid( + ogs_pfcp_user_plane_ip_resource_info_t *info, + ogs_pfcp_f_teid_t *f_teid, int *len) +{ + const int hdr_len = 5; + + ogs_assert(info); + ogs_assert(f_teid); + memset(f_teid, 0, sizeof *f_teid); + + if (info->v4 && info->v6) { + f_teid->ipv4 = 1; + f_teid->both.addr = info->addr; + f_teid->ipv6 = 1; + memcpy(f_teid->both.addr6, info->addr6, OGS_IPV6_LEN); + *len = OGS_IPV4V6_LEN + hdr_len; + } else if (info->v4) { + f_teid->ipv4 = 1; + f_teid->ipv6 = 0; + f_teid->addr = info->addr; + *len = OGS_IPV4_LEN + hdr_len; + } else if (info->v6) { + f_teid->ipv4 = 0; + f_teid->ipv6 = 1; + memcpy(f_teid->addr6, info->addr6, OGS_IPV6_LEN); + *len = OGS_IPV6_LEN + hdr_len; + } else + ogs_assert_if_reached(); + + return OGS_OK; +} + +int ogs_pfcp_paa_to_ue_ip_addr( + ogs_paa_t *paa, ogs_pfcp_ue_ip_addr_t *addr, int *len) +{ + const int hdr_len = 1; + + ogs_assert(paa); + ogs_assert(addr); + + memset(addr, 0, sizeof *addr); + + if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { + addr->ipv4 = 1; + addr->both.addr = paa->both.addr; + addr->ipv6 = 1; + memcpy(addr->both.addr6, paa->both.addr6, OGS_IPV6_LEN); + *len = OGS_IPV4V6_LEN + hdr_len; + } else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV4) { + addr->ipv4 = 1; + addr->ipv6 = 0; + addr->addr = paa->addr; + *len = OGS_IPV4_LEN + hdr_len; + } else if (paa->pdn_type == OGS_GTP_PDN_TYPE_IPV6) { + addr->ipv4 = 0; + addr->ipv6 = 1; + memcpy(addr->addr6, paa->addr6, OGS_IPV6_LEN); + *len = OGS_IPV6_LEN + hdr_len; + } else + ogs_assert_if_reached(); + + return OGS_OK; +} + +int ogs_pfcp_ip_to_outer_header_creation(ogs_ip_t *ip, + ogs_pfcp_outer_header_creation_t *outer_header_creation, int *len) +{ + const int hdr_len = 6; + ogs_assert(ip); - ogs_assert(outer_hdr); - - memset(ip, 0, sizeof(ogs_ip_t)); - - ip->ipv4 = outer_hdr->gtpu_ipv4; - ip->ipv6 = outer_hdr->gtpu_ipv6; + ogs_assert(outer_header_creation); + memset(outer_header_creation, 0, sizeof *outer_header_creation); if (ip->ipv4 && ip->ipv6) { - ip->both.addr = outer_hdr->both.addr; - memcpy(ip->both.addr6, outer_hdr->both.addr6, OGS_IPV6_LEN); - ip->len = OGS_IPV4V6_LEN; + outer_header_creation->gtpu4 = 1; + outer_header_creation->both.addr = ip->both.addr; + outer_header_creation->gtpu6 = 1; + memcpy(outer_header_creation->both.addr6, ip->both.addr6, OGS_IPV6_LEN); + *len = OGS_IPV4V6_LEN + hdr_len; } else if (ip->ipv4) { - ip->addr = outer_hdr->addr; - ip->len = OGS_IPV4_LEN; + outer_header_creation->gtpu4 = 1; + outer_header_creation->gtpu6 = 0; + outer_header_creation->addr = ip->addr; + *len = OGS_IPV4_LEN + hdr_len; } else if (ip->ipv6) { - memcpy(ip->addr6, outer_hdr->addr6, OGS_IPV6_LEN); - ip->len = OGS_IPV6_LEN; + outer_header_creation->gtpu4 = 0; + outer_header_creation->gtpu6 = 1; + memcpy(outer_header_creation->addr6, ip->addr6, OGS_IPV6_LEN); + *len = OGS_IPV6_LEN + hdr_len; } else ogs_assert_if_reached(); return OGS_OK; } + +int ogs_pfcp_outer_header_creation_to_ip( + ogs_pfcp_outer_header_creation_t *outer_header_creation, ogs_ip_t *ip) +{ + ogs_assert(outer_header_creation); + ogs_assert(ip); + memset(ip, 0, sizeof *ip); + + if ((outer_header_creation->gtpu4 || + outer_header_creation->ip4 || + outer_header_creation->udp4) && + (outer_header_creation->gtpu6 || + outer_header_creation->ip6 || + outer_header_creation->udp6)) { + ip->ipv4 = 1; ip->ipv6 = 1; + ip->len = OGS_IPV4V6_LEN; + ip->both.addr = outer_header_creation->both.addr; + memcpy(ip->both.addr6, outer_header_creation->both.addr6, OGS_IPV6_LEN); + } else if (outer_header_creation->gtpu4 || + outer_header_creation->ip4 || + outer_header_creation->udp4) { + ip->ipv4 = 1; + ip->len = OGS_IPV4_LEN; + ip->addr = outer_header_creation->addr; + } else if (outer_header_creation->gtpu6 || + outer_header_creation->ip6 || + outer_header_creation->udp6) { + ip->ipv6 = 1; + ip->len = OGS_IPV6_LEN; + memcpy(ip->addr6, outer_header_creation->addr6, OGS_IPV6_LEN); + } else + return OGS_ERROR; + + return OGS_OK; +} diff --git a/lib/pfcp/conv.h b/lib/pfcp/conv.h index 1fa465108..9c8851281 100644 --- a/lib/pfcp/conv.h +++ b/lib/pfcp/conv.h @@ -28,6 +28,10 @@ extern "C" { #endif +int ogs_pfcp_sockaddr_to_node_id( + ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, int prefer_ipv4, + ogs_pfcp_node_id_t *node_id, int *len); + int ogs_pfcp_f_seid_to_sockaddr( ogs_pfcp_f_seid_t *f_seid, uint16_t port, ogs_sockaddr_t **list); int ogs_pfcp_sockaddr_to_f_seid( @@ -36,9 +40,25 @@ int ogs_pfcp_sockaddr_to_f_seid( int ogs_pfcp_f_seid_to_ip(ogs_pfcp_f_seid_t *f_seid, ogs_ip_t *ip); int ogs_pfcp_sockaddr_to_f_teid( + ogs_sockaddr_t *a, ogs_sockaddr_t *b, ogs_pfcp_f_teid_t *f_teid, int *len); + +int ogs_pfcp_sockaddr_to_user_plane_ip_resource_info( ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, + ogs_pfcp_user_plane_ip_resource_info_t *info); +int ogs_pfcp_user_plane_ip_resource_info_to_sockaddr( + ogs_pfcp_user_plane_ip_resource_info_t *info, + ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6); +int ogs_pfcp_user_plane_ip_resource_info_to_f_teid( + ogs_pfcp_user_plane_ip_resource_info_t *info, ogs_pfcp_f_teid_t *f_teid, int *len); -int ogs_pfcp_outer_hdr_to_ip(ogs_pfcp_outer_hdr_t *outer_hdr, ogs_ip_t *ip); + +int ogs_pfcp_paa_to_ue_ip_addr( + ogs_paa_t *paa, ogs_pfcp_ue_ip_addr_t *addr, int *len); + +int ogs_pfcp_ip_to_outer_header_creation(ogs_ip_t *ip, + ogs_pfcp_outer_header_creation_t *outer_header_creation, int *len); +int ogs_pfcp_outer_header_creation_to_ip( + ogs_pfcp_outer_header_creation_t *outer_header_creation, ogs_ip_t *ip); #ifdef __cplusplus } diff --git a/lib/pfcp/meson.build b/lib/pfcp/meson.build index 11ceebc8a..660650727 100644 --- a/lib/pfcp/meson.build +++ b/lib/pfcp/meson.build @@ -21,16 +21,18 @@ libpfcp_sources = files(''' message.h types.h conv.h - node.h + n4-build.h path.h xact.h + context.h message.c types.c conv.c - node.c + n4-build.c path.c xact.c + context.c '''.split()) libpfcp_inc = include_directories('.') @@ -40,10 +42,10 @@ libpfcp = library('ogspfcp', version : libogslib_version, c_args : '-DOGS_PFCP_COMPILATION', include_directories : [libpfcp_inc, libinc], - dependencies : libcore_dep, + dependencies : [libcore_dep, libapp_dep], install : true) libpfcp_dep = declare_dependency( link_with : libpfcp, include_directories : [libpfcp_inc, libinc], - dependencies : libcore_dep) + dependencies : [libcore_dep, libapp_dep]) diff --git a/lib/pfcp/message.c b/lib/pfcp/message.c index d09db1a9d..a94fcae15 100644 --- a/lib/pfcp/message.c +++ b/lib/pfcp/message.c @@ -20,35 +20,35 @@ /******************************************************************************* * 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: 2019-12-05 22:18:23.150697 by acetcom + * Created on: 2020-04-22 22:57:07.588861 by acetcom * from 29244-g10.docx ******************************************************************************/ #include "ogs-pfcp.h" -ogs_tlv_desc_t ogs_pfcp_tlv_desc_cause_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_cause = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "Cause", OGS_PFCP_CAUSE_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_cause_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_source_interface_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_source_interface = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "Source Interface", OGS_PFCP_SOURCE_INTERFACE_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_source_interface_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_teid_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_teid = { OGS_TLV_VAR_STR, "F-TEID", @@ -59,7 +59,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_teid_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_network_instance_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_network_instance = { OGS_TLV_VAR_STR, "Network Instance", @@ -70,7 +70,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_network_instance_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_sdf_filter_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_sdf_filter = { OGS_TLV_VAR_STR, "SDF Filter", @@ -81,7 +81,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_sdf_filter_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id = { OGS_TLV_VAR_STR, "Application ID", @@ -92,18 +92,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_gate_status_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_gate_status = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "Gate Status", OGS_PFCP_GATE_STATUS_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_gate_status_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_mbr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_mbr = { OGS_TLV_VAR_STR, "MBR", @@ -114,7 +114,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_mbr_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_gbr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_gbr = { OGS_TLV_VAR_STR, "GBR", @@ -125,29 +125,29 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_gbr_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_correlation_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_correlation_id = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT32, "QER Correlation ID", OGS_PFCP_QER_CORRELATION_ID_TYPE, - 0, + 4, 0, sizeof(ogs_pfcp_tlv_qer_correlation_id_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_precedence_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_precedence = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT32, "Precedence", OGS_PFCP_PRECEDENCE_TYPE, - 0, + 4, 0, sizeof(ogs_pfcp_tlv_precedence_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_transport_level_marking_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_transport_level_marking = { OGS_TLV_VAR_STR, "Transport Level Marking", @@ -158,7 +158,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_transport_level_marking_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_threshold_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_threshold = { OGS_TLV_VAR_STR, "Volume Threshold", @@ -169,7 +169,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_threshold_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_threshold_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_threshold = { OGS_TLV_VAR_STR, "Time Threshold", @@ -180,7 +180,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_threshold_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_monitoring_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_monitoring_time = { OGS_TLV_VAR_STR, "Monitoring Time", @@ -191,7 +191,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_monitoring_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_threshold_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_threshold = { OGS_TLV_VAR_STR, "Subsequent Volume Threshold", @@ -202,7 +202,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_threshold_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_threshold_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_threshold = { OGS_TLV_VAR_STR, "Subsequent Time Threshold", @@ -213,7 +213,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_threshold_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_inactivity_detection_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_inactivity_detection_time = { OGS_TLV_VAR_STR, "Inactivity Detection Time", @@ -224,18 +224,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_inactivity_detection_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_reporting_triggers_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_reporting_triggers = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "Reporting Triggers", OGS_PFCP_REPORTING_TRIGGERS_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_reporting_triggers_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_redirect_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_redirect_information = { OGS_TLV_VAR_STR, "Redirect Information", @@ -246,7 +246,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_redirect_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_report_type_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_report_type = { OGS_TLV_VAR_STR, "Report Type", @@ -257,18 +257,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_report_type_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_offending_ie_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_offending_ie = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT16, "Offending IE", OGS_PFCP_OFFENDING_IE_TYPE, - 0, + 2, 0, sizeof(ogs_pfcp_tlv_offending_ie_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_policy_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_policy = { OGS_TLV_VAR_STR, "Forwarding Policy", @@ -279,40 +279,40 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_policy_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_destination_interface_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_destination_interface = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "Destination Interface", OGS_PFCP_DESTINATION_INTERFACE_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_destination_interface_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_up_function_features_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_up_function_features = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT16, "UP Function Features", OGS_PFCP_UP_FUNCTION_FEATURES_TYPE, - 0, + 2, 0, sizeof(ogs_pfcp_tlv_up_function_features_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_apply_action_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_apply_action = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "Apply Action", OGS_PFCP_APPLY_ACTION_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_apply_action_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_service_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_service_information = { OGS_TLV_VAR_STR, "Downlink Data Service Information", @@ -323,7 +323,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_service_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_notification_delay_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_notification_delay = { OGS_TLV_VAR_STR, "Downlink Data Notification Delay", @@ -334,7 +334,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_notification_delay_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_duration_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_duration = { OGS_TLV_VAR_STR, "DL Buffering Duration", @@ -345,7 +345,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_duration_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_suggested_packet_count_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_suggested_packet_count = { OGS_TLV_VAR_STR, "DL Buffering Suggested Packet Count", @@ -356,7 +356,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_suggested_packet_count_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsmreq_flags_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsmreq_flags = { OGS_TLV_VAR_STR, "PFCPSMReq-Flags", @@ -367,7 +367,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsmreq_flags_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrrsp_flags_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrrsp_flags = { OGS_TLV_VAR_STR, "PFCPSRRsp-Flags", @@ -378,7 +378,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrrsp_flags_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_sequence_number_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_sequence_number = { OGS_TLV_VAR_STR, "Sequence Number", @@ -389,7 +389,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_sequence_number_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_metric_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_metric = { OGS_TLV_VAR_STR, "Metric", @@ -400,7 +400,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_metric_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_timer_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_timer = { OGS_TLV_VAR_STR, "Timer", @@ -411,18 +411,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_timer_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdr_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdr_id = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT16, "PDR ID", OGS_PFCP_PDR_ID_TYPE, - 0, + 2, 0, sizeof(ogs_pfcp_tlv_pdr_id_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_seid_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_seid = { OGS_TLV_VAR_STR, "F-SEID", @@ -433,7 +433,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_seid_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_id = { OGS_TLV_VAR_STR, "Node ID", @@ -444,7 +444,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_contents_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_contents = { OGS_TLV_VAR_STR, "PFD contents", @@ -455,18 +455,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_contents_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_method_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_method = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "Measurement Method", OGS_PFCP_MEASUREMENT_METHOD_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_measurement_method_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_trigger_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_trigger = { OGS_TLV_VAR_STR, "Usage Report Trigger", @@ -477,7 +477,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_trigger_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_period_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_period = { OGS_TLV_VAR_STR, "Measurement Period", @@ -488,7 +488,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_period_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_fq_csid_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_fq_csid = { OGS_TLV_VAR_STR, "FQ-CSID", @@ -499,7 +499,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_fq_csid_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_measurement_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_measurement = { OGS_TLV_VAR_STR, "Volume Measurement", @@ -510,7 +510,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_measurement_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_duration_measurement_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_duration_measurement = { OGS_TLV_VAR_STR, "Duration Measurement", @@ -521,7 +521,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_duration_measurement_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_first_packet_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_first_packet = { OGS_TLV_VAR_STR, "Time of First Packet", @@ -532,7 +532,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_first_packet_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_last_packet_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_last_packet = { OGS_TLV_VAR_STR, "Time of Last Packet", @@ -543,7 +543,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_last_packet_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_holding_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_holding_time = { OGS_TLV_VAR_STR, "Quota Holding Time", @@ -554,7 +554,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_holding_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold = { OGS_TLV_VAR_STR, "Dropped DL Traffic Threshold", @@ -565,7 +565,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_quota_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_quota = { OGS_TLV_VAR_STR, "Volume Quota", @@ -576,7 +576,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_quota_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota = { OGS_TLV_VAR_STR, "Time Quota", @@ -587,7 +587,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_start_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_start_time = { OGS_TLV_VAR_STR, "Start Time", @@ -598,7 +598,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_start_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_end_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_end_time = { OGS_TLV_VAR_STR, "End Time", @@ -609,18 +609,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_end_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_urr_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_urr_id = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT32, "URR ID", OGS_PFCP_URR_ID_TYPE, - 0, + 4, 0, sizeof(ogs_pfcp_tlv_urr_id_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_linked_urr_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_linked_urr_id = { OGS_TLV_VAR_STR, "Linked URR ID", @@ -631,7 +631,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_linked_urr_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_creation_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_creation = { OGS_TLV_VAR_STR, "Outer Header Creation", @@ -642,29 +642,29 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_creation_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_bar_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_bar_id = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "BAR ID", OGS_PFCP_BAR_ID_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_bar_id_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_cp_function_features_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_cp_function_features = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "CP Function Features", OGS_PFCP_CP_FUNCTION_FEATURES_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_cp_function_features_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_information = { OGS_TLV_VAR_STR, "Usage Information", @@ -675,7 +675,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_instance_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_instance_id = { OGS_TLV_VAR_STR, "Application Instance ID", @@ -686,7 +686,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_instance_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_flow_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_flow_information = { OGS_TLV_VAR_STR, "Flow Information", @@ -697,7 +697,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_flow_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address = { OGS_TLV_VAR_STR, "UE IP Address", @@ -708,7 +708,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_rate_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_rate = { OGS_TLV_VAR_STR, "Packet Rate", @@ -719,7 +719,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_rate_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_removal_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_removal = { OGS_TLV_VAR_STR, "Outer Header Removal", @@ -730,18 +730,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_removal_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_recovery_time_stamp_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_recovery_time_stamp = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT32, "Recovery Time Stamp", OGS_PFCP_RECOVERY_TIME_STAMP_TYPE, - 0, + 4, 0, sizeof(ogs_pfcp_tlv_recovery_time_stamp_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_flow_level_marking_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_flow_level_marking = { OGS_TLV_VAR_STR, "DL Flow Level Marking", @@ -752,7 +752,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_flow_level_marking_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_header_enrichment_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_header_enrichment = { OGS_TLV_VAR_STR, "Header Enrichment", @@ -763,7 +763,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_header_enrichment_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_information = { OGS_TLV_VAR_STR, "Measurement Information", @@ -774,7 +774,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_report_type_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_report_type = { OGS_TLV_VAR_STR, "Node Report Type", @@ -785,7 +785,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_report_type_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remote_gtp_u_peer_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remote_gtp_u_peer = { OGS_TLV_VAR_STR, "Remote GTP-U Peer", @@ -796,7 +796,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remote_gtp_u_peer_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ur_seqn_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ur_seqn = { OGS_TLV_VAR_STR, "UR-SEQN", @@ -807,7 +807,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ur_seqn_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_activate_predefined_rules_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_activate_predefined_rules = { OGS_TLV_VAR_STR, "Activate Predefined Rules", @@ -818,7 +818,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_activate_predefined_rules_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivate_predefined_rules_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivate_predefined_rules = { OGS_TLV_VAR_STR, "Deactivate Predefined Rules", @@ -829,29 +829,29 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivate_predefined_rules_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_far_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_far_id = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT32, "FAR ID", OGS_PFCP_FAR_ID_TYPE, - 0, + 4, 0, sizeof(ogs_pfcp_tlv_far_id_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_id = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT32, "QER ID", OGS_PFCP_QER_ID_TYPE, - 0, + 4, 0, sizeof(ogs_pfcp_tlv_qer_id_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_oci_flags_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_oci_flags = { OGS_TLV_VAR_STR, "OCI Flags", @@ -862,7 +862,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_oci_flags_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_request_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_request = { OGS_TLV_VAR_STR, "PFCP Association Release Request", @@ -873,7 +873,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_request_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_graceful_release_period_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_graceful_release_period = { OGS_TLV_VAR_STR, "Graceful Release Period", @@ -884,18 +884,18 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_graceful_release_period_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdn_type_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdn_type = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "PDN Type", OGS_PFCP_PDN_TYPE_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_pdn_type_t), { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_failed_rule_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_failed_rule_id = { OGS_TLV_VAR_STR, "Failed Rule ID", @@ -906,7 +906,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_failed_rule_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_mechanism_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_mechanism = { OGS_TLV_VAR_STR, "Time Quota Mechanism", @@ -917,7 +917,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_mechanism_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_ip_resource_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_ip_resource_information = { OGS_TLV_VAR_STR, "User Plane IP Resource Information", @@ -928,7 +928,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_ip_resource_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_inactivity_timer_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_inactivity_timer = { OGS_TLV_VAR_STR, "User Plane Inactivity Timer", @@ -939,7 +939,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_inactivity_timer_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urrs_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urrs = { OGS_TLV_VAR_STR, "Aggregated URRs", @@ -950,7 +950,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urrs_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_multiplier_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_multiplier = { OGS_TLV_VAR_STR, "Multiplier", @@ -961,7 +961,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_multiplier_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urr_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urr_id = { OGS_TLV_VAR_STR, "Aggregated URR ID", @@ -972,7 +972,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urr_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_quota_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_quota = { OGS_TLV_VAR_STR, "Subsequent Volume Quota", @@ -983,7 +983,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_quota_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_quota_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_quota = { OGS_TLV_VAR_STR, "Subsequent Time Quota", @@ -994,7 +994,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_quota_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_rqi_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_rqi = { OGS_TLV_VAR_STR, "RQI", @@ -1005,7 +1005,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_rqi_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_qfi_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_qfi = { OGS_TLV_VAR_STR, "QFI", @@ -1016,7 +1016,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_qfi_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_reference_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_reference = { OGS_TLV_VAR_STR, "Query URR Reference", @@ -1027,7 +1027,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_reference_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_usage_reports_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_usage_reports_information = { OGS_TLV_VAR_STR, "Additional Usage Reports Information", @@ -1038,7 +1038,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_usage_reports_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_traffic_endpoint_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_traffic_endpoint = { OGS_TLV_VAR_STR, "Update Traffic Endpoint", @@ -1049,7 +1049,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_traffic_endpoint_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_traffic_endpoint_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_traffic_endpoint_id = { OGS_TLV_VAR_STR, "Traffic Endpoint ID", @@ -1060,7 +1060,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_traffic_endpoint_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_address_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_address = { OGS_TLV_VAR_STR, "MAC address", @@ -1071,7 +1071,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_address_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_c_tag_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_c_tag = { OGS_TLV_VAR_STR, "C-TAG", @@ -1082,7 +1082,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_c_tag_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_s_tag_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_s_tag = { OGS_TLV_VAR_STR, "S-TAG", @@ -1093,7 +1093,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_s_tag_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethertype_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethertype = { OGS_TLV_VAR_STR, "Ethertype", @@ -1104,7 +1104,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethertype_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_proxying_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_proxying = { OGS_TLV_VAR_STR, "Proxying", @@ -1115,7 +1115,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_proxying_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_id = { OGS_TLV_VAR_STR, "Ethernet Filter ID", @@ -1126,7 +1126,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_properties_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_properties = { OGS_TLV_VAR_STR, "Ethernet Filter Properties", @@ -1137,7 +1137,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_properties_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_suggested_buffering_packets_count_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_suggested_buffering_packets_count = { OGS_TLV_VAR_STR, "Suggested Buffering Packets Count", @@ -1148,7 +1148,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_suggested_buffering_packets_count_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_id = { OGS_TLV_VAR_STR, "User ID", @@ -1159,7 +1159,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_pdu_session_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_pdu_session_information = { OGS_TLV_VAR_STR, "Ethernet PDU Session Information", @@ -1170,7 +1170,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_pdu_session_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_detected_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_detected = { OGS_TLV_VAR_STR, "MAC Addresses Detected", @@ -1181,7 +1181,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_detected_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_removed_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_removed = { OGS_TLV_VAR_STR, "MAC Addresses Removed", @@ -1192,7 +1192,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_removed_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_inactivity_timer_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_inactivity_timer = { OGS_TLV_VAR_STR, "Ethernet Inactivity Timer", @@ -1203,7 +1203,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_inactivity_timer_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_monitoring_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_monitoring_time = { OGS_TLV_VAR_STR, "Additional Monitoring Time", @@ -1214,7 +1214,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_monitoring_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_quota_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_quota = { OGS_TLV_VAR_STR, "Event Quota", @@ -1225,7 +1225,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_quota_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_threshold_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_threshold = { OGS_TLV_VAR_STR, "Event Threshold", @@ -1236,7 +1236,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_threshold_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_quota_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_quota = { OGS_TLV_VAR_STR, "Subsequent Event Quota", @@ -1247,7 +1247,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_quota_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_threshold_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_threshold = { OGS_TLV_VAR_STR, "Subsequent Event Threshold", @@ -1258,7 +1258,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_threshold_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_trace_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_trace_information = { OGS_TLV_VAR_STR, "Trace Information", @@ -1269,7 +1269,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_trace_information_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_route_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_route = { OGS_TLV_VAR_STR, "Framed-Route", @@ -1280,7 +1280,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_route_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_routing_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_routing = { OGS_TLV_VAR_STR, "Framed-Routing", @@ -1291,7 +1291,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_routing_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_ipv6_route_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_ipv6_route = { OGS_TLV_VAR_STR, "Framed-IPv6-Route", @@ -1302,7 +1302,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_ipv6_route_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_time_stamp_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_time_stamp = { OGS_TLV_VAR_STR, "Event Time Stamp", @@ -1313,7 +1313,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_time_stamp_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_averaging_window_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_averaging_window = { OGS_TLV_VAR_STR, "Averaging Window", @@ -1324,7 +1324,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_averaging_window_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_paging_policy_indicator_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_paging_policy_indicator = { OGS_TLV_VAR_STR, "Paging Policy Indicator", @@ -1335,7 +1335,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_paging_policy_indicator_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_apn_dnn_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_apn_dnn = { OGS_TLV_VAR_STR, "APN/DNN", @@ -1346,7 +1346,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_apn_dnn_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc__interface_type_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc__interface_type = { OGS_TLV_VAR_STR, "3GPP Interface Type", @@ -1357,7 +1357,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc__interface_type_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrreq_flags_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrreq_flags = { OGS_TLV_VAR_STR, "PFCPSRReq-Flags", @@ -1368,7 +1368,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrreq_flags_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpaureq_flags_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpaureq_flags = { OGS_TLV_VAR_STR, "PFCPAUReq-Flags", @@ -1379,7 +1379,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpaureq_flags_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_activation_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_activation_time = { OGS_TLV_VAR_STR, "Activation Time", @@ -1390,7 +1390,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_activation_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivation_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivation_time = { OGS_TLV_VAR_STR, "Deactivation Time", @@ -1401,18 +1401,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivation_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_2_0 = -{ - OGS_TLV_VAR_STR, - "Access Forwarding Action Information 2", - OGS_PFCP_ACCESS_FORWARDING_ACTION_INFORMATION_2_TYPE, - 0, - 0, - sizeof(ogs_pfcp_tlv_access_forwarding_action_information_2_t), - { NULL } -}; - -ogs_tlv_desc_t ogs_pfcp_tlv_desc_mar_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_mar_id = { OGS_TLV_VAR_STR, "MAR ID", @@ -1423,7 +1412,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_mar_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_functionality_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_functionality = { OGS_TLV_VAR_STR, "Steering Functionality", @@ -1434,7 +1423,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_functionality_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_mode_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_mode = { OGS_TLV_VAR_STR, "Steering Mode", @@ -1445,7 +1434,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_mode_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_weight_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_weight = { OGS_TLV_VAR_STR, "Weight", @@ -1456,7 +1445,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_weight_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_priority_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_priority = { OGS_TLV_VAR_STR, "Priority", @@ -1467,18 +1456,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_priority_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_2_0 = -{ - OGS_TLV_VAR_STR, - "Update Access Forwarding Action Information 2", - OGS_PFCP_UPDATE_ACCESS_FORWARDING_ACTION_INFORMATION_2_TYPE, - 0, - 0, - sizeof(ogs_pfcp_tlv_update_access_forwarding_action_information_2_t), - { NULL } -}; - -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_pool_identity_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_pool_identity = { OGS_TLV_VAR_STR, "UE IP address Pool Identity", @@ -1489,7 +1467,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_pool_identity_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_alternative_smf_ip_address_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_alternative_smf_ip_address = { OGS_TLV_VAR_STR, "Alternative SMF IP Address", @@ -1500,7 +1478,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_alternative_smf_ip_address_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_information = { OGS_TLV_VAR_STR, "Packet Replication and Detection Carry-On Information", @@ -1511,7 +1489,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_infor { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_smf_set_id_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_smf_set_id = { OGS_TLV_VAR_STR, "SMF Set ID", @@ -1522,7 +1500,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_smf_set_id_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_validity_time_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_validity_time = { OGS_TLV_VAR_STR, "Quota Validity Time", @@ -1533,7 +1511,7 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_validity_time_0 = { NULL } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_packet_filter_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_packet_filter = { OGS_TLV_COMPOUND, "Ethernet Packet Filter", @@ -1542,18 +1520,19 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_packet_filter_0 = 0, sizeof(ogs_pfcp_tlv_ethernet_packet_filter_t), { - &ogs_pfcp_tlv_desc_ethernet_filter_id_0, - &ogs_pfcp_tlv_desc_ethernet_filter_properties_0, - &ogs_pfcp_tlv_desc_mac_address_0, - &ogs_pfcp_tlv_desc_ethertype_0, - &ogs_pfcp_tlv_desc_c_tag_0, - &ogs_pfcp_tlv_desc_s_tag_0, - &ogs_pfcp_tlv_desc_sdf_filter_0, + &ogs_pfcp_tlv_desc_ethernet_filter_id, + &ogs_pfcp_tlv_desc_ethernet_filter_properties, + &ogs_pfcp_tlv_desc_mac_address, + &ogs_pfcp_tlv_desc_ethertype, + &ogs_pfcp_tlv_desc_c_tag, + &ogs_pfcp_tlv_desc_s_tag, + &ogs_pfcp_tlv_desc_sdf_filter, + &ogs_tlv_desc_more4, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdi_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdi = { OGS_TLV_COMPOUND, "PDI", @@ -1562,25 +1541,26 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdi_0 = 0, sizeof(ogs_pfcp_tlv_pdi_t), { - &ogs_pfcp_tlv_desc_source_interface_0, - &ogs_pfcp_tlv_desc_f_teid_0, - &ogs_pfcp_tlv_desc_network_instance_0, - &ogs_pfcp_tlv_desc_ue_ip_address_0, - &ogs_pfcp_tlv_desc_traffic_endpoint_id_0, - &ogs_pfcp_tlv_desc_sdf_filter_0, - &ogs_pfcp_tlv_desc_application_id_0, - &ogs_pfcp_tlv_desc_ethernet_pdu_session_information_0, - &ogs_pfcp_tlv_desc_ethernet_packet_filter_0, - &ogs_pfcp_tlv_desc_qfi_0, - &ogs_pfcp_tlv_desc_framed_route_0, - &ogs_pfcp_tlv_desc_framed_routing_0, - &ogs_pfcp_tlv_desc_framed_ipv6_route_0, - &ogs_pfcp_tlv_desc__interface_type_0, + &ogs_pfcp_tlv_desc_source_interface, + &ogs_pfcp_tlv_desc_f_teid, + &ogs_pfcp_tlv_desc_network_instance, + &ogs_pfcp_tlv_desc_ue_ip_address, + &ogs_pfcp_tlv_desc_traffic_endpoint_id, + &ogs_pfcp_tlv_desc_sdf_filter, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_application_id, + &ogs_pfcp_tlv_desc_ethernet_pdu_session_information, + &ogs_pfcp_tlv_desc_ethernet_packet_filter, + &ogs_pfcp_tlv_desc_qfi, + &ogs_pfcp_tlv_desc_framed_route, + &ogs_pfcp_tlv_desc_framed_routing, + &ogs_pfcp_tlv_desc_framed_ipv6_route, + &ogs_pfcp_tlv_desc__interface_type, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_pdr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_pdr = { OGS_TLV_COMPOUND, "Create PDR", @@ -1589,48 +1569,23 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_pdr_0 = 0, sizeof(ogs_pfcp_tlv_create_pdr_t), { - &ogs_pfcp_tlv_desc_pdr_id_0, - &ogs_pfcp_tlv_desc_precedence_0, - &ogs_pfcp_tlv_desc_pdi_0, - &ogs_pfcp_tlv_desc_outer_header_removal_0, - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_qer_id_0, - &ogs_pfcp_tlv_desc_activate_predefined_rules_0, - &ogs_pfcp_tlv_desc_activation_time_0, - &ogs_pfcp_tlv_desc_deactivation_time_0, - &ogs_pfcp_tlv_desc_mar_id_0, - &ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_information_0, + &ogs_pfcp_tlv_desc_pdr_id, + &ogs_pfcp_tlv_desc_precedence, + &ogs_pfcp_tlv_desc_pdi, + &ogs_pfcp_tlv_desc_outer_header_removal, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_urr_id, + &ogs_pfcp_tlv_desc_qer_id, + &ogs_pfcp_tlv_desc_activate_predefined_rules, + &ogs_pfcp_tlv_desc_activation_time, + &ogs_pfcp_tlv_desc_deactivation_time, + &ogs_pfcp_tlv_desc_mar_id, + &ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_information, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_pdr_1 = -{ - OGS_TLV_COMPOUND, - "Create PDR", - OGS_PFCP_CREATE_PDR_TYPE, - 0, - 1, - sizeof(ogs_pfcp_tlv_create_pdr_t), - { - &ogs_pfcp_tlv_desc_pdr_id_0, - &ogs_pfcp_tlv_desc_precedence_0, - &ogs_pfcp_tlv_desc_pdi_0, - &ogs_pfcp_tlv_desc_outer_header_removal_0, - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_qer_id_0, - &ogs_pfcp_tlv_desc_activate_predefined_rules_0, - &ogs_pfcp_tlv_desc_activation_time_0, - &ogs_pfcp_tlv_desc_deactivation_time_0, - &ogs_pfcp_tlv_desc_mar_id_0, - &ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_information_0, - NULL, - } -}; - -ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_parameters_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_parameters = { OGS_TLV_COMPOUND, "Forwarding Parameters", @@ -1639,21 +1594,21 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_parameters_0 = 0, sizeof(ogs_pfcp_tlv_forwarding_parameters_t), { - &ogs_pfcp_tlv_desc_destination_interface_0, - &ogs_pfcp_tlv_desc_network_instance_0, - &ogs_pfcp_tlv_desc_redirect_information_0, - &ogs_pfcp_tlv_desc_outer_header_creation_0, - &ogs_pfcp_tlv_desc_transport_level_marking_0, - &ogs_pfcp_tlv_desc_forwarding_policy_0, - &ogs_pfcp_tlv_desc_header_enrichment_0, - &ogs_pfcp_tlv_desc_traffic_endpoint_id_0, - &ogs_pfcp_tlv_desc_proxying_0, - &ogs_pfcp_tlv_desc__interface_type_0, + &ogs_pfcp_tlv_desc_destination_interface, + &ogs_pfcp_tlv_desc_network_instance, + &ogs_pfcp_tlv_desc_redirect_information, + &ogs_pfcp_tlv_desc_outer_header_creation, + &ogs_pfcp_tlv_desc_transport_level_marking, + &ogs_pfcp_tlv_desc_forwarding_policy, + &ogs_pfcp_tlv_desc_header_enrichment, + &ogs_pfcp_tlv_desc_traffic_endpoint_id, + &ogs_pfcp_tlv_desc_proxying, + &ogs_pfcp_tlv_desc__interface_type, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_duplicating_parameters_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_duplicating_parameters = { OGS_TLV_COMPOUND, "Duplicating Parameters", @@ -1662,15 +1617,15 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_duplicating_parameters_0 = 0, sizeof(ogs_pfcp_tlv_duplicating_parameters_t), { - &ogs_pfcp_tlv_desc_destination_interface_0, - &ogs_pfcp_tlv_desc_outer_header_creation_0, - &ogs_pfcp_tlv_desc_transport_level_marking_0, - &ogs_pfcp_tlv_desc_forwarding_policy_0, + &ogs_pfcp_tlv_desc_destination_interface, + &ogs_pfcp_tlv_desc_outer_header_creation, + &ogs_pfcp_tlv_desc_transport_level_marking, + &ogs_pfcp_tlv_desc_forwarding_policy, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_far_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_far = { OGS_TLV_COMPOUND, "Create FAR", @@ -1679,34 +1634,16 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_far_0 = 0, sizeof(ogs_pfcp_tlv_create_far_t), { - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_apply_action_0, - &ogs_pfcp_tlv_desc_forwarding_parameters_0, - &ogs_pfcp_tlv_desc_duplicating_parameters_0, - &ogs_pfcp_tlv_desc_bar_id_0, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_apply_action, + &ogs_pfcp_tlv_desc_forwarding_parameters, + &ogs_pfcp_tlv_desc_duplicating_parameters, + &ogs_pfcp_tlv_desc_bar_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_far_1 = -{ - OGS_TLV_COMPOUND, - "Create FAR", - OGS_PFCP_CREATE_FAR_TYPE, - 0, - 1, - sizeof(ogs_pfcp_tlv_create_far_t), - { - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_apply_action_0, - &ogs_pfcp_tlv_desc_forwarding_parameters_0, - &ogs_pfcp_tlv_desc_duplicating_parameters_0, - &ogs_pfcp_tlv_desc_bar_id_0, - NULL, - } -}; - -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_forwarding_parameters_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_forwarding_parameters = { OGS_TLV_COMPOUND, "Update Forwarding Parameters", @@ -1715,21 +1652,21 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_forwarding_parameters_0 = 0, sizeof(ogs_pfcp_tlv_update_forwarding_parameters_t), { - &ogs_pfcp_tlv_desc_destination_interface_0, - &ogs_pfcp_tlv_desc_network_instance_0, - &ogs_pfcp_tlv_desc_redirect_information_0, - &ogs_pfcp_tlv_desc_outer_header_creation_0, - &ogs_pfcp_tlv_desc_transport_level_marking_0, - &ogs_pfcp_tlv_desc_forwarding_policy_0, - &ogs_pfcp_tlv_desc_header_enrichment_0, - &ogs_pfcp_tlv_desc_pfcpsmreq_flags_0, - &ogs_pfcp_tlv_desc_traffic_endpoint_id_0, - &ogs_pfcp_tlv_desc__interface_type_0, + &ogs_pfcp_tlv_desc_destination_interface, + &ogs_pfcp_tlv_desc_network_instance, + &ogs_pfcp_tlv_desc_redirect_information, + &ogs_pfcp_tlv_desc_outer_header_creation, + &ogs_pfcp_tlv_desc_transport_level_marking, + &ogs_pfcp_tlv_desc_forwarding_policy, + &ogs_pfcp_tlv_desc_header_enrichment, + &ogs_pfcp_tlv_desc_pfcpsmreq_flags, + &ogs_pfcp_tlv_desc_traffic_endpoint_id, + &ogs_pfcp_tlv_desc__interface_type, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_duplicating_parameters_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_duplicating_parameters = { OGS_TLV_COMPOUND, "Update Duplicating Parameters", @@ -1738,15 +1675,15 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_duplicating_parameters_0 = 0, sizeof(ogs_pfcp_tlv_update_duplicating_parameters_t), { - &ogs_pfcp_tlv_desc_destination_interface_0, - &ogs_pfcp_tlv_desc_outer_header_creation_0, - &ogs_pfcp_tlv_desc_transport_level_marking_0, - &ogs_pfcp_tlv_desc_forwarding_policy_0, + &ogs_pfcp_tlv_desc_destination_interface, + &ogs_pfcp_tlv_desc_outer_header_creation, + &ogs_pfcp_tlv_desc_transport_level_marking, + &ogs_pfcp_tlv_desc_forwarding_policy, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_far_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_far = { OGS_TLV_COMPOUND, "Update FAR", @@ -1755,16 +1692,16 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_far_0 = 0, sizeof(ogs_pfcp_tlv_update_far_t), { - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_apply_action_0, - &ogs_pfcp_tlv_desc_update_forwarding_parameters_0, - &ogs_pfcp_tlv_desc_update_duplicating_parameters_0, - &ogs_pfcp_tlv_desc_bar_id_0, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_apply_action, + &ogs_pfcp_tlv_desc_update_forwarding_parameters, + &ogs_pfcp_tlv_desc_update_duplicating_parameters, + &ogs_pfcp_tlv_desc_bar_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_context_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_context = { OGS_TLV_COMPOUND, "PFD context", @@ -1773,12 +1710,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_context_0 = 0, sizeof(ogs_pfcp_tlv_pfd_context_t), { - &ogs_pfcp_tlv_desc_pfd_contents_0, + &ogs_pfcp_tlv_desc_pfd_contents, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_s_pfds_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_s_pfds = { OGS_TLV_COMPOUND, "Application ID's PFDs", @@ -1787,13 +1724,13 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_s_pfds_0 = 0, sizeof(ogs_pfcp_tlv_application_id_s_pfds_t), { - &ogs_pfcp_tlv_desc_application_id_0, - &ogs_pfcp_tlv_desc_pfd_context_0, + &ogs_pfcp_tlv_desc_application_id, + &ogs_pfcp_tlv_desc_pfd_context, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_traffic_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_traffic_information = { OGS_TLV_COMPOUND, "Ethernet Traffic Information", @@ -1802,13 +1739,13 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_traffic_information_0 = 0, sizeof(ogs_pfcp_tlv_ethernet_traffic_information_t), { - &ogs_pfcp_tlv_desc_mac_addresses_detected_0, - &ogs_pfcp_tlv_desc_mac_addresses_removed_0, + &ogs_pfcp_tlv_desc_mac_addresses_detected, + &ogs_pfcp_tlv_desc_mac_addresses_removed, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_1_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_1 = { OGS_TLV_COMPOUND, "Access Forwarding Action Information 1", @@ -1817,15 +1754,32 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_1_0 = 0, sizeof(ogs_pfcp_tlv_access_forwarding_action_information_1_t), { - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_weight_0, - &ogs_pfcp_tlv_desc_priority_0, - &ogs_pfcp_tlv_desc_urr_id_0, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_weight, + &ogs_pfcp_tlv_desc_priority, + &ogs_pfcp_tlv_desc_urr_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_1_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_2 = +{ + OGS_TLV_COMPOUND, + "Access Forwarding Action Information 2", + OGS_PFCP_ACCESS_FORWARDING_ACTION_INFORMATION_2_TYPE, + 0, + 0, + sizeof(ogs_pfcp_tlv_access_forwarding_action_information_2_t), + { + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_weight, + &ogs_pfcp_tlv_desc_priority, + &ogs_pfcp_tlv_desc_urr_id, + NULL, + } +}; + +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_1 = { OGS_TLV_COMPOUND, "Update Access Forwarding Action Information 1", @@ -1834,15 +1788,32 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_1_0 0, sizeof(ogs_pfcp_tlv_update_access_forwarding_action_information_1_t), { - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_weight_0, - &ogs_pfcp_tlv_desc_priority_0, - &ogs_pfcp_tlv_desc_urr_id_0, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_weight, + &ogs_pfcp_tlv_desc_priority, + &ogs_pfcp_tlv_desc_urr_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_urr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_2 = +{ + OGS_TLV_COMPOUND, + "Update Access Forwarding Action Information 2", + OGS_PFCP_UPDATE_ACCESS_FORWARDING_ACTION_INFORMATION_2_TYPE, + 0, + 0, + sizeof(ogs_pfcp_tlv_update_access_forwarding_action_information_2_t), + { + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_weight, + &ogs_pfcp_tlv_desc_priority, + &ogs_pfcp_tlv_desc_urr_id, + NULL, + } +}; + +ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_urr = { OGS_TLV_COMPOUND, "Create URR", @@ -1851,39 +1822,39 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_urr_0 = 0, sizeof(ogs_pfcp_tlv_create_urr_t), { - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_measurement_method_0, - &ogs_pfcp_tlv_desc_reporting_triggers_0, - &ogs_pfcp_tlv_desc_measurement_period_0, - &ogs_pfcp_tlv_desc_volume_threshold_0, - &ogs_pfcp_tlv_desc_volume_quota_0, - &ogs_pfcp_tlv_desc_event_threshold_0, - &ogs_pfcp_tlv_desc_event_quota_0, - &ogs_pfcp_tlv_desc_time_threshold_0, - &ogs_pfcp_tlv_desc_time_quota_0, - &ogs_pfcp_tlv_desc_quota_holding_time_0, - &ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold_0, - &ogs_pfcp_tlv_desc_quota_validity_time_0, - &ogs_pfcp_tlv_desc_monitoring_time_0, - &ogs_pfcp_tlv_desc_subsequent_volume_threshold_0, - &ogs_pfcp_tlv_desc_subsequent_time_threshold_0, - &ogs_pfcp_tlv_desc_subsequent_volume_quota_0, - &ogs_pfcp_tlv_desc_subsequent_time_quota_0, - &ogs_pfcp_tlv_desc_subsequent_event_threshold_0, - &ogs_pfcp_tlv_desc_subsequent_event_quota_0, - &ogs_pfcp_tlv_desc_inactivity_detection_time_0, - &ogs_pfcp_tlv_desc_linked_urr_id_0, - &ogs_pfcp_tlv_desc_measurement_information_0, - &ogs_pfcp_tlv_desc_time_quota_mechanism_0, - &ogs_pfcp_tlv_desc_aggregated_urrs_0, - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_ethernet_inactivity_timer_0, - &ogs_pfcp_tlv_desc_additional_monitoring_time_0, + &ogs_pfcp_tlv_desc_urr_id, + &ogs_pfcp_tlv_desc_measurement_method, + &ogs_pfcp_tlv_desc_reporting_triggers, + &ogs_pfcp_tlv_desc_measurement_period, + &ogs_pfcp_tlv_desc_volume_threshold, + &ogs_pfcp_tlv_desc_volume_quota, + &ogs_pfcp_tlv_desc_event_threshold, + &ogs_pfcp_tlv_desc_event_quota, + &ogs_pfcp_tlv_desc_time_threshold, + &ogs_pfcp_tlv_desc_time_quota, + &ogs_pfcp_tlv_desc_quota_holding_time, + &ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold, + &ogs_pfcp_tlv_desc_quota_validity_time, + &ogs_pfcp_tlv_desc_monitoring_time, + &ogs_pfcp_tlv_desc_subsequent_volume_threshold, + &ogs_pfcp_tlv_desc_subsequent_time_threshold, + &ogs_pfcp_tlv_desc_subsequent_volume_quota, + &ogs_pfcp_tlv_desc_subsequent_time_quota, + &ogs_pfcp_tlv_desc_subsequent_event_threshold, + &ogs_pfcp_tlv_desc_subsequent_event_quota, + &ogs_pfcp_tlv_desc_inactivity_detection_time, + &ogs_pfcp_tlv_desc_linked_urr_id, + &ogs_pfcp_tlv_desc_measurement_information, + &ogs_pfcp_tlv_desc_time_quota_mechanism, + &ogs_pfcp_tlv_desc_aggregated_urrs, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_ethernet_inactivity_timer, + &ogs_pfcp_tlv_desc_additional_monitoring_time, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_qer_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_qer = { OGS_TLV_COMPOUND, "Create QER", @@ -1892,22 +1863,22 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_qer_0 = 0, sizeof(ogs_pfcp_tlv_create_qer_t), { - &ogs_pfcp_tlv_desc_qer_id_0, - &ogs_pfcp_tlv_desc_qer_correlation_id_0, - &ogs_pfcp_tlv_desc_gate_status_0, - &ogs_pfcp_tlv_desc_mbr_0, - &ogs_pfcp_tlv_desc_gbr_0, - &ogs_pfcp_tlv_desc_packet_rate_0, - &ogs_pfcp_tlv_desc_dl_flow_level_marking_0, - &ogs_pfcp_tlv_desc_qfi_0, - &ogs_pfcp_tlv_desc_rqi_0, - &ogs_pfcp_tlv_desc_paging_policy_indicator_0, - &ogs_pfcp_tlv_desc_averaging_window_0, + &ogs_pfcp_tlv_desc_qer_id, + &ogs_pfcp_tlv_desc_qer_correlation_id, + &ogs_pfcp_tlv_desc_gate_status, + &ogs_pfcp_tlv_desc_mbr, + &ogs_pfcp_tlv_desc_gbr, + &ogs_pfcp_tlv_desc_packet_rate, + &ogs_pfcp_tlv_desc_dl_flow_level_marking, + &ogs_pfcp_tlv_desc_qfi, + &ogs_pfcp_tlv_desc_rqi, + &ogs_pfcp_tlv_desc_paging_policy_indicator, + &ogs_pfcp_tlv_desc_averaging_window, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_pdr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_pdr = { OGS_TLV_COMPOUND, "Created PDR", @@ -1916,14 +1887,14 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_pdr_0 = 0, sizeof(ogs_pfcp_tlv_created_pdr_t), { - &ogs_pfcp_tlv_desc_pdr_id_0, - &ogs_pfcp_tlv_desc_f_teid_0, - &ogs_pfcp_tlv_desc_ue_ip_address_0, + &ogs_pfcp_tlv_desc_pdr_id, + &ogs_pfcp_tlv_desc_f_teid, + &ogs_pfcp_tlv_desc_ue_ip_address, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_pdr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_pdr = { OGS_TLV_COMPOUND, "Update PDR", @@ -1932,46 +1903,22 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_pdr_0 = 0, sizeof(ogs_pfcp_tlv_update_pdr_t), { - &ogs_pfcp_tlv_desc_pdr_id_0, - &ogs_pfcp_tlv_desc_outer_header_removal_0, - &ogs_pfcp_tlv_desc_precedence_0, - &ogs_pfcp_tlv_desc_pdi_0, - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_qer_id_0, - &ogs_pfcp_tlv_desc_activate_predefined_rules_0, - &ogs_pfcp_tlv_desc_deactivate_predefined_rules_0, - &ogs_pfcp_tlv_desc_activation_time_0, - &ogs_pfcp_tlv_desc_deactivation_time_0, + &ogs_pfcp_tlv_desc_pdr_id, + &ogs_pfcp_tlv_desc_outer_header_removal, + &ogs_pfcp_tlv_desc_precedence, + &ogs_pfcp_tlv_desc_pdi, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_urr_id, + &ogs_pfcp_tlv_desc_qer_id, + &ogs_pfcp_tlv_desc_activate_predefined_rules, + &ogs_pfcp_tlv_desc_deactivate_predefined_rules, + &ogs_pfcp_tlv_desc_activation_time, + &ogs_pfcp_tlv_desc_deactivation_time, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_pdr_1 = -{ - OGS_TLV_COMPOUND, - "Update PDR", - OGS_PFCP_UPDATE_PDR_TYPE, - 0, - 1, - sizeof(ogs_pfcp_tlv_update_pdr_t), - { - &ogs_pfcp_tlv_desc_pdr_id_0, - &ogs_pfcp_tlv_desc_outer_header_removal_0, - &ogs_pfcp_tlv_desc_precedence_0, - &ogs_pfcp_tlv_desc_pdi_0, - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_qer_id_0, - &ogs_pfcp_tlv_desc_activate_predefined_rules_0, - &ogs_pfcp_tlv_desc_deactivate_predefined_rules_0, - &ogs_pfcp_tlv_desc_activation_time_0, - &ogs_pfcp_tlv_desc_deactivation_time_0, - NULL, - } -}; - -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_pfcp_session_report_response_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_pfcp_session_report_response = { OGS_TLV_COMPOUND, "Update BAR PFCP Session Report Response", @@ -1980,16 +1927,16 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_pfcp_session_report_response_0 = 0, sizeof(ogs_pfcp_tlv_update_bar_pfcp_session_report_response_t), { - &ogs_pfcp_tlv_desc_bar_id_0, - &ogs_pfcp_tlv_desc_downlink_data_notification_delay_0, - &ogs_pfcp_tlv_desc_dl_buffering_duration_0, - &ogs_pfcp_tlv_desc_dl_buffering_suggested_packet_count_0, - &ogs_pfcp_tlv_desc_suggested_buffering_packets_count_0, + &ogs_pfcp_tlv_desc_bar_id, + &ogs_pfcp_tlv_desc_downlink_data_notification_delay, + &ogs_pfcp_tlv_desc_dl_buffering_duration, + &ogs_pfcp_tlv_desc_dl_buffering_suggested_packet_count, + &ogs_pfcp_tlv_desc_suggested_buffering_packets_count, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_urr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_urr = { OGS_TLV_COMPOUND, "Update URR", @@ -1998,39 +1945,39 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_urr_0 = 0, sizeof(ogs_pfcp_tlv_update_urr_t), { - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_measurement_method_0, - &ogs_pfcp_tlv_desc_reporting_triggers_0, - &ogs_pfcp_tlv_desc_measurement_period_0, - &ogs_pfcp_tlv_desc_volume_threshold_0, - &ogs_pfcp_tlv_desc_volume_quota_0, - &ogs_pfcp_tlv_desc_time_threshold_0, - &ogs_pfcp_tlv_desc_time_quota_0, - &ogs_pfcp_tlv_desc_event_threshold_0, - &ogs_pfcp_tlv_desc_event_quota_0, - &ogs_pfcp_tlv_desc_quota_holding_time_0, - &ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold_0, - &ogs_pfcp_tlv_desc_quota_validity_time_0, - &ogs_pfcp_tlv_desc_monitoring_time_0, - &ogs_pfcp_tlv_desc_subsequent_volume_threshold_0, - &ogs_pfcp_tlv_desc_subsequent_time_threshold_0, - &ogs_pfcp_tlv_desc_subsequent_volume_quota_0, - &ogs_pfcp_tlv_desc_subsequent_time_quota_0, - &ogs_pfcp_tlv_desc_subsequent_event_threshold_0, - &ogs_pfcp_tlv_desc_subsequent_event_quota_0, - &ogs_pfcp_tlv_desc_inactivity_detection_time_0, - &ogs_pfcp_tlv_desc_linked_urr_id_0, - &ogs_pfcp_tlv_desc_measurement_information_0, - &ogs_pfcp_tlv_desc_time_quota_mechanism_0, - &ogs_pfcp_tlv_desc_aggregated_urrs_0, - &ogs_pfcp_tlv_desc_far_id_0, - &ogs_pfcp_tlv_desc_ethernet_inactivity_timer_0, - &ogs_pfcp_tlv_desc_additional_monitoring_time_0, + &ogs_pfcp_tlv_desc_urr_id, + &ogs_pfcp_tlv_desc_measurement_method, + &ogs_pfcp_tlv_desc_reporting_triggers, + &ogs_pfcp_tlv_desc_measurement_period, + &ogs_pfcp_tlv_desc_volume_threshold, + &ogs_pfcp_tlv_desc_volume_quota, + &ogs_pfcp_tlv_desc_time_threshold, + &ogs_pfcp_tlv_desc_time_quota, + &ogs_pfcp_tlv_desc_event_threshold, + &ogs_pfcp_tlv_desc_event_quota, + &ogs_pfcp_tlv_desc_quota_holding_time, + &ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold, + &ogs_pfcp_tlv_desc_quota_validity_time, + &ogs_pfcp_tlv_desc_monitoring_time, + &ogs_pfcp_tlv_desc_subsequent_volume_threshold, + &ogs_pfcp_tlv_desc_subsequent_time_threshold, + &ogs_pfcp_tlv_desc_subsequent_volume_quota, + &ogs_pfcp_tlv_desc_subsequent_time_quota, + &ogs_pfcp_tlv_desc_subsequent_event_threshold, + &ogs_pfcp_tlv_desc_subsequent_event_quota, + &ogs_pfcp_tlv_desc_inactivity_detection_time, + &ogs_pfcp_tlv_desc_linked_urr_id, + &ogs_pfcp_tlv_desc_measurement_information, + &ogs_pfcp_tlv_desc_time_quota_mechanism, + &ogs_pfcp_tlv_desc_aggregated_urrs, + &ogs_pfcp_tlv_desc_far_id, + &ogs_pfcp_tlv_desc_ethernet_inactivity_timer, + &ogs_pfcp_tlv_desc_additional_monitoring_time, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_qer_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_qer = { OGS_TLV_COMPOUND, "Update QER", @@ -2039,22 +1986,22 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_qer_0 = 0, sizeof(ogs_pfcp_tlv_update_qer_t), { - &ogs_pfcp_tlv_desc_qer_id_0, - &ogs_pfcp_tlv_desc_qer_correlation_id_0, - &ogs_pfcp_tlv_desc_gate_status_0, - &ogs_pfcp_tlv_desc_mbr_0, - &ogs_pfcp_tlv_desc_gbr_0, - &ogs_pfcp_tlv_desc_packet_rate_0, - &ogs_pfcp_tlv_desc_dl_flow_level_marking_0, - &ogs_pfcp_tlv_desc_qfi_0, - &ogs_pfcp_tlv_desc_rqi_0, - &ogs_pfcp_tlv_desc_paging_policy_indicator_0, - &ogs_pfcp_tlv_desc_averaging_window_0, + &ogs_pfcp_tlv_desc_qer_id, + &ogs_pfcp_tlv_desc_qer_correlation_id, + &ogs_pfcp_tlv_desc_gate_status, + &ogs_pfcp_tlv_desc_mbr, + &ogs_pfcp_tlv_desc_gbr, + &ogs_pfcp_tlv_desc_packet_rate, + &ogs_pfcp_tlv_desc_dl_flow_level_marking, + &ogs_pfcp_tlv_desc_qfi, + &ogs_pfcp_tlv_desc_rqi, + &ogs_pfcp_tlv_desc_paging_policy_indicator, + &ogs_pfcp_tlv_desc_averaging_window, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_pdr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_pdr = { OGS_TLV_COMPOUND, "Remove PDR", @@ -2063,12 +2010,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_pdr_0 = 0, sizeof(ogs_pfcp_tlv_remove_pdr_t), { - &ogs_pfcp_tlv_desc_pdr_id_0, + &ogs_pfcp_tlv_desc_pdr_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_far_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_far = { OGS_TLV_COMPOUND, "Remove FAR", @@ -2077,12 +2024,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_far_0 = 0, sizeof(ogs_pfcp_tlv_remove_far_t), { - &ogs_pfcp_tlv_desc_far_id_0, + &ogs_pfcp_tlv_desc_far_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_urr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_urr = { OGS_TLV_COMPOUND, "Remove URR", @@ -2091,12 +2038,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_urr_0 = 0, sizeof(ogs_pfcp_tlv_remove_urr_t), { - &ogs_pfcp_tlv_desc_urr_id_0, + &ogs_pfcp_tlv_desc_urr_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_qer_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_qer = { OGS_TLV_COMPOUND, "Remove QER", @@ -2105,12 +2052,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_qer_0 = 0, sizeof(ogs_pfcp_tlv_remove_qer_t), { - &ogs_pfcp_tlv_desc_qer_id_0, + &ogs_pfcp_tlv_desc_qer_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_load_control_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_load_control_information = { OGS_TLV_COMPOUND, "Load Control Information", @@ -2119,13 +2066,13 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_load_control_information_0 = 0, sizeof(ogs_pfcp_tlv_load_control_information_t), { - &ogs_pfcp_tlv_desc_sequence_number_0, - &ogs_pfcp_tlv_desc_metric_0, + &ogs_pfcp_tlv_desc_sequence_number, + &ogs_pfcp_tlv_desc_metric, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_overload_control_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_overload_control_information = { OGS_TLV_COMPOUND, "Overload Control Information", @@ -2134,15 +2081,15 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_overload_control_information_0 = 0, sizeof(ogs_pfcp_tlv_overload_control_information_t), { - &ogs_pfcp_tlv_desc_sequence_number_0, - &ogs_pfcp_tlv_desc_metric_0, - &ogs_pfcp_tlv_desc_timer_0, - &ogs_pfcp_tlv_desc_oci_flags_0, + &ogs_pfcp_tlv_desc_sequence_number, + &ogs_pfcp_tlv_desc_metric, + &ogs_pfcp_tlv_desc_timer, + &ogs_pfcp_tlv_desc_oci_flags, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_detection_information_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_detection_information = { OGS_TLV_COMPOUND, "Application Detection Information", @@ -2151,14 +2098,14 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_detection_information_0 = 0, sizeof(ogs_pfcp_tlv_application_detection_information_t), { - &ogs_pfcp_tlv_desc_application_id_0, - &ogs_pfcp_tlv_desc_application_instance_id_0, - &ogs_pfcp_tlv_desc_flow_information_0, + &ogs_pfcp_tlv_desc_application_id, + &ogs_pfcp_tlv_desc_application_instance_id, + &ogs_pfcp_tlv_desc_flow_information, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr = { OGS_TLV_COMPOUND, "Query URR", @@ -2167,12 +2114,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_0 = 0, sizeof(ogs_pfcp_tlv_query_urr_t), { - &ogs_pfcp_tlv_desc_urr_id_0, + &ogs_pfcp_tlv_desc_urr_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_modification_response_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_modification_response = { OGS_TLV_COMPOUND, "Usage Report Session Modification Response", @@ -2181,23 +2128,23 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_modification_response_0 = 0, sizeof(ogs_pfcp_tlv_usage_report_session_modification_response_t), { - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_ur_seqn_0, - &ogs_pfcp_tlv_desc_usage_report_trigger_0, - &ogs_pfcp_tlv_desc_start_time_0, - &ogs_pfcp_tlv_desc_end_time_0, - &ogs_pfcp_tlv_desc_volume_measurement_0, - &ogs_pfcp_tlv_desc_duration_measurement_0, - &ogs_pfcp_tlv_desc_time_of_first_packet_0, - &ogs_pfcp_tlv_desc_time_of_last_packet_0, - &ogs_pfcp_tlv_desc_usage_information_0, - &ogs_pfcp_tlv_desc_query_urr_reference_0, - &ogs_pfcp_tlv_desc_ethernet_traffic_information_0, + &ogs_pfcp_tlv_desc_urr_id, + &ogs_pfcp_tlv_desc_ur_seqn, + &ogs_pfcp_tlv_desc_usage_report_trigger, + &ogs_pfcp_tlv_desc_start_time, + &ogs_pfcp_tlv_desc_end_time, + &ogs_pfcp_tlv_desc_volume_measurement, + &ogs_pfcp_tlv_desc_duration_measurement, + &ogs_pfcp_tlv_desc_time_of_first_packet, + &ogs_pfcp_tlv_desc_time_of_last_packet, + &ogs_pfcp_tlv_desc_usage_information, + &ogs_pfcp_tlv_desc_query_urr_reference, + &ogs_pfcp_tlv_desc_ethernet_traffic_information, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_deletion_response_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_deletion_response = { OGS_TLV_COMPOUND, "Usage Report Session Deletion Response", @@ -2206,22 +2153,22 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_deletion_response_0 = 0, sizeof(ogs_pfcp_tlv_usage_report_session_deletion_response_t), { - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_ur_seqn_0, - &ogs_pfcp_tlv_desc_usage_report_trigger_0, - &ogs_pfcp_tlv_desc_start_time_0, - &ogs_pfcp_tlv_desc_end_time_0, - &ogs_pfcp_tlv_desc_volume_measurement_0, - &ogs_pfcp_tlv_desc_duration_measurement_0, - &ogs_pfcp_tlv_desc_time_of_first_packet_0, - &ogs_pfcp_tlv_desc_time_of_last_packet_0, - &ogs_pfcp_tlv_desc_usage_information_0, - &ogs_pfcp_tlv_desc_ethernet_traffic_information_0, + &ogs_pfcp_tlv_desc_urr_id, + &ogs_pfcp_tlv_desc_ur_seqn, + &ogs_pfcp_tlv_desc_usage_report_trigger, + &ogs_pfcp_tlv_desc_start_time, + &ogs_pfcp_tlv_desc_end_time, + &ogs_pfcp_tlv_desc_volume_measurement, + &ogs_pfcp_tlv_desc_duration_measurement, + &ogs_pfcp_tlv_desc_time_of_first_packet, + &ogs_pfcp_tlv_desc_time_of_last_packet, + &ogs_pfcp_tlv_desc_usage_information, + &ogs_pfcp_tlv_desc_ethernet_traffic_information, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_report_request_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_report_request = { OGS_TLV_COMPOUND, "Usage Report Session Report Request", @@ -2230,27 +2177,27 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_report_request_0 = 0, sizeof(ogs_pfcp_tlv_usage_report_session_report_request_t), { - &ogs_pfcp_tlv_desc_urr_id_0, - &ogs_pfcp_tlv_desc_ur_seqn_0, - &ogs_pfcp_tlv_desc_usage_report_trigger_0, - &ogs_pfcp_tlv_desc_start_time_0, - &ogs_pfcp_tlv_desc_end_time_0, - &ogs_pfcp_tlv_desc_volume_measurement_0, - &ogs_pfcp_tlv_desc_duration_measurement_0, - &ogs_pfcp_tlv_desc_application_detection_information_0, - &ogs_pfcp_tlv_desc_ue_ip_address_0, - &ogs_pfcp_tlv_desc_network_instance_0, - &ogs_pfcp_tlv_desc_time_of_first_packet_0, - &ogs_pfcp_tlv_desc_time_of_last_packet_0, - &ogs_pfcp_tlv_desc_usage_information_0, - &ogs_pfcp_tlv_desc_query_urr_reference_0, - &ogs_pfcp_tlv_desc_event_time_stamp_0, - &ogs_pfcp_tlv_desc_ethernet_traffic_information_0, + &ogs_pfcp_tlv_desc_urr_id, + &ogs_pfcp_tlv_desc_ur_seqn, + &ogs_pfcp_tlv_desc_usage_report_trigger, + &ogs_pfcp_tlv_desc_start_time, + &ogs_pfcp_tlv_desc_end_time, + &ogs_pfcp_tlv_desc_volume_measurement, + &ogs_pfcp_tlv_desc_duration_measurement, + &ogs_pfcp_tlv_desc_application_detection_information, + &ogs_pfcp_tlv_desc_ue_ip_address, + &ogs_pfcp_tlv_desc_network_instance, + &ogs_pfcp_tlv_desc_time_of_first_packet, + &ogs_pfcp_tlv_desc_time_of_last_packet, + &ogs_pfcp_tlv_desc_usage_information, + &ogs_pfcp_tlv_desc_query_urr_reference, + &ogs_pfcp_tlv_desc_event_time_stamp, + &ogs_pfcp_tlv_desc_ethernet_traffic_information, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_report_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_report = { OGS_TLV_COMPOUND, "Downlink Data Report", @@ -2259,13 +2206,13 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_report_0 = 0, sizeof(ogs_pfcp_tlv_downlink_data_report_t), { - &ogs_pfcp_tlv_desc_pdr_id_0, - &ogs_pfcp_tlv_desc_downlink_data_service_information_0, + &ogs_pfcp_tlv_desc_pdr_id, + &ogs_pfcp_tlv_desc_downlink_data_service_information, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_bar_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_bar = { OGS_TLV_COMPOUND, "Create BAR", @@ -2274,14 +2221,14 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_bar_0 = 0, sizeof(ogs_pfcp_tlv_create_bar_t), { - &ogs_pfcp_tlv_desc_bar_id_0, - &ogs_pfcp_tlv_desc_downlink_data_notification_delay_0, - &ogs_pfcp_tlv_desc_suggested_buffering_packets_count_0, + &ogs_pfcp_tlv_desc_bar_id, + &ogs_pfcp_tlv_desc_downlink_data_notification_delay, + &ogs_pfcp_tlv_desc_suggested_buffering_packets_count, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_session_modification_request_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_session_modification_request = { OGS_TLV_COMPOUND, "Update BAR Session Modification Request", @@ -2290,14 +2237,14 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_session_modification_request_0 = 0, sizeof(ogs_pfcp_tlv_update_bar_session_modification_request_t), { - &ogs_pfcp_tlv_desc_bar_id_0, - &ogs_pfcp_tlv_desc_downlink_data_notification_delay_0, - &ogs_pfcp_tlv_desc_suggested_buffering_packets_count_0, + &ogs_pfcp_tlv_desc_bar_id, + &ogs_pfcp_tlv_desc_downlink_data_notification_delay, + &ogs_pfcp_tlv_desc_suggested_buffering_packets_count, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_bar_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_bar = { OGS_TLV_COMPOUND, "Remove BAR", @@ -2306,12 +2253,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_bar_0 = 0, sizeof(ogs_pfcp_tlv_remove_bar_t), { - &ogs_pfcp_tlv_desc_bar_id_0, + &ogs_pfcp_tlv_desc_bar_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_error_indication_report_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_error_indication_report = { OGS_TLV_COMPOUND, "Error Indication Report", @@ -2320,12 +2267,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_error_indication_report_0 = 0, sizeof(ogs_pfcp_tlv_error_indication_report_t), { - &ogs_pfcp_tlv_desc_f_teid_0, + &ogs_pfcp_tlv_desc_f_teid, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_path_failure_report_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_path_failure_report = { OGS_TLV_COMPOUND, "User Plane Path Failure Report", @@ -2334,12 +2281,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_path_failure_report_0 = 0, sizeof(ogs_pfcp_tlv_user_plane_path_failure_report_t), { - &ogs_pfcp_tlv_desc_remote_gtp_u_peer_0, + &ogs_pfcp_tlv_desc_remote_gtp_u_peer, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_traffic_endpoint_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_traffic_endpoint = { OGS_TLV_COMPOUND, "Create Traffic Endpoint", @@ -2348,20 +2295,20 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_traffic_endpoint_0 = 0, sizeof(ogs_pfcp_tlv_create_traffic_endpoint_t), { - &ogs_pfcp_tlv_desc_traffic_endpoint_id_0, - &ogs_pfcp_tlv_desc_f_teid_0, - &ogs_pfcp_tlv_desc_network_instance_0, - &ogs_pfcp_tlv_desc_ue_ip_address_0, - &ogs_pfcp_tlv_desc_ethernet_pdu_session_information_0, - &ogs_pfcp_tlv_desc_framed_route_0, - &ogs_pfcp_tlv_desc_framed_routing_0, - &ogs_pfcp_tlv_desc_framed_ipv6_route_0, - &ogs_pfcp_tlv_desc_qfi_0, + &ogs_pfcp_tlv_desc_traffic_endpoint_id, + &ogs_pfcp_tlv_desc_f_teid, + &ogs_pfcp_tlv_desc_network_instance, + &ogs_pfcp_tlv_desc_ue_ip_address, + &ogs_pfcp_tlv_desc_ethernet_pdu_session_information, + &ogs_pfcp_tlv_desc_framed_route, + &ogs_pfcp_tlv_desc_framed_routing, + &ogs_pfcp_tlv_desc_framed_ipv6_route, + &ogs_pfcp_tlv_desc_qfi, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_traffic_endpoint_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_traffic_endpoint = { OGS_TLV_COMPOUND, "Created Traffic Endpoint", @@ -2370,14 +2317,14 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_traffic_endpoint_0 = 0, sizeof(ogs_pfcp_tlv_created_traffic_endpoint_t), { - &ogs_pfcp_tlv_desc_traffic_endpoint_id_0, - &ogs_pfcp_tlv_desc_f_teid_0, - &ogs_pfcp_tlv_desc_ue_ip_address_0, + &ogs_pfcp_tlv_desc_traffic_endpoint_id, + &ogs_pfcp_tlv_desc_f_teid, + &ogs_pfcp_tlv_desc_ue_ip_address, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_traffic_endpoint_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_traffic_endpoint = { OGS_TLV_COMPOUND, "Remove Traffic Endpoint", @@ -2386,12 +2333,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_traffic_endpoint_0 = 0, sizeof(ogs_pfcp_tlv_remove_traffic_endpoint_t), { - &ogs_pfcp_tlv_desc_traffic_endpoint_id_0, + &ogs_pfcp_tlv_desc_traffic_endpoint_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_mar_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_mar = { OGS_TLV_COMPOUND, "Create MAR", @@ -2400,16 +2347,16 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_mar_0 = 0, sizeof(ogs_pfcp_tlv_create_mar_t), { - &ogs_pfcp_tlv_desc_mar_id_0, - &ogs_pfcp_tlv_desc_steering_functionality_0, - &ogs_pfcp_tlv_desc_steering_mode_0, - &ogs_pfcp_tlv_desc_access_forwarding_action_information_1_0, - &ogs_pfcp_tlv_desc_access_forwarding_action_information_2_0, + &ogs_pfcp_tlv_desc_mar_id, + &ogs_pfcp_tlv_desc_steering_functionality, + &ogs_pfcp_tlv_desc_steering_mode, + &ogs_pfcp_tlv_desc_access_forwarding_action_information_1, + &ogs_pfcp_tlv_desc_access_forwarding_action_information_2, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_mar_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_mar = { OGS_TLV_COMPOUND, "Remove MAR", @@ -2418,12 +2365,12 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_mar_0 = 0, sizeof(ogs_pfcp_tlv_remove_mar_t), { - &ogs_pfcp_tlv_desc_mar_id_0, + &ogs_pfcp_tlv_desc_mar_id, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_mar_0 = +ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_mar = { OGS_TLV_COMPOUND, "Update MAR", @@ -2432,133 +2379,136 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_mar_0 = 0, sizeof(ogs_pfcp_tlv_update_mar_t), { - &ogs_pfcp_tlv_desc_mar_id_0, - &ogs_pfcp_tlv_desc_steering_functionality_0, - &ogs_pfcp_tlv_desc_steering_mode_0, - &ogs_pfcp_tlv_desc_update_access_forwarding_action_information_1_0, - &ogs_pfcp_tlv_desc_update_access_forwarding_action_information_2_0, - &ogs_pfcp_tlv_desc_access_forwarding_action_information_1_0, - &ogs_pfcp_tlv_desc_access_forwarding_action_information_2_0, + &ogs_pfcp_tlv_desc_mar_id, + &ogs_pfcp_tlv_desc_steering_functionality, + &ogs_pfcp_tlv_desc_steering_mode, + &ogs_pfcp_tlv_desc_update_access_forwarding_action_information_1, + &ogs_pfcp_tlv_desc_update_access_forwarding_action_information_2, + &ogs_pfcp_tlv_desc_access_forwarding_action_information_1, + &ogs_pfcp_tlv_desc_access_forwarding_action_information_2, NULL, } }; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_heartbeat_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_heartbeat_request = { OGS_TLV_MESSAGE, "PFCP Heartbeat Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_recovery_time_stamp_0, + &ogs_pfcp_tlv_desc_recovery_time_stamp, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_heartbeat_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_heartbeat_response = { OGS_TLV_MESSAGE, "PFCP Heartbeat Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_recovery_time_stamp_0, + &ogs_pfcp_tlv_desc_recovery_time_stamp, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_pfd_management_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_pfd_management_request = { OGS_TLV_MESSAGE, "PFCP PFD Management Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_pfd_context_0, + &ogs_pfcp_tlv_desc_pfd_context, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_pfd_management_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_pfd_management_response = { OGS_TLV_MESSAGE, "PFCP PFD Management Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_offending_ie_0, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_offending_ie, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_setup_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_setup_request = { OGS_TLV_MESSAGE, "PFCP Association Setup Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_recovery_time_stamp_0, - &ogs_pfcp_tlv_desc_up_function_features_0, - &ogs_pfcp_tlv_desc_cp_function_features_0, - &ogs_pfcp_tlv_desc_user_plane_ip_resource_information_0, - &ogs_pfcp_tlv_desc_ue_ip_address_0, - &ogs_pfcp_tlv_desc_alternative_smf_ip_address_0, - &ogs_pfcp_tlv_desc_smf_set_id_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_recovery_time_stamp, + &ogs_pfcp_tlv_desc_up_function_features, + &ogs_pfcp_tlv_desc_cp_function_features, + &ogs_pfcp_tlv_desc_user_plane_ip_resource_information, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_ue_ip_address, + &ogs_pfcp_tlv_desc_alternative_smf_ip_address, + &ogs_pfcp_tlv_desc_smf_set_id, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_setup_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_setup_response = { OGS_TLV_MESSAGE, "PFCP Association Setup Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_recovery_time_stamp_0, - &ogs_pfcp_tlv_desc_up_function_features_0, - &ogs_pfcp_tlv_desc_cp_function_features_0, - &ogs_pfcp_tlv_desc_user_plane_ip_resource_information_0, - &ogs_pfcp_tlv_desc_alternative_smf_ip_address_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_recovery_time_stamp, + &ogs_pfcp_tlv_desc_up_function_features, + &ogs_pfcp_tlv_desc_cp_function_features, + &ogs_pfcp_tlv_desc_user_plane_ip_resource_information, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_alternative_smf_ip_address, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_update_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_update_request = { OGS_TLV_MESSAGE, "PFCP Association Update Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_up_function_features_0, - &ogs_pfcp_tlv_desc_cp_function_features_0, - &ogs_pfcp_tlv_desc_pfcp_association_release_request_0, - &ogs_pfcp_tlv_desc_graceful_release_period_0, - &ogs_pfcp_tlv_desc_user_plane_ip_resource_information_0, - &ogs_pfcp_tlv_desc_pfcpaureq_flags_0, - &ogs_pfcp_tlv_desc_alternative_smf_ip_address_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_up_function_features, + &ogs_pfcp_tlv_desc_cp_function_features, + &ogs_pfcp_tlv_desc_pfcp_association_release_request, + &ogs_pfcp_tlv_desc_graceful_release_period, + &ogs_pfcp_tlv_desc_user_plane_ip_resource_information, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_pfcpaureq_flags, + &ogs_pfcp_tlv_desc_alternative_smf_ip_address, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_update_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_update_response = { OGS_TLV_MESSAGE, "PFCP Association Update Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_up_function_features_0, - &ogs_pfcp_tlv_desc_cp_function_features_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_up_function_features, + &ogs_pfcp_tlv_desc_cp_function_features, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_release_request = { OGS_TLV_MESSAGE, "PFCP Association Release Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, + &ogs_pfcp_tlv_desc_node_id, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_release_response = { OGS_TLV_MESSAGE, "PFCP Association Release Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_cause_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_cause, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_version_not_supported_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_version_not_supported_response = { OGS_TLV_MESSAGE, "PFCP Version Not Supported Response", @@ -2566,150 +2516,178 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_version_not_supported_response = NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_node_report_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_node_report_request = { OGS_TLV_MESSAGE, "PFCP Node Report Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_node_report_type_0, - &ogs_pfcp_tlv_desc_user_plane_path_failure_report_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_node_report_type, + &ogs_pfcp_tlv_desc_user_plane_path_failure_report, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_node_report_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_node_report_response = { OGS_TLV_MESSAGE, "PFCP Node Report Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_offending_ie_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_offending_ie, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_set_deletion_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_set_deletion_request = { OGS_TLV_MESSAGE, "PFCP Session Set Deletion Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_fq_csid_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_set_deletion_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_set_deletion_response = { OGS_TLV_MESSAGE, "PFCP Session Set Deletion Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_offending_ie_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_offending_ie, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_establishment_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_establishment_request = { OGS_TLV_MESSAGE, "PFCP Session Establishment Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_f_seid_0, - &ogs_pfcp_tlv_desc_create_pdr_0, - &ogs_pfcp_tlv_desc_create_pdr_1, - &ogs_pfcp_tlv_desc_create_far_0, - &ogs_pfcp_tlv_desc_create_far_1, - &ogs_pfcp_tlv_desc_create_urr_0, - &ogs_pfcp_tlv_desc_create_qer_0, - &ogs_pfcp_tlv_desc_create_bar_0, - &ogs_pfcp_tlv_desc_create_traffic_endpoint_0, - &ogs_pfcp_tlv_desc_pdn_type_0, - &ogs_pfcp_tlv_desc_fq_csid_0, - &ogs_pfcp_tlv_desc_user_plane_inactivity_timer_0, - &ogs_pfcp_tlv_desc_user_id_0, - &ogs_pfcp_tlv_desc_trace_information_0, - &ogs_pfcp_tlv_desc_apn_dnn_0, - &ogs_pfcp_tlv_desc_create_mar_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_f_seid, + &ogs_pfcp_tlv_desc_create_pdr, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_create_far, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_create_urr, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_create_qer, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_create_bar, + &ogs_pfcp_tlv_desc_create_traffic_endpoint, + &ogs_pfcp_tlv_desc_pdn_type, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_user_plane_inactivity_timer, + &ogs_pfcp_tlv_desc_user_id, + &ogs_pfcp_tlv_desc_trace_information, + &ogs_pfcp_tlv_desc_apn_dnn, + &ogs_pfcp_tlv_desc_create_mar, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_establishment_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_establishment_response = { OGS_TLV_MESSAGE, "PFCP Session Establishment Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_node_id_0, - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_offending_ie_0, - &ogs_pfcp_tlv_desc_f_seid_0, - &ogs_pfcp_tlv_desc_created_pdr_0, - &ogs_pfcp_tlv_desc_load_control_information_0, - &ogs_pfcp_tlv_desc_overload_control_information_0, - &ogs_pfcp_tlv_desc_fq_csid_0, - &ogs_pfcp_tlv_desc_failed_rule_id_0, - &ogs_pfcp_tlv_desc_created_traffic_endpoint_0, + &ogs_pfcp_tlv_desc_node_id, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_offending_ie, + &ogs_pfcp_tlv_desc_f_seid, + &ogs_pfcp_tlv_desc_created_pdr, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_load_control_information, + &ogs_pfcp_tlv_desc_overload_control_information, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_failed_rule_id, + &ogs_pfcp_tlv_desc_created_traffic_endpoint, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_modification_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_modification_request = { OGS_TLV_MESSAGE, "PFCP Session Modification Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_f_seid_0, - &ogs_pfcp_tlv_desc_remove_pdr_0, - &ogs_pfcp_tlv_desc_remove_far_0, - &ogs_pfcp_tlv_desc_remove_urr_0, - &ogs_pfcp_tlv_desc_remove_qer_0, - &ogs_pfcp_tlv_desc_remove_bar_0, - &ogs_pfcp_tlv_desc_remove_traffic_endpoint_0, - &ogs_pfcp_tlv_desc_create_pdr_0, - &ogs_pfcp_tlv_desc_create_pdr_1, - &ogs_pfcp_tlv_desc_create_far_0, - &ogs_pfcp_tlv_desc_create_far_1, - &ogs_pfcp_tlv_desc_create_urr_0, - &ogs_pfcp_tlv_desc_create_qer_0, - &ogs_pfcp_tlv_desc_create_bar_0, - &ogs_pfcp_tlv_desc_create_traffic_endpoint_0, - &ogs_pfcp_tlv_desc_update_pdr_0, - &ogs_pfcp_tlv_desc_update_pdr_1, - &ogs_pfcp_tlv_desc_update_far_0, - &ogs_pfcp_tlv_desc_update_urr_0, - &ogs_pfcp_tlv_desc_update_qer_0, - &ogs_pfcp_tlv_desc_update_bar_session_modification_request_0, - &ogs_pfcp_tlv_desc_update_traffic_endpoint_0, - &ogs_pfcp_tlv_desc_pfcpsmreq_flags_0, - &ogs_pfcp_tlv_desc_query_urr_0, - &ogs_pfcp_tlv_desc_fq_csid_0, - &ogs_pfcp_tlv_desc_user_plane_inactivity_timer_0, - &ogs_pfcp_tlv_desc_query_urr_reference_0, - &ogs_pfcp_tlv_desc_trace_information_0, - &ogs_pfcp_tlv_desc_remove_mar_0, - &ogs_pfcp_tlv_desc_update_mar_0, - &ogs_pfcp_tlv_desc_create_mar_0, - &ogs_pfcp_tlv_desc_node_id_0, + &ogs_pfcp_tlv_desc_f_seid, + &ogs_pfcp_tlv_desc_remove_pdr, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_remove_far, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_remove_urr, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_remove_qer, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_remove_bar, + &ogs_pfcp_tlv_desc_remove_traffic_endpoint, + &ogs_pfcp_tlv_desc_create_pdr, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_create_far, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_create_urr, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_create_qer, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_create_bar, + &ogs_pfcp_tlv_desc_create_traffic_endpoint, + &ogs_pfcp_tlv_desc_update_pdr, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_update_far, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_update_urr, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_update_qer, + &ogs_tlv_desc_more2, + &ogs_pfcp_tlv_desc_update_bar_session_modification_request, + &ogs_pfcp_tlv_desc_update_traffic_endpoint, + &ogs_pfcp_tlv_desc_pfcpsmreq_flags, + &ogs_pfcp_tlv_desc_query_urr, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_fq_csid, + &ogs_pfcp_tlv_desc_user_plane_inactivity_timer, + &ogs_pfcp_tlv_desc_query_urr_reference, + &ogs_pfcp_tlv_desc_trace_information, + &ogs_pfcp_tlv_desc_remove_mar, + &ogs_pfcp_tlv_desc_update_mar, + &ogs_pfcp_tlv_desc_create_mar, + &ogs_pfcp_tlv_desc_node_id, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_modification_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_modification_response = { OGS_TLV_MESSAGE, "PFCP Session Modification Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_offending_ie_0, - &ogs_pfcp_tlv_desc_created_pdr_0, - &ogs_pfcp_tlv_desc_load_control_information_0, - &ogs_pfcp_tlv_desc_overload_control_information_0, - &ogs_pfcp_tlv_desc_usage_report_session_modification_response_0, - &ogs_pfcp_tlv_desc_failed_rule_id_0, - &ogs_pfcp_tlv_desc_additional_usage_reports_information_0, - &ogs_pfcp_tlv_desc_created_traffic_endpoint_0, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_offending_ie, + &ogs_pfcp_tlv_desc_created_pdr, + &ogs_tlv_desc_more4, + &ogs_pfcp_tlv_desc_load_control_information, + &ogs_pfcp_tlv_desc_overload_control_information, + &ogs_pfcp_tlv_desc_usage_report_session_modification_response, + &ogs_pfcp_tlv_desc_failed_rule_id, + &ogs_pfcp_tlv_desc_additional_usage_reports_information, + &ogs_pfcp_tlv_desc_created_traffic_endpoint, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_deletion_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_deletion_request = { OGS_TLV_MESSAGE, "PFCP Session Deletion Request", @@ -2717,48 +2695,48 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_deletion_request = NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_deletion_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_deletion_response = { OGS_TLV_MESSAGE, "PFCP Session Deletion Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_offending_ie_0, - &ogs_pfcp_tlv_desc_load_control_information_0, - &ogs_pfcp_tlv_desc_overload_control_information_0, - &ogs_pfcp_tlv_desc_usage_report_session_deletion_response_0, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_offending_ie, + &ogs_pfcp_tlv_desc_load_control_information, + &ogs_pfcp_tlv_desc_overload_control_information, + &ogs_pfcp_tlv_desc_usage_report_session_deletion_response, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_report_request = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_report_request = { OGS_TLV_MESSAGE, "PFCP Session Report Request", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_report_type_0, - &ogs_pfcp_tlv_desc_downlink_data_report_0, - &ogs_pfcp_tlv_desc_usage_report_session_report_request_0, - &ogs_pfcp_tlv_desc_error_indication_report_0, - &ogs_pfcp_tlv_desc_load_control_information_0, - &ogs_pfcp_tlv_desc_overload_control_information_0, - &ogs_pfcp_tlv_desc_additional_usage_reports_information_0, - &ogs_pfcp_tlv_desc_pfcpsrreq_flags_0, - &ogs_pfcp_tlv_desc_f_seid_0, + &ogs_pfcp_tlv_desc_report_type, + &ogs_pfcp_tlv_desc_downlink_data_report, + &ogs_pfcp_tlv_desc_usage_report_session_report_request, + &ogs_pfcp_tlv_desc_error_indication_report, + &ogs_pfcp_tlv_desc_load_control_information, + &ogs_pfcp_tlv_desc_overload_control_information, + &ogs_pfcp_tlv_desc_additional_usage_reports_information, + &ogs_pfcp_tlv_desc_pfcpsrreq_flags, + &ogs_pfcp_tlv_desc_f_seid, NULL, }}; -ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_report_response = +ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_report_response = { OGS_TLV_MESSAGE, "PFCP Session Report Response", 0, 0, 0, 0, { - &ogs_pfcp_tlv_desc_cause_0, - &ogs_pfcp_tlv_desc_offending_ie_0, - &ogs_pfcp_tlv_desc_update_bar_pfcp_session_report_response_0, - &ogs_pfcp_tlv_desc_pfcpsrrsp_flags_0, - &ogs_pfcp_tlv_desc_f_seid_0, - &ogs_pfcp_tlv_desc_f_teid_0, - &ogs_pfcp_tlv_desc_alternative_smf_ip_address_0, + &ogs_pfcp_tlv_desc_cause, + &ogs_pfcp_tlv_desc_offending_ie, + &ogs_pfcp_tlv_desc_update_bar_pfcp_session_report_response, + &ogs_pfcp_tlv_desc_pfcpsrrsp_flags, + &ogs_pfcp_tlv_desc_f_seid, + &ogs_pfcp_tlv_desc_f_teid, + &ogs_pfcp_tlv_desc_alternative_smf_ip_address, NULL, }}; @@ -2778,7 +2756,7 @@ int ogs_pfcp_parse_msg(ogs_pfcp_message_t *pfcp_message, ogs_pkbuf_t *pkbuf) memset(pfcp_message, 0, sizeof(ogs_pfcp_message_t)); - if (h->seid_p) + if (h->seid_presence) size = OGS_PFCP_HEADER_LEN; else size = OGS_PFCP_HEADER_LEN-OGS_PFCP_SEID_LEN; @@ -2786,7 +2764,7 @@ int ogs_pfcp_parse_msg(ogs_pfcp_message_t *pfcp_message, ogs_pkbuf_t *pkbuf) ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(&pfcp_message->h, pkbuf->data - size, size); - if (h->seid_p) { + if (h->seid_presence) { pfcp_message->h.seid = be64toh(pfcp_message->h.seid); } else { pfcp_message->h.sqn = pfcp_message->h.sqn_only; @@ -2800,95 +2778,95 @@ int ogs_pfcp_parse_msg(ogs_pfcp_message_t *pfcp_message, ogs_pkbuf_t *pkbuf) { case OGS_PFCP_HEARTBEAT_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_heartbeat_request, - &ogs_pfcp_tlv_desc_pfcp_heartbeat_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_heartbeat_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_heartbeat_response, - &ogs_pfcp_tlv_desc_pfcp_heartbeat_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_heartbeat_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_PFD_MANAGEMENT_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_pfd_management_request, - &ogs_pfcp_tlv_desc_pfcp_pfd_management_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_pfd_management_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_PFD_MANAGEMENT_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_pfd_management_response, - &ogs_pfcp_tlv_desc_pfcp_pfd_management_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_pfd_management_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_association_setup_request, - &ogs_pfcp_tlv_desc_pfcp_association_setup_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_association_setup_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_association_setup_response, - &ogs_pfcp_tlv_desc_pfcp_association_setup_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_association_setup_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_UPDATE_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_association_update_request, - &ogs_pfcp_tlv_desc_pfcp_association_update_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_association_update_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_UPDATE_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_association_update_response, - &ogs_pfcp_tlv_desc_pfcp_association_update_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_association_update_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_RELEASE_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_association_release_request, - &ogs_pfcp_tlv_desc_pfcp_association_release_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_association_release_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_RELEASE_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_association_release_response, - &ogs_pfcp_tlv_desc_pfcp_association_release_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_association_release_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_version_not_supported_response, - &ogs_pfcp_tlv_desc_pfcp_version_not_supported_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_version_not_supported_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_NODE_REPORT_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_node_report_request, - &ogs_pfcp_tlv_desc_pfcp_node_report_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_node_report_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_NODE_REPORT_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_node_report_response, - &ogs_pfcp_tlv_desc_pfcp_node_report_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_node_report_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_SET_DELETION_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_set_deletion_request, - &ogs_pfcp_tlv_desc_pfcp_session_set_deletion_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_set_deletion_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_SET_DELETION_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_set_deletion_response, - &ogs_pfcp_tlv_desc_pfcp_session_set_deletion_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_set_deletion_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_establishment_request, - &ogs_pfcp_tlv_desc_pfcp_session_establishment_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_establishment_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_establishment_response, - &ogs_pfcp_tlv_desc_pfcp_session_establishment_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_establishment_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_modification_request, - &ogs_pfcp_tlv_desc_pfcp_session_modification_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_modification_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_modification_response, - &ogs_pfcp_tlv_desc_pfcp_session_modification_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_modification_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_deletion_request, - &ogs_pfcp_tlv_desc_pfcp_session_deletion_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_deletion_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_deletion_response, - &ogs_pfcp_tlv_desc_pfcp_session_deletion_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_deletion_response, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_report_request, - &ogs_pfcp_tlv_desc_pfcp_session_report_request, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_report_request, pkbuf, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE: rv = ogs_tlv_parse_msg(&pfcp_message->pfcp_session_report_response, - &ogs_pfcp_tlv_desc_pfcp_session_report_response, pkbuf, OGS_TLV_MODE_T2_L2); + &ogs_pfcp_msg_desc_pfcp_session_report_response, pkbuf, OGS_TLV_MODE_T2_L2); break; default: ogs_warn("Not implmeneted(type:%d)", pfcp_message->h.type); @@ -2906,95 +2884,95 @@ ogs_pkbuf_t *ogs_pfcp_build_msg(ogs_pfcp_message_t *pfcp_message) switch(pfcp_message->h.type) { case OGS_PFCP_HEARTBEAT_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_heartbeat_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_heartbeat_request, &pfcp_message->pfcp_heartbeat_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_heartbeat_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_heartbeat_response, &pfcp_message->pfcp_heartbeat_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_PFD_MANAGEMENT_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_pfd_management_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_pfd_management_request, &pfcp_message->pfcp_pfd_management_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_PFD_MANAGEMENT_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_pfd_management_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_pfd_management_response, &pfcp_message->pfcp_pfd_management_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_association_setup_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_association_setup_request, &pfcp_message->pfcp_association_setup_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_association_setup_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_association_setup_response, &pfcp_message->pfcp_association_setup_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_UPDATE_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_association_update_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_association_update_request, &pfcp_message->pfcp_association_update_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_UPDATE_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_association_update_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_association_update_response, &pfcp_message->pfcp_association_update_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_RELEASE_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_association_release_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_association_release_request, &pfcp_message->pfcp_association_release_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_ASSOCIATION_RELEASE_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_association_release_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_association_release_response, &pfcp_message->pfcp_association_release_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_version_not_supported_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_version_not_supported_response, &pfcp_message->pfcp_version_not_supported_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_NODE_REPORT_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_node_report_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_node_report_request, &pfcp_message->pfcp_node_report_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_NODE_REPORT_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_node_report_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_node_report_response, &pfcp_message->pfcp_node_report_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_SET_DELETION_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_set_deletion_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_set_deletion_request, &pfcp_message->pfcp_session_set_deletion_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_SET_DELETION_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_set_deletion_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_set_deletion_response, &pfcp_message->pfcp_session_set_deletion_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_establishment_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_establishment_request, &pfcp_message->pfcp_session_establishment_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_establishment_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_establishment_response, &pfcp_message->pfcp_session_establishment_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_modification_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_modification_request, &pfcp_message->pfcp_session_modification_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_modification_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_modification_response, &pfcp_message->pfcp_session_modification_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_deletion_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_deletion_request, &pfcp_message->pfcp_session_deletion_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_deletion_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_deletion_response, &pfcp_message->pfcp_session_deletion_response, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_report_request, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_report_request, &pfcp_message->pfcp_session_report_request, OGS_TLV_MODE_T2_L2); break; case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE: - pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_pfcp_session_report_response, + pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_pfcp_session_report_response, &pfcp_message->pfcp_session_report_response, OGS_TLV_MODE_T2_L2); break; default: diff --git a/lib/pfcp/message.h b/lib/pfcp/message.h index 80c173e19..65636ac40 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: 2019-12-05 22:18:23.140115 by acetcom + * Created on: 2020-04-22 22:57:07.579730 by acetcom * from 29244-g10.docx ******************************************************************************/ @@ -44,7 +44,7 @@ typedef struct ogs_pfcp_header_s { ED4(uint8_t version:3;, uint8_t spare1:3;, uint8_t mp:1;, - uint8_t seid_p:1;) + uint8_t seid_presence:1;) }; uint8_t flags; }; @@ -54,8 +54,8 @@ typedef struct ogs_pfcp_header_s { struct { uint64_t seid; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ -#define OGS_PFCP_XID_TO_SQN(__xid) htonl(((__xid) << 8)) -#define OGS_PFCP_SQN_TO_XID(__sqn) (ntohl(__sqn) >> 8) +#define OGS_PFCP_XID_TO_SQN(__xid) htobe32(((__xid) << 8)) +#define OGS_PFCP_SQN_TO_XID(__sqn) (be32toh(__sqn) >> 8) uint32_t sqn; }; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ @@ -271,230 +271,227 @@ typedef struct ogs_pfcp_header_s { #define OGS_PFCP_QUOTA_VALIDITY_TIME_TYPE 181 /* Infomration Element TLV Descriptor */ -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_cause_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_source_interface_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_teid_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_network_instance_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_sdf_filter_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_gate_status_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mbr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_gbr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_correlation_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_precedence_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_transport_level_marking_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_threshold_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_threshold_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_monitoring_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_threshold_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_threshold_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_inactivity_detection_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_reporting_triggers_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_redirect_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_report_type_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_offending_ie_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_policy_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_destination_interface_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_up_function_features_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_apply_action_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_service_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_notification_delay_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_duration_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_suggested_packet_count_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsmreq_flags_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrrsp_flags_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_sequence_number_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_metric_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_timer_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdr_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_seid_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_contents_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_method_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_trigger_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_period_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_fq_csid_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_measurement_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_duration_measurement_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_first_packet_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_last_packet_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_holding_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_quota_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_start_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_end_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_urr_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_linked_urr_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_creation_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_bar_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_cp_function_features_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_instance_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_flow_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_rate_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_removal_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_recovery_time_stamp_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_flow_level_marking_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_header_enrichment_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_report_type_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remote_gtp_u_peer_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ur_seqn_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_activate_predefined_rules_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivate_predefined_rules_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_far_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_oci_flags_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_request_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_graceful_release_period_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdn_type_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_failed_rule_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_mechanism_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_ip_resource_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_inactivity_timer_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urrs_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_multiplier_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urr_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_quota_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_quota_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_rqi_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_qfi_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_reference_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_usage_reports_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_traffic_endpoint_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_traffic_endpoint_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_address_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_c_tag_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_s_tag_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethertype_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_proxying_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_properties_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_suggested_buffering_packets_count_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_pdu_session_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_detected_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_removed_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_inactivity_timer_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_monitoring_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_quota_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_threshold_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_quota_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_threshold_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_trace_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_route_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_routing_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_ipv6_route_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_time_stamp_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_averaging_window_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_paging_policy_indicator_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_apn_dnn_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc__interface_type_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrreq_flags_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpaureq_flags_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_activation_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivation_time_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_2_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mar_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_functionality_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_mode_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_weight_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_priority_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_2_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_pool_identity_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_alternative_smf_ip_address_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_smf_set_id_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_validity_time_0; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_cause; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_source_interface; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_teid; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_network_instance; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_sdf_filter; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_gate_status; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mbr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_gbr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_correlation_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_precedence; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_transport_level_marking; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_threshold; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_threshold; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_monitoring_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_threshold; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_threshold; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_inactivity_detection_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_reporting_triggers; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_redirect_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_report_type; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_offending_ie; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_policy; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_destination_interface; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_up_function_features; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_apply_action; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_service_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_notification_delay; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_duration; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_buffering_suggested_packet_count; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsmreq_flags; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrrsp_flags; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_sequence_number; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_metric; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_timer; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdr_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_f_seid; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_contents; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_method; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_trigger; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_period; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_fq_csid; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_measurement; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_duration_measurement; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_first_packet; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_of_last_packet; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_holding_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dropped_dl_traffic_threshold; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_volume_quota; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_start_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_end_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_urr_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_linked_urr_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_creation; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_bar_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_cp_function_features; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_instance_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_flow_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_rate; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_outer_header_removal; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_recovery_time_stamp; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_dl_flow_level_marking; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_header_enrichment; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_measurement_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_node_report_type; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remote_gtp_u_peer; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ur_seqn; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_activate_predefined_rules; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivate_predefined_rules; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_far_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_qer_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_oci_flags; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_request; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_graceful_release_period; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdn_type; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_failed_rule_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_time_quota_mechanism; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_ip_resource_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_inactivity_timer; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urrs; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_multiplier; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_aggregated_urr_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_volume_quota; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_time_quota; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_rqi; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_qfi; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_reference; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_usage_reports_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_traffic_endpoint; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_traffic_endpoint_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_address; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_c_tag; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_s_tag; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethertype; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_proxying; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_filter_properties; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_suggested_buffering_packets_count; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_pdu_session_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_detected; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mac_addresses_removed; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_inactivity_timer; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_additional_monitoring_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_quota; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_threshold; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_quota; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_subsequent_event_threshold; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_trace_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_route; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_routing; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_framed_ipv6_route; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_event_time_stamp; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_averaging_window; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_paging_policy_indicator; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_apn_dnn; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc__interface_type; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsrreq_flags; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpaureq_flags; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_activation_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_deactivation_time; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_mar_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_functionality; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_steering_mode; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_weight; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_priority; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ue_ip_address_pool_identity; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_alternative_smf_ip_address; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_packet_replication_and_detection_carry_on_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_smf_set_id; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_quota_validity_time; /* Group Infomration Element TLV Descriptor */ -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_packet_filter_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdi_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_pdr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_pdr_1; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_parameters_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_duplicating_parameters_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_far_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_far_1; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_forwarding_parameters_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_duplicating_parameters_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_far_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_context_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_s_pfds_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_traffic_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_1_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_1_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_urr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_qer_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_pdr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_pdr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_pdr_1; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_pfcp_session_report_response_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_urr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_qer_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_pdr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_far_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_urr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_qer_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_load_control_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_overload_control_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_detection_information_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_modification_response_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_deletion_response_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_report_request_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_report_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_bar_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_session_modification_request_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_bar_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_error_indication_report_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_path_failure_report_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_traffic_endpoint_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_traffic_endpoint_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_traffic_endpoint_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_mar_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_mar_0; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_mar_0; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_packet_filter; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pdi; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_pdr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_forwarding_parameters; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_duplicating_parameters; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_far; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_forwarding_parameters; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_duplicating_parameters; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_far; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfd_context; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_id_s_pfds; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_ethernet_traffic_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_1; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_access_forwarding_action_information_2; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_1; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_access_forwarding_action_information_2; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_urr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_qer; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_pdr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_pdr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_pfcp_session_report_response; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_urr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_qer; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_pdr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_far; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_urr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_qer; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_load_control_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_overload_control_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_application_detection_information; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_query_urr; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_modification_response; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_deletion_response; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_usage_report_session_report_request; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_downlink_data_report; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_bar; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_bar_session_modification_request; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_bar; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_error_indication_report; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_user_plane_path_failure_report; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_traffic_endpoint; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_created_traffic_endpoint; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_traffic_endpoint; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_create_mar; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_remove_mar; +extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_update_mar; /* Message Descriptor */ -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_heartbeat_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_heartbeat_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_pfd_management_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_pfd_management_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_setup_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_setup_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_update_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_update_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_association_release_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_version_not_supported_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_node_report_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_node_report_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_set_deletion_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_set_deletion_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_establishment_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_establishment_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_modification_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_modification_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_deletion_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_deletion_response; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_report_request; -extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcp_session_report_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_heartbeat_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_heartbeat_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_pfd_management_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_pfd_management_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_setup_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_setup_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_update_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_update_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_release_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_association_release_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_version_not_supported_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_node_report_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_node_report_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_set_deletion_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_set_deletion_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_establishment_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_establishment_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_modification_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_modification_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_deletion_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_deletion_response; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_report_request; +extern ogs_tlv_desc_t ogs_pfcp_msg_desc_pfcp_session_report_response; /* Structure for Infomration Element */ -typedef ogs_tlv_octet_t ogs_pfcp_tlv_cause_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_source_interface_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_cause_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_source_interface_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_f_teid_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_network_instance_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_sdf_filter_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_application_id_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_gate_status_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_gate_status_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_mbr_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_gbr_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_qer_correlation_id_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_precedence_t; +typedef ogs_tlv_uint32_t ogs_pfcp_tlv_qer_correlation_id_t; +typedef ogs_tlv_uint32_t ogs_pfcp_tlv_precedence_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_transport_level_marking_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_volume_threshold_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_time_threshold_t; @@ -502,14 +499,14 @@ typedef ogs_tlv_octet_t ogs_pfcp_tlv_monitoring_time_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_subsequent_volume_threshold_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_subsequent_time_threshold_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_inactivity_detection_time_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_reporting_triggers_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_reporting_triggers_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_redirect_information_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_report_type_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_offending_ie_t; +typedef ogs_tlv_uint16_t ogs_pfcp_tlv_offending_ie_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_forwarding_policy_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_destination_interface_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_up_function_features_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_apply_action_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_destination_interface_t; +typedef ogs_tlv_uint16_t ogs_pfcp_tlv_up_function_features_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_apply_action_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_downlink_data_service_information_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_downlink_data_notification_delay_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_dl_buffering_duration_t; @@ -519,11 +516,11 @@ typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpsrrsp_flags_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_sequence_number_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_metric_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_timer_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_pdr_id_t; +typedef ogs_tlv_uint16_t ogs_pfcp_tlv_pdr_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_f_seid_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_node_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfd_contents_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_measurement_method_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_measurement_method_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_usage_report_trigger_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_measurement_period_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_fq_csid_t; @@ -537,18 +534,18 @@ typedef ogs_tlv_octet_t ogs_pfcp_tlv_volume_quota_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_time_quota_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_start_time_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_end_time_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_urr_id_t; +typedef ogs_tlv_uint32_t ogs_pfcp_tlv_urr_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_linked_urr_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_outer_header_creation_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_bar_id_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_cp_function_features_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_bar_id_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_cp_function_features_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_usage_information_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_application_instance_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_flow_information_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_ue_ip_address_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_packet_rate_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_outer_header_removal_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_recovery_time_stamp_t; +typedef ogs_tlv_uint32_t ogs_pfcp_tlv_recovery_time_stamp_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_dl_flow_level_marking_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_header_enrichment_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_measurement_information_t; @@ -557,12 +554,12 @@ typedef ogs_tlv_octet_t ogs_pfcp_tlv_remote_gtp_u_peer_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_ur_seqn_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_activate_predefined_rules_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_deactivate_predefined_rules_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_far_id_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_qer_id_t; +typedef ogs_tlv_uint32_t ogs_pfcp_tlv_far_id_t; +typedef ogs_tlv_uint32_t ogs_pfcp_tlv_qer_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_oci_flags_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcp_association_release_request_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_graceful_release_period_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_pdn_type_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_pdn_type_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_failed_rule_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_time_quota_mechanism_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_user_plane_ip_resource_information_t; @@ -609,13 +606,11 @@ typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpsrreq_flags_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpaureq_flags_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_activation_time_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_deactivation_time_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_access_forwarding_action_information_2_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_mar_id_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_steering_functionality_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_steering_mode_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_weight_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_priority_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_update_access_forwarding_action_information_2_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_ue_ip_address_pool_identity_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_alternative_smf_ip_address_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_packet_replication_and_detection_carry_on_information_t; @@ -631,17 +626,17 @@ typedef struct ogs_pfcp_tlv_ethernet_packet_filter_s { ogs_pfcp_tlv_ethertype_t ethertype; ogs_pfcp_tlv_c_tag_t c_tag; ogs_pfcp_tlv_s_tag_t s_tag; - ogs_pfcp_tlv_sdf_filter_t sdf_filter; + ogs_pfcp_tlv_sdf_filter_t sdf_filter[4]; } ogs_pfcp_tlv_ethernet_packet_filter_t; typedef struct ogs_pfcp_tlv_pdi_s { ogs_tlv_presence_t presence; ogs_pfcp_tlv_source_interface_t source_interface; - ogs_pfcp_tlv_f_teid_t local_f_teid; /* Instance : 0 */ + ogs_pfcp_tlv_f_teid_t local_f_teid; ogs_pfcp_tlv_network_instance_t network_instance; ogs_pfcp_tlv_ue_ip_address_t ue_ip_address; ogs_pfcp_tlv_traffic_endpoint_id_t traffic_endpoint_id; - ogs_pfcp_tlv_sdf_filter_t sdf_filter; + ogs_pfcp_tlv_sdf_filter_t sdf_filter[4]; ogs_pfcp_tlv_application_id_t application_id; ogs_pfcp_tlv_ethernet_pdu_session_information_t ethernet_pdu_session_information; ogs_pfcp_tlv_ethernet_packet_filter_t ethernet_packet_filter; @@ -755,6 +750,14 @@ typedef struct ogs_pfcp_tlv_access_forwarding_action_information_1_s { ogs_pfcp_tlv_urr_id_t urr_id; } ogs_pfcp_tlv_access_forwarding_action_information_1_t; +typedef struct ogs_pfcp_tlv_access_forwarding_action_information_2_s { + ogs_tlv_presence_t presence; + ogs_pfcp_tlv_far_id_t far_id; + ogs_pfcp_tlv_weight_t weight; + ogs_pfcp_tlv_priority_t priority; + ogs_pfcp_tlv_urr_id_t urr_id; +} ogs_pfcp_tlv_access_forwarding_action_information_2_t; + typedef struct ogs_pfcp_tlv_update_access_forwarding_action_information_1_s { ogs_tlv_presence_t presence; ogs_pfcp_tlv_far_id_t far_id; @@ -763,6 +766,14 @@ typedef struct ogs_pfcp_tlv_update_access_forwarding_action_information_1_s { ogs_pfcp_tlv_urr_id_t urr_id; } ogs_pfcp_tlv_update_access_forwarding_action_information_1_t; +typedef struct ogs_pfcp_tlv_update_access_forwarding_action_information_2_s { + ogs_tlv_presence_t presence; + ogs_pfcp_tlv_far_id_t far_id; + ogs_pfcp_tlv_weight_t weight; + ogs_pfcp_tlv_priority_t priority; + ogs_pfcp_tlv_urr_id_t urr_id; +} ogs_pfcp_tlv_update_access_forwarding_action_information_2_t; + typedef struct ogs_pfcp_tlv_create_urr_s { ogs_tlv_presence_t presence; ogs_pfcp_tlv_urr_id_t urr_id; @@ -813,7 +824,7 @@ typedef struct ogs_pfcp_tlv_create_qer_s { typedef struct ogs_pfcp_tlv_created_pdr_s { ogs_tlv_presence_t presence; ogs_pfcp_tlv_pdr_id_t pdr_id; - ogs_pfcp_tlv_f_teid_t local_f_teid; /* Instance : 0 */ + ogs_pfcp_tlv_f_teid_t local_f_teid; ogs_pfcp_tlv_ue_ip_address_t ue_ip_address; } ogs_pfcp_tlv_created_pdr_t; @@ -1012,7 +1023,7 @@ typedef struct ogs_pfcp_tlv_remove_bar_s { typedef struct ogs_pfcp_tlv_error_indication_report_s { ogs_tlv_presence_t presence; - ogs_pfcp_tlv_f_teid_t remote_f_teid; /* Instance : 0 */ + ogs_pfcp_tlv_f_teid_t remote_f_teid; } ogs_pfcp_tlv_error_indication_report_t; typedef struct ogs_pfcp_tlv_user_plane_path_failure_report_s { @@ -1023,7 +1034,7 @@ typedef struct ogs_pfcp_tlv_user_plane_path_failure_report_s { typedef struct ogs_pfcp_tlv_create_traffic_endpoint_s { ogs_tlv_presence_t presence; ogs_pfcp_tlv_traffic_endpoint_id_t traffic_endpoint_id; - ogs_pfcp_tlv_f_teid_t local_f_teid; /* Instance : 0 */ + ogs_pfcp_tlv_f_teid_t local_f_teid; ogs_pfcp_tlv_network_instance_t network_instance; ogs_pfcp_tlv_ue_ip_address_t ue_ip_address; ogs_pfcp_tlv_ethernet_pdu_session_information_t ethernet_pdu_session_information; @@ -1036,7 +1047,7 @@ typedef struct ogs_pfcp_tlv_create_traffic_endpoint_s { typedef struct ogs_pfcp_tlv_created_traffic_endpoint_s { ogs_tlv_presence_t presence; ogs_pfcp_tlv_traffic_endpoint_id_t traffic_endpoint_id; - ogs_pfcp_tlv_f_teid_t local_f_teid; /* Instance : 0 */ + ogs_pfcp_tlv_f_teid_t local_f_teid; ogs_pfcp_tlv_ue_ip_address_t ue_ip_address; } ogs_pfcp_tlv_created_traffic_endpoint_t; @@ -1093,7 +1104,7 @@ typedef struct ogs_pfcp_association_setup_request_s { ogs_pfcp_tlv_recovery_time_stamp_t recovery_time_stamp; ogs_pfcp_tlv_up_function_features_t up_function_features; ogs_pfcp_tlv_cp_function_features_t cp_function_features; - ogs_pfcp_tlv_user_plane_ip_resource_information_t user_plane_ip_resource_information; + ogs_pfcp_tlv_user_plane_ip_resource_information_t user_plane_ip_resource_information[4]; ogs_pfcp_tlv_ue_ip_address_t ue_ip_address_pool_identity; ogs_pfcp_tlv_alternative_smf_ip_address_t alternative_smf_ip_address; ogs_pfcp_tlv_smf_set_id_t smf_set_id; @@ -1105,7 +1116,7 @@ typedef struct ogs_pfcp_association_setup_response_s { ogs_pfcp_tlv_recovery_time_stamp_t recovery_time_stamp; ogs_pfcp_tlv_up_function_features_t up_function_features; ogs_pfcp_tlv_cp_function_features_t cp_function_features; - ogs_pfcp_tlv_user_plane_ip_resource_information_t user_plane_ip_resource_information; + ogs_pfcp_tlv_user_plane_ip_resource_information_t user_plane_ip_resource_information[4]; ogs_pfcp_tlv_alternative_smf_ip_address_t alternative_smf_ip_address; } ogs_pfcp_association_setup_response_t; @@ -1115,7 +1126,7 @@ typedef struct ogs_pfcp_association_update_request_s { ogs_pfcp_tlv_cp_function_features_t cp_function_features; ogs_pfcp_tlv_pfcp_association_release_request_t pfcp_association_release_request; ogs_pfcp_tlv_graceful_release_period_t graceful_release_period; - ogs_pfcp_tlv_user_plane_ip_resource_information_t user_plane_ip_resource_information; + ogs_pfcp_tlv_user_plane_ip_resource_information_t user_plane_ip_resource_information[4]; ogs_pfcp_tlv_pfcpaureq_flags_t pfcpaureq_flags; ogs_pfcp_tlv_alternative_smf_ip_address_t alternative_smf_ip_address; } ogs_pfcp_association_update_request_t; @@ -1154,6 +1165,12 @@ typedef struct ogs_pfcp_node_report_response_s { typedef struct ogs_pfcp_session_set_deletion_request_s { ogs_pfcp_tlv_node_id_t node_id; ogs_pfcp_tlv_fq_csid_t sgw_c_fq_csid; + ogs_pfcp_tlv_fq_csid_t pgw_c_fq_csid; + ogs_pfcp_tlv_fq_csid_t sgw_u_fq_csid; + ogs_pfcp_tlv_fq_csid_t pgw_u_fq_csid; + ogs_pfcp_tlv_fq_csid_t twan_fq_csid; + ogs_pfcp_tlv_fq_csid_t epdg_fq_csid; + ogs_pfcp_tlv_fq_csid_t mme_fq_csid; } ogs_pfcp_session_set_deletion_request_t; typedef struct ogs_pfcp_session_set_deletion_response_s { @@ -1165,16 +1182,18 @@ typedef struct ogs_pfcp_session_set_deletion_response_s { typedef struct ogs_pfcp_session_establishment_request_s { ogs_pfcp_tlv_node_id_t node_id; ogs_pfcp_tlv_f_seid_t cp_f_seid; - ogs_pfcp_tlv_create_pdr_t create_pdr; - ogs_pfcp_tlv_create_pdr_t create_pdr1; - ogs_pfcp_tlv_create_far_t create_far; - ogs_pfcp_tlv_create_far_t create_far1; - ogs_pfcp_tlv_create_urr_t create_urr; - ogs_pfcp_tlv_create_qer_t create_qer; + ogs_pfcp_tlv_create_pdr_t create_pdr[4]; + ogs_pfcp_tlv_create_far_t create_far[4]; + ogs_pfcp_tlv_create_urr_t create_urr[2]; + ogs_pfcp_tlv_create_qer_t create_qer[2]; ogs_pfcp_tlv_create_bar_t create_bar; ogs_pfcp_tlv_create_traffic_endpoint_t create_traffic_endpoint; ogs_pfcp_tlv_pdn_type_t pdn_type; ogs_pfcp_tlv_fq_csid_t sgw_c_fq_csid; + ogs_pfcp_tlv_fq_csid_t mme_fq_csid; + ogs_pfcp_tlv_fq_csid_t pgw_c_fq_csid; + ogs_pfcp_tlv_fq_csid_t epdg_fq_csid; + ogs_pfcp_tlv_fq_csid_t twan_fq_csid; ogs_pfcp_tlv_user_plane_inactivity_timer_t user_plane_inactivity_timer; ogs_pfcp_tlv_user_id_t user_id; ogs_pfcp_tlv_trace_information_t trace_information; @@ -1187,40 +1206,42 @@ typedef struct ogs_pfcp_session_establishment_response_s { ogs_pfcp_tlv_cause_t cause; ogs_pfcp_tlv_offending_ie_t offending_ie; ogs_pfcp_tlv_f_seid_t up_f_seid; - ogs_pfcp_tlv_created_pdr_t created_pdr; + ogs_pfcp_tlv_created_pdr_t created_pdr[4]; ogs_pfcp_tlv_load_control_information_t load_control_information; ogs_pfcp_tlv_overload_control_information_t overload_control_information; ogs_pfcp_tlv_fq_csid_t sgw_u_fq_csid; + ogs_pfcp_tlv_fq_csid_t pgw_u_fq_csid; ogs_pfcp_tlv_failed_rule_id_t failed_rule_id; ogs_pfcp_tlv_created_traffic_endpoint_t created_traffic_endpoint; } ogs_pfcp_session_establishment_response_t; typedef struct ogs_pfcp_session_modification_request_s { ogs_pfcp_tlv_f_seid_t cp_f_seid; - ogs_pfcp_tlv_remove_pdr_t remove_pdr; - ogs_pfcp_tlv_remove_far_t remove_far; - ogs_pfcp_tlv_remove_urr_t remove_urr; - ogs_pfcp_tlv_remove_qer_t remove_qer; + ogs_pfcp_tlv_remove_pdr_t remove_pdr[4]; + ogs_pfcp_tlv_remove_far_t remove_far[4]; + ogs_pfcp_tlv_remove_urr_t remove_urr[2]; + ogs_pfcp_tlv_remove_qer_t remove_qer[2]; ogs_pfcp_tlv_remove_bar_t remove_bar; ogs_pfcp_tlv_remove_traffic_endpoint_t remove_traffic_endpoint; - ogs_pfcp_tlv_create_pdr_t create_pdr; - ogs_pfcp_tlv_create_pdr_t create_pdr1; - ogs_pfcp_tlv_create_far_t create_far; - ogs_pfcp_tlv_create_far_t create_far1; - ogs_pfcp_tlv_create_urr_t create_urr; - ogs_pfcp_tlv_create_qer_t create_qer; + ogs_pfcp_tlv_create_pdr_t create_pdr[4]; + ogs_pfcp_tlv_create_far_t create_far[4]; + ogs_pfcp_tlv_create_urr_t create_urr[2]; + ogs_pfcp_tlv_create_qer_t create_qer[2]; ogs_pfcp_tlv_create_bar_t create_bar; ogs_pfcp_tlv_create_traffic_endpoint_t create_traffic_endpoint; - ogs_pfcp_tlv_update_pdr_t update_pdr; - ogs_pfcp_tlv_update_pdr_t update_pdr1; - ogs_pfcp_tlv_update_far_t update_far; - ogs_pfcp_tlv_update_urr_t update_urr; - ogs_pfcp_tlv_update_qer_t update_qer; + ogs_pfcp_tlv_update_pdr_t update_pdr[4]; + ogs_pfcp_tlv_update_far_t update_far[4]; + ogs_pfcp_tlv_update_urr_t update_urr[2]; + ogs_pfcp_tlv_update_qer_t update_qer[2]; ogs_pfcp_tlv_update_bar_session_modification_request_t update_bar; ogs_pfcp_tlv_update_traffic_endpoint_t update_traffic_endpoint; ogs_pfcp_tlv_pfcpsmreq_flags_t pfcpsmreq_flags; ogs_pfcp_tlv_query_urr_t query_urr; ogs_pfcp_tlv_fq_csid_t pgw_c_fq_csid; + ogs_pfcp_tlv_fq_csid_t sgw_c_fq_csid; + ogs_pfcp_tlv_fq_csid_t mme_fq_csid; + ogs_pfcp_tlv_fq_csid_t epdg_fq_csid; + ogs_pfcp_tlv_fq_csid_t twan_fq_csid; ogs_pfcp_tlv_user_plane_inactivity_timer_t user_plane_inactivity_timer; ogs_pfcp_tlv_query_urr_reference_t query_urr_reference; ogs_pfcp_tlv_trace_information_t trace_information; @@ -1233,7 +1254,7 @@ typedef struct ogs_pfcp_session_modification_request_s { typedef struct ogs_pfcp_session_modification_response_s { ogs_pfcp_tlv_cause_t cause; ogs_pfcp_tlv_offending_ie_t offending_ie; - ogs_pfcp_tlv_created_pdr_t created_pdr; + ogs_pfcp_tlv_created_pdr_t created_pdr[4]; ogs_pfcp_tlv_load_control_information_t load_control_information; ogs_pfcp_tlv_overload_control_information_t overload_control_information; ogs_pfcp_tlv_usage_report_session_modification_response_t usage_report; diff --git a/lib/pfcp/n4-build.c b/lib/pfcp/n4-build.c new file mode 100644 index 000000000..3578ace88 --- /dev/null +++ b/lib/pfcp/n4-build.c @@ -0,0 +1,54 @@ +/* + * 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-pfcp.h" + +ogs_pkbuf_t *ogs_pfcp_n4_build_heartbeat_request(uint8_t type) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_heartbeat_request_t *req = NULL; + + ogs_debug("[PFCP] Heartbeat Request"); + + req = &pfcp_message.pfcp_heartbeat_request; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + req->recovery_time_stamp.presence = 1; + req->recovery_time_stamp.u32 = ogs_pfcp_self()->pfcp_started; + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} + +ogs_pkbuf_t *ogs_pfcp_n4_build_heartbeat_response(uint8_t type) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_heartbeat_response_t *rsp = NULL; + + ogs_debug("[PFCP] Heartbeat Response"); + + rsp = &pfcp_message.pfcp_heartbeat_response; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + rsp->recovery_time_stamp.presence = 1; + rsp->recovery_time_stamp.u32 = ogs_pfcp_self()->pfcp_started; + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} diff --git a/lib/pfcp/n4-build.h b/lib/pfcp/n4-build.h new file mode 100644 index 000000000..20f4c5426 --- /dev/null +++ b/lib/pfcp/n4-build.h @@ -0,0 +1,34 @@ +/* + * 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_PFCP_N4_BUILD_H +#define OGS_PFCP_N4_BUILD_H + +#ifdef __cplusplus +extern "C" { +#endif + +ogs_pkbuf_t *ogs_pfcp_n4_build_heartbeat_request(uint8_t type); +ogs_pkbuf_t *ogs_pfcp_n4_build_heartbeat_response(uint8_t type); + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_PFCP_N4_BUILD_H */ diff --git a/lib/pfcp/node.c b/lib/pfcp/node.c deleted file mode 100644 index bb4406277..000000000 --- a/lib/pfcp/node.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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-pfcp.h" - -static OGS_POOL(pool, ogs_pfcp_node_t); - -int ogs_pfcp_node_init(int size) -{ - ogs_pool_init(&pool, size); - - return OGS_OK; -} -int ogs_pfcp_node_final(void) -{ - ogs_pool_final(&pool); - - return OGS_OK; -} - -ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *sa_list) -{ - ogs_pfcp_node_t *node = NULL; - - ogs_assert(sa_list); - - ogs_pool_alloc(&pool, &node); - ogs_assert(node); - memset(node, 0, sizeof(ogs_pfcp_node_t)); - - node->sa_list = sa_list; - - ogs_list_init(&node->local_list); - ogs_list_init(&node->remote_list); - - return node; -} - -void ogs_pfcp_node_free(ogs_pfcp_node_t *node) -{ - ogs_assert(node); - - if (node->sock) - ogs_sock_destroy(node->sock); - - ogs_pfcp_xact_delete_all(node); - - ogs_freeaddrinfo(node->sa_list); - ogs_pool_free(&pool, node); -} - -ogs_pfcp_node_t *ogs_pfcp_node_add(ogs_list_t *list, ogs_pfcp_f_seid_t *f_seid, - uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4) -{ - int rv; - ogs_pfcp_node_t *node = NULL; - ogs_sockaddr_t *addr = NULL; - - ogs_assert(list); - ogs_assert(f_seid); - ogs_assert(port); - - rv = ogs_pfcp_f_seid_to_sockaddr(f_seid, port, &addr); - ogs_assert(rv == OGS_OK); - - rv = ogs_filter_ip_version(&addr, no_ipv4, no_ipv6, prefer_ipv4); - ogs_assert(addr); - - rv = ogs_socknode_fill_scope_id_in_local(addr); - ogs_assert(rv == OGS_OK); - - node = ogs_pfcp_node_new(addr); - ogs_assert(node); - - rv = ogs_pfcp_f_seid_to_ip(f_seid, &node->ip); - ogs_assert(rv == OGS_OK); - - ogs_list_add(list, node); - - return node; -} - -ogs_pfcp_node_t *ogs_pfcp_node_add_by_addr( - ogs_list_t *list, ogs_sockaddr_t *addr) -{ - ogs_pfcp_node_t *gnode = NULL; - ogs_sockaddr_t *new = NULL; - - ogs_assert(list); - ogs_assert(addr); - - ogs_copyaddrinfo(&new, addr); - gnode = ogs_pfcp_node_new(new); - - ogs_assert(gnode); - memcpy(&gnode->remote_addr, new, sizeof gnode->remote_addr); - - ogs_list_add(list, gnode); - - return gnode; -} - -void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node) -{ - ogs_assert(node); - - ogs_list_remove(list, node); - - ogs_pfcp_node_free(node); -} - -void ogs_pfcp_node_remove_all(ogs_list_t *list) -{ - ogs_pfcp_node_t *node = NULL, *next_node = NULL; - - ogs_list_for_each_safe(list, next_node, node) - ogs_pfcp_node_remove(list, node); -} - -ogs_pfcp_node_t *ogs_pfcp_node_find_by_addr( - ogs_list_t *list, ogs_sockaddr_t *addr) -{ - ogs_pfcp_node_t *node = NULL; - - ogs_assert(list); - ogs_assert(addr); - - ogs_list_for_each(list, node) { - if (ogs_sockaddr_is_equal(&node->remote_addr, addr) == true) - break; - } - - return node; -} - -ogs_pfcp_node_t *ogs_pfcp_node_find_by_f_seid( - ogs_list_t *list, ogs_pfcp_f_seid_t *f_seid) -{ - int rv; - ogs_pfcp_node_t *node = NULL; - ogs_ip_t ip; - - ogs_assert(list); - ogs_assert(f_seid); - - rv = ogs_pfcp_f_seid_to_ip(f_seid, &ip); - ogs_assert(rv == OGS_OK); - - ogs_list_for_each(list, node) { - if (memcmp(&node->ip, &ip, ip.len) == 0) - break; - } - - return node; -} diff --git a/lib/pfcp/node.h b/lib/pfcp/node.h deleted file mode 100644 index 5fdba9a38..000000000 --- a/lib/pfcp/node.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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_PFCP_INSIDE) && !defined(OGS_PFCP_COMPILATION) -#error "This header cannot be included directly." -#endif - -#ifndef OGS_PFCP_NODE_H -#define OGS_PFCP_NODE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define OGS_SETUP_PFCP_NODE(__cTX, __pNODE) \ - do { \ - ogs_assert((__cTX)); \ - ogs_assert((__pNODE)); \ - (__cTX)->pnode = __pNODE; \ - } while(0) - -/** - * This structure represents the commonalities of PFCP node such as MME, SGW, - * PGW gateway. Some of members may not be used by the specific type of node */ -typedef struct ogs_pfcp_node_s { - ogs_lnode_t node; /* A node of list_t */ - - ogs_sockaddr_t *sa_list; /* Socket Address List */ - - ogs_sock_t *sock; /* Socket Instance */ - ogs_ip_t ip; /* Socket Address */ - ogs_sockaddr_t remote_addr; /* Connected Address */ - - ogs_list_t local_list; - ogs_list_t remote_list; - - ogs_pfcp_node_id_t node_id; /* Target Node ID */ - union { - uint8_t up_functions_features; - uint8_t cp_functions_features; - }; - ogs_pfcp_user_plane_ip_resource_information_t user_plane_info; -} ogs_pfcp_node_t; - -int ogs_pfcp_node_init(int size); -int ogs_pfcp_node_final(void); - -ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *sa_list); -void ogs_pfcp_node_free(ogs_pfcp_node_t *node); - -ogs_pfcp_node_t *ogs_pfcp_node_add( - ogs_list_t *list, ogs_pfcp_f_seid_t *f_seid, - uint16_t port, int no_ipv4, int no_ipv6, int prefer_ipv4); -ogs_pfcp_node_t *ogs_pfcp_node_add_by_addr( - ogs_list_t *list, ogs_sockaddr_t *addr); -void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node); -void ogs_pfcp_node_remove_all(ogs_list_t *list); - -ogs_pfcp_node_t *ogs_pfcp_node_find_by_addr( - ogs_list_t *list, ogs_sockaddr_t *addr); -ogs_pfcp_node_t *ogs_pfcp_node_find_by_f_seid( - ogs_list_t *list, ogs_pfcp_f_seid_t *f_seid); - -#ifdef __cplusplus -} -#endif - -#endif /* OGS_PFCP_NODE_H */ diff --git a/lib/pfcp/ogs-pfcp.h b/lib/pfcp/ogs-pfcp.h index 05e309e78..6183dff69 100644 --- a/lib/pfcp/ogs-pfcp.h +++ b/lib/pfcp/ogs-pfcp.h @@ -22,14 +22,22 @@ #include "ogs-core.h" -#define OGS_PFCP_UDP_PORT 8805 +#define OGS_PFCP_UDP_PORT 8805 + +#define OGS_MAX_NUM_OF_PDR 4 +#define OGS_MAX_NUM_OF_FAR 4 +#define OGS_MAX_NUM_OF_URR 2 +#define OGS_MAX_NUM_OF_QER 2 +#define OGS_MAX_NUM_OF_BAR 1 +#define OGS_MAX_NUM_OF_GTPU_RESOURCE 4 #define OGS_PFCP_INSIDE #include "pfcp/message.h" #include "pfcp/types.h" #include "pfcp/conv.h" -#include "pfcp/node.h" +#include "pfcp/context.h" +#include "pfcp/n4-build.h" #include "pfcp/path.h" #include "pfcp/xact.h" diff --git a/lib/pfcp/path.c b/lib/pfcp/path.c index 8ed5ab5fe..020fb034a 100644 --- a/lib/pfcp/path.c +++ b/lib/pfcp/path.c @@ -34,16 +34,17 @@ ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node) return pfcp; } -int ogs_pfcp_connect(ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *gnode) +int ogs_pfcp_connect( + ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *node) { ogs_sockaddr_t *addr; char buf[OGS_ADDRSTRLEN]; ogs_assert(ipv4 || ipv6); - ogs_assert(gnode); - ogs_assert(gnode->sa_list); + ogs_assert(node); + ogs_assert(node->sa_list); - addr = gnode->sa_list; + addr = node->sa_list; while (addr) { ogs_sock_t *sock = NULL; @@ -55,11 +56,11 @@ int ogs_pfcp_connect(ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *gnode) ogs_assert_if_reached(); if (sock) { - ogs_info("pfcp_connect() [%s]:%d", + ogs_info("ogs_pfcp_connect() [%s]:%d", OGS_ADDR(addr, buf), OGS_PORT(addr)); - gnode->sock = sock; - memcpy(&gnode->remote_addr, addr, sizeof gnode->remote_addr); + node->sock = sock; + memcpy(&node->addr, addr, sizeof node->addr); break; } @@ -67,23 +68,23 @@ int ogs_pfcp_connect(ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *gnode) } if (addr == NULL) { - ogs_log_message(OGS_LOG_WARN, ogs_socket_errno, - "pfcp_connect() [%s]:%d failed", - OGS_ADDR(gnode->sa_list, buf), OGS_PORT(gnode->sa_list)); + ogs_error("ogs_pfcp_connect() [%s]:%d failed", + OGS_ADDR(node->sa_list, buf), OGS_PORT(node->sa_list)); + ogs_error("Please check the IP version between SMF and UPF nodes."); return OGS_ERROR; } return OGS_OK; } -int ogs_pfcp_send(ogs_pfcp_node_t *gnode, ogs_pkbuf_t *pkbuf) +int ogs_pfcp_send(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf) { ssize_t sent; ogs_sock_t *sock = NULL; - ogs_assert(gnode); + ogs_assert(node); ogs_assert(pkbuf); - sock = gnode->sock; + sock = node->sock; ogs_assert(sock); sent = ogs_send(sock->fd, pkbuf->data, pkbuf->len, 0); @@ -95,24 +96,125 @@ int ogs_pfcp_send(ogs_pfcp_node_t *gnode, ogs_pkbuf_t *pkbuf) return OGS_OK; } -int ogs_pfcp_sendto(ogs_pfcp_node_t *gnode, ogs_pkbuf_t *pkbuf) +int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf) { ssize_t sent; ogs_sock_t *sock = NULL; ogs_sockaddr_t *addr = NULL; - ogs_assert(gnode); + ogs_assert(node); ogs_assert(pkbuf); - sock = gnode->sock; + sock = node->sock; ogs_assert(sock); - addr = &gnode->remote_addr; + addr = &node->addr; ogs_assert(addr); sent = ogs_sendto(sock->fd, pkbuf->data, pkbuf->len, 0, addr); if (sent < 0 || sent != pkbuf->len) { - ogs_error("ogs_send() failed"); + ogs_error("ogs_sendto() failed"); return OGS_ERROR; } return OGS_OK; } + +void ogs_pfcp_send_heartbeat_response(ogs_pfcp_xact_t *xact) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_HEARTBEAT_RESPONSE_TYPE; + h.seid = 0; + + n4buf = ogs_pfcp_n4_build_heartbeat_response(h.type); + ogs_expect_or_return(n4buf); + + rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void ogs_pfcp_send_error_message( + ogs_pfcp_xact_t *xact, uint64_t seid, uint8_t type, + uint8_t cause_value, uint16_t offending_ie_value) +{ + int rv; + ogs_pfcp_message_t errmsg; + ogs_pfcp_tlv_cause_t *cause = NULL; + ogs_pfcp_tlv_offending_ie_t *offending_ie = NULL; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(xact); + + memset(&errmsg, 0, sizeof(ogs_pfcp_message_t)); + errmsg.h.seid = seid; + errmsg.h.type = type; + + switch (type) { + case OGS_PFCP_PFD_MANAGEMENT_RESPONSE_TYPE: + cause = &errmsg.pfcp_pfd_management_response.cause; + offending_ie = &errmsg.pfcp_pfd_management_response.offending_ie; + break; + case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE: + cause = &errmsg.pfcp_association_setup_response.cause; + break; + case OGS_PFCP_ASSOCIATION_UPDATE_RESPONSE_TYPE: + cause = &errmsg.pfcp_association_update_response.cause; + break; + case OGS_PFCP_ASSOCIATION_RELEASE_RESPONSE_TYPE: + cause = &errmsg.pfcp_association_release_response.cause; + break; + case OGS_PFCP_NODE_REPORT_RESPONSE_TYPE: + cause = &errmsg.pfcp_node_report_response.cause; + offending_ie = &errmsg.pfcp_node_report_response.offending_ie; + break; + case OGS_PFCP_SESSION_SET_DELETION_RESPONSE_TYPE: + cause = &errmsg.pfcp_session_set_deletion_response.cause; + offending_ie = &errmsg.pfcp_session_set_deletion_response.offending_ie; + break; + case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE: + cause = &errmsg.pfcp_session_establishment_response.cause; + offending_ie = &errmsg.pfcp_session_establishment_response.offending_ie; + break; + case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE: + cause = &errmsg.pfcp_session_modification_response.cause; + offending_ie = &errmsg.pfcp_session_modification_response.offending_ie; + break; + case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE: + cause = &errmsg.pfcp_session_deletion_response.cause; + offending_ie = &errmsg.pfcp_session_deletion_response.offending_ie; + break; + case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE: + cause = &errmsg.pfcp_session_report_response.cause; + offending_ie = &errmsg.pfcp_session_report_response.offending_ie; + break; + default: + ogs_assert_if_reached(); + return; + } + + ogs_assert(cause); + + cause->presence = 1; + cause->u8 = cause_value; + + if (offending_ie && offending_ie_value) { + offending_ie->presence = 1; + offending_ie->u16 = offending_ie_value; + } + + pkbuf = ogs_pfcp_build_msg(&errmsg); + ogs_expect_or_return(pkbuf); + + rv = ogs_pfcp_xact_update_tx(xact, &errmsg.h, pkbuf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} diff --git a/lib/pfcp/path.h b/lib/pfcp/path.h index 95df7b133..dddc0abc1 100644 --- a/lib/pfcp/path.h +++ b/lib/pfcp/path.h @@ -32,14 +32,18 @@ typedef struct ogs_pfcp_xact_s ogs_pfcp_xact_t; ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node); int ogs_pfcp_connect( - ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *gnode); + ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *node); -int ogs_pfcp_send(ogs_pfcp_node_t *gnode, ogs_pkbuf_t *pkbuf); -int ogs_pfcp_sendto(ogs_pfcp_node_t *gnode, ogs_pkbuf_t *pkbuf); +int ogs_pfcp_send(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf); +int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf); ogs_pkbuf_t *ogs_pfcp_handle_echo_req(ogs_pkbuf_t *pkt); + +void ogs_pfcp_send_heartbeat_response(ogs_pfcp_xact_t *xact); + void ogs_pfcp_send_error_message( - ogs_pfcp_xact_t *xact, uint32_t teid, uint8_t type, uint8_t cause_value); + ogs_pfcp_xact_t *xact, uint64_t seid, uint8_t type, + uint8_t cause_value, uint16_t offending_ie_value); #ifdef __cplusplus } diff --git a/lib/pfcp/support/README.md b/lib/pfcp/support/README.md index f0e8f46e4..f3d51a1c6 100644 --- a/lib/pfcp/support/README.md +++ b/lib/pfcp/support/README.md @@ -13,4 +13,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-f40.docx -o .. + python pfcp-tlv.py -f 29244-g10.docx -o .. diff --git a/lib/pfcp/support/cache/tlv-group-list.py b/lib/pfcp/support/cache/tlv-group-list.py index 768ff8932..8f6777f8d 100644 --- a/lib/pfcp/support/cache/tlv-group-list.py +++ b/lib/pfcp/support/cache/tlv-group-list.py @@ -1,363 +1,362 @@ ies = [] -ies.append({ "ie_type" : "Application ID", "ie_value" : "Application ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the Application ID for which PFDs shall be provisioned in the UP function."}) -ies.append({ "ie_type" : "PFD context", "ie_value" : "PFD context", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the PFD needs to be provisioned in the UP function.When present, it shall describe the PFD to be provisioned in the UP function.Several IEs with the same IE type may be present to provision multiple PFDs for this Application ID.When this IE is absent, the UP function shall delete all the PFDs received and stored earlier in the UP function for this Application ID."}) +ies.append({ "ie_type" : "Application ID", "ie_value" : "Application ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the Application ID for which PFDs shall be provisioned in the UP function."}) +ies.append({ "ie_type" : "PFD context", "ie_value" : "PFD context", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the PFD needs to be provisioned in the UP function.When present, it shall describe the PFD to be provisioned in the UP function.Several IEs with the same IE type may be present to provision multiple PFDs for this Application ID.When this IE is absent, the UP function shall delete all the PFDs received and stored earlier in the UP function for this Application ID."}) group_list["Application ID's PFDs"] = { "index" : "158", "type" : "58", "ies" : ies } ies = [] -ies.append({ "ie_type" : "PFD contents", "ie_value" : "PFD Contents", "presence" : "M", "instance" : "0", "comment" : "This IE shall describe the PFD to be provisioned in the UP function. Several IEs with the same IE type may be present to provision multiple contents for this PFD. (NOTE 1)"}) +ies.append({ "ie_type" : "PFD contents", "ie_value" : "PFD Contents", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall describe the PFD to be provisioned in the UP function. Several IEs with the same IE type may be present to provision multiple contents for this PFD. (NOTE 1)"}) group_list["PFD context"] = { "index" : "159", "type" : "59", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Remote GTP-U Peer", "ie_value" : "Remote GTP-U Peer ", "presence" : "M", "instance" : "0", "comment" : "This IE shall include the IP address of the remote GTP-U peer towards which a user plane path failure has been detected.More than one IE with this type may be included to represent multiple remote GTP-U peers towards which a user plane path failure has been detected."}) +ies.append({ "ie_type" : "Remote GTP-U Peer", "ie_value" : "Remote GTP-U Peer ", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall include the IP address of the remote GTP-U peer towards which a user plane path failure has been detected.More than one IE with this type may be included to represent multiple remote GTP-U peers towards which a user plane path failure has been detected."}) group_list["User Plane Path Failure Report"] = { "index" : "202", "type" : "102", "ies" : ies } ies = [] -ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the PDR among all the PDRs configured for that PFCP session."}) -ies.append({ "ie_type" : "Precedence", "ie_value" : "Precedence", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the PDRs precedence to be applied by the UP function among all PDRs of the PFCP session, when looking for a PDR matching an incoming packet."}) -ies.append({ "ie_type" : "PDI", "ie_value" : "PDI", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the PDI against which incoming packets will be matched.See Table 7.5.2.2-2."}) -ies.append({ "ie_type" : "Outer Header Removal", "ie_value" : "Outer Header Removal", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to remove one or more outer header(s) from the packets matching this PDR."}) -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Activate Predefined Rules IE is not included or if it is included but it does not result in activating a predefined FAR, and if the MAR ID is not included.When present this IE shall contain the FAR ID to be associated to the PDR."}) -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a measurement action shall be applied to packets matching this PDR.When present, this IE shall contain the URR IDs to be associated to the PDR.Several IEs within the same IE type may be present to represent a list of URRs to be associated to the PDR."}) -ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a QoS enforcement or QoS marking action shall be applied to packets matching this PDR.When present, this IE shall contain the QER IDs to be associated to the PDR. Several IEs within the same IE type may be present to represent a list of QERs to be associated to the PDR."}) -ies.append({ "ie_type" : "Activate Predefined Rules", "ie_value" : "Activate Predefined Rules", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if Predefined Rule(s) shall be activated for this PDR. When present this IE shall contain one Predefined Rules name.Several IEs with the same IE type may be present to represent multiple Activate Predefined Rules names."}) -ies.append({ "ie_type" : "Activation Time", "ie_value" : "Activation Time", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the PDR activation shall be deferred. (NOTE 1)"}) -ies.append({ "ie_type" : "Deactivation Time", "ie_value" : "Deactivation Time", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the PDR deactivation shall be deferred. (NOTE 1)"}) -ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the PDR is provisioned to match the downlink traffic towards the UE for a PFCP session established for a MA PDU session."}) -ies.append({ "ie_type" : "Packet Replication and Detection Carry-On Information", "ie_value" : "Packet Replication and Detection Carry-On Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the PDR is provisioned to match a broadcast packet. When present, it contains the information to instruct the UPF to replicate the packet and to carry-on the look-up of other PDRs of other PFCP sessions matching the packet (see clause 5.2.1)."}) +ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the PDR among all the PDRs configured for that PFCP session."}) +ies.append({ "ie_type" : "Precedence", "ie_value" : "Precedence", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the PDRs precedence to be applied by the UP function among all PDRs of the PFCP session, when looking for a PDR matching an incoming packet."}) +ies.append({ "ie_type" : "PDI", "ie_value" : "PDI", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the PDI against which incoming packets will be matched.See Table 7.5.2.2-2."}) +ies.append({ "ie_type" : "Outer Header Removal", "ie_value" : "Outer Header Removal", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to remove one or more outer header(s) from the packets matching this PDR."}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Activate Predefined Rules IE is not included or if it is included but it does not result in activating a predefined FAR, and if the MAR ID is not included.When present this IE shall contain the FAR ID to be associated to the PDR."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a measurement action shall be applied to packets matching this PDR.When present, this IE shall contain the URR IDs to be associated to the PDR.Several IEs within the same IE type may be present to represent a list of URRs to be associated to the PDR."}) +ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a QoS enforcement or QoS marking action shall be applied to packets matching this PDR.When present, this IE shall contain the QER IDs to be associated to the PDR. Several IEs within the same IE type may be present to represent a list of QERs to be associated to the PDR."}) +ies.append({ "ie_type" : "Activate Predefined Rules", "ie_value" : "Activate Predefined Rules", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if Predefined Rule(s) shall be activated for this PDR. When present this IE shall contain one Predefined Rules name.Several IEs with the same IE type may be present to represent multiple Activate Predefined Rules names."}) +ies.append({ "ie_type" : "Activation Time", "ie_value" : "Activation Time", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the PDR activation shall be deferred. (NOTE 1)"}) +ies.append({ "ie_type" : "Deactivation Time", "ie_value" : "Deactivation Time", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the PDR deactivation shall be deferred. (NOTE 1)"}) +ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the PDR is provisioned to match the downlink traffic towards the UE for a PFCP session established for a MA PDU session."}) +ies.append({ "ie_type" : "Packet Replication and Detection Carry-On Information", "ie_value" : "Packet Replication and Detection Carry-On Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the PDR is provisioned to match a broadcast packet. When present, it contains the information to instruct the UPF to replicate the packet and to carry-on the look-up of other PDRs of other PFCP sessions matching the packet (see clause 5.2.1)."}) group_list["Create PDR"] = { "index" : "101", "type" : "1", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Source Interface", "ie_value" : "Source Interface", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the source interface of the incoming packet."}) -ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "O", "instance" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present.If present, this IE shall identify the local F-TEID to match for an incoming packet.The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of F-TEID and the CP function requests the UP function to assign a local F-TEID to the PDR."}) -ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "O", "instance" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present. It shall be present if the CP function requests the UP function to allocate a UE IP address/prefix and the Traffic Endpoint ID is not present.If present, this IE shall identify the Network instance to match for the incoming packet. See NOTE 1, NOTE2."}) -ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address", "presence" : "O", "instance" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present.If present, this IE shall identify the source or destination IP address to match for the incoming packet. (NOTE 5)The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of UE IP address/ prefix and the CP function requests the UP function to assign a UE IP address/prefix to the PDR."}) -ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "C", "instance" : "0", "comment" : "This IE may be present if the UP function has indicated the support of PDI optimization.If present, this IE shall uniquely identify the Traffic Endpoint for that PFCP session.Several IEs with the same IE type may be present to provision several Traffic Endpoints with different Traffic Endpoint IDs, from which the UPF may receive packets pertaining to the same service data flow, which is subject for the same FAR, QER and URR, if the UPF has indicated it supports MTE feature as specified in clause 8.2.25. See NOTE 6."}) -ies.append({ "ie_type" : "SDF Filter", "ie_value" : "SDF Filter", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the SDF filter to match for the incoming packet. Several IEs with the same IE type may be present to provision a list of SDF Filters. The full set of applicable SDF filters, if any, shall be provided during the creation or the modification of the PDI.See NOTE 3."}) -ies.append({ "ie_type" : "Application ID", "ie_value" : "Application ID", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the Application ID to match for the incoming packet. "}) -ies.append({ "ie_type" : "Ethernet PDU Session Information", "ie_value" : "Ethernet PDU Session Information", "presence" : "O", "instance" : "0", "comment" : "This IE may be present to identify all the (DL) Ethernet packets matching an Ethernet PDU session (see clause 5.13.1)."}) -ies.append({ "ie_type" : "Ethernet Packet Filter", "ie_value" : "Ethernet Packet Filter", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the Ethernet PDU to match for the incoming packet.Several IEs with the same IE type may be present to represent a list of Ethernet Packet Filters.The full set of applicable Ethernet Packet filters, if any, shall be provided during the creation or the modification of the PDI."}) -ies.append({ "ie_type" : "QFI", "ie_value" : "QFI", "presence" : "O", "instance" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present and the QFI(s) are included in the Traffic Endpoint.If present, this IE shall identify the QoS Flow Identifier to match for the incoming packet.Several IEs with the same IE type may be present to provision a list of QFIs. When present, the full set of applicable QFIs shall be provided during the creation or the modification of the PDI. "}) -ies.append({ "ie_type" : "Framed-Route", "ie_value" : "Framed-Route", "presence" : "O", "instance" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed route.Several IEs with the same IE type may be present to provision a list of framed routes. (NOTE 5)"}) -ies.append({ "ie_type" : "Framed-Routing", "ie_value" : "Framed-Routing", "presence" : "O", "instance" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed route. "}) -ies.append({ "ie_type" : "Framed-IPv6-Route", "ie_value" : "Framed-IPv6-Route", "presence" : "O", "instance" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed IPv6 route.Several IEs with the same IE type may be present to provision a list of framed IPv6 routes. (NOTE 5)"}) -ies.append({ "ie_type" : "3GPP Interface Type", "ie_value" : "Source Interface Type", "presence" : "O", "instance" : "0", "comment" : "This IE may be present to indicate the 3GPP interface type of the source interface, if required by functionalities in the UP Function, e.g. for performance measurements."}) +ies.append({ "ie_type" : "Source Interface", "ie_value" : "Source Interface", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the source interface of the incoming packet."}) +ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present.If present, this IE shall identify the local F-TEID to match for an incoming packet.The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of F-TEID and the CP function requests the UP function to assign a local F-TEID to the PDR."}) +ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present. It shall be present if the CP function requests the UP function to allocate a UE IP address/prefix and the Traffic Endpoint ID is not present.If present, this IE shall identify the Network instance to match for the incoming packet. See NOTE 1, NOTE2."}) +ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present.If present, this IE shall identify the source or destination IP address to match for the incoming packet. (NOTE 5)The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of UE IP address/ prefix and the CP function requests the UP function to assign a UE IP address/prefix to the PDR."}) +ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present if the UP function has indicated the support of PDI optimization.If present, this IE shall uniquely identify the Traffic Endpoint for that PFCP session.Several IEs with the same IE type may be present to provision several Traffic Endpoints with different Traffic Endpoint IDs, from which the UPF may receive packets pertaining to the same service data flow, which is subject for the same FAR, QER and URR, if the UPF has indicated it supports MTE feature as specified in clause 8.2.25. See NOTE 6."}) +type_list["SDF Filter"]["max_tlv_more"] = "3" +ies.append({ "ie_type" : "SDF Filter", "ie_value" : "SDF Filter", "presence" : "O", "tlv_more" : "3", "comment" : "If present, this IE shall identify the SDF filter to match for the incoming packet. Several IEs with the same IE type may be present to provision a list of SDF Filters. The full set of applicable SDF filters, if any, shall be provided during the creation or the modification of the PDI.See NOTE 3."}) +ies.append({ "ie_type" : "Application ID", "ie_value" : "Application ID", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the Application ID to match for the incoming packet. "}) +ies.append({ "ie_type" : "Ethernet PDU Session Information", "ie_value" : "Ethernet PDU Session Information", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present to identify all the (DL) Ethernet packets matching an Ethernet PDU session (see clause 5.13.1)."}) +ies.append({ "ie_type" : "Ethernet Packet Filter", "ie_value" : "Ethernet Packet Filter", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the Ethernet PDU to match for the incoming packet.Several IEs with the same IE type may be present to represent a list of Ethernet Packet Filters.The full set of applicable Ethernet Packet filters, if any, shall be provided during the creation or the modification of the PDI."}) +ies.append({ "ie_type" : "QFI", "ie_value" : "QFI", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall not be present if Traffic Endpoint ID is present and the QFI(s) are included in the Traffic Endpoint.If present, this IE shall identify the QoS Flow Identifier to match for the incoming packet.Several IEs with the same IE type may be present to provision a list of QFIs. When present, the full set of applicable QFIs shall be provided during the creation or the modification of the PDI. "}) +ies.append({ "ie_type" : "Framed-Route", "ie_value" : "Framed-Route", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed route.Several IEs with the same IE type may be present to provision a list of framed routes. (NOTE 5)"}) +ies.append({ "ie_type" : "Framed-Routing", "ie_value" : "Framed-Routing", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed route. "}) +ies.append({ "ie_type" : "Framed-IPv6-Route", "ie_value" : "Framed-IPv6-Route", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed IPv6 route.Several IEs with the same IE type may be present to provision a list of framed IPv6 routes. (NOTE 5)"}) +ies.append({ "ie_type" : "3GPP Interface Type", "ie_value" : "Source Interface Type", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present to indicate the 3GPP interface type of the source interface, if required by functionalities in the UP Function, e.g. for performance measurements."}) group_list["PDI"] = { "index" : "102", "type" : "2", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Ethernet Filter ID", "ie_value" : "Ethernet Filter ID", "presence" : "C", "instance" : "0", "comment" : "This shall be present if Bidirectional Ethernet filter is required. This IE shall uniquely identify an Ethernet Filter among all the Ethernet Filters provisioned for a given PFCP session."}) -ies.append({ "ie_type" : "Ethernet Filter Properties", "ie_value" : "Ethernet Filter Properties", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present when provisioning a bidirectional Ethernet Filter the first time (see clause 5.13.4)."}) -ies.append({ "ie_type" : "MAC address", "ie_value" : "MAC address", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the MAC address.This IE may be present up to 16 times."}) -ies.append({ "ie_type" : "Ethertype", "ie_value" : "Ethertype", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the Ethertype."}) -ies.append({ "ie_type" : "C-TAG", "ie_value" : "C-TAG", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the Customer-VLAN tag."}) -ies.append({ "ie_type" : "S-TAG", "ie_value" : "S-TAG", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the Service-VLAN tag."}) -ies.append({ "ie_type" : "SDF Filter", "ie_value" : "SDF Filter", "presence" : "O", "instance" : "0", "comment" : "If packet filtering is required, for Ethernet frames with Ethertype indicating IPv4 or IPv6 payload, this IE shall describe the IP Packet Filter Set.Several IEs with the same IE type may be present to represent a list of SDF filters."}) +ies.append({ "ie_type" : "Ethernet Filter ID", "ie_value" : "Ethernet Filter ID", "presence" : "C", "tlv_more" : "0", "comment" : "This shall be present if Bidirectional Ethernet filter is required. This IE shall uniquely identify an Ethernet Filter among all the Ethernet Filters provisioned for a given PFCP session."}) +ies.append({ "ie_type" : "Ethernet Filter Properties", "ie_value" : "Ethernet Filter Properties", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present when provisioning a bidirectional Ethernet Filter the first time (see clause 5.13.4)."}) +ies.append({ "ie_type" : "MAC address", "ie_value" : "MAC address", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the MAC address.This IE may be present up to 16 times."}) +ies.append({ "ie_type" : "Ethertype", "ie_value" : "Ethertype", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the Ethertype."}) +ies.append({ "ie_type" : "C-TAG", "ie_value" : "C-TAG", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the Customer-VLAN tag."}) +ies.append({ "ie_type" : "S-TAG", "ie_value" : "S-TAG", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the Service-VLAN tag."}) +ies.append({ "ie_type" : "SDF Filter", "ie_value" : "SDF Filter", "presence" : "O", "tlv_more" : "3", "comment" : "If packet filtering is required, for Ethernet frames with Ethertype indicating IPv4 or IPv6 payload, this IE shall describe the IP Packet Filter Set.Several IEs with the same IE type may be present to represent a list of SDF filters."}) group_list["Ethernet Packet Filter"] = { "index" : "232", "type" : "132", "ies" : ies } ies = [] -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the FAR among all the FARs configured for that PFCP session."}) -ies.append({ "ie_type" : "Apply Action", "ie_value" : "Apply Action", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the action to apply to the packets, See clauses 5.2.1 and 5.2.3."}) -ies.append({ "ie_type" : "Forwarding Parameters", "ie_value" : "Forwarding Parameters", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present when the Apply Action requests the packets to be forwarded. It may be present otherwise.When present, this IE shall contain the forwarding instructions to be applied by the UP function when the Apply Action requests the packets to be forwarded.See table 7.5.2.3-2."}) -ies.append({ "ie_type" : "Duplicating Parameters", "ie_value" : "Duplicating Parameters", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present when the Apply Action requests the packets to be duplicated. It may be present otherwise.When present, this IE shall contain the forwarding instructions to be applied by the UP function for the traffic to be duplicated, when the Apply Action requests the packets to be duplicated.Several IEs with the same IE type may be present to represent to duplicate the packets to different destinations. See NOTE 1.See table 7.5.2.3-3."}) -ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "O", "instance" : "0", "comment" : "When present, this IE shall contain the BAR ID of the BAR defining the buffering instructions to be applied by the UP function when the Apply Action requests the packets to be buffered. "}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the FAR among all the FARs configured for that PFCP session."}) +ies.append({ "ie_type" : "Apply Action", "ie_value" : "Apply Action", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the action to apply to the packets, See clauses 5.2.1 and 5.2.3."}) +ies.append({ "ie_type" : "Forwarding Parameters", "ie_value" : "Forwarding Parameters", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present when the Apply Action requests the packets to be forwarded. It may be present otherwise.When present, this IE shall contain the forwarding instructions to be applied by the UP function when the Apply Action requests the packets to be forwarded.See table 7.5.2.3-2."}) +ies.append({ "ie_type" : "Duplicating Parameters", "ie_value" : "Duplicating Parameters", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present when the Apply Action requests the packets to be duplicated. It may be present otherwise.When present, this IE shall contain the forwarding instructions to be applied by the UP function for the traffic to be duplicated, when the Apply Action requests the packets to be duplicated.Several IEs with the same IE type may be present to represent to duplicate the packets to different destinations. See NOTE 1.See table 7.5.2.3-3."}) +ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "O", "tlv_more" : "0", "comment" : "When present, this IE shall contain the BAR ID of the BAR defining the buffering instructions to be applied by the UP function when the Apply Action requests the packets to be buffered. "}) group_list["Create FAR"] = { "index" : "103", "type" : "3", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the destination interface of the outgoing packet."}) -ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "O", "instance" : "0", "comment" : "When present, this IE shall identify the Network instance towards which to send the outgoing packet. See NOTE 1."}) -ies.append({ "ie_type" : "Redirect Information", "ie_value" : "Redirect Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to enforce traffic redirection towards a redirect destination provided by the CP function. "}) -ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to add one or more outer header(s) to the outgoing packet. If present, it shall contain the F-TEID of the remote GTP-U peer when adding a GTP-U/UDP/IP header, or the Destination IP address and/or Port Number when adding a UDP/IP header or an IP header or the C-TAG/S-TAG (for 5GC). See NOTE 2."}) -ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level Marking", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to mark the IP header with the DSCP marking as defined by IETFRFC2474[22]. When present for EPC, it shall contain the value of the DSCP in the TOS/Traffic Class field set based on the QCI, and optionally the ARP priority level, of the associated EPS bearer, as described in clause 5.10 of 3GPPTS23.214[2]. When present for 5GC, it shall contain the value of the DSCP in the TOS/Traffic Class field set based on the 5QI, the Priority Level (if explicitly signalled), and optionally the ARP priority level, of the associated QoS flow, as described in clause 5.8.2.7 of 3GPPTS23.501[28],"}) -ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a specific forwarding policy is required to be applied to the packets. It shall be present if the Destination Interface IE is set to SGi-LAN / N6-LAN. It may be present if the Destination Interface is set to Core, Access, or CP-Function. See NOTE 2.When present, it shall contain an Identifier of the Forwarding Policy locally configured in the UP function."}) -ies.append({ "ie_type" : "Header Enrichment", "ie_value" : "Header Enrichment", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UP function indicated support of Header Enrichment of UL traffic. When present, it shall contain information for header enrichment."}) -ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Linked Traffic Endpoint ID", "presence" : "C", "instance" : "0", "comment" : "This IE may be present, if it is available and the UP function indicated support of the PDI optimisation feature, (see clause 8.2.25). When present, it shall identify the Traffic Endpoint ID allocated for this PFCP session to receive the traffic in the reverse direction (see clause 5.2.3.1)."}) -ies.append({ "ie_type" : "Proxying", "ie_value" : "Proxying", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if proxying is to be performed by the UP function.When present, this IE shall contain the information that the UPF shall respond to Address Resolution Protocol and / or IPv6 Neighbour Solicitation based on the local cache information for the Ethernet PDUs."}) -ies.append({ "ie_type" : "3GPP Interface Type", "ie_value" : "Destination Interface Type", "presence" : "O", "instance" : "0", "comment" : "This IE may be present to indicate the 3GPP interface type of the destination interface, if required by functionalities in the UP Function, e.g. for performance measurements."}) +ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the destination interface of the outgoing packet."}) +ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "O", "tlv_more" : "0", "comment" : "When present, this IE shall identify the Network instance towards which to send the outgoing packet. See NOTE 1."}) +ies.append({ "ie_type" : "Redirect Information", "ie_value" : "Redirect Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to enforce traffic redirection towards a redirect destination provided by the CP function. "}) +ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to add one or more outer header(s) to the outgoing packet. If present, it shall contain the F-TEID of the remote GTP-U peer when adding a GTP-U/UDP/IP header, or the Destination IP address and/or Port Number when adding a UDP/IP header or an IP header or the C-TAG/S-TAG (for 5GC). See NOTE 2."}) +ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level Marking", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to mark the IP header with the DSCP marking as defined by IETFRFC2474[22]. When present for EPC, it shall contain the value of the DSCP in the TOS/Traffic Class field set based on the QCI, and optionally the ARP priority level, of the associated EPS bearer, as described in clause 5.10 of 3GPPTS23.214[2]. When present for 5GC, it shall contain the value of the DSCP in the TOS/Traffic Class field set based on the 5QI, the Priority Level (if explicitly signalled), and optionally the ARP priority level, of the associated QoS flow, as described in clause 5.8.2.7 of 3GPPTS23.501[28],"}) +ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a specific forwarding policy is required to be applied to the packets. It shall be present if the Destination Interface IE is set to SGi-LAN / N6-LAN. It may be present if the Destination Interface is set to Core, Access, or CP-Function. See NOTE 2.When present, it shall contain an Identifier of the Forwarding Policy locally configured in the UP function."}) +ies.append({ "ie_type" : "Header Enrichment", "ie_value" : "Header Enrichment", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the UP function indicated support of Header Enrichment of UL traffic. When present, it shall contain information for header enrichment."}) +ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Linked Traffic Endpoint ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present, if it is available and the UP function indicated support of the PDI optimisation feature, (see clause 8.2.25). When present, it shall identify the Traffic Endpoint ID allocated for this PFCP session to receive the traffic in the reverse direction (see clause 5.2.3.1)."}) +ies.append({ "ie_type" : "Proxying", "ie_value" : "Proxying", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if proxying is to be performed by the UP function.When present, this IE shall contain the information that the UPF shall respond to Address Resolution Protocol and / or IPv6 Neighbour Solicitation based on the local cache information for the Ethernet PDUs."}) +ies.append({ "ie_type" : "3GPP Interface Type", "ie_value" : "Destination Interface Type", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present to indicate the 3GPP interface type of the destination interface, if required by functionalities in the UP Function, e.g. for performance measurements."}) group_list["Forwarding Parameters"] = { "index" : "104", "type" : "4", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the destination interface of the outgoing packet."}) -ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to add one or more outer header(s) to the outgoing packet. If present, it shall contain the F-TEID of the remote GTP-U peer. See NOTE 1."}) -ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level marking", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to mark the IP header with the DSCP marking as defined by IETFRFC2474[22]. When present, it shall contain the value of the DSCP in the TOS/Traffic Class field. "}) -ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a specific forwarding policy is required to be applied to the packets. When present, it shall contain an Identifier of the Forwarding Policy locally configured in the UP function."}) +ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the destination interface of the outgoing packet."}) +ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to add one or more outer header(s) to the outgoing packet. If present, it shall contain the F-TEID of the remote GTP-U peer. See NOTE 1."}) +ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level marking", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to mark the IP header with the DSCP marking as defined by IETFRFC2474[22]. When present, it shall contain the value of the DSCP in the TOS/Traffic Class field. "}) +ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a specific forwarding policy is required to be applied to the packets. When present, it shall contain an Identifier of the Forwarding Policy locally configured in the UP function."}) group_list["Duplicating Parameters"] = { "index" : "105", "type" : "5", "ies" : ies } ies = [] -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the URR among all the URRs configured for this PFCP session."}) -ies.append({ "ie_type" : "Measurement Method", "ie_value" : "Measurement Method", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the method for measuring the network resources usage, i.e. whether the data volume, duration (i.e. time), combined volume/duration, or event shall be measured."}) -ies.append({ "ie_type" : "Reporting Triggers", "ie_value" : "Reporting Triggers", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the trigger(s) for reporting network resources usage to the CP function, e.g. periodic reporting or reporting upon reaching a threshold, or envelope closure."}) -ies.append({ "ie_type" : "Measurement Period", "ie_value" : "Measurement Period", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if periodic reporting is required. When present, it shall indicate the period for generating and reporting usage reports. "}) -ies.append({ "ie_type" : "Volume Threshold", "ie_value" : "Volume Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if volume-based measurement is used and reporting is required upon reaching a volume threshold. When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR."}) -ies.append({ "ie_type" : "Volume Quota", "ie_value" : "Volume Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if volume-based measurement is used and the CP function needs to provision a Volume Quota in the UP function (see clause 5.2.2.2)When present, it shall indicate the Volume Quota value."}) -ies.append({ "ie_type" : "Event Threshold", "ie_value" : "Event Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if event-based measurement is used and reporting is required upon reaching an event threshold. When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR."}) -ies.append({ "ie_type" : "Event Quota", "ie_value" : "Event Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if event-based measurement is used and the CP function needs to provision an Event Quota in the UP function (see clause 5.2.2.2)When present, it shall indicate the Event Quota value."}) -ies.append({ "ie_type" : "Time Threshold", "ie_value" : "Time Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if time-based measurement is used and reporting is required upon reaching a time threshold. When present, it shall indicate the time usage after which the UP function shall report network resources usage to the CP function for this URR."}) -ies.append({ "ie_type" : "Time Quota", "ie_value" : "Time Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if time-based measurement is used and the CP function needs to provision a Time Quota in the UP function (see clause 5.2.2.2)When present, it shall indicate the Time Quota value"}) -ies.append({ "ie_type" : "Quota Holding Time", "ie_value" : "Quota Holding Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, for a time, volume or event-based measurement, if reporting is required and packets are no longer permitted to pass on when no packets are received during a given inactivity period.When present, it shall contain the duration of the inactivity period."}) -ies.append({ "ie_type" : "Dropped DL Traffic Threshold", "ie_value" : "Dropped DL Traffic Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if reporting is required when the DL traffic being dropped exceeds a threshold.When present, it shall contain the threshold of the DL traffic being dropped."}) -ies.append({ "ie_type" : "Quota Validity Time", "ie_value" : "Quota Validity Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if reporting is required when the Quota Validity time for a given Quota is over."}) -ies.append({ "ie_type" : "Monitoring Time", "ie_value" : "Monitoring Time", "presence" : "O", "instance" : "0", "comment" : "When present, this IE shall contain the time at which the UP function shall re-apply the volume or time threshold. "}) -ies.append({ "ie_type" : "Subsequent Volume Threshold", "ie_value" : "Subsequent Volume Threshold", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the Monitoring Time IE is present and volume-based measurement is used.When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Time Threshold", "ie_value" : "Subsequent Time Threshold", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the Monitoring Time IE is present and time-based measurement is used.When present, it shall indicate the time usage after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Volume Quota", "ie_value" : "Subsequent Volume Quota", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if Monitoring Time IE is present and volume-based measurement is used (see clause 5.2.2.2).When present, it shall indicate the Volume Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Time Quota", "ie_value" : "Subsequent Time Quota", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if Monitoring Time IE is present and time-based measurement is used (see clause 5.2.2.2)When present, it shall indicate the Time Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Event Threshold", "ie_value" : "Subsequent Event Threshold", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the Monitoring Time IE is present and event-based measurement is used.When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Event Quota", "ie_value" : "Subsequent Event Quota", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if Monitoring Time IE is present and event-based measurement is used (see clause 5.2.2.2).When present, it shall indicate the Event Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Inactivity Detection Time", "ie_value" : "Inactivity Detection Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if time-based measurement is used and the time measurement need to be suspended when no packets are received during a given inactivity period. When present, it shall contain the duration of the inactivity period."}) -ies.append({ "ie_type" : "Linked URR ID", "ie_value" : "Linked URR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if linked usage reporting is required. When present, this IE shall contain the linked URR ID which is related with this URR (see clause 5.2.2.4).Several IEs with the same IE type may be present to represent multiple linked URRs which are related with this URR."}) -ies.append({ "ie_type" : "Measurement Information", "ie_value" : "Measurement Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if any of the following flag is set to 1.Applicable flags are:- Measurement Before QoS Enforcement Flag: this flag shall be set to 1 if the traffic usage before any QoS Enforcement is requested to be measured.- Inactive Measurement Flag: this flag shall be set to 1 if the measurement shall be paused (inactive). The measurement shall be performed (active) if the bit is set to 0 or if the Measurement Information IE is not present in the Create URR IE.- Reduced Application Detection Information Flag: this flag may be set to 1, if the Reporting Triggers request to report the start or stop of application, to request the UP function to only report the Application ID in the Application Detection Information, e.g. for envelope reporting.- Immediate Start Time Metering Flag: this flag may be set to 1 if time-based measurement is used and the UP function is requested to start the time metering immediately at receiving the flag. .- Measurement of Number of Packets Flag: this flag may be set to 1 when the Volume-based measurement applies, to request the UP function to report the number of packets in UL/DL/Total in addition to the measurement in octet."}) -ies.append({ "ie_type" : "Time Quota Mechanism", "ie_value" : "Time Quota Mechanism", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if time-based measurement based on CTP or DTP is used."}) -ies.append({ "ie_type" : "Aggregated URRs", "ie_value" : "Aggregated URRs", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the URR is used to support a Credit Pool.Several IEs with the same IE type may be present to provide multiple aggregated URRs."}) -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID for Quota Action", "presence" : "C", "instance" : "0", "comment" : "This IE may be present if the Volume Quota IE and/or the Time Quota IE and/or Event Quota IE is provisioned in the URR and the UP Function indicated support of the Quota Action feature.When present, it shall contain the identifier of the substitute FAR the UP function shall apply, for the traffic associated to this URR, when exhausting any of these quotas. See NOTE 1. "}) -ies.append({ "ie_type" : "Ethernet Inactivity Timer", "ie_value" : "Ethernet Inactivity Timer", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if Ethernet traffic reporting is used and the SMF requests the UP function to also report inactive UE MAC addresses.When present, it shall contain the duration of the Ethernet inactivity period."}) -ies.append({ "ie_type" : "Additional Monitoring Time", "ie_value" : "Additional Monitoring Time", "presence" : "O", "instance" : "0", "comment" : "When present, this IE shall contain the time at which the UP function shall re-apply the volume or time or event threshold/quota provisioned in the IE.Several IEs with the same IE type may be present to provide multiple Monitoring Times."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the URR among all the URRs configured for this PFCP session."}) +ies.append({ "ie_type" : "Measurement Method", "ie_value" : "Measurement Method", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the method for measuring the network resources usage, i.e. whether the data volume, duration (i.e. time), combined volume/duration, or event shall be measured."}) +ies.append({ "ie_type" : "Reporting Triggers", "ie_value" : "Reporting Triggers", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the trigger(s) for reporting network resources usage to the CP function, e.g. periodic reporting or reporting upon reaching a threshold, or envelope closure."}) +ies.append({ "ie_type" : "Measurement Period", "ie_value" : "Measurement Period", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if periodic reporting is required. When present, it shall indicate the period for generating and reporting usage reports. "}) +ies.append({ "ie_type" : "Volume Threshold", "ie_value" : "Volume Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if volume-based measurement is used and reporting is required upon reaching a volume threshold. When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR."}) +ies.append({ "ie_type" : "Volume Quota", "ie_value" : "Volume Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if volume-based measurement is used and the CP function needs to provision a Volume Quota in the UP function (see clause 5.2.2.2)When present, it shall indicate the Volume Quota value."}) +ies.append({ "ie_type" : "Event Threshold", "ie_value" : "Event Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if event-based measurement is used and reporting is required upon reaching an event threshold. When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR."}) +ies.append({ "ie_type" : "Event Quota", "ie_value" : "Event Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if event-based measurement is used and the CP function needs to provision an Event Quota in the UP function (see clause 5.2.2.2)When present, it shall indicate the Event Quota value."}) +ies.append({ "ie_type" : "Time Threshold", "ie_value" : "Time Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if time-based measurement is used and reporting is required upon reaching a time threshold. When present, it shall indicate the time usage after which the UP function shall report network resources usage to the CP function for this URR."}) +ies.append({ "ie_type" : "Time Quota", "ie_value" : "Time Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if time-based measurement is used and the CP function needs to provision a Time Quota in the UP function (see clause 5.2.2.2)When present, it shall indicate the Time Quota value"}) +ies.append({ "ie_type" : "Quota Holding Time", "ie_value" : "Quota Holding Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, for a time, volume or event-based measurement, if reporting is required and packets are no longer permitted to pass on when no packets are received during a given inactivity period.When present, it shall contain the duration of the inactivity period."}) +ies.append({ "ie_type" : "Dropped DL Traffic Threshold", "ie_value" : "Dropped DL Traffic Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if reporting is required when the DL traffic being dropped exceeds a threshold.When present, it shall contain the threshold of the DL traffic being dropped."}) +ies.append({ "ie_type" : "Quota Validity Time", "ie_value" : "Quota Validity Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if reporting is required when the Quota Validity time for a given Quota is over."}) +ies.append({ "ie_type" : "Monitoring Time", "ie_value" : "Monitoring Time", "presence" : "O", "tlv_more" : "0", "comment" : "When present, this IE shall contain the time at which the UP function shall re-apply the volume or time threshold. "}) +ies.append({ "ie_type" : "Subsequent Volume Threshold", "ie_value" : "Subsequent Volume Threshold", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the Monitoring Time IE is present and volume-based measurement is used.When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Time Threshold", "ie_value" : "Subsequent Time Threshold", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the Monitoring Time IE is present and time-based measurement is used.When present, it shall indicate the time usage after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Volume Quota", "ie_value" : "Subsequent Volume Quota", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if Monitoring Time IE is present and volume-based measurement is used (see clause 5.2.2.2).When present, it shall indicate the Volume Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Time Quota", "ie_value" : "Subsequent Time Quota", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if Monitoring Time IE is present and time-based measurement is used (see clause 5.2.2.2)When present, it shall indicate the Time Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Event Threshold", "ie_value" : "Subsequent Event Threshold", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the Monitoring Time IE is present and event-based measurement is used.When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Event Quota", "ie_value" : "Subsequent Event Quota", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if Monitoring Time IE is present and event-based measurement is used (see clause 5.2.2.2).When present, it shall indicate the Event Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Inactivity Detection Time", "ie_value" : "Inactivity Detection Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if time-based measurement is used and the time measurement need to be suspended when no packets are received during a given inactivity period. When present, it shall contain the duration of the inactivity period."}) +ies.append({ "ie_type" : "Linked URR ID", "ie_value" : "Linked URR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if linked usage reporting is required. When present, this IE shall contain the linked URR ID which is related with this URR (see clause 5.2.2.4).Several IEs with the same IE type may be present to represent multiple linked URRs which are related with this URR."}) +ies.append({ "ie_type" : "Measurement Information", "ie_value" : "Measurement Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if any of the following flag is set to 1.Applicable flags are:- Measurement Before QoS Enforcement Flag: this flag shall be set to 1 if the traffic usage before any QoS Enforcement is requested to be measured.- Inactive Measurement Flag: this flag shall be set to 1 if the measurement shall be paused (inactive). The measurement shall be performed (active) if the bit is set to 0 or if the Measurement Information IE is not present in the Create URR IE.- Reduced Application Detection Information Flag: this flag may be set to 1, if the Reporting Triggers request to report the start or stop of application, to request the UP function to only report the Application ID in the Application Detection Information, e.g. for envelope reporting.- Immediate Start Time Metering Flag: this flag may be set to 1 if time-based measurement is used and the UP function is requested to start the time metering immediately at receiving the flag. .- Measurement of Number of Packets Flag: this flag may be set to 1 when the Volume-based measurement applies, to request the UP function to report the number of packets in UL/DL/Total in addition to the measurement in octet."}) +ies.append({ "ie_type" : "Time Quota Mechanism", "ie_value" : "Time Quota Mechanism", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if time-based measurement based on CTP or DTP is used."}) +ies.append({ "ie_type" : "Aggregated URRs", "ie_value" : "Aggregated URRs", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the URR is used to support a Credit Pool.Several IEs with the same IE type may be present to provide multiple aggregated URRs."}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID for Quota Action", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present if the Volume Quota IE and/or the Time Quota IE and/or Event Quota IE is provisioned in the URR and the UP Function indicated support of the Quota Action feature.When present, it shall contain the identifier of the substitute FAR the UP function shall apply, for the traffic associated to this URR, when exhausting any of these quotas. See NOTE 1. "}) +ies.append({ "ie_type" : "Ethernet Inactivity Timer", "ie_value" : "Ethernet Inactivity Timer", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if Ethernet traffic reporting is used and the SMF requests the UP function to also report inactive UE MAC addresses.When present, it shall contain the duration of the Ethernet inactivity period."}) +ies.append({ "ie_type" : "Additional Monitoring Time", "ie_value" : "Additional Monitoring Time", "presence" : "O", "tlv_more" : "0", "comment" : "When present, this IE shall contain the time at which the UP function shall re-apply the volume or time or event threshold/quota provisioned in the IE.Several IEs with the same IE type may be present to provide multiple Monitoring Times."}) group_list["Create URR"] = { "index" : "106", "type" : "6", "ies" : ies } ies = [] -ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the QER among all the QER configured for that PFCP session"}) -ies.append({ "ie_type" : "QER Correlation ID", "ie_value" : "QER Correlation ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to correlate the QERs of several PFCP sessions, for APN-AMBR enforcement of multiple UEs PDN connections to the same APN."}) -ies.append({ "ie_type" : "Gate Status", "ie_value" : "Gate Status", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate whether the packets are allowed to be forwarded (the gate is open) or shall be discarded (the gate is closed) in the uplink and/or downlink directions."}) -ies.append({ "ie_type" : "MBR", "ie_value" : "Maximum Bitrate", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if an MBR enforcement action shall be applied to packets matching this PDR. When present, this IE shall indicate the uplink and/or downlink maximum bit rate to be enforced for packets matching the PDR.For EPC, this IE may be set to the value of:- the APN-AMBR, for a QER that is referenced by all the PDRs of the non-GBR bearers of a PDN connection;- the TDF session MBR, for a QER that is referenced by all the PDRs of a TDF session;- the bearer MBR, for a QER that is referenced by all the PDRs of a bearer;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF.For 5GC, this IE may be set to the value of:- the Session-AMBR, for a QER that is referenced by all the PDRs of the non-GBR QoS flows of a PDU session;- the QoS Flow MBR, for a QER that is referenced by all the PDRs of a QoS Flow;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF."}) -ies.append({ "ie_type" : "GBR", "ie_value" : "Guaranteed Bitrate", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a GBR has been authorized to packets matching this PDR. When present, this IE shall indicate the authorized uplink and/or downlink guaranteed bit rate.This IE may be set to the value of:- the aggregate GBR, for a QER that is referenced by all the PDRs of a GBR bearer;- the QoS Flow GBR, for a QER that is referenced by all the PDRs of a QoS Flow (for 5GC);- the SDF GBR, for a QER that is referenced by all the PDRs of a SDF."}) -ies.append({ "ie_type" : "Packet Rate", "ie_value" : "Packet Rate", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a Packet Rate enforcement action (in terms of number of packets per time interval) shall be applied to packets matching this PDR.When present, this IE shall indicate the uplink and/or downlink maximum packet rate to be enforced for packets matching the PDR.This IE may be set to the value of:- downlink packet rate for Serving PLMN Rate Control, for a QER that is referenced by all PDRs of the UE belonging to the PDN connection using CIoT EPS Optimizations as described in 3GPPTS23.401[2]);- uplink and/or downlink packet rate for APN Rate Control, for a QER that is referenced by all the PDRs of the UE belonging to PDN connections to the same APN using CIoT EPS Optimizations as described in 3GPPTS23.401[2])."}) -ies.append({ "ie_type" : "DL Flow Level Marking", "ie_value" : "DL Flow Level Marking", "presence" : "C", "instance" : "0", "comment" : "This IE shall be set if the UP function is required to mark the packets for QoS purposes:- by the TDF-C, for DL flow level marking for application indication (see clause 5.4.5);- by the PGW-C, for setting the GTP-U Service Class Indicator extension header for service indication towards GERAN (see clause 5.4.12)."}) -ies.append({ "ie_type" : "QFI", "ie_value" : "QoS flow identifier", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the QoS flow identifier shall be inserted by the UPF."}) -ies.append({ "ie_type" : "RQI", "ie_value" : "Reflective QoS", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function is required to insert a Reflective QoS Identifier to request reflective QoS for uplink traffic."}) -ies.append({ "ie_type" : "Paging Policy Indicator", "ie_value" : "Paging Policy Indicator", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UPF is required to set the Paging Policy Indicator (PPI) in outgoing packets (see clause 5.4.3.2 of 3GPPTS23.501[28]).When present, it shall be set to the PPI value to set. "}) -ies.append({ "ie_type" : "Averaging Window", "ie_value" : "Averaging Window", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UP function is required to use a different Averaging window than the default one. (NOTE)"}) +ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the QER among all the QER configured for that PFCP session"}) +ies.append({ "ie_type" : "QER Correlation ID", "ie_value" : "QER Correlation ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to correlate the QERs of several PFCP sessions, for APN-AMBR enforcement of multiple UEs PDN connections to the same APN."}) +ies.append({ "ie_type" : "Gate Status", "ie_value" : "Gate Status", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate whether the packets are allowed to be forwarded (the gate is open) or shall be discarded (the gate is closed) in the uplink and/or downlink directions."}) +ies.append({ "ie_type" : "MBR", "ie_value" : "Maximum Bitrate", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if an MBR enforcement action shall be applied to packets matching this PDR. When present, this IE shall indicate the uplink and/or downlink maximum bit rate to be enforced for packets matching the PDR.For EPC, this IE may be set to the value of:- the APN-AMBR, for a QER that is referenced by all the PDRs of the non-GBR bearers of a PDN connection;- the TDF session MBR, for a QER that is referenced by all the PDRs of a TDF session;- the bearer MBR, for a QER that is referenced by all the PDRs of a bearer;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF.For 5GC, this IE may be set to the value of:- the Session-AMBR, for a QER that is referenced by all the PDRs of the non-GBR QoS flows of a PDU session;- the QoS Flow MBR, for a QER that is referenced by all the PDRs of a QoS Flow;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF."}) +ies.append({ "ie_type" : "GBR", "ie_value" : "Guaranteed Bitrate", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a GBR has been authorized to packets matching this PDR. When present, this IE shall indicate the authorized uplink and/or downlink guaranteed bit rate.This IE may be set to the value of:- the aggregate GBR, for a QER that is referenced by all the PDRs of a GBR bearer;- the QoS Flow GBR, for a QER that is referenced by all the PDRs of a QoS Flow (for 5GC);- the SDF GBR, for a QER that is referenced by all the PDRs of a SDF."}) +ies.append({ "ie_type" : "Packet Rate", "ie_value" : "Packet Rate", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a Packet Rate enforcement action (in terms of number of packets per time interval) shall be applied to packets matching this PDR.When present, this IE shall indicate the uplink and/or downlink maximum packet rate to be enforced for packets matching the PDR.This IE may be set to the value of:- downlink packet rate for Serving PLMN Rate Control, for a QER that is referenced by all PDRs of the UE belonging to the PDN connection using CIoT EPS Optimizations as described in 3GPPTS23.401[2]);- uplink and/or downlink packet rate for APN Rate Control, for a QER that is referenced by all the PDRs of the UE belonging to PDN connections to the same APN using CIoT EPS Optimizations as described in 3GPPTS23.401[2])."}) +ies.append({ "ie_type" : "DL Flow Level Marking", "ie_value" : "DL Flow Level Marking", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be set if the UP function is required to mark the packets for QoS purposes:- by the TDF-C, for DL flow level marking for application indication (see clause 5.4.5);- by the PGW-C, for setting the GTP-U Service Class Indicator extension header for service indication towards GERAN (see clause 5.4.12)."}) +ies.append({ "ie_type" : "QFI", "ie_value" : "QoS flow identifier", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the QoS flow identifier shall be inserted by the UPF."}) +ies.append({ "ie_type" : "RQI", "ie_value" : "Reflective QoS", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function is required to insert a Reflective QoS Identifier to request reflective QoS for uplink traffic."}) +ies.append({ "ie_type" : "Paging Policy Indicator", "ie_value" : "Paging Policy Indicator", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UPF is required to set the Paging Policy Indicator (PPI) in outgoing packets (see clause 5.4.3.2 of 3GPPTS23.501[28]).When present, it shall be set to the PPI value to set. "}) +ies.append({ "ie_type" : "Averaging Window", "ie_value" : "Averaging Window", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the UP function is required to use a different Averaging window than the default one. (NOTE)"}) group_list["Create QER"] = { "index" : "107", "type" : "7", "ies" : ies } ies = [] -ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the BAR provisioned for that PFCP session."}) -ies.append({ "ie_type" : "Downlink Data Notification Delay", "ie_value" : "Downlink Data Notification Delay", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function indicated support of the Downlink Data Notification Delay parameter (see clause 8.2.28) and the UP function has to delay the notification to the CP function about the arrival of DL data packets.When present, it shall contain the delay the UP function shall apply between receiving a downlink data packet and notifying the CP function about it, when the Apply Action parameter requests to buffer the packets and notify the CP function."}) -ies.append({ "ie_type" : "Suggested Buffering Packets Count", "ie_value" : "Suggested Buffering Packets Count", "presence" : "C", "instance" : "0", "comment" : "This IE may be present if the UP Function indicated support of the the feature UDBC.When present, it shall contain the number of packets that are suggested to be buffered when the Apply Action parameter requests to buffer the packets. The packets that exceed the limit shall be discarded."}) +ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the BAR provisioned for that PFCP session."}) +ies.append({ "ie_type" : "Downlink Data Notification Delay", "ie_value" : "Downlink Data Notification Delay", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function indicated support of the Downlink Data Notification Delay parameter (see clause 8.2.28) and the UP function has to delay the notification to the CP function about the arrival of DL data packets.When present, it shall contain the delay the UP function shall apply between receiving a downlink data packet and notifying the CP function about it, when the Apply Action parameter requests to buffer the packets and notify the CP function."}) +ies.append({ "ie_type" : "Suggested Buffering Packets Count", "ie_value" : "Suggested Buffering Packets Count", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present if the UP Function indicated support of the the feature UDBC.When present, it shall contain the number of packets that are suggested to be buffered when the Apply Action parameter requests to buffer the packets. The packets that exceed the limit shall be discarded."}) group_list["Create BAR"] = { "index" : "185", "type" : "85", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the Traffic Endpoint for that Sx session."}) -ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the local F-TEID to match for an incoming packet.The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of F-TEID and the CP function requests the UP function to assign a local F-TEID to the Traffic Endpoint."}) -ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "O", "instance" : "0", "comment" : "This IE shall be present if the CP function requests the UP function to allocate a UE IP address/prefix.If present, this IE shall identify the Network instance to match for the incoming packet. See NOTE 1, NOTE2."}) -ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall identify the source or destination IP address to match for the incoming packet. (NOTE 3)The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of UE IP address/ prefix and the CP function requests the UP function to assign a UE IP address/prefix to the Traffic Endpoint."}) -ies.append({ "ie_type" : "Ethernet PDU Session Information", "ie_value" : "Ethernet PDU Session Information", "presence" : "O", "instance" : "0", "comment" : "This IE may be present to identify all the (DL) Ethernet packets matching an Ethernet PDU session (see clause 5.13.1)."}) -ies.append({ "ie_type" : "Framed-Route", "ie_value" : "Framed-Route", "presence" : "O", "instance" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed route.Several IEs with the same IE type may be present to provision a list of framed routes. (NOTE 3)"}) -ies.append({ "ie_type" : "Framed-Routing", "ie_value" : "Framed-Routing", "presence" : "O", "instance" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe the framed routing associated to a framed route. "}) -ies.append({ "ie_type" : "Framed-IPv6-Route", "ie_value" : "Framed-IPv6-Route", "presence" : "O", "instance" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed IPv6 route.Several IEs with the same IE type may be present to provision a list of framed IPv6 routes. (NOTE 3)"}) -ies.append({ "ie_type" : "QFI", "ie_value" : "QFI", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UPF has indicated it supports MTE feature as specified in clause 8.2.25.If present, this IE shall identify the QoS Flow Identifier to match for the incoming packet received from the traffic endpoint.Several IEs with the same IE type may be present to provision a list of QFIs. When present, the full set of applicable QFIs shall be provided."}) +ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the Traffic Endpoint for that Sx session."}) +ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the local F-TEID to match for an incoming packet.The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of F-TEID and the CP function requests the UP function to assign a local F-TEID to the Traffic Endpoint."}) +ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall be present if the CP function requests the UP function to allocate a UE IP address/prefix.If present, this IE shall identify the Network instance to match for the incoming packet. See NOTE 1, NOTE2."}) +ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall identify the source or destination IP address to match for the incoming packet. (NOTE 3)The CP function shall set the CHOOSE (CH) bit to 1 if the UP function supports the allocation of UE IP address/ prefix and the CP function requests the UP function to assign a UE IP address/prefix to the Traffic Endpoint."}) +ies.append({ "ie_type" : "Ethernet PDU Session Information", "ie_value" : "Ethernet PDU Session Information", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present to identify all the (DL) Ethernet packets matching an Ethernet PDU session (see clause 5.13.1)."}) +ies.append({ "ie_type" : "Framed-Route", "ie_value" : "Framed-Route", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed route.Several IEs with the same IE type may be present to provision a list of framed routes. (NOTE 3)"}) +ies.append({ "ie_type" : "Framed-Routing", "ie_value" : "Framed-Routing", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe the framed routing associated to a framed route. "}) +ies.append({ "ie_type" : "Framed-IPv6-Route", "ie_value" : "Framed-IPv6-Route", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present for a DL PDR if the UPF indicated support of Framed Routing (see clause 8.2.25). If present, this IE shall describe a framed IPv6 route.Several IEs with the same IE type may be present to provision a list of framed IPv6 routes. (NOTE 3)"}) +ies.append({ "ie_type" : "QFI", "ie_value" : "QFI", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the UPF has indicated it supports MTE feature as specified in clause 8.2.25.If present, this IE shall identify the QoS Flow Identifier to match for the incoming packet received from the traffic endpoint.Several IEs with the same IE type may be present to provision a list of QFIs. When present, the full set of applicable QFIs shall be provided."}) group_list["Create Traffic Endpoint"] = { "index" : "227", "type" : "127", "ies" : ies } ies = [] -ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the MAR among all the MARs configured for that PFCP session."}) -ies.append({ "ie_type" : "Steering Functionality", "ie_value" : "Steering Functionality", "presence" : "M", "instance" : "0", "comment" : "This IE shall be present to indicate the applicable traffic steering functionality."}) -ies.append({ "ie_type" : "Steering Mode", "ie_value" : "Steering Mode", "presence" : "M", "instance" : "0", "comment" : "This IE shall be present to indicate the steering mode."}) -ies.append({ "ie_type" : "Access Forwarding Action Information 1", "ie_value" : "Access Forwarding Action Information 1", "presence" : "M", "instance" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information."}) -ies.append({ "ie_type" : "Access Forwarding Action Information 2", "ie_value" : "Access Forwarding Action Information 2", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information if the UE is registered for both non-3GPP and 3GPP accesses."}) +ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the MAR among all the MARs configured for that PFCP session."}) +ies.append({ "ie_type" : "Steering Functionality", "ie_value" : "Steering Functionality", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall be present to indicate the applicable traffic steering functionality."}) +ies.append({ "ie_type" : "Steering Mode", "ie_value" : "Steering Mode", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall be present to indicate the steering mode."}) +ies.append({ "ie_type" : "Access Forwarding Action Information 1", "ie_value" : "Access Forwarding Action Information 1", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information."}) +ies.append({ "ie_type" : "Access Forwarding Action Information 2", "ie_value" : "Access Forwarding Action Information 2", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information if the UE is registered for both non-3GPP and 3GPP accesses."}) group_list["Create MAR"] = { "index" : "265", "type" : "165", "ies" : ies } ies = [] -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the FAR among all the FARs configured for this PFCP session. "}) -ies.append({ "ie_type" : "Weight", "ie_value" : "Weight", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if steering mode is set to Load Balancing to identify the weight of the FAR.(NOTE 1) "}) -ies.append({ "ie_type" : "Priority", "ie_value" : "Priority", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the steering mode is set to Active-Standby or Priority-based. (NOTE 2)"}) -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall uniquely identify the URR among all the URRs configured for the PFCP session. This enables the SMF to request separate usage reports for different FARs (i.e. different accesses) (NOTE 3)Several IEs within the same IE type may be present to represent a list of URRs to be associated to the FAR."}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the FAR among all the FARs configured for this PFCP session. "}) +ies.append({ "ie_type" : "Weight", "ie_value" : "Weight", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if steering mode is set to Load Balancing to identify the weight of the FAR.(NOTE 1) "}) +ies.append({ "ie_type" : "Priority", "ie_value" : "Priority", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the steering mode is set to Active-Standby or Priority-based. (NOTE 2)"}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the URR among all the URRs configured for the PFCP session. This enables the SMF to request separate usage reports for different FARs (i.e. different accesses) (NOTE 3)Several IEs within the same IE type may be present to represent a list of URRs to be associated to the FAR."}) group_list["Access Forwarding Action Information 1"] = { "index" : "266", "type" : "166", "ies" : ies } -ies = [] group_list["Access Forwarding Action Information 2"] = { "index" : "267", "type" : "167", "ies" : ies } ies = [] -ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "instance" : "0", "comment" : ""}) -ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "C", "instance" : "0", "comment" : "If the UP function allocates the F-TEID, this IE shall be present and shall contain the local F-TEID to be used for this PDR."}) -ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP Address", "presence" : "C", "instance" : "0", "comment" : "If the UP function allocates the UE IP address/prefix, this IE shall be present and shall contain the UE IP address/ prefix assigned by the UP function."}) +ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "tlv_more" : "0", "comment" : ""}) +ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "C", "tlv_more" : "0", "comment" : "If the UP function allocates the F-TEID, this IE shall be present and shall contain the local F-TEID to be used for this PDR."}) +ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP Address", "presence" : "C", "tlv_more" : "0", "comment" : "If the UP function allocates the UE IP address/prefix, this IE shall be present and shall contain the UE IP address/ prefix assigned by the UP function."}) group_list["Created PDR"] = { "index" : "108", "type" : "8", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Sequence Number", "ie_value" : "Load Control Sequence Number", "presence" : "M", "instance" : "0", "comment" : "See clause 6.2.3.3.2 for the description and use of this parameter."}) -ies.append({ "ie_type" : "Metric", "ie_value" : "Load Metric", "presence" : "M", "instance" : "0", "comment" : "See clause 6.2.3.3.2 for the description and use of this parameter."}) +ies.append({ "ie_type" : "Sequence Number", "ie_value" : "Load Control Sequence Number", "presence" : "M", "tlv_more" : "0", "comment" : "See clause 6.2.3.3.2 for the description and use of this parameter."}) +ies.append({ "ie_type" : "Metric", "ie_value" : "Load Metric", "presence" : "M", "tlv_more" : "0", "comment" : "See clause 6.2.3.3.2 for the description and use of this parameter."}) group_list["Load Control Information"] = { "index" : "151", "type" : "51", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Sequence Number", "ie_value" : "Overload Control Sequence Number", "presence" : "M", "instance" : "0", "comment" : "See clause 6.2.4.3.2 for the description and use of this parameter."}) -ies.append({ "ie_type" : "Metric", "ie_value" : "Overload Reduction Metric", "presence" : "M", "instance" : "0", "comment" : "See clause 6.2.4.3.2 for the description and use of this parameter."}) -ies.append({ "ie_type" : "Timer", "ie_value" : "Period of Validity", "presence" : "M", "instance" : "0", "comment" : "See clause 6.2.4.3.2 for the description and use of this parameter."}) -ies.append({ "ie_type" : "OCI Flags", "ie_value" : "Overload Control Information Flags", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if any of flag in this IE is set. "}) +ies.append({ "ie_type" : "Sequence Number", "ie_value" : "Overload Control Sequence Number", "presence" : "M", "tlv_more" : "0", "comment" : "See clause 6.2.4.3.2 for the description and use of this parameter."}) +ies.append({ "ie_type" : "Metric", "ie_value" : "Overload Reduction Metric", "presence" : "M", "tlv_more" : "0", "comment" : "See clause 6.2.4.3.2 for the description and use of this parameter."}) +ies.append({ "ie_type" : "Timer", "ie_value" : "Period of Validity", "presence" : "M", "tlv_more" : "0", "comment" : "See clause 6.2.4.3.2 for the description and use of this parameter."}) +ies.append({ "ie_type" : "OCI Flags", "ie_value" : "Overload Control Information Flags", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if any of flag in this IE is set. "}) group_list["Overload Control Information"] = { "index" : "154", "type" : "54", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the Traffic Endpoint for that Sx session."}) -ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "C", "instance" : "0", "comment" : "If the UP function allocates the F-TEID, this IE shall be present and shall contain the local F-TEID to be used for this Traffic Endpoint."}) -ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP Address", "presence" : "C", "instance" : "0", "comment" : "If the UP function allocates the UE IP address/prefix, this IE shall be present and shall contain the UE IP address/ prefix assigned by the UP function."}) +ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the Traffic Endpoint for that Sx session."}) +ies.append({ "ie_type" : "F-TEID", "ie_value" : "Local F-TEID", "presence" : "C", "tlv_more" : "0", "comment" : "If the UP function allocates the F-TEID, this IE shall be present and shall contain the local F-TEID to be used for this Traffic Endpoint."}) +ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP Address", "presence" : "C", "tlv_more" : "0", "comment" : "If the UP function allocates the UE IP address/prefix, this IE shall be present and shall contain the UE IP address/ prefix assigned by the UP function."}) group_list["Created Traffic Endpoint"] = { "index" : "228", "type" : "128", "ies" : ies } ies = [] -ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the PDR among all the PDRs configured for that PFCP session."}) -ies.append({ "ie_type" : "Outer Header Removal", "ie_value" : "Outer Header Removal", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it needs to be changed."}) -ies.append({ "ie_type" : "Precedence", "ie_value" : "Precedence", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if there is a change in the PDRs precedence to be applied by the UP function among all PDRs of the PFCP session, when looking for a PDR matching an incoming packet."}) -ies.append({ "ie_type" : "PDI", "ie_value" : "PDI", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if there is a change within the PDI against which incoming packets will be matched. When present, this IE shall replace the PDI previously stored in the UP function for this PDR. See Table 7.5.2.2-2."}) -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it needs to be changed"}) -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a measurement action shall be applied or no longer applied to packets matching this PDR.When present, this IE shall contain the list of all the URR IDs to be associated to the PDR."}) -ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a QoS enforcement action shall be applied or no longer applied to packets matching this PDR.When present, this IE shall contain the list of all the QER IDs to be associated to the PDR."}) -ies.append({ "ie_type" : "Activate Predefined Rules", "ie_value" : "Activate Predefined Rules", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if new Predefined Rule(s) needs to be activated for the PDR. When present this IE shall contain one Predefined Rules name.Several IEs with the same IE type may be present to represent multiple Activate Predefined Rules names."}) -ies.append({ "ie_type" : "Deactivate Predefined Rules", "ie_value" : "Deactivate Predefined Rules", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if Predefined Rule(s) needs to be deactivated for the PDR. When present this IE shall contain one Predefined Rules name.Several IEs with the same IE type may be present to represent multiple Activate Predefined Rules names."}) -ies.append({ "ie_type" : "Activation Time", "ie_value" : "Activation Time", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the PDR activation time shall be changed. (NOTE 2)"}) -ies.append({ "ie_type" : "Deactivation Time", "ie_value" : "Deactivation Time", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the PDR deactivation time shall be changed. (NOTE 2)"}) +ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the PDR among all the PDRs configured for that PFCP session."}) +ies.append({ "ie_type" : "Outer Header Removal", "ie_value" : "Outer Header Removal", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it needs to be changed."}) +ies.append({ "ie_type" : "Precedence", "ie_value" : "Precedence", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if there is a change in the PDRs precedence to be applied by the UP function among all PDRs of the PFCP session, when looking for a PDR matching an incoming packet."}) +ies.append({ "ie_type" : "PDI", "ie_value" : "PDI", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if there is a change within the PDI against which incoming packets will be matched. When present, this IE shall replace the PDI previously stored in the UP function for this PDR. See Table 7.5.2.2-2."}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it needs to be changed"}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a measurement action shall be applied or no longer applied to packets matching this PDR.When present, this IE shall contain the list of all the URR IDs to be associated to the PDR."}) +ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a QoS enforcement action shall be applied or no longer applied to packets matching this PDR.When present, this IE shall contain the list of all the QER IDs to be associated to the PDR."}) +ies.append({ "ie_type" : "Activate Predefined Rules", "ie_value" : "Activate Predefined Rules", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if new Predefined Rule(s) needs to be activated for the PDR. When present this IE shall contain one Predefined Rules name.Several IEs with the same IE type may be present to represent multiple Activate Predefined Rules names."}) +ies.append({ "ie_type" : "Deactivate Predefined Rules", "ie_value" : "Deactivate Predefined Rules", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if Predefined Rule(s) needs to be deactivated for the PDR. When present this IE shall contain one Predefined Rules name.Several IEs with the same IE type may be present to represent multiple Activate Predefined Rules names."}) +ies.append({ "ie_type" : "Activation Time", "ie_value" : "Activation Time", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the PDR activation time shall be changed. (NOTE 2)"}) +ies.append({ "ie_type" : "Deactivation Time", "ie_value" : "Deactivation Time", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the PDR deactivation time shall be changed. (NOTE 2)"}) group_list["Update PDR"] = { "index" : "109", "type" : "9", "ies" : ies } ies = [] -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the FAR to be updated."}) -ies.append({ "ie_type" : "Apply Action", "ie_value" : "Apply Action", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed."}) -ies.append({ "ie_type" : "Update Forwarding Parameters", "ie_value" : "Update Forwarding parameters", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed.See table 7.5.4.3-2."}) -ies.append({ "ie_type" : "Update Duplicating Parameters", "ie_value" : "Update Duplicating Parameters", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed. See table 7.5.4.3-3.Several IEs with the same IE type may be present to request to duplicate the packets to different destinations."}) -ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the BAR ID associated to the FAR needs to be modified. "}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the FAR to be updated."}) +ies.append({ "ie_type" : "Apply Action", "ie_value" : "Apply Action", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed."}) +ies.append({ "ie_type" : "Update Forwarding Parameters", "ie_value" : "Update Forwarding parameters", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed.See table 7.5.4.3-2."}) +ies.append({ "ie_type" : "Update Duplicating Parameters", "ie_value" : "Update Duplicating Parameters", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed. See table 7.5.4.3-3.Several IEs with the same IE type may be present to request to duplicate the packets to different destinations."}) +ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the BAR ID associated to the FAR needs to be modified. "}) group_list["Update FAR"] = { "index" : "110", "type" : "10", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed.When present, it shall indicate the destination interface of the outgoing packet."}) -ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network instance", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed."}) -ies.append({ "ie_type" : "Redirect Information", "ie_value" : "Redirect Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the instructions regarding the redirection of traffic by the UP function need to be modified."}) -ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) -ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level Marking", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed"}) -ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) -ies.append({ "ie_type" : "Header Enrichment", "ie_value" : "Header Enrichment", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed"}) -ies.append({ "ie_type" : "PFCPSMReq-Flags", "ie_value" : "PFCPSMReq-Flags", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- SNDEM (Send End Marker Packets): this IE shall be present if the CP function modifies the F-TEID of the downstream node in the Outer Header Creation IE and the CP function requests the UP function to construct and send GTP-U End Marker messages towards the old F-TEID of the downstream node. "}) -ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Linked Traffic Endpoint ID", "presence" : "C", "instance" : "0", "comment" : "This IE may be present, if it is changed and the UP function indicated support of the PDI optimization feature, (see clause 8.2.25). When present, it shall identify the Traffic Endpoint ID allocated for this PFCP session to receive the traffic in the reverse direction (see clause 5.2.3.1)."}) -ies.append({ "ie_type" : "3GPP Interface Type", "ie_value" : "Destination Interface Type", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present to indicate the 3GPP interface type of the destination interface, if the value has changed."}) +ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed.When present, it shall indicate the destination interface of the outgoing packet."}) +ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network instance", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed."}) +ies.append({ "ie_type" : "Redirect Information", "ie_value" : "Redirect Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the instructions regarding the redirection of traffic by the UP function need to be modified."}) +ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) +ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level Marking", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed"}) +ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) +ies.append({ "ie_type" : "Header Enrichment", "ie_value" : "Header Enrichment", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed"}) +ies.append({ "ie_type" : "PFCPSMReq-Flags", "ie_value" : "PFCPSMReq-Flags", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- SNDEM (Send End Marker Packets): this IE shall be present if the CP function modifies the F-TEID of the downstream node in the Outer Header Creation IE and the CP function requests the UP function to construct and send GTP-U End Marker messages towards the old F-TEID of the downstream node. "}) +ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Linked Traffic Endpoint ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present, if it is changed and the UP function indicated support of the PDI optimization feature, (see clause 8.2.25). When present, it shall identify the Traffic Endpoint ID allocated for this PFCP session to receive the traffic in the reverse direction (see clause 5.2.3.1)."}) +ies.append({ "ie_type" : "3GPP Interface Type", "ie_value" : "Destination Interface Type", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present to indicate the 3GPP interface type of the destination interface, if the value has changed."}) group_list["Update Forwarding Parameters"] = { "index" : "111", "type" : "11", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed.When present, it shall indicate the destination interface of the outgoing packet."}) -ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) -ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level Marking", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed."}) -ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "instance" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) +ies.append({ "ie_type" : "Destination Interface", "ie_value" : "Destination Interface", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed.When present, it shall indicate the destination interface of the outgoing packet."}) +ies.append({ "ie_type" : "Outer Header Creation", "ie_value" : "Outer Header Creation", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) +ies.append({ "ie_type" : "Transport Level Marking", "ie_value" : "Transport Level Marking", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed."}) +ies.append({ "ie_type" : "Forwarding Policy", "ie_value" : "Forwarding Policy", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall only be provided if it is changed. SeeNOTE1."}) group_list["Update Duplicating Parameters"] = { "index" : "205", "type" : "105", "ies" : ies } ies = [] -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the URR among all the URRs configured for that PFCP session"}) -ies.append({ "ie_type" : "Measurement Method", "ie_value" : "Measurement Method", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the measurement method needs to be modified.When present, this IE shall indicate the method for measuring the network resources usage, i.e. whether the data volume, duration (i.e. time), combined volume/duration, or event shall be measured."}) -ies.append({ "ie_type" : "Reporting Triggers", "ie_value" : "Reporting Triggers", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the reporting triggers needs to be modified.When present, this IE shall indicate the trigger(s) for reporting network resources usage to the CP function, e.g. periodic reporting or reporting upon reaching a threshold, or envelope closure."}) -ies.append({ "ie_type" : "Measurement Period", "ie_value" : "Measurement Period", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Measurement Period needs to be modified.When present, it shall indicate the period for generating and reporting usage reports. "}) -ies.append({ "ie_type" : "Volume Threshold", "ie_value" : "Volume Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Volume Threshold needs to be modified. When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR."}) -ies.append({ "ie_type" : "Volume Quota", "ie_value" : "Volume Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Volume Quota needs to be modified.When present, it shall indicate the Volume Quota value."}) -ies.append({ "ie_type" : "Time Threshold", "ie_value" : "Time Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Time Threshold needs to be modified. When present, it shall indicate the time usage after which the UP function shall report network resources usage to the CP function for this URR."}) -ies.append({ "ie_type" : "Time Quota", "ie_value" : "Time Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Time Quota needs to be modified.When present, it shall indicate the Time Quota value."}) -ies.append({ "ie_type" : "Event Threshold", "ie_value" : "Event Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if Event Threshold needs to be modified.When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR."}) -ies.append({ "ie_type" : "Event Quota", "ie_value" : "Event Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if Event Quota needs to be modified.When present, it shall indicate the Event Quota value."}) -ies.append({ "ie_type" : "Quota Holding Time", "ie_value" : "Quota Holding Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Quota Holding Time needs to be modified.When present, it shall contain the duration of the Quota Holding Time."}) -ies.append({ "ie_type" : "Dropped DL Traffic Threshold", "ie_value" : "Dropped DL Traffic Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Dropped DL Threshold needs to be modified.When present, it shall contain the threshold of the DL traffic being dropped."}) -ies.append({ "ie_type" : "Quota Validity Time", "ie_value" : "Quota Validity Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if Quota Validity time was not sent earlier or quota validity time value needs to be modified."}) -ies.append({ "ie_type" : "Monitoring Time", "ie_value" : "Monitoring Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Monitoring Time needs to be modified. When present, this IE shall contain the time at which the UP function shall re-apply the volume or time threshold. "}) -ies.append({ "ie_type" : "Subsequent Volume Threshold", "ie_value" : "Subsequent Volume Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Subsequent Volume Threshold needs to be modified and volume-based measurement is used.When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Time Threshold", "ie_value" : "Subsequent Time Threshold", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Subsequent Time Threshold needs to be modified. When present, it shall indicate the time usage value after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Volume Quota", "ie_value" : "Subsequent Volume Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Subsequent Volume Quota needs to be modified.When present, it shall indicate the Volume Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Time Quota", "ie_value" : "Subsequent Time Quota", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Subsequent Time Quota needs to be modified.When present, it shall indicate the Time Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Event Threshold", "ie_value" : "Subsequent Event Threshold", "presence" : "O", "instance" : "0", "comment" : "This IE shall be present if the Subsequent Event Threshold needs to be modified.When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Subsequent Event Quota", "ie_value" : "Subsequent Event Quota", "presence" : "O", "instance" : "0", "comment" : "This IE shall be present if the Subsequent Event Quota needs to be modified.When present, it shall indicate the Event Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) -ies.append({ "ie_type" : "Inactivity Detection Time", "ie_value" : "Inactivity Detection Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Inactivity Detection Time needs to be modified.When present, it shall indicate the duration of the inactivity period after which time measurement needs to be suspended when no packets are received during this inactivity period. "}) -ies.append({ "ie_type" : "Linked URR ID", "ie_value" : "Linked URR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if linked usage reporting is required. When present, this IE shall contain the linked URR ID which is related with this URR (see clause 5.2.2.4).Several IEs with the same IE type may be present to represent multiple linked URRs which are related with this URR."}) -ies.append({ "ie_type" : "Measurement Information", "ie_value" : "Measurement Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if any of the following flag is set to 1.Applicable flags are:- Inactive Measurement Flag: this flag shall be set to 1 if the measurement shall be paused (inactive). The measurement shall be performed (active) if the bit is set to 0 or if the Measurement Information IE is not present in the Update URR IE.- Reduced Application Detection Information Flag: this flag may be set to 1, if the Reporting Triggers request to report the start or stop of application, to request the UP function to only report the Application ID in the Application Detection Information, e.g. for envelope reporting.- Immediate Start Time Metering Flag: this flag may be set to 1 if time-based measurement is used and the UP function is requested to start the time metering immediately at receiving the flag."}) -ies.append({ "ie_type" : "Time Quota Mechanism", "ie_value" : "Time Quota Mechanism", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if time-based measurement based on CTP or DTP needs to be modified."}) -ies.append({ "ie_type" : "Aggregated URRs", "ie_value" : "Aggregated URRs", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the Aggregated URRs IE needs to be modified. See Table 7.5.2.4-2.Several IEs with the same IE type may be present to provision multiple aggregated URRs.When present, this IE shall provide the complete list of the aggregated URRs."}) -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID for Quota Action", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the FAR ID for Quota Action IE needs to be modified. This IE may be present if the Volume Quota IE or the Time Quota IE or Event Quota IE is newly provisioned in the URR and the UP Function indicated support of the Quota Action.When present, it shall contain the identifier of the substitute FAR the UP function shall apply, for the traffic associated to this URR, when exhausting any of these quotas. See NOTE 1. "}) -ies.append({ "ie_type" : "Ethernet Inactivity Timer", "ie_value" : "Ethernet Inactivity Timer", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Ethernet Inactivity Timer needs to be modified. When present, it shall contain the duration of the Ethernet inactivity period."}) -ies.append({ "ie_type" : "Additional Monitoring Time", "ie_value" : "Additional Monitoring Time", "presence" : "O", "instance" : "0", "comment" : "This IE shall be present if the additional Monitoring Time needs to be modified. When present, this IE shall contain the time at which the UP function shall re-apply the volume or time or event threshold/quota. See Table 7.5.2.4-3.The CP function shall provide the full set of Additional Monitoring Times IE(s). The UP function shall replace any Additional Monitoring Times IE(s) provisioned earlier by the new set of received IE(s)."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the URR among all the URRs configured for that PFCP session"}) +ies.append({ "ie_type" : "Measurement Method", "ie_value" : "Measurement Method", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the measurement method needs to be modified.When present, this IE shall indicate the method for measuring the network resources usage, i.e. whether the data volume, duration (i.e. time), combined volume/duration, or event shall be measured."}) +ies.append({ "ie_type" : "Reporting Triggers", "ie_value" : "Reporting Triggers", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the reporting triggers needs to be modified.When present, this IE shall indicate the trigger(s) for reporting network resources usage to the CP function, e.g. periodic reporting or reporting upon reaching a threshold, or envelope closure."}) +ies.append({ "ie_type" : "Measurement Period", "ie_value" : "Measurement Period", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Measurement Period needs to be modified.When present, it shall indicate the period for generating and reporting usage reports. "}) +ies.append({ "ie_type" : "Volume Threshold", "ie_value" : "Volume Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Volume Threshold needs to be modified. When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR."}) +ies.append({ "ie_type" : "Volume Quota", "ie_value" : "Volume Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Volume Quota needs to be modified.When present, it shall indicate the Volume Quota value."}) +ies.append({ "ie_type" : "Time Threshold", "ie_value" : "Time Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Time Threshold needs to be modified. When present, it shall indicate the time usage after which the UP function shall report network resources usage to the CP function for this URR."}) +ies.append({ "ie_type" : "Time Quota", "ie_value" : "Time Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Time Quota needs to be modified.When present, it shall indicate the Time Quota value."}) +ies.append({ "ie_type" : "Event Threshold", "ie_value" : "Event Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if Event Threshold needs to be modified.When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR."}) +ies.append({ "ie_type" : "Event Quota", "ie_value" : "Event Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if Event Quota needs to be modified.When present, it shall indicate the Event Quota value."}) +ies.append({ "ie_type" : "Quota Holding Time", "ie_value" : "Quota Holding Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Quota Holding Time needs to be modified.When present, it shall contain the duration of the Quota Holding Time."}) +ies.append({ "ie_type" : "Dropped DL Traffic Threshold", "ie_value" : "Dropped DL Traffic Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Dropped DL Threshold needs to be modified.When present, it shall contain the threshold of the DL traffic being dropped."}) +ies.append({ "ie_type" : "Quota Validity Time", "ie_value" : "Quota Validity Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if Quota Validity time was not sent earlier or quota validity time value needs to be modified."}) +ies.append({ "ie_type" : "Monitoring Time", "ie_value" : "Monitoring Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Monitoring Time needs to be modified. When present, this IE shall contain the time at which the UP function shall re-apply the volume or time threshold. "}) +ies.append({ "ie_type" : "Subsequent Volume Threshold", "ie_value" : "Subsequent Volume Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Subsequent Volume Threshold needs to be modified and volume-based measurement is used.When present, it shall indicate the traffic volume value after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Time Threshold", "ie_value" : "Subsequent Time Threshold", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Subsequent Time Threshold needs to be modified. When present, it shall indicate the time usage value after which the UP function shall report network resources usage to the CP function for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Volume Quota", "ie_value" : "Subsequent Volume Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Subsequent Volume Quota needs to be modified.When present, it shall indicate the Volume Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Time Quota", "ie_value" : "Subsequent Time Quota", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Subsequent Time Quota needs to be modified.When present, it shall indicate the Time Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Event Threshold", "ie_value" : "Subsequent Event Threshold", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall be present if the Subsequent Event Threshold needs to be modified.When present, it shall indicate the number of events after which the UP function shall report to the CP function for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Subsequent Event Quota", "ie_value" : "Subsequent Event Quota", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall be present if the Subsequent Event Quota needs to be modified.When present, it shall indicate the Event Quota value which the UP function shall use for this URR for the period after the Monitoring Time."}) +ies.append({ "ie_type" : "Inactivity Detection Time", "ie_value" : "Inactivity Detection Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Inactivity Detection Time needs to be modified.When present, it shall indicate the duration of the inactivity period after which time measurement needs to be suspended when no packets are received during this inactivity period. "}) +ies.append({ "ie_type" : "Linked URR ID", "ie_value" : "Linked URR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if linked usage reporting is required. When present, this IE shall contain the linked URR ID which is related with this URR (see clause 5.2.2.4).Several IEs with the same IE type may be present to represent multiple linked URRs which are related with this URR."}) +ies.append({ "ie_type" : "Measurement Information", "ie_value" : "Measurement Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if any of the following flag is set to 1.Applicable flags are:- Inactive Measurement Flag: this flag shall be set to 1 if the measurement shall be paused (inactive). The measurement shall be performed (active) if the bit is set to 0 or if the Measurement Information IE is not present in the Update URR IE.- Reduced Application Detection Information Flag: this flag may be set to 1, if the Reporting Triggers request to report the start or stop of application, to request the UP function to only report the Application ID in the Application Detection Information, e.g. for envelope reporting.- Immediate Start Time Metering Flag: this flag may be set to 1 if time-based measurement is used and the UP function is requested to start the time metering immediately at receiving the flag."}) +ies.append({ "ie_type" : "Time Quota Mechanism", "ie_value" : "Time Quota Mechanism", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if time-based measurement based on CTP or DTP needs to be modified."}) +ies.append({ "ie_type" : "Aggregated URRs", "ie_value" : "Aggregated URRs", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the Aggregated URRs IE needs to be modified. See Table 7.5.2.4-2.Several IEs with the same IE type may be present to provision multiple aggregated URRs.When present, this IE shall provide the complete list of the aggregated URRs."}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID for Quota Action", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the FAR ID for Quota Action IE needs to be modified. This IE may be present if the Volume Quota IE or the Time Quota IE or Event Quota IE is newly provisioned in the URR and the UP Function indicated support of the Quota Action.When present, it shall contain the identifier of the substitute FAR the UP function shall apply, for the traffic associated to this URR, when exhausting any of these quotas. See NOTE 1. "}) +ies.append({ "ie_type" : "Ethernet Inactivity Timer", "ie_value" : "Ethernet Inactivity Timer", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Ethernet Inactivity Timer needs to be modified. When present, it shall contain the duration of the Ethernet inactivity period."}) +ies.append({ "ie_type" : "Additional Monitoring Time", "ie_value" : "Additional Monitoring Time", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall be present if the additional Monitoring Time needs to be modified. When present, this IE shall contain the time at which the UP function shall re-apply the volume or time or event threshold/quota. See Table 7.5.2.4-3.The CP function shall provide the full set of Additional Monitoring Times IE(s). The UP function shall replace any Additional Monitoring Times IE(s) provisioned earlier by the new set of received IE(s)."}) group_list["Update URR"] = { "index" : "113", "type" : "13", "ies" : ies } ies = [] -ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the QER among all the QRs configured for that PFCP session"}) -ies.append({ "ie_type" : "QER Correlation ID", "ie_value" : "QER Correlation ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the QER correlation ID in this QER needs to be modified.See NOTE 1."}) -ies.append({ "ie_type" : "Gate Status", "ie_value" : "Gate Status", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Gate Status needs to be modified. When present, it shall indicate whether the packets are allowed to be forwarded (the gate is open) or shall be discarded (the gate is closed) in the uplink and/or downlink directions.See NOTE 1."}) -ies.append({ "ie_type" : "MBR", "ie_value" : "Maximum Bitrate", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if an MBR enforcement action applied to packets matching this PDR need to be modified.When present, this IE shall indicate the uplink and/or downlink maximum bit rate to be enforced for packets matching the PDR.For EPC, this IE may be set to the value of:- the APN-AMBR, for a QER that is referenced by all the PDRs of the non-GBR bearers of a PDN connection;- the TDF session MBR, for a QER that is referenced by all the PDRs of a TDF session;- the bearer MBR, for a QER that is referenced by all the PDRs of a bearer;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF.For 5GC, this IE may be set to the value of:- the Session-AMBR, for a QER that is referenced by all the PDRs of the non-GBR QoS flows of a PDU session;- the QoS Flow MBR, for a QER that is referenced by all the PDRs of a QoS Flow;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF.See NOTE 1."}) -ies.append({ "ie_type" : "GBR", "ie_value" : "Guaranteed Bitrate", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a GBR authorization to packets matching this PDR needs to be modified. When present, this IE shall indicate the authorized uplink and/or downlink guaranteed bit rate.This IE may be set to the value of:- the aggregate GBR, for a QER that is referenced by all the PDRs of a GBR bearer;- the QoS Flow GBR, for a QER that is referenced by all the PDRs of a QoS Flow (for 5GC);- the SDF GBR, for a QER that is referenced by all the PDRs of a SDF.See NOTE 1."}) -ies.append({ "ie_type" : "Packet Rate", "ie_value" : "Packet Rate", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a Packet Rate enforcement action (in terms of number of packets per time interval) need to be modified for packets matching this PDR. "}) -ies.append({ "ie_type" : "DL Flow Level Marking", "ie_value" : "DL Flow Level Marking", "presence" : "C", "instance" : "0", "comment" : "This IE shall be set if the DL Flow Level Marking IE needs to be modified.See NOTE 1."}) -ies.append({ "ie_type" : "QFI", "ie_value" : "QoS flow identifier", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it needs to be modified."}) -ies.append({ "ie_type" : "RQI", "ie_value" : "Reflective QoS", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it needs to be modified."}) -ies.append({ "ie_type" : "Paging Policy Indicator", "ie_value" : "Paging Policy Indicator", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it needs to be modified."}) -ies.append({ "ie_type" : "Averaging Window", "ie_value" : "Averaging Window", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UP function is required to modify the Averaging Window. (NOTE 2)"}) +ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the QER among all the QRs configured for that PFCP session"}) +ies.append({ "ie_type" : "QER Correlation ID", "ie_value" : "QER Correlation ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the QER correlation ID in this QER needs to be modified.See NOTE 1."}) +ies.append({ "ie_type" : "Gate Status", "ie_value" : "Gate Status", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Gate Status needs to be modified. When present, it shall indicate whether the packets are allowed to be forwarded (the gate is open) or shall be discarded (the gate is closed) in the uplink and/or downlink directions.See NOTE 1."}) +ies.append({ "ie_type" : "MBR", "ie_value" : "Maximum Bitrate", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if an MBR enforcement action applied to packets matching this PDR need to be modified.When present, this IE shall indicate the uplink and/or downlink maximum bit rate to be enforced for packets matching the PDR.For EPC, this IE may be set to the value of:- the APN-AMBR, for a QER that is referenced by all the PDRs of the non-GBR bearers of a PDN connection;- the TDF session MBR, for a QER that is referenced by all the PDRs of a TDF session;- the bearer MBR, for a QER that is referenced by all the PDRs of a bearer;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF.For 5GC, this IE may be set to the value of:- the Session-AMBR, for a QER that is referenced by all the PDRs of the non-GBR QoS flows of a PDU session;- the QoS Flow MBR, for a QER that is referenced by all the PDRs of a QoS Flow;- the SDF MBR, for a QER that is referenced by all the PDRs of a SDF.See NOTE 1."}) +ies.append({ "ie_type" : "GBR", "ie_value" : "Guaranteed Bitrate", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a GBR authorization to packets matching this PDR needs to be modified. When present, this IE shall indicate the authorized uplink and/or downlink guaranteed bit rate.This IE may be set to the value of:- the aggregate GBR, for a QER that is referenced by all the PDRs of a GBR bearer;- the QoS Flow GBR, for a QER that is referenced by all the PDRs of a QoS Flow (for 5GC);- the SDF GBR, for a QER that is referenced by all the PDRs of a SDF.See NOTE 1."}) +ies.append({ "ie_type" : "Packet Rate", "ie_value" : "Packet Rate", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a Packet Rate enforcement action (in terms of number of packets per time interval) need to be modified for packets matching this PDR. "}) +ies.append({ "ie_type" : "DL Flow Level Marking", "ie_value" : "DL Flow Level Marking", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be set if the DL Flow Level Marking IE needs to be modified.See NOTE 1."}) +ies.append({ "ie_type" : "QFI", "ie_value" : "QoS flow identifier", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it needs to be modified."}) +ies.append({ "ie_type" : "RQI", "ie_value" : "Reflective QoS", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it needs to be modified."}) +ies.append({ "ie_type" : "Paging Policy Indicator", "ie_value" : "Paging Policy Indicator", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it needs to be modified."}) +ies.append({ "ie_type" : "Averaging Window", "ie_value" : "Averaging Window", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the UP function is required to modify the Averaging Window. (NOTE 2)"}) group_list["Update QER"] = { "index" : "114", "type" : "14", "ies" : ies } ies = [] -ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the PDR to be deleted."}) +ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the PDR to be deleted."}) group_list["Remove PDR"] = { "index" : "115", "type" : "15", "ies" : ies } ies = [] -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the FAR to be deleted."}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the FAR to be deleted."}) group_list["Remove FAR"] = { "index" : "116", "type" : "16", "ies" : ies } ies = [] -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the URR to be deleted."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the URR to be deleted."}) group_list["Remove URR"] = { "index" : "117", "type" : "17", "ies" : ies } ies = [] -ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the QER to be deleted."}) +ies.append({ "ie_type" : "QER ID", "ie_value" : "QER ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the QER to be deleted."}) group_list["Remove QER"] = { "index" : "118", "type" : "18", "ies" : ies } ies = [] -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the URR being queried."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the URR being queried."}) group_list["Query URR"] = { "index" : "177", "type" : "77", "ies" : ies } ies = [] -ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the BAR Rule to be modified."}) -ies.append({ "ie_type" : "Downlink Data Notification Delay", "ie_value" : "Downlink Data Notification Delay", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function indicated support of the Downlink Data Notification Delay parameter (see clause 8.2.28) and the Downlink Data Notification Delay needs to be modified.When present, it shall contain the delay the UP function shall apply between receiving a downlink data packet and notifying the CP function about it, when the Apply Action parameter requests to buffer the packets and notify the CP function."}) -ies.append({ "ie_type" : "Suggested Buffering Packets Count", "ie_value" : "Suggested Buffering Packets Count", "presence" : "C", "instance" : "0", "comment" : "This IE may be present if the UP Function indicated support of the the feature UDBC.When present, it shall contain the number of packets that are suggested to be buffered when the Apply Action parameter requests to buffer the packets. The packets that exceed the limit shall be discarded."}) +ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the BAR Rule to be modified."}) +ies.append({ "ie_type" : "Downlink Data Notification Delay", "ie_value" : "Downlink Data Notification Delay", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function indicated support of the Downlink Data Notification Delay parameter (see clause 8.2.28) and the Downlink Data Notification Delay needs to be modified.When present, it shall contain the delay the UP function shall apply between receiving a downlink data packet and notifying the CP function about it, when the Apply Action parameter requests to buffer the packets and notify the CP function."}) +ies.append({ "ie_type" : "Suggested Buffering Packets Count", "ie_value" : "Suggested Buffering Packets Count", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present if the UP Function indicated support of the the feature UDBC.When present, it shall contain the number of packets that are suggested to be buffered when the Apply Action parameter requests to buffer the packets. The packets that exceed the limit shall be discarded."}) group_list["Update BAR Session Modification Request"] = { "index" : "186", "type" : "86", "ies" : ies } ies = [] -ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the BAR to be deleted."}) +ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the BAR to be deleted."}) group_list["Remove BAR"] = { "index" : "187", "type" : "87", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the Traffic Endpoint to be deleted."}) +ies.append({ "ie_type" : "Traffic Endpoint ID", "ie_value" : "Traffic Endpoint ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the Traffic Endpoint to be deleted."}) group_list["Remove Traffic Endpoint"] = { "index" : "230", "type" : "130", "ies" : ies } ies = [] -ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the MAR to be deleted."}) +ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the MAR to be deleted."}) group_list["Remove MAR"] = { "index" : "268", "type" : "168", "ies" : ies } ies = [] -ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the MAR to be updated."}) -ies.append({ "ie_type" : "Steering Functionality", "ie_value" : "Steering Functionality", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed."}) -ies.append({ "ie_type" : "Steering Mode", "ie_value" : "Steering Mode", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed."}) -ies.append({ "ie_type" : "Update Access Forwarding Action Information 1", "ie_value" : "Update Access Forwarding Action Information 1", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Access Forwarding Action Information 1 was provisioned previously and if any of IEs is to be changed.This IE shall also be present to remove Access Forwarding Action Information 1 that was provisioned previously if the UE deregisters from the corresponding access. This shall be done by including this IE with a null length."}) -ies.append({ "ie_type" : "Update Access Forwarding Action Information 2", "ie_value" : "Update Access Forwarding Action Information 2", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Access Forwarding Action Information 2 was provisioned previously and if any of IEs is to be changed.This IE shall also be present to remove Access Forwarding Action Information 2 that was provisioned previously if the UE deregisters from the corresponding access. This shall be done by including this IE with a null length."}) -ies.append({ "ie_type" : "Access Forwarding Action Information 1", "ie_value" : "Access Forwarding Action Information 1", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information when another access is added, i.e. when the UE is registered in both non-3GPP and 3GPP accesses.See Table 7.5.2.8-2. "}) -ies.append({ "ie_type" : "Access Forwarding Action Information 2", "ie_value" : "Access Forwarding Action Information 2", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information when another access is added, i.e. when the UE is registered in both non-3GPP and 3GPP accesses.See Table 7.5.2.8-3. "}) +ies.append({ "ie_type" : "MAR ID", "ie_value" : "MAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the MAR to be updated."}) +ies.append({ "ie_type" : "Steering Functionality", "ie_value" : "Steering Functionality", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed."}) +ies.append({ "ie_type" : "Steering Mode", "ie_value" : "Steering Mode", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed."}) +ies.append({ "ie_type" : "Update Access Forwarding Action Information 1", "ie_value" : "Update Access Forwarding Action Information 1", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Access Forwarding Action Information 1 was provisioned previously and if any of IEs is to be changed.This IE shall also be present to remove Access Forwarding Action Information 1 that was provisioned previously if the UE deregisters from the corresponding access. This shall be done by including this IE with a null length."}) +ies.append({ "ie_type" : "Update Access Forwarding Action Information 2", "ie_value" : "Update Access Forwarding Action Information 2", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Access Forwarding Action Information 2 was provisioned previously and if any of IEs is to be changed.This IE shall also be present to remove Access Forwarding Action Information 2 that was provisioned previously if the UE deregisters from the corresponding access. This shall be done by including this IE with a null length."}) +ies.append({ "ie_type" : "Access Forwarding Action Information 1", "ie_value" : "Access Forwarding Action Information 1", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information when another access is added, i.e. when the UE is registered in both non-3GPP and 3GPP accesses.See Table 7.5.2.8-2. "}) +ies.append({ "ie_type" : "Access Forwarding Action Information 2", "ie_value" : "Access Forwarding Action Information 2", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present to provision access specific (non-3gpp or 3gpp) forwarding action information when another access is added, i.e. when the UE is registered in both non-3GPP and 3GPP accesses.See Table 7.5.2.8-3. "}) group_list["Update MAR"] = { "index" : "269", "type" : "169", "ies" : ies } ies = [] -ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed. "}) -ies.append({ "ie_type" : "Weight", "ie_value" : "Weight", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed."}) -ies.append({ "ie_type" : "Priority", "ie_value" : "Priority", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it is changed."}) -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a measurement action shall be applied or no longer applied to packets for this access.When present, this IE shall contain the list of all the URR IDs to be associated to this access."}) +ies.append({ "ie_type" : "FAR ID", "ie_value" : "FAR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed. "}) +ies.append({ "ie_type" : "Weight", "ie_value" : "Weight", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed."}) +ies.append({ "ie_type" : "Priority", "ie_value" : "Priority", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it is changed."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a measurement action shall be applied or no longer applied to packets for this access.When present, this IE shall contain the list of all the URR IDs to be associated to this access."}) group_list["Update Access Forwarding Action Information 1"] = { "index" : "275", "type" : "175", "ies" : ies } -ies = [] group_list["Update Access Forwarding Action Information 2"] = { "index" : "276", "type" : "176", "ies" : ies } ies = [] -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the URR for which usage is reported."}) -ies.append({ "ie_type" : "UR-SEQN", "ie_value" : "UR-SEQN", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the Usage Report for the URR (see clause 5.2.2.3)."}) -ies.append({ "ie_type" : "Usage Report Trigger", "ie_value" : "Usage Report Trigger", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the trigger for this report."}) -ies.append({ "ie_type" : "Start Time", "ie_value" : "Start Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was started."}) -ies.append({ "ie_type" : "End Time", "ie_value" : "End Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was generated."}) -ies.append({ "ie_type" : "Volume Measurement", "ie_value" : "Volume Measurement", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a volume measurement needs to be reported."}) -ies.append({ "ie_type" : "Duration Measurement", "ie_value" : "Duration Measurement", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a duration measurement needs to be reported."}) -ies.append({ "ie_type" : "Time of First Packet", "ie_value" : "Time of First Packet", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if available for this URR."}) -ies.append({ "ie_type" : "Time of Last Packet", "ie_value" : "Time of Last Packet", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if available for this URR."}) -ies.append({ "ie_type" : "Usage Information", "ie_value" : "Usage Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function reports Usage Reports before and after a Monitoring Time or before and after QoS enforcement. When present, it shall indicate whether the usage is reported for the period before or after that time, or before or after QoS enforcement."}) -ies.append({ "ie_type" : "Query URR Reference", "ie_value" : "Query URR Reference", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if this usage report is sent as a result of a query URR received in an PFCP Session Modification Request and the Query URR Reference IE was present in the PFCP Session Modification Request.When present, it shall be set to the Query URR Reference value received in the PFCP Session Modification Request. "}) -ies.append({ "ie_type" : "Ethernet Traffic Information", "ie_value" : "Ethernet Traffic Information", "presence" : "C", "instance" : "0", "comment" : " This IE shall be present if Ethernet Traffic Information needs to be reported. "}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the URR for which usage is reported."}) +ies.append({ "ie_type" : "UR-SEQN", "ie_value" : "UR-SEQN", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the Usage Report for the URR (see clause 5.2.2.3)."}) +ies.append({ "ie_type" : "Usage Report Trigger", "ie_value" : "Usage Report Trigger", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the trigger for this report."}) +ies.append({ "ie_type" : "Start Time", "ie_value" : "Start Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was started."}) +ies.append({ "ie_type" : "End Time", "ie_value" : "End Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was generated."}) +ies.append({ "ie_type" : "Volume Measurement", "ie_value" : "Volume Measurement", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a volume measurement needs to be reported."}) +ies.append({ "ie_type" : "Duration Measurement", "ie_value" : "Duration Measurement", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a duration measurement needs to be reported."}) +ies.append({ "ie_type" : "Time of First Packet", "ie_value" : "Time of First Packet", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if available for this URR."}) +ies.append({ "ie_type" : "Time of Last Packet", "ie_value" : "Time of Last Packet", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if available for this URR."}) +ies.append({ "ie_type" : "Usage Information", "ie_value" : "Usage Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function reports Usage Reports before and after a Monitoring Time or before and after QoS enforcement. When present, it shall indicate whether the usage is reported for the period before or after that time, or before or after QoS enforcement."}) +ies.append({ "ie_type" : "Query URR Reference", "ie_value" : "Query URR Reference", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if this usage report is sent as a result of a query URR received in an PFCP Session Modification Request and the Query URR Reference IE was present in the PFCP Session Modification Request.When present, it shall be set to the Query URR Reference value received in the PFCP Session Modification Request. "}) +ies.append({ "ie_type" : "Ethernet Traffic Information", "ie_value" : "Ethernet Traffic Information", "presence" : "C", "tlv_more" : "0", "comment" : " This IE shall be present if Ethernet Traffic Information needs to be reported. "}) group_list["Usage Report Session Modification Response"] = { "index" : "178", "type" : "78", "ies" : ies } ies = [] -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the URR for which usage is reported."}) -ies.append({ "ie_type" : "UR-SEQN", "ie_value" : "UR-SEQN", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the Usage Report for the URR (see clause 5.2.2.3)."}) -ies.append({ "ie_type" : "Usage Report Trigger", "ie_value" : "Usage Report Trigger", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the trigger for this report."}) -ies.append({ "ie_type" : "Start Time", "ie_value" : "Start Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was started."}) -ies.append({ "ie_type" : "End Time", "ie_value" : "End Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was generated."}) -ies.append({ "ie_type" : "Volume Measurement", "ie_value" : "Volume Measurement", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a volume needs to be reported."}) -ies.append({ "ie_type" : "Duration Measurement", "ie_value" : "Duration Measurement", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a duration measurement needs to be reported."}) -ies.append({ "ie_type" : "Time of First Packet", "ie_value" : "Time of First Packet", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if available for this URR."}) -ies.append({ "ie_type" : "Time of Last Packet", "ie_value" : "Time of Last Packet", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if available for this URR."}) -ies.append({ "ie_type" : "Usage Information", "ie_value" : "Usage Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function reports Usage Reports before and after a Monitoring Time, or before and after QoS enforcement. When present, it shall indicate whether the usage is reported for the period before or after that time, or before or after QoS enforcement."}) -ies.append({ "ie_type" : "Ethernet Traffic Information", "ie_value" : "Ethernet Traffic Information", "presence" : "C", "instance" : "0", "comment" : " This IE shall be present if Ethernet Traffic Information needs to be reported. See Table 7.5.8.3-3."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the URR for which usage is reported."}) +ies.append({ "ie_type" : "UR-SEQN", "ie_value" : "UR-SEQN", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the Usage Report for the URR (see clause 5.2.2.3)."}) +ies.append({ "ie_type" : "Usage Report Trigger", "ie_value" : "Usage Report Trigger", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the trigger for this report."}) +ies.append({ "ie_type" : "Start Time", "ie_value" : "Start Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was started."}) +ies.append({ "ie_type" : "End Time", "ie_value" : "End Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was generated."}) +ies.append({ "ie_type" : "Volume Measurement", "ie_value" : "Volume Measurement", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a volume needs to be reported."}) +ies.append({ "ie_type" : "Duration Measurement", "ie_value" : "Duration Measurement", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a duration measurement needs to be reported."}) +ies.append({ "ie_type" : "Time of First Packet", "ie_value" : "Time of First Packet", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if available for this URR."}) +ies.append({ "ie_type" : "Time of Last Packet", "ie_value" : "Time of Last Packet", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if available for this URR."}) +ies.append({ "ie_type" : "Usage Information", "ie_value" : "Usage Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function reports Usage Reports before and after a Monitoring Time, or before and after QoS enforcement. When present, it shall indicate whether the usage is reported for the period before or after that time, or before or after QoS enforcement."}) +ies.append({ "ie_type" : "Ethernet Traffic Information", "ie_value" : "Ethernet Traffic Information", "presence" : "C", "tlv_more" : "0", "comment" : " This IE shall be present if Ethernet Traffic Information needs to be reported. See Table 7.5.8.3-3."}) group_list["Usage Report Session Deletion Response"] = { "index" : "179", "type" : "79", "ies" : ies } ies = [] -ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the PDR for which downlink data packets have been received at the UP function.More than one IE with this type may be included to represent multiple PDRs having received downlink data packets."}) -ies.append({ "ie_type" : "Downlink Data Service Information", "ie_value" : "Downlink Data Service Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included for an PFCP session with an IP PDN type, if the UP function supports the Paging Policy Differentiation feature (see clause 4.9 of 3GPPTS23.401[14]) and clause 5.4.3.2 of 3GPPTS23.501[28]).When present, for each PDR and for each packet that triggers a Downlink Data Notification, the UP function shall copy, into the Paging Policy Indication value within this IE, the value of the DSCP in TOS (IPv4) or TC (IPv6) information received in the IP payload of the GTP-U packet from the PGW (see IETFRFC2474[13]).For 5GC, this IE shall also be included over N4, for each PDR and for each packet that triggers a Downlink Data Notification, if the QFI of the downlink data packet is available.One IE with this type shall be included per PDR ID reported in the message. When multiple PDR ID IEs are present in the message, the Downlink Data Service Information IEs shall be reported according to the order of the PDR ID IEs."}) +ies.append({ "ie_type" : "PDR ID", "ie_value" : "PDR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the PDR for which downlink data packets have been received at the UP function.More than one IE with this type may be included to represent multiple PDRs having received downlink data packets."}) +ies.append({ "ie_type" : "Downlink Data Service Information", "ie_value" : "Downlink Data Service Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included for an PFCP session with an IP PDN type, if the UP function supports the Paging Policy Differentiation feature (see clause 4.9 of 3GPPTS23.401[14]) and clause 5.4.3.2 of 3GPPTS23.501[28]).When present, for each PDR and for each packet that triggers a Downlink Data Notification, the UP function shall copy, into the Paging Policy Indication value within this IE, the value of the DSCP in TOS (IPv4) or TC (IPv6) information received in the IP payload of the GTP-U packet from the PGW (see IETFRFC2474[13]).For 5GC, this IE shall also be included over N4, for each PDR and for each packet that triggers a Downlink Data Notification, if the QFI of the downlink data packet is available.One IE with this type shall be included per PDR ID reported in the message. When multiple PDR ID IEs are present in the message, the Downlink Data Service Information IEs shall be reported according to the order of the PDR ID IEs."}) group_list["Downlink Data Report"] = { "index" : "183", "type" : "83", "ies" : ies } ies = [] -ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the URR for which usage is reported."}) -ies.append({ "ie_type" : "UR-SEQN", "ie_value" : "UR-SEQN", "presence" : "M", "instance" : "0", "comment" : "This IE shall uniquely identify the Usage Report for the URR (see clause 5.2.2.3)."}) -ies.append({ "ie_type" : "Usage Report Trigger", "ie_value" : "Usage Report Trigger", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the trigger for this report."}) -ies.append({ "ie_type" : "Start Time", "ie_value" : "Start Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was started."}) -ies.append({ "ie_type" : "End Time", "ie_value" : "End Time", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was generated."}) -ies.append({ "ie_type" : "Volume Measurement", "ie_value" : "Volume Measurement", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a volume measurement needs to be reported."}) -ies.append({ "ie_type" : "Duration Measurement", "ie_value" : "Duration Measurement", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a duration measurement needs to be reported."}) -ies.append({ "ie_type" : "Application Detection Information", "ie_value" : "Application Detection Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if application detection information needs to be reported."}) -ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the start or stop of an application has been detected and no UE IP address was provisioned in the PDI. See NOTE 1."}) -ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the start or stop of an application has been detected, no UE IP address was provisioned in the PDI and multiple PDNs with overlapping IP addresses are used in the UP function. See NOTE 1."}) -ies.append({ "ie_type" : "Time of First Packet", "ie_value" : "Time of First Packet", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if available for this URR."}) -ies.append({ "ie_type" : "Time of Last Packet", "ie_value" : "Time of Last Packet", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if available for this URR."}) -ies.append({ "ie_type" : "Usage Information", "ie_value" : "Usage Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function reports Usage Reports before and after a Monitoring Time, or before and after QoS enforcement. When present, it shall indicate whether the usage is reported for the period before or after that time, or before or after QoS enforcement."}) -ies.append({ "ie_type" : "Query URR Reference", "ie_value" : "Query URR Reference", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if this usage report is sent as a result of a query URR received in an PFCP Session Modification Request and the Query URR Reference IE was present in the PFCP Session Modification Request.When present, it shall be set to the Query URR Reference value received in the PFCP Session Modification Request. "}) -ies.append({ "ie_type" : "Event Time Stamp", "ie_value" : "Event Time Stamp", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present, if the report is related to an event.When present, it shall be set to the time when the event occurs.Several IEs with the same IE type may be present to report multiple occurrences for an event for this URR ID."}) -ies.append({ "ie_type" : "Ethernet Traffic Information", "ie_value" : "Ethernet Traffic Information", "presence" : "C", "instance" : "0", "comment" : " This IE shall be present if Ethernet Traffic Information needs to be reported. See Table 7.5.8.3-3."}) +ies.append({ "ie_type" : "URR ID", "ie_value" : "URR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the URR for which usage is reported."}) +ies.append({ "ie_type" : "UR-SEQN", "ie_value" : "UR-SEQN", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall uniquely identify the Usage Report for the URR (see clause 5.2.2.3)."}) +ies.append({ "ie_type" : "Usage Report Trigger", "ie_value" : "Usage Report Trigger", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the trigger for this report."}) +ies.append({ "ie_type" : "Start Time", "ie_value" : "Start Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was started."}) +ies.append({ "ie_type" : "End Time", "ie_value" : "End Time", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, except if the Usage Report Trigger indicates Start of Traffic, Stop of Traffic or MAC Addresses Reporting.When present, this IE shall provide the timestamp when the collection of the information in this report was generated."}) +ies.append({ "ie_type" : "Volume Measurement", "ie_value" : "Volume Measurement", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a volume measurement needs to be reported."}) +ies.append({ "ie_type" : "Duration Measurement", "ie_value" : "Duration Measurement", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a duration measurement needs to be reported."}) +ies.append({ "ie_type" : "Application Detection Information", "ie_value" : "Application Detection Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if application detection information needs to be reported."}) +ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the start or stop of an application has been detected and no UE IP address was provisioned in the PDI. See NOTE 1."}) +ies.append({ "ie_type" : "Network Instance", "ie_value" : "Network Instance", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the start or stop of an application has been detected, no UE IP address was provisioned in the PDI and multiple PDNs with overlapping IP addresses are used in the UP function. See NOTE 1."}) +ies.append({ "ie_type" : "Time of First Packet", "ie_value" : "Time of First Packet", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if available for this URR."}) +ies.append({ "ie_type" : "Time of Last Packet", "ie_value" : "Time of Last Packet", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if available for this URR."}) +ies.append({ "ie_type" : "Usage Information", "ie_value" : "Usage Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function reports Usage Reports before and after a Monitoring Time, or before and after QoS enforcement. When present, it shall indicate whether the usage is reported for the period before or after that time, or before or after QoS enforcement."}) +ies.append({ "ie_type" : "Query URR Reference", "ie_value" : "Query URR Reference", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if this usage report is sent as a result of a query URR received in an PFCP Session Modification Request and the Query URR Reference IE was present in the PFCP Session Modification Request.When present, it shall be set to the Query URR Reference value received in the PFCP Session Modification Request. "}) +ies.append({ "ie_type" : "Event Time Stamp", "ie_value" : "Event Time Stamp", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present, if the report is related to an event.When present, it shall be set to the time when the event occurs.Several IEs with the same IE type may be present to report multiple occurrences for an event for this URR ID."}) +ies.append({ "ie_type" : "Ethernet Traffic Information", "ie_value" : "Ethernet Traffic Information", "presence" : "C", "tlv_more" : "0", "comment" : " This IE shall be present if Ethernet Traffic Information needs to be reported. See Table 7.5.8.3-3."}) group_list["Usage Report Session Report Request"] = { "index" : "180", "type" : "80", "ies" : ies } ies = [] -ies.append({ "ie_type" : "Application ID", "ie_value" : "Application ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the Application ID for which a start or stop of traffic is reported."}) -ies.append({ "ie_type" : "Application Instance ID", "ie_value" : "Application Instance ID", "presence" : "C", "instance" : "0", "comment" : "When present, this IE shall identify the Application Instance Identifier for which a start or stop of traffic is reported. It shall be present, when reporting the start of an application, if the Reduced Application Detection Information flag was not set in the Measurement Information and if the flow information for the detected application is deducible. It shall be present, when reporting the stop of an application, if the Reduced Application Detection Information flag was not set in the Measurement Information and if it was provided when reporting the start of the application."}) -ies.append({ "ie_type" : "Flow Information", "ie_value" : "Flow Information", "presence" : "C", "instance" : "0", "comment" : "When present, this IE shall contain the flow information for the detected application. It shall be present, when reporting the start of an application, if the Reduced Application Detection Information flag was not set in the Measurement Information and if the flow information for the detected application is deducible."}) +ies.append({ "ie_type" : "Application ID", "ie_value" : "Application ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the Application ID for which a start or stop of traffic is reported."}) +ies.append({ "ie_type" : "Application Instance ID", "ie_value" : "Application Instance ID", "presence" : "C", "tlv_more" : "0", "comment" : "When present, this IE shall identify the Application Instance Identifier for which a start or stop of traffic is reported. It shall be present, when reporting the start of an application, if the Reduced Application Detection Information flag was not set in the Measurement Information and if the flow information for the detected application is deducible. It shall be present, when reporting the stop of an application, if the Reduced Application Detection Information flag was not set in the Measurement Information and if it was provided when reporting the start of the application."}) +ies.append({ "ie_type" : "Flow Information", "ie_value" : "Flow Information", "presence" : "C", "tlv_more" : "0", "comment" : "When present, this IE shall contain the flow information for the detected application. It shall be present, when reporting the start of an application, if the Reduced Application Detection Information flag was not set in the Measurement Information and if the flow information for the detected application is deducible."}) group_list["Application Detection Information"] = { "index" : "168", "type" : "68", "ies" : ies } ies = [] -ies.append({ "ie_type" : "MAC Addresses Detected", "ie_value" : "MAC Addresses Detected", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if one or more new MAC addresses have been detected.When present, it shall identify the MAC (Ethernet) addresses newly detected as source address of frames sent UL by the UE."}) -ies.append({ "ie_type" : "MAC Addresses Removed", "ie_value" : "MAC Addresses Removed", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if one or more new MAC addresses have been removed.When present, it shall identify the MAC (Ethernet) addresses that have been inactive for a duration exceeding the Ethernet inactivity Timer. "}) +ies.append({ "ie_type" : "MAC Addresses Detected", "ie_value" : "MAC Addresses Detected", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if one or more new MAC addresses have been detected.When present, it shall identify the MAC (Ethernet) addresses newly detected as source address of frames sent UL by the UE."}) +ies.append({ "ie_type" : "MAC Addresses Removed", "ie_value" : "MAC Addresses Removed", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if one or more new MAC addresses have been removed.When present, it shall identify the MAC (Ethernet) addresses that have been inactive for a duration exceeding the Ethernet inactivity Timer. "}) group_list["Ethernet Traffic Information"] = { "index" : "243", "type" : "143", "ies" : ies } ies = [] -ies.append({ "ie_type" : "F-TEID", "ie_value" : "Remote F-TEID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the remote F-TEID of the GTP-U bearer for which an Error Indication has been received at the UP function.More than one IE with this type may be included to represent multiple remote F-TEID for which an Error Indication has been received."}) +ies.append({ "ie_type" : "F-TEID", "ie_value" : "Remote F-TEID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the remote F-TEID of the GTP-U bearer for which an Error Indication has been received at the UP function.More than one IE with this type may be included to represent multiple remote F-TEID for which an Error Indication has been received."}) group_list["Error Indication Report"] = { "index" : "199", "type" : "99", "ies" : ies } ies = [] -ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall identify the BAR Rule to be modified."}) -ies.append({ "ie_type" : "Downlink Data Notification Delay", "ie_value" : "Downlink Data Notification Delay", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function indicated support of the Downlink Data Notification Delay parameter (see clause 8.2.25) and the Downlink Data Notification Delay needs to be modified.When present, it shall contain the delay the UP function shall apply between receiving a downlink data packet and notifying the CP function about it, when the Apply Action parameter requests to buffer the packets and notify the CP function."}) -ies.append({ "ie_type" : "DL Buffering Duration", "ie_value" : "DL Buffering Duration", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function indicated support of the DL Buffering Duration parameter (see clause 8.2.25) and extended buffering of downlink data packet is required in the UP function.When present, this IE shall indicate the duration during which the UP function shall buffer the downlink data packets without sending any further notification to the CP function about the arrival of DL data packets."}) -ies.append({ "ie_type" : "DL Buffering Suggested Packet Count", "ie_value" : "DL Buffering Suggested Packet Count", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if extended buffering of downlink data packet is required in the UP function.When present, this IE shall indicate the maximum number of downlink data packets suggested to be buffered in the UP function."}) -ies.append({ "ie_type" : "Suggested Buffering Packets Count", "ie_value" : "Suggested Buffering Packets Count", "presence" : "C", "instance" : "0", "comment" : "This IE may be present if the UP Function indicated support of the feature UDBC.When present, it shall contain the number of packets that are suggested to be buffered when the Apply Action parameter requests to buffer the packets. The packets that exceed the limit shall be discarded."}) +ies.append({ "ie_type" : "BAR ID", "ie_value" : "BAR ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall identify the BAR Rule to be modified."}) +ies.append({ "ie_type" : "Downlink Data Notification Delay", "ie_value" : "Downlink Data Notification Delay", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function indicated support of the Downlink Data Notification Delay parameter (see clause 8.2.25) and the Downlink Data Notification Delay needs to be modified.When present, it shall contain the delay the UP function shall apply between receiving a downlink data packet and notifying the CP function about it, when the Apply Action parameter requests to buffer the packets and notify the CP function."}) +ies.append({ "ie_type" : "DL Buffering Duration", "ie_value" : "DL Buffering Duration", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function indicated support of the DL Buffering Duration parameter (see clause 8.2.25) and extended buffering of downlink data packet is required in the UP function.When present, this IE shall indicate the duration during which the UP function shall buffer the downlink data packets without sending any further notification to the CP function about the arrival of DL data packets."}) +ies.append({ "ie_type" : "DL Buffering Suggested Packet Count", "ie_value" : "DL Buffering Suggested Packet Count", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if extended buffering of downlink data packet is required in the UP function.When present, this IE shall indicate the maximum number of downlink data packets suggested to be buffered in the UP function."}) +ies.append({ "ie_type" : "Suggested Buffering Packets Count", "ie_value" : "Suggested Buffering Packets Count", "presence" : "C", "tlv_more" : "0", "comment" : "This IE may be present if the UP Function indicated support of the feature UDBC.When present, it shall contain the number of packets that are suggested to be buffered when the Apply Action parameter requests to buffer the packets. The packets that exceed the limit shall be discarded."}) group_list["Update BAR PFCP Session Report Response"] = { "index" : "112", "type" : "12", "ies" : ies } diff --git a/lib/pfcp/support/cache/tlv-msg-1.py b/lib/pfcp/support/cache/tlv-msg-1.py index ed3bbc9f2..b53ce617f 100644 --- a/lib/pfcp/support/cache/tlv-msg-1.py +++ b/lib/pfcp/support/cache/tlv-msg-1.py @@ -1,3 +1,3 @@ ies = [] -ies.append({ "ie_type" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the time stamp when the PFCP entity was started see clause 19A of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the time stamp when the PFCP entity was started see clause 19A of 3GPPTS23.007[24]."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-10.py b/lib/pfcp/support/cache/tlv-msg-10.py index d9c03de5c..ea12ad001 100644 --- a/lib/pfcp/support/cache/tlv-msg-10.py +++ b/lib/pfcp/support/cache/tlv-msg-10.py @@ -1,4 +1,4 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +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" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-12.py b/lib/pfcp/support/cache/tlv-msg-12.py index e75765323..a28a96da1 100644 --- a/lib/pfcp/support/cache/tlv-msg-12.py +++ b/lib/pfcp/support/cache/tlv-msg-12.py @@ -1,5 +1,5 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "Node Report Type", "ie_value" : "Node Report Type", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the type of the report."}) -ies.append({ "ie_type" : "User Plane Path Failure Report", "ie_value" : "User Plane Path Failure Report", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Node Report Type indicates a User Plane Path Failure Report."}) +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" : "Node Report Type", "ie_value" : "Node Report Type", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the type of the report."}) +ies.append({ "ie_type" : "User Plane Path Failure Report", "ie_value" : "User Plane Path Failure Report", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Node Report Type indicates a User Plane Path Failure Report."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-13.py b/lib/pfcp/support/cache/tlv-msg-13.py index 158147c5f..46244470e 100644 --- a/lib/pfcp/support/cache/tlv-msg-13.py +++ b/lib/pfcp/support/cache/tlv-msg-13.py @@ -1,5 +1,5 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the rejection cause is due to a conditional or mandatory IE missing or faulty."}) +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" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the rejection cause is due to a conditional or mandatory IE missing or faulty."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-14.py b/lib/pfcp/support/cache/tlv-msg-14.py index fb57571a6..ecac9c75c 100644 --- a/lib/pfcp/support/cache/tlv-msg-14.py +++ b/lib/pfcp/support/cache/tlv-msg-14.py @@ -1,4 +1,10 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the node identity of the originating node of the message."}) -ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-C FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the node identity of the originating node of the message."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-C FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "PGW-C FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-U FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "PGW-U FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "TWAN FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "ePDG FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "MME FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-15.py b/lib/pfcp/support/cache/tlv-msg-15.py index ce4deb944..a85698a62 100644 --- a/lib/pfcp/support/cache/tlv-msg-15.py +++ b/lib/pfcp/support/cache/tlv-msg-15.py @@ -1,5 +1,5 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending node."}) -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the rejection is due to an conditional or mandatory IE missing or faulty."}) +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" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the rejection is due to an conditional or mandatory IE missing or faulty."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-2.py b/lib/pfcp/support/cache/tlv-msg-2.py index ed3bbc9f2..b53ce617f 100644 --- a/lib/pfcp/support/cache/tlv-msg-2.py +++ b/lib/pfcp/support/cache/tlv-msg-2.py @@ -1,3 +1,3 @@ ies = [] -ies.append({ "ie_type" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the time stamp when the PFCP entity was started see clause 19A of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the time stamp when the PFCP entity was started see clause 19A of 3GPPTS23.007[24]."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-3.py b/lib/pfcp/support/cache/tlv-msg-3.py index 28d8c03a5..8f6cffafb 100644 --- a/lib/pfcp/support/cache/tlv-msg-3.py +++ b/lib/pfcp/support/cache/tlv-msg-3.py @@ -1,3 +1,3 @@ ies = [] -ies.append({ "ie_type" : "PFD context", "ie_value" : "Application ID's PFDs", "presence" : "C", "instance" : "0", "comment" : "This IE shall contain an Application Identifier and the associated PFDs to be provisioned in the UP function.Several IEs with the same IE type may be present to provision PFDs for multiple Application IDs.The UP function shall delete all the PFDs received and stored earlier for all the Application IDs if this IE is absent in the message."}) +ies.append({ "ie_type" : "PFD context", "ie_value" : "Application ID's PFDs", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall contain an Application Identifier and the associated PFDs to be provisioned in the UP function.Several IEs with the same IE type may be present to provision PFDs for multiple Application IDs.The UP function shall delete all the PFDs received and stored earlier for all the Application IDs if this IE is absent in the message."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-4.py b/lib/pfcp/support/cache/tlv-msg-4.py index 0dfc4c4cb..a1fd0ce43 100644 --- a/lib/pfcp/support/cache/tlv-msg-4.py +++ b/lib/pfcp/support/cache/tlv-msg-4.py @@ -1,4 +1,4 @@ ies = [] -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the rejection is due to an conditional or mandatory IE missing or faulty."}) +ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the rejection is due to an conditional or mandatory IE missing or faulty."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-5.py b/lib/pfcp/support/cache/tlv-msg-5.py index 52e1fe7be..df0144f05 100644 --- a/lib/pfcp/support/cache/tlv-msg-5.py +++ b/lib/pfcp/support/cache/tlv-msg-5.py @@ -1,10 +1,11 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the time stamp when the CP or UP function was started, see clause 19A of 3GPPTS23.007[24]. (NOTE)"}) -ies.append({ "ie_type" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function sends this message and the UP function supports at least one UP feature defined in this IE.When present, this IE shall indicate the features the UP function supports."}) -ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the CP function sends this message and the CP function supports at least one CP feature defined in this IE.When present, this IE shall indicate the features the CP function supports."}) -ies.append({ "ie_type" : "User Plane IP Resource Information", "ie_value" : "User Plane IP Resource Information", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an IPv4 and/or an IPv6 address, together with a TEID range that the CP function shall use to allocate GTP-U F-TEID in the UP function.Several IEs with the same IE type may be present to represent multiple User Plane IP Resources."}) -ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address Pool Identity", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an UE IP address Pool IdentitySeveral IEs with the same IE type may be present to represent multiple UE IP address Pool Identities."}) -ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the SMF advertises the support of the SSET feature in the CP Function Features IE (see clause 8.2.58).When present, this IE shall contain an IPv4 and/or IPv6 address of an alternative SMF.Several IEs with the same IE type may be present to represent multiple alternative SMF IP addresses. "}) -ies.append({ "ie_type" : "SMF Set ID", "ie_value" : "SMF Set ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the SMF advertises the support of the MPAS feature in the CP Function Features IE (see clause 5.22.3).When present, this IE shall contain an FQDN representing the SMF set to which the SMF belongs. "}) +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" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the time stamp when the CP or UP function was started, see clause 19A of 3GPPTS23.007[24]. (NOTE)"}) +ies.append({ "ie_type" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function sends this message and the UP function supports at least one UP feature defined in this IE.When present, this IE shall indicate the features the UP function supports."}) +ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the CP function sends this message and the CP function supports at least one CP feature defined in this IE.When present, this IE shall indicate the features the CP function supports."}) +type_list["User Plane IP Resource Information"]["max_tlv_more"] = "3" +ies.append({ "ie_type" : "User Plane IP Resource Information", "ie_value" : "User Plane IP Resource Information", "presence" : "O", "tlv_more" : "3", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an IPv4 and/or an IPv6 address, together with a TEID range that the CP function shall use to allocate GTP-U F-TEID in the UP function.Several IEs with the same IE type may be present to represent multiple User Plane IP Resources."}) +ies.append({ "ie_type" : "UE IP Address", "ie_value" : "UE IP address Pool Identity", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an UE IP address Pool IdentitySeveral IEs with the same IE type may be present to represent multiple UE IP address Pool Identities."}) +ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the SMF advertises the support of the SSET feature in the CP Function Features IE (see clause 8.2.58).When present, this IE shall contain an IPv4 and/or IPv6 address of an alternative SMF.Several IEs with the same IE type may be present to represent multiple alternative SMF IP addresses. "}) +ies.append({ "ie_type" : "SMF Set ID", "ie_value" : "SMF Set ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the SMF advertises the support of the MPAS feature in the CP Function Features IE (see clause 5.22.3).When present, this IE shall contain an FQDN representing the SMF set to which the SMF belongs. "}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-50.py b/lib/pfcp/support/cache/tlv-msg-50.py index 5414501e9..f172e9eab 100644 --- a/lib/pfcp/support/cache/tlv-msg-50.py +++ b/lib/pfcp/support/cache/tlv-msg-50.py @@ -1,19 +1,21 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "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", "instance" : "0", "comment" : "This IE shall contain the unique identifier allocated by the CP function identifying the session."}) -ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "O", "instance" : "0", "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."}) -ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "M", "instance" : "1", "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."}) -ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "O", "instance" : "0", "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."}) -ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "M", "instance" : "1", "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."}) -ies.append({ "ie_type" : "Create URR", "ie_value" : "Create URR", "presence" : "C", "instance" : "0", "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."}) -ies.append({ "ie_type" : "Create QER", "ie_value" : "Create QER", "presence" : "C", "instance" : "0", "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", "instance" : "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", "instance" : "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."}) -ies.append({ "ie_type" : "PDN Type", "ie_value" : "PDN Type", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the PFCP session is setup for an individual PDN connection or PDU session (see clause 5.2.1).When present, this IE shall indicate whether this is an IP or non-IP PDN connection/PDU session or, for 5GC, an Ethernet PDU session. See NOTE 3."}) -ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-C FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included according to the requirements in clause23 of 3GPPTS 23.007[24]."}) -ies.append({ "ie_type" : "User Plane Inactivity Timer", "ie_value" : "User Plane Inactivity Timer", "presence" : "O", "instance" : "0", "comment" : "This IE may be present to request the UP function to send a User Plane Inactivity Report when no user plane packets are received for this PFCP session for a duration exceeding the User Plane Inactivity Timer.When present, it shall contain the duration of the inactivity period after which a User Plane Inactivity Report shall be generated."}) -ies.append({ "ie_type" : "User ID", "ie_value" : "User ID", "presence" : "O", "instance" : "0", "comment" : "This IE may be present, based on operator policy. It shall only be sent if the UP function is in a trusted environment.See NOTE."}) -ies.append({ "ie_type" : "Trace Information", "ie_value" : "Trace Information", "presence" : "O", "instance" : "0", "comment" : "When present, this IE shall contain the trace instructions to be applied by the UP function for this PFCP session."}) -ies.append({ "ie_type" : "APN/DNN", "ie_value" : "APN/DNN", "presence" : "O", "instance" : "0", "comment" : "This IE may be present, if related functionalities in the UP function require the APN/DNN information. See NOTE 2."}) -ies.append({ "ie_type" : "Create MAR", "ie_value" : "Create MAR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present for a N4 session established for a MA PDU session.Several IEs with the same IE type may be present to represent multiple MARs.See Table 7.5.2.8-1."}) +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."}) +ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "M", "tlv_more" : "3", "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."}) +ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "M", "tlv_more" : "3", "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."}) +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."}) +ies.append({ "ie_type" : "Create QER", "ie_value" : "Create QER", "presence" : "C", "tlv_more" : "1", "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."}) +ies.append({ "ie_type" : "PDN Type", "ie_value" : "PDN Type", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the PFCP session is setup for an individual PDN connection or PDU session (see clause 5.2.1).When present, this IE shall indicate whether this is an IP or non-IP PDN connection/PDU session or, for 5GC, an Ethernet PDU session. See NOTE 3."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-C FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause23 of 3GPPTS 23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "MME FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included when received on the S11 interface or on S5/S8 interface according to the requirements in clause23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "PGW-C FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "ePDG FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "TWAN FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "User Plane Inactivity Timer", "ie_value" : "User Plane Inactivity Timer", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present to request the UP function to send a User Plane Inactivity Report when no user plane packets are received for this PFCP session for a duration exceeding the User Plane Inactivity Timer.When present, it shall contain the duration of the inactivity period after which a User Plane Inactivity Report shall be generated."}) +ies.append({ "ie_type" : "User ID", "ie_value" : "User ID", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present, based on operator policy. It shall only be sent if the UP function is in a trusted environment.See NOTE."}) +ies.append({ "ie_type" : "Trace Information", "ie_value" : "Trace Information", "presence" : "O", "tlv_more" : "0", "comment" : "When present, this IE shall contain the trace instructions to be applied by the UP function for this PFCP session."}) +ies.append({ "ie_type" : "APN/DNN", "ie_value" : "APN/DNN", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present, if related functionalities in the UP function require the APN/DNN information. See NOTE 2."}) +ies.append({ "ie_type" : "Create MAR", "ie_value" : "Create MAR", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present for a N4 session established for a MA PDU session.Several IEs with the same IE type may be present to represent multiple MARs.See Table 7.5.2.8-1."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-51.py b/lib/pfcp/support/cache/tlv-msg-51.py index 88c3490ff..e4b9ed312 100644 --- a/lib/pfcp/support/cache/tlv-msg-51.py +++ b/lib/pfcp/support/cache/tlv-msg-51.py @@ -1,12 +1,14 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the rejection is due to a conditional or mandatory IE missing or faulty."}) -ies.append({ "ie_type" : "F-SEID", "ie_value" : "UP F-SEID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the cause is set to Request accepted (success). When present, it shall contain the unique identifier allocated by the UP function identifing the session."}) -ies.append({ "ie_type" : "Created PDR", "ie_value" : "Created PDR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the cause is set to success and the UP function was requested to allocate a local F-TEID or a UE IP address/prefix for the PDR.When present, this IE shall contain the PDR information associated to the PFCP session. There may be several instances of this IE.See table 7.5.3.2-1."}) -ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "instance" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) -ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network.See Table 7.5.3.4-1."}) -ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-U FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) -ies.append({ "ie_type" : "Failed Rule ID", "ie_value" : "Failed Rule ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the Cause IE indicates a rejection due to a rule creation or modification failure. "}) -ies.append({ "ie_type" : "Created Traffic Endpoint", "ie_value" : "Created Traffic Endpoint", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the cause is set to success and the UP function was requested to allocate a local F-TEID or a UE IP address/prefix in a Create Traffic Endpoint IE. When present, it shall contain the local F-TEID or UE IP address/prefix to be used for this Traffic Endpoint.There may be several instances of this IE."}) +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" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the rejection is due to a conditional or mandatory IE missing or faulty."}) +ies.append({ "ie_type" : "F-SEID", "ie_value" : "UP F-SEID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the cause is set to Request accepted (success). When present, it shall contain the unique identifier allocated by the UP function identifing the session."}) +type_list["Created PDR"]["max_tlv_more"] = "3" +ies.append({ "ie_type" : "Created PDR", "ie_value" : "Created PDR", "presence" : "C", "tlv_more" : "3", "comment" : "This IE shall be present if the cause is set to success and the UP function was requested to allocate a local F-TEID or a UE IP address/prefix for the PDR.When present, this IE shall contain the PDR information associated to the PFCP session. There may be several instances of this IE.See table 7.5.3.2-1."}) +ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) +ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network.See Table 7.5.3.4-1."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-U FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "PGW-U FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "Failed Rule ID", "ie_value" : "Failed Rule ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the Cause IE indicates a rejection due to a rule creation or modification failure. "}) +ies.append({ "ie_type" : "Created Traffic Endpoint", "ie_value" : "Created Traffic Endpoint", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the cause is set to success and the UP function was requested to allocate a local F-TEID or a UE IP address/prefix in a Create Traffic Endpoint IE. When present, it shall contain the local F-TEID or UE IP address/prefix to be used for this Traffic Endpoint.There may be several instances of this IE."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-52.py b/lib/pfcp/support/cache/tlv-msg-52.py index f2a797ce2..1670fbbd3 100644 --- a/lib/pfcp/support/cache/tlv-msg-52.py +++ b/lib/pfcp/support/cache/tlv-msg-52.py @@ -1,37 +1,47 @@ ies = [] -ies.append({ "ie_type" : "F-SEID", "ie_value" : "CP F-SEID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the CP function decides to change its F-SEID for the PFCP session. The UP function shall use the new CP F-SEID for subsequent PFCP Session related messages for this PFCP Session. See Note 2."}) -ies.append({ "ie_type" : "Remove PDR", "ie_value" : "Remove PDR", "presence" : "C", "instance" : "0", "comment" : "When present, this IE shall contain the PDR Rule which is requested to be removed. See Table 7.5.4-6-1.Several IEs within the same IE type may be present to represent a list of PDRs to remove."}) -ies.append({ "ie_type" : "Remove FAR", "ie_value" : "Remove FAR", "presence" : "C", "instance" : "0", "comment" : "When present, this IE shall contain the FAR Rule which is requested to be removed. See Table 7.5.4-7-1.Several IEs within the same IE type may be present to represent a list of FARs to remove."}) -ies.append({ "ie_type" : "Remove URR", "ie_value" : "Remove URR", "presence" : "C", "instance" : "0", "comment" : "When present, this shall contain the URR Rule which is requested to be removed. See Table 7.5.4-8-1.Several IEs within the same IE type may be present to represent a list of URRs to remove."}) -ies.append({ "ie_type" : "Remove QER", "ie_value" : "Remove QER", "presence" : "C", "instance" : "0", "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", "instance" : "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", "instance" : "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_instance"] = "1" -ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "O", "instance" : "0", "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."}) -ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "C", "instance" : "1", "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_instance"] = "1" -ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "O", "instance" : "0", "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."}) -ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "C", "instance" : "1", "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."}) -ies.append({ "ie_type" : "Create URR", "ie_value" : "Create URR", "presence" : "C", "instance" : "0", "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."}) -ies.append({ "ie_type" : "Create QER", "ie_value" : "Create QER", "presence" : "C", "instance" : "0", "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", "instance" : "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", "instance" : "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."}) -type_list["Update PDR"]["max_instance"] = "1" -ies.append({ "ie_type" : "Update PDR", "ie_value" : "Update PDR", "presence" : "O", "instance" : "0", "comment" : "This IE shall be present if a PDR previously created for the PFCP session need to be modified. See Table 7.5.4.2-1.Several IEs within the same IE type may be present to represent a list of PDRs to update."}) -ies.append({ "ie_type" : "Update PDR", "ie_value" : "Update PDR", "presence" : "C", "instance" : "1", "comment" : "This IE shall be present if a PDR previously created for the PFCP session need to be modified. See Table 7.5.4.2-1.Several IEs within the same IE type may be present to represent a list of PDRs to update."}) -ies.append({ "ie_type" : "Update FAR", "ie_value" : "Update FAR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a FAR previously created for the PFCP session need to be modified. See Table 7.5.4.3-1. Several IEs within the same IE type may be present to represent a list of FARs to update."}) -ies.append({ "ie_type" : "Update URR", "ie_value" : "Update URR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if URR(s) previously created for the PFCP session need to be modified.Several IEs within the same IE type may be present to represent a list of modified URRs. Previously URRs that are not modified shall not be included. See Table 7.5.4.4-1."}) -ies.append({ "ie_type" : "Update QER", "ie_value" : "Update QER", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if QER(s) previously created for the PFCP session need to be modified.Several IEs within the same IE type may be present to represent a list of modified QERs.Previously created QERs that are not modified shall not be included.See Table 7.5.4.5-1."}) -ies.append({ "ie_type" : "Update BAR Session Modification Request", "ie_value" : "Update BAR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a BAR previously created for the PFCP session needs to be modified.A previously created BAR that is not modified shall not be included.See Table 7.5.4.11-1."}) -ies.append({ "ie_type" : "Update Traffic Endpoint", "ie_value" : "Update Traffic Endpoint", "presence" : "C", "instance" : "0", "comment" : "When present this IE shall contain the information associated with the traffic endpoint to be updated, if the UP function has indicated support of PDI optimization.All the PDRs that refer to the Traffic Endpoint shall use the updated Traffic Endpoint information.See Table 7.5.4.13-1."}) -ies.append({ "ie_type" : "PFCPSMReq-Flags", "ie_value" : "PFCPSMReq-Flags", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- DROBU (Drop Buffered Packets): the CP function shall set this flag if the UP function is requested to drop the packets currently buffered for this PFCP session (see NOTE 1).- QAURR (Query All URRs): the CP function shall set this flag if the CP function requests immediate usage report(s) for all the URRs previously provisioned for this PFCP session (see NOTE 3). "}) -ies.append({ "ie_type" : "Query URR", "ie_value" : "Query URR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the CP function requests immediate usage report(s) to the UP function.Several IEs within the same IE type may be present to represent a list of URRs for which an immediate report is requested.See Table 7.5.4.10-1.See NOTE 3."}) -ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "PGW-C FQ-CSID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) -ies.append({ "ie_type" : "User Plane Inactivity Timer", "ie_value" : "User Plane Inactivity Timer", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if it needs to be changed."}) -ies.append({ "ie_type" : "Query URR Reference", "ie_value" : "Query URR Reference", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the Query URR IE is present or the QAURR flag is set to 1. When present, it shall contain a reference identifying the query request, which the UP function shall return in any usage report sent in response to the query."}) -ies.append({ "ie_type" : "Trace Information", "ie_value" : "Trace Information", "presence" : "O", "instance" : "0", "comment" : "When present, this IE shall contain the trace instructions to be applied by the UP function for this PFCP session.A Trace Information with a null length indicates that the trace session shall be deactivated. "}) -ies.append({ "ie_type" : "Remove MAR", "ie_value" : "Remove MAR", "presence" : "C", "instance" : "0", "comment" : "When present, this IE shall contain the MAR Rule which is requested to be removed. See Table 7.5.4.15-1.Several IEs within the same IE type may be present to represent a list of MARs to remove."}) -ies.append({ "ie_type" : "Update MAR", "ie_value" : "Update MAR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a MAR previously created for the PFCP session needs to be modified. See Table 7.5.4.16-1.Several IEs within the same IE type may be present to represent a list of MARs to update."}) -ies.append({ "ie_type" : "Create MAR", "ie_value" : "Create MAR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the CP function requests the UP function to create a new MAR for a new PDR. See Table 7.5.2.8-1.Several IEs within the same IE type may be present to represent a list of MARs to create."}) -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a new SMF in an SMF Set, with one PFCP association per SMF and UPF (see clause 5.22.3), takes over the control of the PFCP session.When present, it shall contain the unique identifier of the new SMF."}) +ies.append({ "ie_type" : "F-SEID", "ie_value" : "CP F-SEID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the CP function decides to change its F-SEID for the PFCP session. The UP function shall use the new CP F-SEID for subsequent PFCP Session related messages for this PFCP Session. See Note 2."}) +type_list["Remove PDR"]["max_tlv_more"] = "3" +ies.append({ "ie_type" : "Remove PDR", "ie_value" : "Remove PDR", "presence" : "C", "tlv_more" : "3", "comment" : "When present, this IE shall contain the PDR Rule which is requested to be removed. See Table 7.5.4-6-1.Several IEs within the same IE type may be present to represent a list of PDRs to remove."}) +type_list["Remove FAR"]["max_tlv_more"] = "3" +ies.append({ "ie_type" : "Remove FAR", "ie_value" : "Remove FAR", "presence" : "C", "tlv_more" : "3", "comment" : "When present, this IE shall contain the FAR Rule which is requested to be removed. See Table 7.5.4-7-1.Several IEs within the same IE type may be present to represent a list of FARs to remove."}) +type_list["Remove URR"]["max_tlv_more"] = "1" +ies.append({ "ie_type" : "Remove URR", "ie_value" : "Remove URR", "presence" : "C", "tlv_more" : "1", "comment" : "When present, this shall contain the URR Rule which is requested to be removed. See Table 7.5.4-8-1.Several IEs within the same IE type may be present to represent a list of URRs to remove."}) +type_list["Remove QER"]["max_tlv_more"] = "1" +ies.append({ "ie_type" : "Remove QER", "ie_value" : "Remove QER", "presence" : "C", "tlv_more" : "1", "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"] = "3" +ies.append({ "ie_type" : "Create PDR", "ie_value" : "Create PDR", "presence" : "C", "tlv_more" : "3", "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"] = "3" +ies.append({ "ie_type" : "Create FAR", "ie_value" : "Create FAR", "presence" : "C", "tlv_more" : "3", "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"] = "1" +ies.append({ "ie_type" : "Create QER", "ie_value" : "Create QER", "presence" : "C", "tlv_more" : "1", "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."}) +type_list["Update PDR"]["max_tlv_more"] = "3" +ies.append({ "ie_type" : "Update PDR", "ie_value" : "Update PDR", "presence" : "C", "tlv_more" : "3", "comment" : "This IE shall be present if a PDR previously created for the PFCP session need to be modified. See Table 7.5.4.2-1.Several IEs within the same IE type may be present to represent a list of PDRs to update."}) +type_list["Update FAR"]["max_tlv_more"] = "3" +ies.append({ "ie_type" : "Update FAR", "ie_value" : "Update FAR", "presence" : "C", "tlv_more" : "3", "comment" : "This IE shall be present if a FAR previously created for the PFCP session need to be modified. See Table 7.5.4.3-1. Several IEs within the same IE type may be present to represent a list of FARs to update."}) +type_list["Update URR"]["max_tlv_more"] = "1" +ies.append({ "ie_type" : "Update URR", "ie_value" : "Update URR", "presence" : "C", "tlv_more" : "1", "comment" : "This IE shall be present if URR(s) previously created for the PFCP session need to be modified.Several IEs within the same IE type may be present to represent a list of modified URRs. Previously URRs that are not modified shall not be included. See Table 7.5.4.4-1."}) +type_list["Update QER"]["max_tlv_more"] = "1" +ies.append({ "ie_type" : "Update QER", "ie_value" : "Update QER", "presence" : "C", "tlv_more" : "1", "comment" : "This IE shall be present if QER(s) previously created for the PFCP session need to be modified.Several IEs within the same IE type may be present to represent a list of modified QERs.Previously created QERs that are not modified shall not be included.See Table 7.5.4.5-1."}) +ies.append({ "ie_type" : "Update BAR Session Modification Request", "ie_value" : "Update BAR", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a BAR previously created for the PFCP session needs to be modified.A previously created BAR that is not modified shall not be included.See Table 7.5.4.11-1."}) +ies.append({ "ie_type" : "Update Traffic Endpoint", "ie_value" : "Update Traffic Endpoint", "presence" : "C", "tlv_more" : "0", "comment" : "When present this IE shall contain the information associated with the traffic endpoint to be updated, if the UP function has indicated support of PDI optimization.All the PDRs that refer to the Traffic Endpoint shall use the updated Traffic Endpoint information.See Table 7.5.4.13-1."}) +ies.append({ "ie_type" : "PFCPSMReq-Flags", "ie_value" : "PFCPSMReq-Flags", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- DROBU (Drop Buffered Packets): the CP function shall set this flag if the UP function is requested to drop the packets currently buffered for this PFCP session (see NOTE 1).- QAURR (Query All URRs): the CP function shall set this flag if the CP function requests immediate usage report(s) for all the URRs previously provisioned for this PFCP session (see NOTE 3). "}) +ies.append({ "ie_type" : "Query URR", "ie_value" : "Query URR", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the CP function requests immediate usage report(s) to the UP function.Several IEs within the same IE type may be present to represent a list of URRs for which an immediate report is requested.See Table 7.5.4.10-1.See NOTE 3."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "PGW-C FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "SGW-C FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "MME FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "ePDG FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "FQ-CSID", "ie_value" : "TWAN FQ-CSID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included according to the requirements in clause 23 of 3GPPTS23.007[24]."}) +ies.append({ "ie_type" : "User Plane Inactivity Timer", "ie_value" : "User Plane Inactivity Timer", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if it needs to be changed."}) +ies.append({ "ie_type" : "Query URR Reference", "ie_value" : "Query URR Reference", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the Query URR IE is present or the QAURR flag is set to 1. When present, it shall contain a reference identifying the query request, which the UP function shall return in any usage report sent in response to the query."}) +ies.append({ "ie_type" : "Trace Information", "ie_value" : "Trace Information", "presence" : "O", "tlv_more" : "0", "comment" : "When present, this IE shall contain the trace instructions to be applied by the UP function for this PFCP session.A Trace Information with a null length indicates that the trace session shall be deactivated. "}) +ies.append({ "ie_type" : "Remove MAR", "ie_value" : "Remove MAR", "presence" : "C", "tlv_more" : "0", "comment" : "When present, this IE shall contain the MAR Rule which is requested to be removed. See Table 7.5.4.15-1.Several IEs within the same IE type may be present to represent a list of MARs to remove."}) +ies.append({ "ie_type" : "Update MAR", "ie_value" : "Update MAR", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a MAR previously created for the PFCP session needs to be modified. See Table 7.5.4.16-1.Several IEs within the same IE type may be present to represent a list of MARs to update."}) +ies.append({ "ie_type" : "Create MAR", "ie_value" : "Create MAR", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the CP function requests the UP function to create a new MAR for a new PDR. See Table 7.5.2.8-1.Several IEs within the same IE type may be present to represent a list of MARs to create."}) +ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a new SMF in an SMF Set, with one PFCP association per SMF and UPF (see clause 5.22.3), takes over the control of the PFCP session.When present, it shall contain the unique identifier of the new SMF."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-53.py b/lib/pfcp/support/cache/tlv-msg-53.py index 01db69aa3..08405ebc9 100644 --- a/lib/pfcp/support/cache/tlv-msg-53.py +++ b/lib/pfcp/support/cache/tlv-msg-53.py @@ -1,11 +1,11 @@ ies = [] -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the rejection is due to a conditional or mandatory IE missing or faulty."}) -ies.append({ "ie_type" : "Created PDR", "ie_value" : "Created PDR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the cause is set to success, new PDR(s) were requested to be created and the UP function was requested to allocate the local F-TEID for the PDR(s).When present, this IE shall contain the PDR information associated to the PFCP session.See Table 7.5.3.2-1."}) -ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "instance" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) -ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network."}) -ies.append({ "ie_type" : "Usage Report Session Modification Response", "ie_value" : "Usage Report", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if: - the Query URR IE was present or the QAURR flag was set to 1 in the PFCP Session Modification Request, - traffic usage measurements for that URR are available at the UP function, and - the UP function decides to return some or all of the requested usage reports in the PFCP Session Modification Response.This IE shall be also present if: - a URR or the last PDR associated to a URR has been removed, - non-null traffic usage measurements for that URR are available in the UP function, and - the UP function decides to return some or all of the related usage reports in the PFCP Session Modification Response (see clause 5.2.2.3.1).Several IEs within the same IE type may be present to represent a list of Usage Reports."}) -ies.append({ "ie_type" : "Failed Rule ID", "ie_value" : "Failed Rule ID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the Cause IE indicates a rejection due to a rule creation or modification failure."}) -ies.append({ "ie_type" : "Additional Usage Reports Information", "ie_value" : "Additional Usage Reports Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the Query URR IE was present or the QAURR flag was set to 1 in the PFCP Session Modification Request, and usage reports need to be sent in additional PFCP Session Report Request messages (see clause 5.2.2.3.1).When present, this IE shall either indicate that additional usage reports will follow, or indicate the total number of usage reports that need to be sent in PFCP Session Report Request messages. "}) -ies.append({ "ie_type" : "Created Traffic Endpoint", "ie_value" : "Created/Updated Traffic Endpoint", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the cause is set to success, Traffic Endpoint(s) were requested to be created or updated, and the UP function was requested to allocate the local F-TEID for the Traffic Endpoint(s).When present, this IE shall contain the Traffic Endpoint information associated to the PFCP session.See Table 7.5.3.5-1."}) +ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the rejection is due to a conditional or mandatory IE missing or faulty."}) +ies.append({ "ie_type" : "Created PDR", "ie_value" : "Created PDR", "presence" : "C", "tlv_more" : "3", "comment" : "This IE shall be present if the cause is set to success, new PDR(s) were requested to be created and the UP function was requested to allocate the local F-TEID for the PDR(s).When present, this IE shall contain the PDR information associated to the PFCP session.See Table 7.5.3.2-1."}) +ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) +ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network."}) +ies.append({ "ie_type" : "Usage Report Session Modification Response", "ie_value" : "Usage Report", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if: - the Query URR IE was present or the QAURR flag was set to 1 in the PFCP Session Modification Request, - traffic usage measurements for that URR are available at the UP function, and - the UP function decides to return some or all of the requested usage reports in the PFCP Session Modification Response.This IE shall be also present if: - a URR or the last PDR associated to a URR has been removed, - non-null traffic usage measurements for that URR are available in the UP function, and - the UP function decides to return some or all of the related usage reports in the PFCP Session Modification Response (see clause 5.2.2.3.1).Several IEs within the same IE type may be present to represent a list of Usage Reports."}) +ies.append({ "ie_type" : "Failed Rule ID", "ie_value" : "Failed Rule ID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the Cause IE indicates a rejection due to a rule creation or modification failure."}) +ies.append({ "ie_type" : "Additional Usage Reports Information", "ie_value" : "Additional Usage Reports Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the Query URR IE was present or the QAURR flag was set to 1 in the PFCP Session Modification Request, and usage reports need to be sent in additional PFCP Session Report Request messages (see clause 5.2.2.3.1).When present, this IE shall either indicate that additional usage reports will follow, or indicate the total number of usage reports that need to be sent in PFCP Session Report Request messages. "}) +ies.append({ "ie_type" : "Created Traffic Endpoint", "ie_value" : "Created/Updated Traffic Endpoint", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the cause is set to success, Traffic Endpoint(s) were requested to be created or updated, and the UP function was requested to allocate the local F-TEID for the Traffic Endpoint(s).When present, this IE shall contain the Traffic Endpoint information associated to the PFCP session.See Table 7.5.3.5-1."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-55.py b/lib/pfcp/support/cache/tlv-msg-55.py index aca6f6f90..12feb0050 100644 --- a/lib/pfcp/support/cache/tlv-msg-55.py +++ b/lib/pfcp/support/cache/tlv-msg-55.py @@ -1,7 +1,7 @@ ies = [] -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the rejection is due to an conditional or mandatory IE missing or faulty."}) -ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "instance" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) -ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network.See Table 7.5.3.4-1."}) -ies.append({ "ie_type" : "Usage Report Session Deletion Response", "ie_value" : "Usage Report", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a URR had been provisioned in the UP function for the PFCP session being deleted and traffic usage measurements for that URR are available at the UP function.Several IEs within the same IE type may be present to represent a list of Usage Reports."}) +ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the rejection is due to an conditional or mandatory IE missing or faulty."}) +ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) +ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network.See Table 7.5.3.4-1."}) +ies.append({ "ie_type" : "Usage Report Session Deletion Response", "ie_value" : "Usage Report", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a URR had been provisioned in the UP function for the PFCP session being deleted and traffic usage measurements for that URR are available at the UP function.Several IEs within the same IE type may be present to represent a list of Usage Reports."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-56.py b/lib/pfcp/support/cache/tlv-msg-56.py index 0d56e6d7d..5208a798e 100644 --- a/lib/pfcp/support/cache/tlv-msg-56.py +++ b/lib/pfcp/support/cache/tlv-msg-56.py @@ -1,11 +1,11 @@ ies = [] -ies.append({ "ie_type" : "Report Type", "ie_value" : "Report Type", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the type of the report."}) -ies.append({ "ie_type" : "Downlink Data Report", "ie_value" : "Downlink Data Report", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Report Type indicates a Downlink Data Report. "}) -ies.append({ "ie_type" : "Usage Report Session Report Request", "ie_value" : "Usage Report", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Report Type indicates a Usage Report.Several IEs within the same IE type may be present to represent a list of Usage Reports."}) -ies.append({ "ie_type" : "Error Indication Report", "ie_value" : "Error Indication Report", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the Report Type indicates an Error Indication Report. "}) -ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "instance" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) -ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "instance" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network.See Table 7.5.3.4-1."}) -ies.append({ "ie_type" : "Additional Usage Reports Information", "ie_value" : "Additional Usage Reports Information", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included in one additional PFCP Session Report Request message, if the PFCP Session Modification Response indicated that more reports would follow (i.e. if the AURI flag was set to 1) (see clause 5.2.2.3.1).When present, this IE shall indicate the total number of usage reports that need to be sent in PFCP Session Report Request messages. "}) -ies.append({ "ie_type" : "PFCPSRReq-Flags", "ie_value" : "PFCPSRReq-Flags", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- PSDBU (PFCP Session Deleted By the UP function): if both the CP function and UP function support the EPFAR feature, the UP function may set this flag if the UP function needs to delete the PFCP session, e.g. to report all remaining non-zero usage reports for all URRs in the PFCP Session and the PFCP session is being deleted locally in the UP function."}) -ies.append({ "ie_type" : "F-SEID", "ie_value" : "Old CP F-SEID", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UPF sends the PFCP Session Report Request to a different SMF in an SMF Set. See clauses 5.22.2 and 5.22.3.When present, it shall indicate the CP F-SEID assigned by the previous SMF to the PFCP session. "}) +ies.append({ "ie_type" : "Report Type", "ie_value" : "Report Type", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the type of the report."}) +ies.append({ "ie_type" : "Downlink Data Report", "ie_value" : "Downlink Data Report", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Report Type indicates a Downlink Data Report. "}) +ies.append({ "ie_type" : "Usage Report Session Report Request", "ie_value" : "Usage Report", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Report Type indicates a Usage Report.Several IEs within the same IE type may be present to represent a list of Usage Reports."}) +ies.append({ "ie_type" : "Error Indication Report", "ie_value" : "Error Indication Report", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the Report Type indicates an Error Indication Report. "}) +ies.append({ "ie_type" : "Load Control Information", "ie_value" : "Load Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "The UP function may include this IE if it supports the load control feature and the feature is activated in the network.See Table 7.5.3.3-1."}) +ies.append({ "ie_type" : "Overload Control Information", "ie_value" : "Overload Control Information", "presence" : "O", "tlv_more" : "0", "comment" : "During an overload condition, the UP function may include this IE if it supports the overload control feature and the feature is activated in the network.See Table 7.5.3.4-1."}) +ies.append({ "ie_type" : "Additional Usage Reports Information", "ie_value" : "Additional Usage Reports Information", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included in one additional PFCP Session Report Request message, if the PFCP Session Modification Response indicated that more reports would follow (i.e. if the AURI flag was set to 1) (see clause 5.2.2.3.1).When present, this IE shall indicate the total number of usage reports that need to be sent in PFCP Session Report Request messages. "}) +ies.append({ "ie_type" : "PFCPSRReq-Flags", "ie_value" : "PFCPSRReq-Flags", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- PSDBU (PFCP Session Deleted By the UP function): if both the CP function and UP function support the EPFAR feature, the UP function may set this flag if the UP function needs to delete the PFCP session, e.g. to report all remaining non-zero usage reports for all URRs in the PFCP Session and the PFCP session is being deleted locally in the UP function."}) +ies.append({ "ie_type" : "F-SEID", "ie_value" : "Old CP F-SEID", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UPF sends the PFCP Session Report Request to a different SMF in an SMF Set. See clauses 5.22.2 and 5.22.3.When present, it shall indicate the CP F-SEID assigned by the previous SMF to the PFCP session. "}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-57.py b/lib/pfcp/support/cache/tlv-msg-57.py index 4d426bbf2..a47d7288d 100644 --- a/lib/pfcp/support/cache/tlv-msg-57.py +++ b/lib/pfcp/support/cache/tlv-msg-57.py @@ -1,9 +1,9 @@ ies = [] -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if the rejection is due to a conditional or mandatory IE missing or faulty."}) -ies.append({ "ie_type" : "Update BAR PFCP Session Report Response", "ie_value" : "Update BAR", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if a BAR previously created for the PFCP session needs to be modified.A previously created BAR that is not modified shall not be included.See Table 7.5.9.2-1."}) -ies.append({ "ie_type" : "PFCPSRRsp-Flags", "ie_value" : "PFCPSRRsp-Flags", "presence" : "C", "instance" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- DROBU (Drop Buffered Packets): the CP function shall set this flag if the UP function needs to drop the packets currently buffered for this PFCP session (see NOTE 1)."}) -ies.append({ "ie_type" : "F-SEID", "ie_value" : "CP F-SEID", "presence" : "O", "instance" : "0", "comment" : "This IE may be set by the SMF if the UPF indicated support of PFCP sessions successively controlled by different SMFs of a same SMF Set and the Cause IE indicates Request accepted (success)(see clause 5.22).When present, it shall be set to the new F-SEID that the UPF shall use for sending subsequent PFCP session related messages."}) -ies.append({ "ie_type" : "F-TEID", "ie_value" : "N4-u F-TEID", "presence" : "O", "instance" : "0", "comment" : "This IE may be set by the SMF if the UPF indicated support of PFCP sessions successively controlled by different SMFs of a same SMF Set and the Cause IE indicates Request accepted (success).When present, it shall be set to the new N4-u F-TEID that the UPF shall use for data forwarding towards the SMF. "}) -ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "instance" : "0", "comment" : "This IE may be set by the SMF if the UPF indicated support of PFCP sessions successively controlled by different SMFs of a same SMF Set and the Cause IE indicates Redirection Requested (see clause 5.22).When present, it shall be set to the IP address of the new SMF to contact. "}) +ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Offending IE", "ie_value" : "Offending IE", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if the rejection is due to a conditional or mandatory IE missing or faulty."}) +ies.append({ "ie_type" : "Update BAR PFCP Session Report Response", "ie_value" : "Update BAR", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if a BAR previously created for the PFCP session needs to be modified.A previously created BAR that is not modified shall not be included.See Table 7.5.9.2-1."}) +ies.append({ "ie_type" : "PFCPSRRsp-Flags", "ie_value" : "PFCPSRRsp-Flags", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- DROBU (Drop Buffered Packets): the CP function shall set this flag if the UP function needs to drop the packets currently buffered for this PFCP session (see NOTE 1)."}) +ies.append({ "ie_type" : "F-SEID", "ie_value" : "CP F-SEID", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be set by the SMF if the UPF indicated support of PFCP sessions successively controlled by different SMFs of a same SMF Set and the Cause IE indicates Request accepted (success)(see clause 5.22).When present, it shall be set to the new F-SEID that the UPF shall use for sending subsequent PFCP session related messages."}) +ies.append({ "ie_type" : "F-TEID", "ie_value" : "N4-u F-TEID", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be set by the SMF if the UPF indicated support of PFCP sessions successively controlled by different SMFs of a same SMF Set and the Cause IE indicates Request accepted (success).When present, it shall be set to the new N4-u F-TEID that the UPF shall use for data forwarding towards the SMF. "}) +ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be set by the SMF if the UPF indicated support of PFCP sessions successively controlled by different SMFs of a same SMF Set and the Cause IE indicates Redirection Requested (see clause 5.22).When present, it shall be set to the IP address of the new SMF to contact. "}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-6.py b/lib/pfcp/support/cache/tlv-msg-6.py index e65fdee48..e6873c649 100644 --- a/lib/pfcp/support/cache/tlv-msg-6.py +++ b/lib/pfcp/support/cache/tlv-msg-6.py @@ -1,9 +1,9 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the time stamp when the CP or UP function was started, see clause 19A of 3GPPTS23.007[24]. (NOTE)"}) -ies.append({ "ie_type" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function sends this message and the UP function supports at least one UP feature defined in this IE.When present, this IE shall indicate the features the UP function supports."}) -ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the CP function sends this message and the CP function supports at least one CP feature defined in this IE.When present, this IE indicates the features the CP function supports."}) -ies.append({ "ie_type" : "User Plane IP Resource Information", "ie_value" : "User Plane IP Resource Information", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an IPv4 and/or an IPv6 address, together with a TEID range that the CP function shall use to allocate GTP-U F-TEID in the UP function.Several IEs with the same IE type may be present to represent multiple User Plane IP Resources."}) -ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the SMF advertises the support of the SSET feature in the CP Function Features IE (see clause 8.2.58).When present, this IE shall contain an IPv4 and/or IPv6 address of an alternative SMF.Several IEs with the same IE type may be present to represent multiple alternative SMF IP addresses. "}) +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" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "Recovery Time Stamp", "ie_value" : "Recovery Time Stamp", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall contain the time stamp when the CP or UP function was started, see clause 19A of 3GPPTS23.007[24]. (NOTE)"}) +ies.append({ "ie_type" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function sends this message and the UP function supports at least one UP feature defined in this IE.When present, this IE shall indicate the features the UP function supports."}) +ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the CP function sends this message and the CP function supports at least one CP feature defined in this IE.When present, this IE indicates the features the CP function supports."}) +ies.append({ "ie_type" : "User Plane IP Resource Information", "ie_value" : "User Plane IP Resource Information", "presence" : "O", "tlv_more" : "3", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an IPv4 and/or an IPv6 address, together with a TEID range that the CP function shall use to allocate GTP-U F-TEID in the UP function.Several IEs with the same IE type may be present to represent multiple User Plane IP Resources."}) +ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the SMF advertises the support of the SSET feature in the CP Function Features IE (see clause 8.2.58).When present, this IE shall contain an IPv4 and/or IPv6 address of an alternative SMF.Several IEs with the same IE type may be present to represent multiple alternative SMF IP addresses. "}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-7.py b/lib/pfcp/support/cache/tlv-msg-7.py index 828ab03f6..17445cff5 100644 --- a/lib/pfcp/support/cache/tlv-msg-7.py +++ b/lib/pfcp/support/cache/tlv-msg-7.py @@ -1,10 +1,10 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the UP function."}) -ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the CP function."}) -ies.append({ "ie_type" : "PFCP Association Release Request", "ie_value" : "PFCP Association Release Request", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function requests the CP function to release the PFCP association."}) -ies.append({ "ie_type" : "Graceful Release Period", "ie_value" : "Graceful Release Period", "presence" : "C", "instance" : "0", "comment" : "This IE shall be present if the UP function requests a graceful release of the PFCP association."}) -ies.append({ "ie_type" : "User Plane IP Resource Information", "ie_value" : "User Plane IP Resource Information", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an IPv4 and/or an IPv6 address, together with a TEID range that the CP function shall use to allocate GTP-U F-TEID in the UP function.Several IEs with the same IE type may be present to represent multiple User Plane IP Resources. "}) -ies.append({ "ie_type" : "PFCPAUReq-Flags", "ie_value" : "PFCPAUReq-Flags", "presence" : "O", "instance" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- PARPS (PFCP Association Release Preparation Start): if both the CP function and UP function support the EPFAR feature, the CP or UP function may set this flag to 1 to indicate that the PFCP association is to be released and all non-zero usage reports for those PFCP Sessions affected by the release of the PFCP association shall be reported."}) -ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "instance" : "0", "comment" : "This IE may be present if the SMF advertises the support of the SSET feature in the CP Function Features IE (see clause 8.2.58).When present, this IE shall contain an IPv4 and/or IPv6 address of an alternative SMF.Several IEs with the same IE type may be present to represent multiple alternative SMF IP addresses. "}) +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" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the UP function."}) +ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the CP function."}) +ies.append({ "ie_type" : "PFCP Association Release Request", "ie_value" : "PFCP Association Release Request", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function requests the CP function to release the PFCP association."}) +ies.append({ "ie_type" : "Graceful Release Period", "ie_value" : "Graceful Release Period", "presence" : "C", "tlv_more" : "0", "comment" : "This IE shall be present if the UP function requests a graceful release of the PFCP association."}) +ies.append({ "ie_type" : "User Plane IP Resource Information", "ie_value" : "User Plane IP Resource Information", "presence" : "O", "tlv_more" : "3", "comment" : "This IE may be present if the UP function sends this message.When present, this IE shall contain an IPv4 and/or an IPv6 address, together with a TEID range that the CP function shall use to allocate GTP-U F-TEID in the UP function.Several IEs with the same IE type may be present to represent multiple User Plane IP Resources. "}) +ies.append({ "ie_type" : "PFCPAUReq-Flags", "ie_value" : "PFCPAUReq-Flags", "presence" : "O", "tlv_more" : "0", "comment" : "This IE shall be included if at least one of the flags is set to 1.- PARPS (PFCP Association Release Preparation Start): if both the CP function and UP function support the EPFAR feature, the CP or UP function may set this flag to 1 to indicate that the PFCP association is to be released and all non-zero usage reports for those PFCP Sessions affected by the release of the PFCP association shall be reported."}) +ies.append({ "ie_type" : "Alternative SMF IP Address", "ie_value" : "Alternative SMF IP Address", "presence" : "O", "tlv_more" : "0", "comment" : "This IE may be present if the SMF advertises the support of the SSET feature in the CP Function Features IE (see clause 8.2.58).When present, this IE shall contain an IPv4 and/or IPv6 address of an alternative SMF.Several IEs with the same IE type may be present to represent multiple alternative SMF IP addresses. "}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-8.py b/lib/pfcp/support/cache/tlv-msg-8.py index 5235de0a1..f3dfcc12c 100644 --- a/lib/pfcp/support/cache/tlv-msg-8.py +++ b/lib/pfcp/support/cache/tlv-msg-8.py @@ -1,6 +1,6 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) -ies.append({ "ie_type" : "Cause", "ie_value" : "Cause", "presence" : "M", "instance" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) -ies.append({ "ie_type" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the UP function."}) -ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "O", "instance" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the CP function."}) +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" : "Cause", "ie_value" : "Cause", "presence" : "M", "tlv_more" : "0", "comment" : "This IE shall indicate the acceptance or the rejection of the corresponding request message."}) +ies.append({ "ie_type" : "UP Function Features", "ie_value" : "UP Function Features", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the UP function."}) +ies.append({ "ie_type" : "CP Function Features", "ie_value" : "CP Function Features", "presence" : "O", "tlv_more" : "0", "comment" : "If present, this IE shall indicate the supported Features when the sending node is the CP function."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-msg-9.py b/lib/pfcp/support/cache/tlv-msg-9.py index 4598dc765..d86abc424 100644 --- a/lib/pfcp/support/cache/tlv-msg-9.py +++ b/lib/pfcp/support/cache/tlv-msg-9.py @@ -1,3 +1,3 @@ ies = [] -ies.append({ "ie_type" : "Node ID", "ie_value" : "Node ID", "presence" : "M", "instance" : "0", "comment" : "This IE shall contain the unique identifier of the sending Node."}) +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."}) msg_list[key]["ies"] = ies diff --git a/lib/pfcp/support/cache/tlv-type-list.py b/lib/pfcp/support/cache/tlv-type-list.py index 5368b0a53..352f89ce9 100644 --- a/lib/pfcp/support/cache/tlv-type-list.py +++ b/lib/pfcp/support/cache/tlv-type-list.py @@ -1,181 +1,181 @@ -type_list["Create PDR"] = { "type" : "1", "max_instance" : "0" } -type_list["PDI"] = { "type" : "2", "max_instance" : "0" } -type_list["Create FAR"] = { "type" : "3", "max_instance" : "0" } -type_list["Forwarding Parameters"] = { "type" : "4", "max_instance" : "0" } -type_list["Duplicating Parameters"] = { "type" : "5", "max_instance" : "0" } -type_list["Create URR"] = { "type" : "6", "max_instance" : "0" } -type_list["Create QER"] = { "type" : "7", "max_instance" : "0" } -type_list["Created PDR"] = { "type" : "8", "max_instance" : "0" } -type_list["Update PDR"] = { "type" : "9", "max_instance" : "0" } -type_list["Update FAR"] = { "type" : "10", "max_instance" : "0" } -type_list["Update Forwarding Parameters"] = { "type" : "11", "max_instance" : "0" } -type_list["Update BAR PFCP Session Report Response"] = { "type" : "12", "max_instance" : "0" } -type_list["Update URR"] = { "type" : "13", "max_instance" : "0" } -type_list["Update QER"] = { "type" : "14", "max_instance" : "0" } -type_list["Remove PDR"] = { "type" : "15", "max_instance" : "0" } -type_list["Remove FAR"] = { "type" : "16", "max_instance" : "0" } -type_list["Remove URR"] = { "type" : "17", "max_instance" : "0" } -type_list["Remove QER"] = { "type" : "18", "max_instance" : "0" } -type_list["Cause"] = { "type" : "19", "max_instance" : "0" } -type_list["Source Interface"] = { "type" : "20", "max_instance" : "0" } -type_list["F-TEID"] = { "type" : "21", "max_instance" : "0" } -type_list["Network Instance"] = { "type" : "22", "max_instance" : "0" } -type_list["SDF Filter"] = { "type" : "23", "max_instance" : "0" } -type_list["Application ID"] = { "type" : "24", "max_instance" : "0" } -type_list["Gate Status"] = { "type" : "25", "max_instance" : "0" } -type_list["MBR"] = { "type" : "26", "max_instance" : "0" } -type_list["GBR"] = { "type" : "27", "max_instance" : "0" } -type_list["QER Correlation ID"] = { "type" : "28", "max_instance" : "0" } -type_list["Precedence"] = { "type" : "29", "max_instance" : "0" } -type_list["Transport Level Marking"] = { "type" : "30", "max_instance" : "0" } -type_list["Volume Threshold"] = { "type" : "31", "max_instance" : "0" } -type_list["Time Threshold"] = { "type" : "32", "max_instance" : "0" } -type_list["Monitoring Time"] = { "type" : "33", "max_instance" : "0" } -type_list["Subsequent Volume Threshold"] = { "type" : "34", "max_instance" : "0" } -type_list["Subsequent Time Threshold"] = { "type" : "35", "max_instance" : "0" } -type_list["Inactivity Detection Time"] = { "type" : "36", "max_instance" : "0" } -type_list["Reporting Triggers"] = { "type" : "37", "max_instance" : "0" } -type_list["Redirect Information"] = { "type" : "38", "max_instance" : "0" } -type_list["Report Type"] = { "type" : "39", "max_instance" : "0" } -type_list["Offending IE"] = { "type" : "40", "max_instance" : "0" } -type_list["Forwarding Policy"] = { "type" : "41", "max_instance" : "0" } -type_list["Destination Interface"] = { "type" : "42", "max_instance" : "0" } -type_list["UP Function Features"] = { "type" : "43", "max_instance" : "0" } -type_list["Apply Action"] = { "type" : "44", "max_instance" : "0" } -type_list["Downlink Data Service Information"] = { "type" : "45", "max_instance" : "0" } -type_list["Downlink Data Notification Delay"] = { "type" : "46", "max_instance" : "0" } -type_list["DL Buffering Duration"] = { "type" : "47", "max_instance" : "0" } -type_list["DL Buffering Suggested Packet Count"] = { "type" : "48", "max_instance" : "0" } -type_list["PFCPSMReq-Flags"] = { "type" : "49", "max_instance" : "0" } -type_list["PFCPSRRsp-Flags"] = { "type" : "50", "max_instance" : "0" } -type_list["Load Control Information"] = { "type" : "51", "max_instance" : "0" } -type_list["Sequence Number"] = { "type" : "52", "max_instance" : "0" } -type_list["Metric"] = { "type" : "53", "max_instance" : "0" } -type_list["Overload Control Information"] = { "type" : "54", "max_instance" : "0" } -type_list["Timer"] = { "type" : "55", "max_instance" : "0" } -type_list["PDR ID"] = { "type" : "56", "max_instance" : "0" } -type_list["F-SEID"] = { "type" : "57", "max_instance" : "0" } -type_list["Application ID's PFDs"] = { "type" : "58", "max_instance" : "0" } -type_list["PFD context"] = { "type" : "59", "max_instance" : "0" } -type_list["Node ID"] = { "type" : "60", "max_instance" : "0" } -type_list["PFD contents"] = { "type" : "61", "max_instance" : "0" } -type_list["Measurement Method"] = { "type" : "62", "max_instance" : "0" } -type_list["Usage Report Trigger"] = { "type" : "63", "max_instance" : "0" } -type_list["Measurement Period"] = { "type" : "64", "max_instance" : "0" } -type_list["FQ-CSID"] = { "type" : "65", "max_instance" : "0" } -type_list["Volume Measurement"] = { "type" : "66", "max_instance" : "0" } -type_list["Duration Measurement"] = { "type" : "67", "max_instance" : "0" } -type_list["Application Detection Information"] = { "type" : "68", "max_instance" : "0" } -type_list["Time of First Packet"] = { "type" : "69", "max_instance" : "0" } -type_list["Time of Last Packet"] = { "type" : "70", "max_instance" : "0" } -type_list["Quota Holding Time"] = { "type" : "71", "max_instance" : "0" } -type_list["Dropped DL Traffic Threshold"] = { "type" : "72", "max_instance" : "0" } -type_list["Volume Quota"] = { "type" : "73", "max_instance" : "0" } -type_list["Time Quota"] = { "type" : "74", "max_instance" : "0" } -type_list["Start Time"] = { "type" : "75", "max_instance" : "0" } -type_list["End Time"] = { "type" : "76", "max_instance" : "0" } -type_list["Query URR"] = { "type" : "77", "max_instance" : "0" } -type_list["Usage Report Session Modification Response"] = { "type" : "78", "max_instance" : "0" } -type_list["Usage Report Session Deletion Response"] = { "type" : "79", "max_instance" : "0" } -type_list["Usage Report Session Report Request"] = { "type" : "80", "max_instance" : "0" } -type_list["URR ID"] = { "type" : "81", "max_instance" : "0" } -type_list["Linked URR ID"] = { "type" : "82", "max_instance" : "0" } -type_list["Downlink Data Report"] = { "type" : "83", "max_instance" : "0" } -type_list["Outer Header Creation"] = { "type" : "84", "max_instance" : "0" } -type_list["Create BAR"] = { "type" : "85", "max_instance" : "0" } -type_list["Update BAR Session Modification Request"] = { "type" : "86", "max_instance" : "0" } -type_list["Remove BAR"] = { "type" : "87", "max_instance" : "0" } -type_list["BAR ID"] = { "type" : "88", "max_instance" : "0" } -type_list["CP Function Features"] = { "type" : "89", "max_instance" : "0" } -type_list["Usage Information"] = { "type" : "90", "max_instance" : "0" } -type_list["Application Instance ID"] = { "type" : "91", "max_instance" : "0" } -type_list["Flow Information"] = { "type" : "92", "max_instance" : "0" } -type_list["UE IP Address"] = { "type" : "93", "max_instance" : "0" } -type_list["Packet Rate"] = { "type" : "94", "max_instance" : "0" } -type_list["Outer Header Removal"] = { "type" : "95", "max_instance" : "0" } -type_list["Recovery Time Stamp"] = { "type" : "96", "max_instance" : "0" } -type_list["DL Flow Level Marking"] = { "type" : "97", "max_instance" : "0" } -type_list["Header Enrichment"] = { "type" : "98", "max_instance" : "0" } -type_list["Error Indication Report"] = { "type" : "99", "max_instance" : "0" } -type_list["Measurement Information"] = { "type" : "100", "max_instance" : "0" } -type_list["Node Report Type"] = { "type" : "101", "max_instance" : "0" } -type_list["User Plane Path Failure Report"] = { "type" : "102", "max_instance" : "0" } -type_list["Remote GTP-U Peer"] = { "type" : "103", "max_instance" : "0" } -type_list["UR-SEQN"] = { "type" : "104", "max_instance" : "0" } -type_list["Update Duplicating Parameters"] = { "type" : "105", "max_instance" : "0" } -type_list["Activate Predefined Rules"] = { "type" : "106", "max_instance" : "0" } -type_list["Deactivate Predefined Rules"] = { "type" : "107", "max_instance" : "0" } -type_list["FAR ID"] = { "type" : "108", "max_instance" : "0" } -type_list["QER ID"] = { "type" : "109", "max_instance" : "0" } -type_list["OCI Flags"] = { "type" : "110", "max_instance" : "0" } -type_list["PFCP Association Release Request"] = { "type" : "111", "max_instance" : "0" } -type_list["Graceful Release Period"] = { "type" : "112", "max_instance" : "0" } -type_list["PDN Type"] = { "type" : "113", "max_instance" : "0" } -type_list["Failed Rule ID"] = { "type" : "114", "max_instance" : "0" } -type_list["Time Quota Mechanism"] = { "type" : "115", "max_instance" : "0" } -type_list["User Plane IP Resource Information"] = { "type" : "116", "max_instance" : "0" } -type_list["User Plane Inactivity Timer"] = { "type" : "117", "max_instance" : "0" } -type_list["Aggregated URRs"] = { "type" : "118", "max_instance" : "0" } -type_list["Multiplier"] = { "type" : "119", "max_instance" : "0" } -type_list["Aggregated URR ID"] = { "type" : "120", "max_instance" : "0" } -type_list["Subsequent Volume Quota"] = { "type" : "121", "max_instance" : "0" } -type_list["Subsequent Time Quota"] = { "type" : "122", "max_instance" : "0" } -type_list["RQI"] = { "type" : "123", "max_instance" : "0" } -type_list["QFI"] = { "type" : "124", "max_instance" : "0" } -type_list["Query URR Reference"] = { "type" : "125", "max_instance" : "0" } -type_list["Additional Usage Reports Information"] = { "type" : "126", "max_instance" : "0" } -type_list["Create Traffic Endpoint"] = { "type" : "127", "max_instance" : "0" } -type_list["Created Traffic Endpoint"] = { "type" : "128", "max_instance" : "0" } -type_list["Update Traffic Endpoint"] = { "type" : "129", "max_instance" : "0" } -type_list["Remove Traffic Endpoint"] = { "type" : "130", "max_instance" : "0" } -type_list["Traffic Endpoint ID"] = { "type" : "131", "max_instance" : "0" } -type_list["Ethernet Packet Filter"] = { "type" : "132", "max_instance" : "0" } -type_list["MAC address"] = { "type" : "133", "max_instance" : "0" } -type_list["C-TAG"] = { "type" : "134", "max_instance" : "0" } -type_list["S-TAG"] = { "type" : "135", "max_instance" : "0" } -type_list["Ethertype"] = { "type" : "136", "max_instance" : "0" } -type_list["Proxying"] = { "type" : "137", "max_instance" : "0" } -type_list["Ethernet Filter ID"] = { "type" : "138", "max_instance" : "0" } -type_list["Ethernet Filter Properties"] = { "type" : "139", "max_instance" : "0" } -type_list["Suggested Buffering Packets Count"] = { "type" : "140", "max_instance" : "0" } -type_list["User ID"] = { "type" : "141", "max_instance" : "0" } -type_list["Ethernet PDU Session Information"] = { "type" : "142", "max_instance" : "0" } -type_list["Ethernet Traffic Information"] = { "type" : "143", "max_instance" : "0" } -type_list["MAC Addresses Detected"] = { "type" : "144", "max_instance" : "0" } -type_list["MAC Addresses Removed"] = { "type" : "145", "max_instance" : "0" } -type_list["Ethernet Inactivity Timer"] = { "type" : "146", "max_instance" : "0" } -type_list["Additional Monitoring Time"] = { "type" : "147", "max_instance" : "0" } -type_list["Event Quota"] = { "type" : "148", "max_instance" : "0" } -type_list["Event Threshold"] = { "type" : "149", "max_instance" : "0" } -type_list["Subsequent Event Quota"] = { "type" : "150", "max_instance" : "0" } -type_list["Subsequent Event Threshold"] = { "type" : "151", "max_instance" : "0" } -type_list["Trace Information"] = { "type" : "152", "max_instance" : "0" } -type_list["Framed-Route"] = { "type" : "153", "max_instance" : "0" } -type_list["Framed-Routing"] = { "type" : "154", "max_instance" : "0" } -type_list["Framed-IPv6-Route"] = { "type" : "155", "max_instance" : "0" } -type_list["Event Time Stamp"] = { "type" : "156", "max_instance" : "0" } -type_list["Averaging Window"] = { "type" : "157", "max_instance" : "0" } -type_list["Paging Policy Indicator"] = { "type" : "158", "max_instance" : "0" } -type_list["APN/DNN"] = { "type" : "159", "max_instance" : "0" } -type_list["3GPP Interface Type"] = { "type" : "160", "max_instance" : "0" } -type_list["PFCPSRReq-Flags"] = { "type" : "161", "max_instance" : "0" } -type_list["PFCPAUReq-Flags"] = { "type" : "162", "max_instance" : "0" } -type_list["Activation Time"] = { "type" : "163", "max_instance" : "0" } -type_list["Deactivation Time"] = { "type" : "164", "max_instance" : "0" } -type_list["Create MAR"] = { "type" : "165", "max_instance" : "0" } -type_list["Access Forwarding Action Information 1"] = { "type" : "166", "max_instance" : "0" } -type_list["Access Forwarding Action Information 2"] = { "type" : "167", "max_instance" : "0" } -type_list["Remove MAR"] = { "type" : "168", "max_instance" : "0" } -type_list["Update MAR"] = { "type" : "169", "max_instance" : "0" } -type_list["MAR ID"] = { "type" : "170", "max_instance" : "0" } -type_list["Steering Functionality"] = { "type" : "171", "max_instance" : "0" } -type_list["Steering Mode"] = { "type" : "172", "max_instance" : "0" } -type_list["Weight"] = { "type" : "173", "max_instance" : "0" } -type_list["Priority"] = { "type" : "174", "max_instance" : "0" } -type_list["Update Access Forwarding Action Information 1"] = { "type" : "175", "max_instance" : "0" } -type_list["Update Access Forwarding Action Information 2"] = { "type" : "176", "max_instance" : "0" } -type_list["UE IP address Pool Identity"] = { "type" : "177", "max_instance" : "0" } -type_list["Alternative SMF IP Address"] = { "type" : "178", "max_instance" : "0" } -type_list["Packet Replication and Detection Carry-On Information"] = { "type" : "179", "max_instance" : "0" } -type_list["SMF Set ID"] = { "type" : "180", "max_instance" : "0" } -type_list["Quota Validity Time"] = { "type" : "181", "max_instance" : "0" } +type_list["Create PDR"] = { "type" : "1", "max_tlv_more" : "0" } +type_list["PDI"] = { "type" : "2", "max_tlv_more" : "0" } +type_list["Create FAR"] = { "type" : "3", "max_tlv_more" : "0" } +type_list["Forwarding Parameters"] = { "type" : "4", "max_tlv_more" : "0" } +type_list["Duplicating Parameters"] = { "type" : "5", "max_tlv_more" : "0" } +type_list["Create URR"] = { "type" : "6", "max_tlv_more" : "0" } +type_list["Create QER"] = { "type" : "7", "max_tlv_more" : "0" } +type_list["Created PDR"] = { "type" : "8", "max_tlv_more" : "0" } +type_list["Update PDR"] = { "type" : "9", "max_tlv_more" : "0" } +type_list["Update FAR"] = { "type" : "10", "max_tlv_more" : "0" } +type_list["Update Forwarding Parameters"] = { "type" : "11", "max_tlv_more" : "0" } +type_list["Update BAR PFCP Session Report Response"] = { "type" : "12", "max_tlv_more" : "0" } +type_list["Update URR"] = { "type" : "13", "max_tlv_more" : "0" } +type_list["Update QER"] = { "type" : "14", "max_tlv_more" : "0" } +type_list["Remove PDR"] = { "type" : "15", "max_tlv_more" : "0" } +type_list["Remove FAR"] = { "type" : "16", "max_tlv_more" : "0" } +type_list["Remove URR"] = { "type" : "17", "max_tlv_more" : "0" } +type_list["Remove QER"] = { "type" : "18", "max_tlv_more" : "0" } +type_list["Cause"] = { "type" : "19", "max_tlv_more" : "0" } +type_list["Source Interface"] = { "type" : "20", "max_tlv_more" : "0" } +type_list["F-TEID"] = { "type" : "21", "max_tlv_more" : "0" } +type_list["Network Instance"] = { "type" : "22", "max_tlv_more" : "0" } +type_list["SDF Filter"] = { "type" : "23", "max_tlv_more" : "0" } +type_list["Application ID"] = { "type" : "24", "max_tlv_more" : "0" } +type_list["Gate Status"] = { "type" : "25", "max_tlv_more" : "0" } +type_list["MBR"] = { "type" : "26", "max_tlv_more" : "0" } +type_list["GBR"] = { "type" : "27", "max_tlv_more" : "0" } +type_list["QER Correlation ID"] = { "type" : "28", "max_tlv_more" : "0" } +type_list["Precedence"] = { "type" : "29", "max_tlv_more" : "0" } +type_list["Transport Level Marking"] = { "type" : "30", "max_tlv_more" : "0" } +type_list["Volume Threshold"] = { "type" : "31", "max_tlv_more" : "0" } +type_list["Time Threshold"] = { "type" : "32", "max_tlv_more" : "0" } +type_list["Monitoring Time"] = { "type" : "33", "max_tlv_more" : "0" } +type_list["Subsequent Volume Threshold"] = { "type" : "34", "max_tlv_more" : "0" } +type_list["Subsequent Time Threshold"] = { "type" : "35", "max_tlv_more" : "0" } +type_list["Inactivity Detection Time"] = { "type" : "36", "max_tlv_more" : "0" } +type_list["Reporting Triggers"] = { "type" : "37", "max_tlv_more" : "0" } +type_list["Redirect Information"] = { "type" : "38", "max_tlv_more" : "0" } +type_list["Report Type"] = { "type" : "39", "max_tlv_more" : "0" } +type_list["Offending IE"] = { "type" : "40", "max_tlv_more" : "0" } +type_list["Forwarding Policy"] = { "type" : "41", "max_tlv_more" : "0" } +type_list["Destination Interface"] = { "type" : "42", "max_tlv_more" : "0" } +type_list["UP Function Features"] = { "type" : "43", "max_tlv_more" : "0" } +type_list["Apply Action"] = { "type" : "44", "max_tlv_more" : "0" } +type_list["Downlink Data Service Information"] = { "type" : "45", "max_tlv_more" : "0" } +type_list["Downlink Data Notification Delay"] = { "type" : "46", "max_tlv_more" : "0" } +type_list["DL Buffering Duration"] = { "type" : "47", "max_tlv_more" : "0" } +type_list["DL Buffering Suggested Packet Count"] = { "type" : "48", "max_tlv_more" : "0" } +type_list["PFCPSMReq-Flags"] = { "type" : "49", "max_tlv_more" : "0" } +type_list["PFCPSRRsp-Flags"] = { "type" : "50", "max_tlv_more" : "0" } +type_list["Load Control Information"] = { "type" : "51", "max_tlv_more" : "0" } +type_list["Sequence Number"] = { "type" : "52", "max_tlv_more" : "0" } +type_list["Metric"] = { "type" : "53", "max_tlv_more" : "0" } +type_list["Overload Control Information"] = { "type" : "54", "max_tlv_more" : "0" } +type_list["Timer"] = { "type" : "55", "max_tlv_more" : "0" } +type_list["PDR ID"] = { "type" : "56", "max_tlv_more" : "0" } +type_list["F-SEID"] = { "type" : "57", "max_tlv_more" : "0" } +type_list["Application ID's PFDs"] = { "type" : "58", "max_tlv_more" : "0" } +type_list["PFD context"] = { "type" : "59", "max_tlv_more" : "0" } +type_list["Node ID"] = { "type" : "60", "max_tlv_more" : "0" } +type_list["PFD contents"] = { "type" : "61", "max_tlv_more" : "0" } +type_list["Measurement Method"] = { "type" : "62", "max_tlv_more" : "0" } +type_list["Usage Report Trigger"] = { "type" : "63", "max_tlv_more" : "0" } +type_list["Measurement Period"] = { "type" : "64", "max_tlv_more" : "0" } +type_list["FQ-CSID"] = { "type" : "65", "max_tlv_more" : "0" } +type_list["Volume Measurement"] = { "type" : "66", "max_tlv_more" : "0" } +type_list["Duration Measurement"] = { "type" : "67", "max_tlv_more" : "0" } +type_list["Application Detection Information"] = { "type" : "68", "max_tlv_more" : "0" } +type_list["Time of First Packet"] = { "type" : "69", "max_tlv_more" : "0" } +type_list["Time of Last Packet"] = { "type" : "70", "max_tlv_more" : "0" } +type_list["Quota Holding Time"] = { "type" : "71", "max_tlv_more" : "0" } +type_list["Dropped DL Traffic Threshold"] = { "type" : "72", "max_tlv_more" : "0" } +type_list["Volume Quota"] = { "type" : "73", "max_tlv_more" : "0" } +type_list["Time Quota"] = { "type" : "74", "max_tlv_more" : "0" } +type_list["Start Time"] = { "type" : "75", "max_tlv_more" : "0" } +type_list["End Time"] = { "type" : "76", "max_tlv_more" : "0" } +type_list["Query URR"] = { "type" : "77", "max_tlv_more" : "0" } +type_list["Usage Report Session Modification Response"] = { "type" : "78", "max_tlv_more" : "0" } +type_list["Usage Report Session Deletion Response"] = { "type" : "79", "max_tlv_more" : "0" } +type_list["Usage Report Session Report Request"] = { "type" : "80", "max_tlv_more" : "0" } +type_list["URR ID"] = { "type" : "81", "max_tlv_more" : "0" } +type_list["Linked URR ID"] = { "type" : "82", "max_tlv_more" : "0" } +type_list["Downlink Data Report"] = { "type" : "83", "max_tlv_more" : "0" } +type_list["Outer Header Creation"] = { "type" : "84", "max_tlv_more" : "0" } +type_list["Create BAR"] = { "type" : "85", "max_tlv_more" : "0" } +type_list["Update BAR Session Modification Request"] = { "type" : "86", "max_tlv_more" : "0" } +type_list["Remove BAR"] = { "type" : "87", "max_tlv_more" : "0" } +type_list["BAR ID"] = { "type" : "88", "max_tlv_more" : "0" } +type_list["CP Function Features"] = { "type" : "89", "max_tlv_more" : "0" } +type_list["Usage Information"] = { "type" : "90", "max_tlv_more" : "0" } +type_list["Application Instance ID"] = { "type" : "91", "max_tlv_more" : "0" } +type_list["Flow Information"] = { "type" : "92", "max_tlv_more" : "0" } +type_list["UE IP Address"] = { "type" : "93", "max_tlv_more" : "0" } +type_list["Packet Rate"] = { "type" : "94", "max_tlv_more" : "0" } +type_list["Outer Header Removal"] = { "type" : "95", "max_tlv_more" : "0" } +type_list["Recovery Time Stamp"] = { "type" : "96", "max_tlv_more" : "0" } +type_list["DL Flow Level Marking"] = { "type" : "97", "max_tlv_more" : "0" } +type_list["Header Enrichment"] = { "type" : "98", "max_tlv_more" : "0" } +type_list["Error Indication Report"] = { "type" : "99", "max_tlv_more" : "0" } +type_list["Measurement Information"] = { "type" : "100", "max_tlv_more" : "0" } +type_list["Node Report Type"] = { "type" : "101", "max_tlv_more" : "0" } +type_list["User Plane Path Failure Report"] = { "type" : "102", "max_tlv_more" : "0" } +type_list["Remote GTP-U Peer"] = { "type" : "103", "max_tlv_more" : "0" } +type_list["UR-SEQN"] = { "type" : "104", "max_tlv_more" : "0" } +type_list["Update Duplicating Parameters"] = { "type" : "105", "max_tlv_more" : "0" } +type_list["Activate Predefined Rules"] = { "type" : "106", "max_tlv_more" : "0" } +type_list["Deactivate Predefined Rules"] = { "type" : "107", "max_tlv_more" : "0" } +type_list["FAR ID"] = { "type" : "108", "max_tlv_more" : "0" } +type_list["QER ID"] = { "type" : "109", "max_tlv_more" : "0" } +type_list["OCI Flags"] = { "type" : "110", "max_tlv_more" : "0" } +type_list["PFCP Association Release Request"] = { "type" : "111", "max_tlv_more" : "0" } +type_list["Graceful Release Period"] = { "type" : "112", "max_tlv_more" : "0" } +type_list["PDN Type"] = { "type" : "113", "max_tlv_more" : "0" } +type_list["Failed Rule ID"] = { "type" : "114", "max_tlv_more" : "0" } +type_list["Time Quota Mechanism"] = { "type" : "115", "max_tlv_more" : "0" } +type_list["User Plane IP Resource Information"] = { "type" : "116", "max_tlv_more" : "0" } +type_list["User Plane Inactivity Timer"] = { "type" : "117", "max_tlv_more" : "0" } +type_list["Aggregated URRs"] = { "type" : "118", "max_tlv_more" : "0" } +type_list["Multiplier"] = { "type" : "119", "max_tlv_more" : "0" } +type_list["Aggregated URR ID"] = { "type" : "120", "max_tlv_more" : "0" } +type_list["Subsequent Volume Quota"] = { "type" : "121", "max_tlv_more" : "0" } +type_list["Subsequent Time Quota"] = { "type" : "122", "max_tlv_more" : "0" } +type_list["RQI"] = { "type" : "123", "max_tlv_more" : "0" } +type_list["QFI"] = { "type" : "124", "max_tlv_more" : "0" } +type_list["Query URR Reference"] = { "type" : "125", "max_tlv_more" : "0" } +type_list["Additional Usage Reports Information"] = { "type" : "126", "max_tlv_more" : "0" } +type_list["Create Traffic Endpoint"] = { "type" : "127", "max_tlv_more" : "0" } +type_list["Created Traffic Endpoint"] = { "type" : "128", "max_tlv_more" : "0" } +type_list["Update Traffic Endpoint"] = { "type" : "129", "max_tlv_more" : "0" } +type_list["Remove Traffic Endpoint"] = { "type" : "130", "max_tlv_more" : "0" } +type_list["Traffic Endpoint ID"] = { "type" : "131", "max_tlv_more" : "0" } +type_list["Ethernet Packet Filter"] = { "type" : "132", "max_tlv_more" : "0" } +type_list["MAC address"] = { "type" : "133", "max_tlv_more" : "0" } +type_list["C-TAG"] = { "type" : "134", "max_tlv_more" : "0" } +type_list["S-TAG"] = { "type" : "135", "max_tlv_more" : "0" } +type_list["Ethertype"] = { "type" : "136", "max_tlv_more" : "0" } +type_list["Proxying"] = { "type" : "137", "max_tlv_more" : "0" } +type_list["Ethernet Filter ID"] = { "type" : "138", "max_tlv_more" : "0" } +type_list["Ethernet Filter Properties"] = { "type" : "139", "max_tlv_more" : "0" } +type_list["Suggested Buffering Packets Count"] = { "type" : "140", "max_tlv_more" : "0" } +type_list["User ID"] = { "type" : "141", "max_tlv_more" : "0" } +type_list["Ethernet PDU Session Information"] = { "type" : "142", "max_tlv_more" : "0" } +type_list["Ethernet Traffic Information"] = { "type" : "143", "max_tlv_more" : "0" } +type_list["MAC Addresses Detected"] = { "type" : "144", "max_tlv_more" : "0" } +type_list["MAC Addresses Removed"] = { "type" : "145", "max_tlv_more" : "0" } +type_list["Ethernet Inactivity Timer"] = { "type" : "146", "max_tlv_more" : "0" } +type_list["Additional Monitoring Time"] = { "type" : "147", "max_tlv_more" : "0" } +type_list["Event Quota"] = { "type" : "148", "max_tlv_more" : "0" } +type_list["Event Threshold"] = { "type" : "149", "max_tlv_more" : "0" } +type_list["Subsequent Event Quota"] = { "type" : "150", "max_tlv_more" : "0" } +type_list["Subsequent Event Threshold"] = { "type" : "151", "max_tlv_more" : "0" } +type_list["Trace Information"] = { "type" : "152", "max_tlv_more" : "0" } +type_list["Framed-Route"] = { "type" : "153", "max_tlv_more" : "0" } +type_list["Framed-Routing"] = { "type" : "154", "max_tlv_more" : "0" } +type_list["Framed-IPv6-Route"] = { "type" : "155", "max_tlv_more" : "0" } +type_list["Event Time Stamp"] = { "type" : "156", "max_tlv_more" : "0" } +type_list["Averaging Window"] = { "type" : "157", "max_tlv_more" : "0" } +type_list["Paging Policy Indicator"] = { "type" : "158", "max_tlv_more" : "0" } +type_list["APN/DNN"] = { "type" : "159", "max_tlv_more" : "0" } +type_list["3GPP Interface Type"] = { "type" : "160", "max_tlv_more" : "0" } +type_list["PFCPSRReq-Flags"] = { "type" : "161", "max_tlv_more" : "0" } +type_list["PFCPAUReq-Flags"] = { "type" : "162", "max_tlv_more" : "0" } +type_list["Activation Time"] = { "type" : "163", "max_tlv_more" : "0" } +type_list["Deactivation Time"] = { "type" : "164", "max_tlv_more" : "0" } +type_list["Create MAR"] = { "type" : "165", "max_tlv_more" : "0" } +type_list["Access Forwarding Action Information 1"] = { "type" : "166", "max_tlv_more" : "0" } +type_list["Access Forwarding Action Information 2"] = { "type" : "167", "max_tlv_more" : "0" } +type_list["Remove MAR"] = { "type" : "168", "max_tlv_more" : "0" } +type_list["Update MAR"] = { "type" : "169", "max_tlv_more" : "0" } +type_list["MAR ID"] = { "type" : "170", "max_tlv_more" : "0" } +type_list["Steering Functionality"] = { "type" : "171", "max_tlv_more" : "0" } +type_list["Steering Mode"] = { "type" : "172", "max_tlv_more" : "0" } +type_list["Weight"] = { "type" : "173", "max_tlv_more" : "0" } +type_list["Priority"] = { "type" : "174", "max_tlv_more" : "0" } +type_list["Update Access Forwarding Action Information 1"] = { "type" : "175", "max_tlv_more" : "0" } +type_list["Update Access Forwarding Action Information 2"] = { "type" : "176", "max_tlv_more" : "0" } +type_list["UE IP address Pool Identity"] = { "type" : "177", "max_tlv_more" : "0" } +type_list["Alternative SMF IP Address"] = { "type" : "178", "max_tlv_more" : "0" } +type_list["Packet Replication and Detection Carry-On Information"] = { "type" : "179", "max_tlv_more" : "0" } +type_list["SMF Set ID"] = { "type" : "180", "max_tlv_more" : "0" } +type_list["Quota Validity Time"] = { "type" : "181", "max_tlv_more" : "0" } diff --git a/lib/pfcp/support/pfcp-tlv.py b/lib/pfcp/support/pfcp-tlv.py index e73448200..c2fe9b65b 100644 --- a/lib/pfcp/support/pfcp-tlv.py +++ b/lib/pfcp/support/pfcp-tlv.py @@ -96,10 +96,6 @@ 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') - #if instance.isdigit() is not True: - # return None - instance = "0" # PFCP has no instance note = cells[0].text.encode('ascii', 'ignore') if note.find('NOTE') != -1: return None @@ -147,20 +143,31 @@ def get_cells(cells): if ie_value[len(ie_value)-1] == ' ': ie_value = ie_value[:len(ie_value)-1] - if ie_type == 'Create PDR' or ie_type == 'Create FAR' or ie_type == 'Update PDR': - instance = "1" + tlv_more = "0" # PFCP has no tlv_more + if ie_type == 'Create PDR' or ie_type == 'Created PDR' or ie_type == 'Update PDR' or ie_type == "Remove PDR": + tlv_more = "3" + if ie_type == 'Create FAR' or ie_type == 'Update FAR' or ie_type == "Remove FAR": + tlv_more = "3" + if ie_type == 'Create URR' or ie_type == 'Update URR' or ie_type == "Remove URR": + tlv_more = "1" + if ie_type == 'Create QER' or ie_type == 'Update QER' or ie_type == "Remove QER": + tlv_more = "1" + if ie_type == 'User Plane IP Resource Information': + tlv_more = "3" + if ie_type == 'SDF Filter': + tlv_more = "3" - if int(instance) > int(type_list[ie_type]["max_instance"]): - type_list[ie_type]["max_instance"] = instance - write_file(f, "type_list[\"" + ie_type + "\"][\"max_instance\"] = \"" + instance + "\"\n") + if int(tlv_more) > int(type_list[ie_type]["max_tlv_more"]): + type_list[ie_type]["max_tlv_more"] = tlv_more + write_file(f, "type_list[\"" + ie_type + "\"][\"max_tlv_more\"] = \"" + tlv_more + "\"\n") - return { "ie_type" : ie_type, "ie_value" : ie_value, "presence" : presence, "instance" : instance, "comment" : comment } + return { "ie_type" : ie_type, "ie_value" : ie_value, "presence" : presence, "tlv_more" : tlv_more, "comment" : comment } def write_cells_to_file(name, cells): write_file(f, name + ".append({ \"ie_type\" : \"" + cells["ie_type"] + \ "\", \"ie_value\" : \"" + cells["ie_value"] + \ "\", \"presence\" : \"" + cells["presence"] + \ - "\", \"instance\" : \"" + cells["instance"] + \ + "\", \"tlv_more\" : \"" + cells["tlv_more"] + \ "\", \"comment\" : \"" + cells["comment"] + "\"})\n") try: @@ -253,9 +260,9 @@ else: key = re.sub('\s*$', '', key) type = row.cells[0].text.encode('ascii', 'ignore') - type_list[key] = { "type": type , "max_instance" : "0" } + type_list[key] = { "type": type , "max_tlv_more" : "0" } write_file(f, "type_list[\"" + key + "\"] = { \"type\" : \"" + type) - write_file(f, "\", \"max_instance\" : \"0\" }\n") + write_file(f, "\", \"max_tlv_more\" : \"0\" }\n") f.close() d_info("[Group IE List]") @@ -312,7 +319,7 @@ else: if ie_name.find('Access Forwarding Action Information 2') != -1: ie_idx = str(int(ie_type)+100) - write_file(f, "ies = []\n") + group_list[ie_name] = { "index" : ie_idx, "type" : ie_type, "ies" : ies } write_file(f, "group_list[\"" + ie_name + "\"] = { \"index\" : \"" + ie_idx + "\", \"type\" : \"" + ie_type + "\", \"ies\" : ies }\n") continue @@ -324,13 +331,8 @@ else: if cells is None: continue - ies_is_added = True - for ie in ies: - if (cells["ie_type"], cells["instance"]) == (ie["ie_type"], ie["instance"]): - ies_is_added = False - if ies_is_added is True: - ies.append(cells) - write_cells_to_file("ies", cells) + ies.append(cells) + write_cells_to_file("ies", cells) ie_idx = str(int(ie_type)+100) group_list[ie_name] = { "index" : ie_idx, "type" : ie_type, "ies" : ies } @@ -372,8 +374,6 @@ for key in msg_list.keys(): document = Document(filename) f = open(cachefile, 'w') - ies = [] - write_file(f, "ies = []\n") table = document.tables[msg_list[key]["table"]] if key.find('Association') != -1: start_i = 1 @@ -382,38 +382,47 @@ for key in msg_list.keys(): else: start_i = 2 + ies = [] + write_file(f, "ies = []\n") if key != "PFCP Session Deletion Request" and key != "PFCP Version Not Supported Response": for row in table.rows[start_i:]: cells = get_cells(row.cells) if cells is None: continue - - if (cells["ie_type"] == 'Create PDR' or cells["ie_type"] == 'Create FAR' or cells["ie_type"] == 'Update PDR'): - cells["instance"] = '0' - cells["presence"] = 'O' - ies.append(cells) - write_cells_to_file("ies", cells) - cells = get_cells(row.cells) - ies_is_added = True - for ie in ies: - if (cells["ie_type"], cells["instance"]) == (ie["ie_type"], ie["instance"]): - ies_is_added = False - if ies_is_added is True: - ies.append(cells) - write_cells_to_file("ies", cells) + item = { + "ie_type" : cells["ie_type"], + "ie_value" : cells["ie_value"], + "presence" : cells["presence"], + "tlv_more" : cells["tlv_more"], + "comment" : cells["comment"] + } + ies.append(item) + write_cells_to_file("ies", item) + msg_list[key]["ies"] = ies write_file(f, "msg_list[key][\"ies\"] = ies\n") f.close() -#type_list["Recovery"]["size"] = 1 # Type : 3 -#type_list["EBI"]["size"] = 1 # Type : 73 -#type_list["RAT Type"]["size"] = 1 # Type : 82 -#type_list["PDN Type"]["size"] = 1 # Type : 99 -#type_list["Port Number"]["size"] = 2 # Type : 126 -#type_list["APN Restriction"]["size"] = 1 # Type : 127 -#type_list["Selection Mode"]["size"] = 1 # Type : 128 -#type_list["Node Type"]["size"] = 1 # Type : 128 +type_list["Cause"]["size"] = 1 # Type 19 +type_list["Source Interface"]["size"] = 1 # Type 20 +type_list["Gate Status"]["size"] = 1 # Type 25 +type_list["QER Correlation ID"]["size"] = 4 # Type 28 +type_list["Precedence"]["size"] = 4 # Type 29 +type_list["Reporting Triggers"]["size"] = 1 # Type 37 +type_list["Offending IE"]["size"] = 2 # Type 40 +type_list["Destination Interface"]["size"] = 1 # Type 42 +type_list["UP Function Features"]["size"] = 2 # Type 43 +type_list["Apply Action"]["size"] = 1 # Type 44 +type_list["PDR ID"]["size"] = 2 # Type 56 +type_list["Measurement Method"]["size"] = 1 # Type 62 +type_list["URR ID"]["size"] = 4 # Type 81 +type_list["BAR ID"]["size"] = 1 # Type 88 +type_list["CP Function Features"]["size"] = 1 # Type 89 +type_list["Recovery Time Stamp"]["size"] = 4 # Type 96 +type_list["FAR ID"]["size"] = 4 # Type 108 +type_list["QER ID"]["size"] = 4 # Type 109 +type_list["PDN Type"]["size"] = 1 # Type 113 f = open(outdir + 'message.h', 'w') output_header_to_file(f) @@ -437,7 +446,7 @@ typedef struct ogs_pfcp_header_s { ED4(uint8_t version:3;, uint8_t spare1:3;, uint8_t mp:1;, - uint8_t seid_p:1;) + uint8_t seid_presence:1;) }; uint8_t flags; }; @@ -447,8 +456,8 @@ typedef struct ogs_pfcp_header_s { struct { uint64_t seid; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ -#define OGS_PFCP_XID_TO_SQN(__xid) htonl(((__xid) << 8)) -#define OGS_PFCP_SQN_TO_XID(__sqn) (ntohl(__sqn) >> 8) +#define OGS_PFCP_XID_TO_SQN(__xid) htobe32(((__xid) << 8)) +#define OGS_PFCP_SQN_TO_XID(__sqn) (be32toh(__sqn) >> 8) uint32_t sqn; }; /* sqn : 31bit ~ 8bit, spare : 7bit ~ 0bit */ @@ -475,12 +484,7 @@ f.write("/* Infomration Element TLV Descriptor */\n") for (k, v) in sorted_type_list: if k in group_list.keys(): continue - for instance in range(0, int(type_list[k]["max_instance"])+1): - if v_lower(k)=="cause" or v_lower(k)=="sequence_number" or v_lower(k)=="f_teid": - f.write("extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_" + v_lower(k)) - else: - f.write("extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_" + v_lower(k)) - f.write("_" + str(instance) + ";\n") + f.write("extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_" + v_lower(k) + ";\n") f.write("\n") for k, v in group_list.items(): @@ -522,14 +526,12 @@ sorted_group_list = sorted(tmp, key=lambda tup: int(tup[1]), reverse=False) f.write("/* Group Infomration Element TLV Descriptor */\n") for (k, v) in sorted_group_list: - for instance in range(0, int(type_list[k]["max_instance"])+1): - f.write("extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_" + v_lower(k)) - f.write("_" + str(instance) + ";\n") + f.write("extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_" + v_lower(k) + ";\n") f.write("\n") f.write("/* Message Descriptor */\n") for (k, v) in sorted_msg_list: - f.write("extern ogs_tlv_desc_t ogs_pfcp_tlv_desc_" + v_lower(k) + ";\n") + f.write("extern ogs_tlv_desc_t ogs_pfcp_msg_desc_" + v_lower(k) + ";\n") f.write("\n") f.write("/* Structure for Infomration Element */\n") @@ -557,18 +559,11 @@ for (k, v) in sorted_group_list: f.write("typedef struct ogs_pfcp_tlv_" + v_lower(k) + "_s {\n") f.write(" ogs_tlv_presence_t presence;\n") for ies in group_list[k]["ies"]: - f.write(" ogs_pfcp_tlv_" + v_lower(ies["ie_type"]) + "_t " + \ - v_lower(ies["ie_value"])) - if ies["ie_type"] == "F-TEID": - if ies["ie_value"] == "S2b-U ePDG F-TEID": - f.write("_" + ies["instance"] + ";") - elif ies["ie_value"] == "S2a-U TWAN F-TEID": - f.write("_" + ies["instance"] + ";") - else: - f.write(";") - f.write(" /* Instance : " + ies["instance"] + " */\n") + if type_list[ies["ie_type"]]["max_tlv_more"] != "0": + f.write(" ogs_pfcp_tlv_" + v_lower(ies["ie_type"]) + "_t " + v_lower(ies["ie_value"]) + "[" + str(int(ies["tlv_more"])+1) + "];\n") else: - f.write(";\n") + f.write(" ogs_pfcp_tlv_" + v_lower(ies["ie_type"]) + "_t " + \ + v_lower(ies["ie_value"]) + ";\n") f.write("} ogs_pfcp_tlv_" + v_lower(k) + "_t;\n") f.write("\n") @@ -577,13 +572,11 @@ for (k, v) in sorted_msg_list: if "ies" in msg_list[k]: f.write("typedef struct ogs_" + v_lower(k) + "_s {\n") for ies in msg_list[k]["ies"]: - # 0403 modify - if ies["instance"] != "0": - f.write(" ogs_pfcp_tlv_" + v_lower(ies["ie_type"]) + "_t " + \ - v_lower(ies["ie_value"]) + ies["instance"] + ";\n") + if type_list[ies["ie_type"]]["max_tlv_more"] != "0": + f.write(" ogs_pfcp_tlv_" + v_lower(ies["ie_type"]) + "_t " + v_lower(ies["ie_value"]) + "[" + str(int(ies["tlv_more"])+1) + "];\n") else: - f.write(" ogs_pfcp_tlv_" + v_lower(ies["ie_type"]) + "_t " + \ - v_lower(ies["ie_value"]) + ";\n") + f.write(" ogs_pfcp_tlv_" + v_lower(ies["ie_type"]) + "_t " + v_lower(ies["ie_value"]) + ";\n") + f.write("} ogs_" + v_lower(k) + "_t;\n") f.write("\n") @@ -616,68 +609,61 @@ f.write("""#include "ogs-pfcp.h" for (k, v) in sorted_type_list: if k in group_list.keys(): continue - for instance in range(0, int(type_list[k]["max_instance"])+1): - if v_lower(k)=="cause" or v_lower(k)=="sequence_number" or v_lower(k)=="f_teid": - f.write("ogs_tlv_desc_t ogs_pfcp_tlv_desc_%s_%d =\n" % (v_lower(k), instance)) + f.write("ogs_tlv_desc_t ogs_pfcp_tlv_desc_%s =\n" % v_lower(k)) + f.write("{\n") + if "size" in type_list[k]: + if type_list[k]["size"] == 1: + f.write(" OGS_TLV_UINT8,\n") + elif type_list[k]["size"] == 2: + f.write(" OGS_TLV_UINT16,\n") + elif type_list[k]["size"] == 3: + f.write(" OGS_TLV_UINT24,\n") + elif type_list[k]["size"] == 4: + f.write(" OGS_TLV_UINT32,\n") else: - f.write("ogs_tlv_desc_t ogs_pfcp_tlv_desc_%s_%d =\n" % (v_lower(k), instance)) - f.write("{\n") - if "size" in type_list[k]: - if type_list[k]["size"] == 1: - f.write(" OGS_TLV_UINT8,\n") - elif type_list[k]["size"] == 2: - f.write(" OGS_TLV_UINT16,\n") - elif type_list[k]["size"] == 3: - f.write(" OGS_TLV_UINT24,\n") - elif type_list[k]["size"] == 4: - f.write(" OGS_TLV_UINT32,\n") - else: - assert False, "Unknown size = %d for key = %s" % (type_list[k]["size"], k) - else: - f.write(" OGS_TLV_VAR_STR,\n") - f.write(" \"%s\",\n" % k) - f.write(" OGS_PFCP_%s_TYPE,\n" % v_upper(k)) - if "size" in type_list[k]: - f.write(" %d,\n" % type_list[k]["size"]) - else: - f.write(" 0,\n") - f.write(" %d,\n" % instance) - f.write(" sizeof(ogs_pfcp_tlv_%s_t),\n" % v_lower(k)) - f.write(" { NULL }\n") - f.write("};\n\n") + assert False, "Unknown size = %d for key = %s" % (type_list[k]["size"], k) + else: + f.write(" OGS_TLV_VAR_STR,\n") + f.write(" \"%s\",\n" % k) + f.write(" OGS_PFCP_%s_TYPE,\n" % v_upper(k)) + if "size" in type_list[k]: + f.write(" %d,\n" % type_list[k]["size"]) + else: + f.write(" 0,\n") + f.write(" 0,\n") + f.write(" sizeof(ogs_pfcp_tlv_%s_t),\n" % v_lower(k)) + f.write(" { NULL }\n") + f.write("};\n\n") for (k, v) in sorted_group_list: - for instance in range(0, int(type_list[k]["max_instance"])+1): - f.write("ogs_tlv_desc_t ogs_pfcp_tlv_desc_%s_%d =\n" % (v_lower(k), instance)) - f.write("{\n") - f.write(" OGS_TLV_COMPOUND,\n") - f.write(" \"%s\",\n" % k) - f.write(" OGS_PFCP_%s_TYPE,\n" % v_upper(k)) - f.write(" 0,\n") - f.write(" %d,\n" % instance) - f.write(" sizeof(ogs_pfcp_tlv_%s_t),\n" % v_lower(k)) - f.write(" {\n") - for ies in group_list[k]["ies"]: - if v_lower(ies["ie_type"])=="cause" or v_lower(ies["ie_type"])=="sequence_number" or v_lower(ies["ie_type"])=="f_teid": - f.write(" &ogs_pfcp_tlv_desc_%s_%s,\n" % (v_lower(ies["ie_type"]), v_lower(ies["instance"]))) - else: - f.write(" &ogs_pfcp_tlv_desc_%s_%s,\n" % (v_lower(ies["ie_type"]), v_lower(ies["instance"]))) - f.write(" NULL,\n") - f.write(" }\n") - f.write("};\n\n") + f.write("ogs_tlv_desc_t ogs_pfcp_tlv_desc_%s =\n" % v_lower(k)) + f.write("{\n") + f.write(" OGS_TLV_COMPOUND,\n") + f.write(" \"%s\",\n" % k) + f.write(" OGS_PFCP_%s_TYPE,\n" % v_upper(k)) + f.write(" 0,\n") + f.write(" 0,\n") + f.write(" sizeof(ogs_pfcp_tlv_%s_t),\n" % v_lower(k)) + f.write(" {\n") + for ies in group_list[k]["ies"]: + f.write(" &ogs_pfcp_tlv_desc_%s,\n" % v_lower(ies["ie_type"])) + if type_list[ies["ie_type"]]["max_tlv_more"] != "0": + f.write(" &ogs_tlv_desc_more" + str(int(ies["tlv_more"])+1) + ",\n") + f.write(" NULL,\n") + f.write(" }\n") + f.write("};\n\n") for (k, v) in sorted_msg_list: if "ies" in msg_list[k]: - f.write("ogs_tlv_desc_t ogs_pfcp_tlv_desc_%s =\n" % v_lower(k)) + f.write("ogs_tlv_desc_t ogs_pfcp_msg_desc_%s =\n" % v_lower(k)) f.write("{\n") f.write(" OGS_TLV_MESSAGE,\n") f.write(" \"%s\",\n" % k) f.write(" 0, 0, 0, 0, {\n") for ies in msg_list[k]["ies"]: - if v_lower(ies["ie_type"])=="cause" or v_lower(ies["ie_type"])=="sequence_number" or v_lower(ies["ie_type"])=="f_teid": - f.write(" &ogs_pfcp_tlv_desc_%s_%s,\n" % (v_lower(ies["ie_type"]), v_lower(ies["instance"]))) - else: - f.write(" &ogs_pfcp_tlv_desc_%s_%s,\n" % (v_lower(ies["ie_type"]), v_lower(ies["instance"]))) + f.write(" &ogs_pfcp_tlv_desc_%s,\n" % v_lower(ies["ie_type"])) + if type_list[ies["ie_type"]]["max_tlv_more"] != "0": + f.write(" &ogs_tlv_desc_more" + str(int(ies["tlv_more"])+1) + ",\n") f.write(" NULL,\n") f.write("}};\n\n") f.write("\n") @@ -697,7 +683,7 @@ f.write("""int ogs_pfcp_parse_msg(ogs_pfcp_message_t *pfcp_message, ogs_pkbuf_t memset(pfcp_message, 0, sizeof(ogs_pfcp_message_t)); - if (h->seid_p) + if (h->seid_presence) size = OGS_PFCP_HEADER_LEN; else size = OGS_PFCP_HEADER_LEN-OGS_PFCP_SEID_LEN; @@ -705,7 +691,7 @@ f.write("""int ogs_pfcp_parse_msg(ogs_pfcp_message_t *pfcp_message, ogs_pkbuf_t ogs_assert(ogs_pkbuf_pull(pkbuf, size)); memcpy(&pfcp_message->h, pkbuf->data - size, size); - if (h->seid_p) { + if (h->seid_presence) { pfcp_message->h.seid = be64toh(pfcp_message->h.seid); } else { pfcp_message->h.sqn = pfcp_message->h.sqn_only; @@ -722,7 +708,7 @@ for (k, v) in sorted_msg_list: if "ies" in msg_list[k]: f.write(" case OGS_%s_TYPE:\n" % v_upper(k)) f.write(" rv = ogs_tlv_parse_msg(&pfcp_message->%s,\n" % v_lower(k)) - f.write(" &ogs_pfcp_tlv_desc_%s, pkbuf, OGS_TLV_MODE_T2_L2);\n" % v_lower(k)) + f.write(" &ogs_pfcp_msg_desc_%s, pkbuf, OGS_TLV_MODE_T2_L2);\n" % v_lower(k)) f.write(" break;\n") f.write(""" default: ogs_warn("Not implmeneted(type:%d)", pfcp_message->h.type); @@ -745,7 +731,7 @@ f.write("""ogs_pkbuf_t *ogs_pfcp_build_msg(ogs_pfcp_message_t *pfcp_message) for (k, v) in sorted_msg_list: if "ies" in msg_list[k]: f.write(" case OGS_%s_TYPE:\n" % v_upper(k)) - f.write(" pkbuf = ogs_tlv_build_msg(&ogs_pfcp_tlv_desc_%s,\n" % v_lower(k)) + f.write(" pkbuf = ogs_tlv_build_msg(&ogs_pfcp_msg_desc_%s,\n" % v_lower(k)) f.write(" &pfcp_message->%s, OGS_TLV_MODE_T2_L2);\n" % v_lower(k)) f.write(" break;\n") f.write(""" default: diff --git a/lib/pfcp/types.c b/lib/pfcp/types.c index 7976da77d..6114d492c 100644 --- a/lib/pfcp/types.c +++ b/lib/pfcp/types.c @@ -24,8 +24,8 @@ int __ogs_pfcp_domain; const char *ogs_pfcp_cause_get_name(uint8_t cause) { switch(cause) { - case OGS_PFCP_CAUSE_SUCCESS: - return "OGS_PFCP_CAUSE_SUCCESS"; + case OGS_PFCP_CAUSE_REQUEST_ACCEPTED: + return "OGS_PFCP_CAUSE_REQUEST_ACCEPTED"; break; case OGS_PFCP_CAUSE_REQUEST_REJECTED: return "OGS_PFCP_CAUSE_REQUEST_REJECTED"; @@ -74,3 +74,334 @@ const char *ogs_pfcp_cause_get_name(uint8_t cause) } return "OGS_PFCP_CAUSE_UNKNOWN"; } + +int16_t ogs_pfcp_build_user_plane_ip_resource_info( + ogs_tlv_octet_t *octet, + ogs_pfcp_user_plane_ip_resource_info_t *info, + void *data, int data_len) +{ + ogs_pfcp_user_plane_ip_resource_info_t target; + int16_t size = 0; + + ogs_assert(info); + ogs_assert(octet); + ogs_assert(data); + ogs_assert(data_len); + + octet->data = data; + memcpy(&target, info, sizeof(ogs_pfcp_user_plane_ip_resource_info_t)); + + ogs_assert(size + sizeof(target.flags) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.flags, sizeof(target.flags)); + size += sizeof(target.flags); + + if (target.teidri) { + ogs_assert(size + sizeof(target.teid_range) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.teid_range, sizeof(target.teid_range)); + size += sizeof(target.teid_range); + } + + if (target.v4) { + ogs_assert(size + sizeof(target.addr) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.addr, sizeof(target.addr)); + size += sizeof(target.addr); + } + + if (target.v6) { + ogs_assert(size + OGS_IPV6_LEN <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.addr6, OGS_IPV6_LEN); + size += OGS_IPV6_LEN; + } + + if (target.assoni) { + int len = ogs_fqdn_build((char *)octet->data + size, + target.network_instance, strlen(target.network_instance)); + size += len; + } + + if (target.assosi) { + ogs_assert(size + sizeof(target.source_interface) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.source_interface, sizeof(target.source_interface)); + size += sizeof(target.source_interface); + } + + octet->len = size; + + return octet->len; +} + +int16_t ogs_pfcp_parse_user_plane_ip_resource_info( + ogs_pfcp_user_plane_ip_resource_info_t *info, + ogs_tlv_octet_t *octet) +{ + int16_t size = 0; + + ogs_assert(info); + ogs_assert(octet); + + memset(info, 0, sizeof(ogs_pfcp_user_plane_ip_resource_info_t)); + + memcpy(&info->flags, + (unsigned char *)octet->data + size, sizeof(info->flags)); + size++; + + if (info->teidri) { + ogs_assert(size + sizeof(info->teid_range) <= octet->len); + memcpy(&info->teid_range, (unsigned char *)octet->data + size, + sizeof(info->teid_range)); + size += sizeof(info->teid_range); + } + + if (info->v4) { + ogs_assert(size + sizeof(info->addr) <= octet->len); + memcpy(&info->addr, + (unsigned char *)octet->data + size, + sizeof(info->addr)); + size += sizeof(info->addr); + } + + if (info->v6) { + ogs_assert(size + OGS_IPV6_LEN <= octet->len); + memcpy(&info->addr6, (unsigned char *)octet->data + size, OGS_IPV6_LEN); + size += OGS_IPV6_LEN; + } + + if (info->assoni) { + int len = octet->len - size; + if (info->assosi) len--; + + ogs_fqdn_parse(info->network_instance, (char *)octet->data + size, len); + size += len; + } + + if (info->assosi) { + ogs_assert(size + sizeof(info->source_interface) <= + octet->len); + memcpy(&info->source_interface, (unsigned char *)octet->data + size, + sizeof(info->source_interface)); + size += sizeof(info->source_interface); + } + + ogs_assert(size == octet->len); + + return size; +} + +int16_t ogs_pfcp_build_sdf_filter( + ogs_tlv_octet_t *octet, ogs_pfcp_sdf_filter_t *filter, + void *data, int data_len) +{ + ogs_pfcp_sdf_filter_t target; + int16_t size = 0; + + ogs_assert(filter); + ogs_assert(octet); + ogs_assert(data); + ogs_assert(data_len); + + octet->data = data; + memcpy(&target, filter, sizeof(ogs_pfcp_sdf_filter_t)); + + ogs_assert(size + sizeof(target.flags) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.flags, sizeof(target.flags)); + size += sizeof(target.flags); + + ogs_assert(size + sizeof(target.spare2) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.spare2, sizeof(target.spare2)); + size += sizeof(target.spare2); + + if (target.fd) { + ogs_assert(size + sizeof(target.flow_description_len) <= data_len); + target.flow_description_len = htobe16(target.flow_description_len); + memcpy((unsigned char *)octet->data + size, + &target.flow_description_len, + sizeof(target.flow_description_len)); + size += sizeof(target.flow_description_len); + + ogs_assert(size + filter->flow_description_len <= data_len); + memcpy((char *)octet->data + size, + filter->flow_description, filter->flow_description_len); + size += filter->flow_description_len; + } + + if (target.ttc) { + ogs_assert(size + sizeof(target.tos_traffic_class) <= data_len); + target.tos_traffic_class = htobe16(target.tos_traffic_class); + memcpy((unsigned char *)octet->data + size, + &target.tos_traffic_class, sizeof(target.tos_traffic_class)); + size += sizeof(target.tos_traffic_class); + } + + if (target.spi) { + ogs_assert(size + sizeof(target.security_parameter_index) <= data_len); + target.security_parameter_index = + htobe32(target.security_parameter_index); + memcpy((unsigned char *)octet->data + size, + &target.security_parameter_index, + sizeof(target.security_parameter_index)); + size += sizeof(target.security_parameter_index); + } + + if (target.fl) { + int bit24_len = 3; + ogs_assert(size + bit24_len <= data_len); + target.flow_label = htobe32(target.flow_label); + memcpy((unsigned char *)octet->data + size, + &target.flow_label, bit24_len); + size += bit24_len; + } + + if (target.bid) { + ogs_assert(size + sizeof(target.sdf_filter_id) <= data_len); + target.sdf_filter_id = + htobe32(target.sdf_filter_id); + memcpy((unsigned char *)octet->data + size, + &target.sdf_filter_id, sizeof(target.sdf_filter_id)); + size += sizeof(target.sdf_filter_id); + } + + octet->len = size; + + return octet->len; +} + +int16_t ogs_pfcp_parse_sdf_filter( + ogs_pfcp_sdf_filter_t *filter, ogs_tlv_octet_t *octet) +{ + int16_t size = 0; + + ogs_assert(filter); + ogs_assert(octet); + + memset(filter, 0, sizeof(ogs_pfcp_sdf_filter_t)); + + ogs_assert(size + sizeof(filter->flags) <= octet->len); + memcpy(&filter->flags, + (unsigned char *)octet->data + size, sizeof(filter->flags)); + size++; + + ogs_assert(size + sizeof(filter->spare2) <= octet->len); + memcpy(&filter->spare2, + (unsigned char *)octet->data + size, sizeof(filter->flags)); + size++; + + if (filter->fd) { + ogs_assert(size + sizeof(filter->flow_description_len) <= octet->len); + memcpy(&filter->flow_description_len, + (unsigned char *)octet->data + size, + sizeof(filter->flow_description_len)); + filter->flow_description_len = be16toh(filter->flow_description_len); + size += sizeof(filter->flow_description_len); + + filter->flow_description = (char *)octet->data + size; + size += filter->flow_description_len; + } + + if (filter->ttc) { + ogs_assert(size + sizeof(filter->tos_traffic_class) <= octet->len); + memcpy(&filter->tos_traffic_class, + (unsigned char *)octet->data + size, + sizeof(filter->tos_traffic_class)); + filter->tos_traffic_class = be32toh(filter->tos_traffic_class); + size += sizeof(filter->tos_traffic_class); + } + + if (filter->spi) { + ogs_assert(size + sizeof(filter->security_parameter_index) <= + octet->len); + memcpy(&filter->security_parameter_index, + (unsigned char *)octet->data + size, + sizeof(filter->security_parameter_index)); + filter->security_parameter_index = + be32toh(filter->security_parameter_index); + size += sizeof(filter->security_parameter_index); + } + + if (filter->fl) { + int bit24_len = 3; + ogs_assert(size + bit24_len <= octet->len); + memcpy(&filter->flow_label, + (unsigned char *)octet->data + size, bit24_len); + filter->flow_label = be32toh(filter->flow_label); + size += bit24_len; + } + + if (filter->bid) { + ogs_assert(size + sizeof(filter->sdf_filter_id) <= octet->len); + memcpy(&filter->sdf_filter_id, (unsigned char *)octet->data + size, + sizeof(filter->sdf_filter_id)); + filter->sdf_filter_id = be32toh(filter->sdf_filter_id); + size += sizeof(filter->sdf_filter_id); + } + + ogs_assert(size == octet->len); + + return size; +} + +int16_t ogs_pfcp_build_bitrate(ogs_tlv_octet_t *octet, + ogs_pfcp_bitrate_t *bitrate, void *data, int data_len) +{ + ogs_pfcp_bitrate_t target; + int16_t size = 0; + + ogs_assert(bitrate); + ogs_assert(octet); + ogs_assert(data); + ogs_assert(data_len >= OGS_PFCP_BITRATE_LEN); + + octet->data = data; + memcpy(&target, bitrate, sizeof(ogs_pfcp_bitrate_t)); + + /* + * Ch 8.15 Bearer QoS in TS 29.274 v15.9.0 + * + * The UL/DL MBR and GBR fields are encoded as kilobits + * per second (1 kbps = 1000 bps) in binary value. + */ + ogs_uint64_to_buffer(target.uplink / 1000, 5, + (unsigned char *)octet->data + size); + size += 5; + ogs_uint64_to_buffer(target.downlink / 1000, 5, + (unsigned char *)octet->data + size); + size += 5; + + octet->len = size; + + return octet->len; +} +int16_t ogs_pfcp_parse_bitrate( + ogs_pfcp_bitrate_t *bitrate, ogs_tlv_octet_t *octet) +{ + int16_t size = 0; + + ogs_assert(bitrate); + ogs_assert(octet); + ogs_assert(octet->len == OGS_PFCP_BITRATE_LEN); + + memset(bitrate, 0, sizeof(ogs_pfcp_bitrate_t)); + + /* + * Ch 8.15 Bearer QoS in TS 29.274 v15.9.0 + * + * The UL/DL MBR and GBR fields are encoded as kilobits + * per second (1 kbps = 1000 bps) in binary value. + */ + bitrate->uplink = ogs_buffer_to_uint64( + (unsigned char *)octet->data + size, 5) * 1000; + size += 5; + bitrate->downlink = ogs_buffer_to_uint64( + (unsigned char *)octet->data + size, 5) * 1000; + size += 5; + + ogs_assert(size == octet->len); + + return size; +} diff --git a/lib/pfcp/types.h b/lib/pfcp/types.h index 1b70ddddc..993ebc452 100644 --- a/lib/pfcp/types.h +++ b/lib/pfcp/types.h @@ -28,7 +28,15 @@ extern "C" { #endif -#define OGS_PFCP_CAUSE_SUCCESS 1 +#define OGS_PFCP_VERSION 1 + +typedef uint16_t ogs_pfcp_pdr_id_t; +typedef uint32_t ogs_pfcp_far_id_t; +typedef uint32_t ogs_pfcp_urr_id_t; +typedef uint32_t ogs_pfcp_qer_id_t; +typedef uint8_t ogs_pfcp_bar_id_t; + +#define OGS_PFCP_CAUSE_REQUEST_ACCEPTED 1 #define OGS_PFCP_CAUSE_REQUEST_REJECTED 64 #define OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND 65 #define OGS_PFCP_CAUSE_MANDATORY_IE_MISSING 66 @@ -46,52 +54,140 @@ extern "C" { const char *ogs_pfcp_cause_get_name(uint8_t cause); -#define OGS_PFCP_FAR_APPLY_ACTION_DROP 1 -#define OGS_PFCP_FAR_APPLY_ACTION_FORW 2 -#define OGS_PFCP_FAR_APPLY_ACTION_BUFF 4 -#define OGS_PFCP_FAR_APPLY_ACTION_NOCP 8 -#define OGS_PFCP_FAR_APPLY_ACTION_DUPL 16 +/* + * 8.2.11 Precedence + * + * The Precedence value shall be encoded as an Unsigned32 binary integer value. The lower precedence values + * indicate higher precedence of the PDR, and the higher precedence values + * indicate lower precedence of the PDR when matching a packet. + */ +typedef uint32_t ogs_pfcp_precedence_t; -#define OGS_PFCP_FAR_DEST_INTF_ACCESS 0 //$ DL traffic -#define OGS_PFCP_FAR_DEST_INTF_CORE 1 //$ UL traffic -#define OGS_PFCP_FAR_DEST_INTF_SGILAN 2 //$ SGi-LAN -#define OGS_PFCP_FAR_DEST_INTF_CPF 3 //$ CP-Function -#define OGS_PFCP_FAR_DEST_INTF_LIF 4 //$ LI Function +/* + * 8.2.2 Source Interface + * NOTE 1: The "Access" and "Core" values denote an uplink and downlink + * traffic direction respectively. + * NOTE 2: For indirect data forwarding, the Source Interface in the PDR and + * the Destination Interface in the FAR shall both be set to "Access", + * in the forwarding SGW(s). The Interface value does not infer any + * traffic direction, in PDRs and FARs set up for indirect data + * forwarding, i.e. with both the Source and Destination Interfaces set + * to Access. + * + * 8.2.24 Destination Interface + * NOTE 1: The "Access" and "Core" values denote a downlink and uplink + * traffic direction respectively. + * NOTE 2: LI Function may denote an SX3LIF or an LMISF. See clause 5.7. + * NOTE 3: For indirect data forwarding, the Source Interface in the PDR and + * the Destination Interface in the FAR shall both be set to "Access", + * in the forwarding SGW(s). The Interface value does not infer any + * traffic direction, in PDRs and FARs set up for indirect data + * forwarding, i.e. with both the Source and Destination Interfaces set + * to Access. + * NOTE 4: For a HTTP redirection, the Source Interface in the PDR to match + * the uplink packets to be redirected and the Destination Interface in + * the FAR to enable the HTTP redirection shall both be set to "Access". + */ +#define OGS_PFCP_INTERFACE_ACCESS 0 +#define OGS_PFCP_INTERFACE_CORE 1 +#define OGS_PFCP_INTERFACE_SGI_N6_LAN 2 +#define OGS_PFCP_INTERFACE_CP_FUNCTION 3 +#define OGS_PFCP_INTERFACE_LI_FUNCTION 4 +#define OGS_PFCP_INTERFACE_UNKNOWN 0xff +typedef uint8_t ogs_pfcp_interface_t; -#define OGS_PGWC_PRECEDENCE_BASE 31 +/* + * 8.2.26 Apply Action + * + * Bit 1 – DROP (Drop): when set to 1, this indicates a request + * to drop the packets. + * Bit 2 – FORW (Forward): when set to 1, this indicates a request + * to forward the packets. + * Bit 3 – BUFF (Buffer): when set to 1, this indicates a request + * to buffer the packets. + * Bit 4 – NOCP (Notify the CP function): when set to 1, + * this indicates a request to notify the CP function about the + * arrival of a first downlink packet being buffered. + * Bit 5 – DUPL (Duplicate): when set to 1, this indicates a request + * to duplicate the packets. + * Bit 6 to 8 – Spare, for future use and set to 0. + * + * One and only one of the DROP, FORW and BUFF flags shall be set to 1. + * The NOCP flag may only be set if the BUFF flag is set. + * The DUPL flag may be set with any of the DROP, FORW, BUFF and NOCP flags. + */ +#define OGS_PFCP_APPLY_ACTION_DROP 1 +#define OGS_PFCP_APPLY_ACTION_FORW 2 +#define OGS_PFCP_APPLY_ACTION_BUFF 4 +#define OGS_PFCP_APPLY_ACTION_NOCP 8 +#define OGS_PFCP_APPLY_ACTION_DUPL 16 +typedef uint8_t ogs_pfcp_apply_action_t; -#define OGS_PFCP_OUTER_HDR_RMV_DESC_GTPU_IP4 0 -#define OGS_PFCP_OUTER_HDR_RMV_DESC_GTPU_IP6 1 -#define OGS_PFCP_OUTER_HDR_RMV_DESC_UDP_IP4 2 -#define OGS_PFCP_OUTER_HDR_RMV_DESC_UDP_IP6 3 -#define OGS_PFCP_OUTER_HDR_RMV_DESC_NULL 0xFF +/* + * 8.2.64 Outer Header Remaval + * + * NOTE 1: The SGW-U/I-UPF shall store GTP-U extension header(s) required + * to be forwarded for this packet (as required by the comprehension rules + * of Figure 5.2.1-2 of 3GPP TS 29.281 [3]) that are not requested + * to be deleted by the GTP-U Extension Header Deletion field. + * NOTE 2: The SGW-U/I-UPF shall store the GTP-U message type + * for a GTP-U signalling message which is required to be forwarded, + * e.g. for an End Marker message. + * NOTE 3: This value may apply to DL packets received by a PGW-U + * for non-IP PDN connections with SGi tunnelling based + * on UDP/IP encapsulation (see clause 4.3.17.8.3.3.2 of 3GPP TS 23.401 [14]). + * NOTE 4: The CP function shall use this value to instruct UP function + * to remove the GTP-U/UDP/IP header regardless it is IPv4 or IPv6. + * NOTE 5: This value may apply to DL packets received by a UPF over N6 for + * Ethernet PDU sessions over (see clause 5.8.2.11.3 of 3GPP TS 23.501 [28]). + * NOTE 6: This value may apply e.g. to DL packets received by a UPF + * (PDU Session Anchor) over N6, when explicit N6 traffic routing information + * is provided to the SMF (see clause 5.6.7 of 3GPP TS 23.501 [28]). + * + * The GTP-U Extension Header Deletion field (octet 6) shall be present + * if it is required to delete GTP-U extension header(s) from incoming GTP-PDUs. + * Octet 6 shall be absent if all GTP-U extension headers required + * to be forwarded shall be stored as indicated in NOTE 1 of Table 8.2.64-1. + * + * The GTP-U Extension Header Deletion field, when present, shall be encoded + * as specified in Table 8.2.64-2. It takes the form of a bitmask where each bit + * provides instructions on the information to be deleted from the incoming + * GTP-PDU packet. Spare bits shall be ignored by the receiver. + */ +typedef struct ogs_pfcp_outer_header_removal_s { +#define OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV4 0 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV6 1 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_UDP_IPV4 2 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_UDP_IPV6 3 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_IPV4 4 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_IPV6 5 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IP 6 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_VLAN_STAG 7 +#define OGS_PFCP_OUTER_HEADER_REMOVAL_SLAN_CTAG 8 + uint8_t description; -#define OGS_PFCP_SRC_INTF_ACCESS 0 //$ UL traffic -#define OGS_PFCP_SRC_INTF_CORE 1 //$ DL traffic -#define OGS_PFCP_SRC_INTF_SGILAN 2 //$ SGi-LAN -#define OGS_PFCP_SRC_INTF_CP_F 3 //$ CP-function +#define OGS_PFCP_PDU_SESSION_CONTAINER_TO_BE_DELETED 1 + uint8_t gtpu_extheader_deletion; +} ogs_pfcp_outer_header_removal_t; -#define OGS_PFCP_PDN_TYPE_IPV4 1 -#define OGS_PFCP_PDN_TYPE_IPV6 2 -#define OGS_PFCP_PDN_TYPE_IPV4V6 3 -#define OGS_PFCP_PDN_TYPE_NONIP 4 +#define OGS_PFCP_NODE_ID_IPV4 0 +#define OGS_PFCP_NODE_ID_IPV6 1 +#define OGS_PFCP_NODE_ID_FQDN 2 +typedef struct ogs_pfcp_node_id_s { +ED2(uint8_t spare:4;, + uint8_t type:4;) + union { + uint32_t addr; + uint8_t addr6[OGS_IPV6_LEN]; + char fqdn[OGS_MAX_FQDN_LEN]; + }; +} __attribute__ ((packed)) ogs_pfcp_node_id_t; -#define OGS_PFCP_UE_IP_ADDR_HDR_LEN 1 -#define OGS_PFCP_UE_IP_ADDR_IPV4_LEN \ - OGS_IPV4_LEN + OGS_PFCP_UE_IP_ADDR_HDR_LEN -#define OGS_PFCP_UE_IP_ADDR_IPV6_LEN \ - OGS_IPV6_LEN + OGS_PFCP_UE_IP_ADDR_HDR_LEN -#define OGS_PFCP_UE_IP_ADDR_IPV4V6_LEN \ - OGS_IPV4V6_LEN + OGS_PFCP_UE_IP_ADDR_HDR_LEN - -#define OGS_PFCP_UE_IP_ADDR_SOURCE 0 -#define OGS_PFCP_UE_IP_ADDR_DESITINATION 1 - -typedef struct ogs_pfcp_ue_ip_addr_s { -ED4(uint8_t spare:5;, - uint8_t sd:1;, /* source or destination*/ - uint8_t ipv4:1;, - uint8_t ipv6:1;) +typedef struct ogs_pfcp_f_seid_s { +ED3(uint8_t spare:6;, + uint8_t ipv4:1;, + uint8_t ipv6:1;) + uint64_t seid; union { uint32_t addr; uint8_t addr6[OGS_IPV6_LEN]; @@ -100,15 +196,15 @@ ED4(uint8_t spare:5;, uint8_t addr6[OGS_IPV6_LEN]; } both; }; -} __attribute__ ((packed)) ogs_pfcp_ue_ip_addr_t; +} __attribute__ ((packed)) ogs_pfcp_f_seid_t; typedef struct ogs_pfcp_f_teid_s { -ED5(uint8_t spare:4;, - uint8_t chid:1;, - uint8_t ch:1;, - uint8_t ipv6:1;, - uint8_t ipv4:1;) - uint32_t teid; +ED5(uint8_t spare:4;, + uint8_t chid:1;, + uint8_t ch:1;, + uint8_t ipv6:1;, + uint8_t ipv4:1;) + uint32_t teid; union { union { uint32_t addr; @@ -122,11 +218,42 @@ ED5(uint8_t spare:4;, }; } __attribute__ ((packed)) ogs_pfcp_f_teid_t; -typedef struct ogs_pfcp_f_seid_s { -ED3(uint8_t spare:6;, - uint8_t ipv4:1;, - uint8_t ipv6:1;) - uint64_t seid; +/* + * 8.2.62 UE IP Address + * + * - Bit 1 – V6: If this bit is set to "1", then the IPv6 address field + * shall be present in the UE IP Address, otherwise the IPv6 address field + * shall not be present. + * - Bit 2 – V4: If this bit is set to "1", then the IPv4 address field + * shall be present in the UE IP Address, otherwise the IPv4 address field + * shall not be present. + * - Bit 3 – S/D: This bit is only applicable to the UE IP Address IE + * in the PDI IE. It shall be set to "0" and ignored by the receiver + * in IEs other than PDI IE. In the PDI IE, if this bit is set to "0", + * this indicates a Source IP address; if this bit is set to "1", + * this indicates a Destination IP address. + * - Bit 4 – IPv6D: This bit is only applicable to the UE IP address IE + * in the PDI IE and whhen V6 bit is set to "1". If this bit is set to "1", + * then the IPv6 Prefix Delegation Bits field shall be present, + * otherwise the UP function shall consider IPv6 prefix is default /64. + * - Bit 5 to 8 Spare, for future use and set to 0. + * + * Octets "m to (m+3)" or "p to (p+15)" (IPv4 address / IPv6 address fields), + * if present, shall contain the address value. + * + * Octet r, if present, shall contain the number of bits is allocated + * for IPv6 prefix delegation, e.g. if /60 prefix is used, the value + * is set to "4". When using UE IP address IE in a PDI to match the packets, + * the UP function shall only use the IPv6 prefix part and + * ignore the interface identifier part. + */ +typedef struct ogs_pfcp_ue_ip_addr_s { +ED4(uint8_t spare:5;, +#define OGS_PFCP_UE_IP_SRC 0 +#define OGS_PFCP_UE_IP_DST 1 + uint8_t sd:1;, + uint8_t ipv4:1;, + uint8_t ipv6:1;) union { uint32_t addr; uint8_t addr6[OGS_IPV6_LEN]; @@ -135,31 +262,73 @@ ED3(uint8_t spare:6;, uint8_t addr6[OGS_IPV6_LEN]; } both; }; -} __attribute__ ((packed)) ogs_pfcp_f_seid_t; +} __attribute__ ((packed)) ogs_pfcp_ue_ip_addr_t; -typedef struct ogs_pfcp_node_id_s { -ED2(uint8_t spare:4;, - uint8_t type:4;) -#define OGS_PFCP_NODE_ID_IPV4 0 -#define OGS_PFCP_NODE_ID_IPV6 1 -#define OGS_PFCP_NODE_ID_FQDN 2 -#define OGS_PFPC_NODE_ID_LEN(__nid) \ - (1 + ((__nid.type != PFCP_NODE_ID_IPV4) ? \ - (__nid.type != PFCP_NODE_ID_IPV6 ? -1 : 16 ) : 4)) - union { - uint32_t addr; - uint8_t addr6[OGS_IPV6_LEN]; - }; -} __attribute__ ((packed)) ogs_pfcp_node_id_t; - -typedef struct ogs_pfcp_outer_hdr_s { -ED5(uint8_t spare:4;, - uint8_t udp_ipv6:1;, - uint8_t udp_ipv4:1;, - uint8_t gtpu_ipv6:1;, - uint8_t gtpu_ipv4:1;) - uint8_t void0; - uint32_t teid; +/* + * 8.2.56 Outer Header Creation + * + * NOTE 1: The SGW-U/I-UPF shall also create GTP-U extension header(s) + * if any has been stored for this packet, during a previous outer header + * removal (see clause 8.2.64). + * NOTE 2: This value may apply to UL packets sent by a PGW-U + * for non-IP PDN connections with SGi tunnelling based on UDP/IP encapsulation + * (see clause 4.3.17.8.3.3.2 of 3GPP TS 23.401 [14]). + * NOTE 3: The SGW-U/I-UPF shall set the GTP-U message type + * to the value stored during the previous outer header removal. + * NOTE 4: This value may apply to UL packets sent by a UPF + * for Ethernet PDU sessions over N6 + * (see clause 5.8.2.11.6 of 3GPP TS 23.501 [28]). + * NOTE 5: This value may apply e.g. to UL packets sent by a UPF + * (PDU Session Anchor) over N6, when explicit N6 traffic routing information is provided to the SMF (see clause 5.6.7 of 3GPP TS 23.501 [28]). + * + * At least one bit of the Outer Header Creation Description field + * shall be set to 1. Bits 5/1 and 5/2 may both be set to 1 if an F-TEID + * with both an IPv4 and IPv6 addresses has been assigned by the GTP-U peer. + * In this case, the UP function shall send the outgoing packet + * towards the IPv4 or IPv6 address. + * + * The TEID field shall be present if the Outer Header Creation Description + * requests the creation of a GTP-U header. Otherwise it shall not be present. + * When present, it shall contain the destination GTP-U TEID to set + * in the GTP-U header of the outgoing packet. + * + * The IPv4 Address field shall be present if the Outer Header Creation + * Description requests the creation of an IPv4 header. Otherwise it shall + * not be present. When present, it shall contain the destination IPv4 address + * to set in the IPv4 header of the outgoing packet. + * + * The IPv6 Address field shall be present if the Outer Header Creation + * Description requests the creation of an IPv6 header. Otherwise it shall + * not be present. When present, it shall contain the destination IPv6 address + * to set in the IPv6 header of the outgoing packet. + * + * The Port Number field shall be present if the Outer Header Creation + * Description requests the creation of a UDP/IP header + * (i.e. it is set to the value 4). Otherwise it shall not be present. + * When present, it shall contain the destination Port Number to set + * in the UDP header of the outgoing packet. + * + * The C-TAG field shall be present if the Outer Header Creation Description + * requests the setting of the C-Tag in Ethernet packet. Otherwise it shall + * not be present. When present, it shall contain the destination Customer-VLAN + * tag to set in the Customer-VLAN tag header of the outgoing packet. + * + * The S-TAG field shall be present if the Outer Header Creation Description + * requests the setting of the S-Tag in Ethernet packet. Otherwise it shall + * not be present. When present, it shall contain the destination Service-VLAN + * tag to set in the Service-VLAN tag header of the outgoing packet. + */ +typedef struct ogs_pfcp_outer_header_creation_s { +ED8(uint8_t stag:1;, + uint8_t ctag:1;, + uint8_t ip6:1;, + uint8_t ip4:1;, + uint8_t udp6:1;, + uint8_t udp4:1;, + uint8_t gtpu6:1;, + uint8_t gtpu4:1;) + uint8_t spare; + uint32_t teid; union { uint32_t addr; uint8_t addr6[OGS_IPV6_LEN]; @@ -168,49 +337,242 @@ ED5(uint8_t spare:4;, uint8_t addr6[OGS_IPV6_LEN]; } both; }; -} __attribute__ ((packed)) ogs_pfcp_outer_hdr_t; +} __attribute__ ((packed)) ogs_pfcp_outer_header_creation_t; -typedef struct ogs_pfcp_report_type_s { -ED5(uint8_t spare0:4;, - uint8_t upir:1;, /* User Plane Inactivity Report */ - uint8_t erir:1;, /* Error Indication Report */ - uint8_t usar:1;, /* Usage Report */ - uint8_t dldr:1;) /* Downlink Data Report */ -} __attribute__ ((packed)) pfcp_report_type_t; +/* 8.2.82 User Plane IP Resource Information + * + * The following flags are coded within Octet 5: + * - Bit 1 – V4: If this bit is set to "1", then the IPv4 address field + * shall be present, otherwise the IPv4 address field shall not be present. + * - Bit 2 – V6: If this bit is set to "1", then the IPv6 address field + * shall be present, otherwise the IPv6 address field shall not be present. + * - Bit 3-5 – TEID Range Indication (TEIDRI): the value of this field + * indicates the number of bits in the most significant octet of a TEID + * that are used to partition the TEID range, + * e.g. if this field is set to "4", then the first 4 bits in the TEID + * are used to partition the TEID range. + * - Bit 6 – Associated Network Instance (ASSONI): if this bit is set to "1", + * then the Network Instance field shall be present, otherwise the Network + * Instance field shall not be present. + * - Bit 7 – Associated Source Interface (ASSOSI): if this bit is set to "1", + * then the Source Interface field shall be present, + * otherwise the Source Interface field shall not be present. + * - Bit 8: Spare, for future use and set to 0. + * + * At least one of the V4 and V6 flags shall be set to "1", + * and both may be set to "1". + * + * If both the ASSONI and ASSOSI flags are set to "0", this shall indicate + * that the User Plane IP Resource Information provided can be used + * by CP function for any Network Instance and any Source Interface + * of GTP-U user plane in the UP function. Octet 6 (TEID Range) shall be + * present if the TEID Range Indication is not set to zero and + * shall contain a value of the bits which are used to partition the TEID range. + * E.g. if the TEID Range Indication is set to "4", then Octet 6 shall be + * one of values between 0 and 15. When TEID Range Indication is set to zero, + * the Octet 6 shall not be present, the TEID is not partitioned, + * i.e. all TEID values are available for use by the CP function. + * + * Octets "m to (m+3)" and/or "p to (p+15)" (IPv4 address / IPv6 address fields) + * , if present, shall contain the respective IP address values. + * + * Octets "k to l", if present, shall contain a Network Instance value + * as encoded in octet "5 to n+4" of the Figure 8.2.4-1 in clause 8.2.4, + * identifying a Network Instance with which the IP address or TEID Range + * is associated. + * + * Octet r, if present, shall contain a Source Interface value as encoded + * in octet 5 of the Figure 8.2.2-1 in clause 8.2.2, + * identifying the Source Interface with which the IP address or TEID Range + * is associated. + */ -typedef struct ogs_pfcp_downlink_data_service_information_s { -#define OGS_PFCP_DOWNLINK_DATA_SERVICE_INFORMATION_LEN(__data) \ - (sizeof(struct _pfcp_downlink_data_service_information_t) - \ - (__data).ppi - (__data).qfii) -ED3(uint8_t spare1:6;, - uint8_t ppi:1;, /* Paging Policy Indication */ - uint8_t qfii:1;) -ED2( - uint8_t spare2:2;, - uint8_t paging_policy_indication:6; -) -ED2( - uint8_t spare:2;, - uint8_t QFI:6; -) -} __attribute__ ((packed)) ogs_pfcp_downlink_data_service_information_t; +/* Flags(1) + TEID Range(1) + IPV4(4) + IPV6(16) + Source Interface(1) = 23 */ +#define OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN \ + (23 + OGS_MAX_APN_LEN) +typedef struct ogs_pfcp_user_plane_ip_resource_info_s { + union { + struct { +ED6(uint8_t spare:1;, + uint8_t assosi:1;, + uint8_t assoni:1;, + uint8_t teidri:3;, + uint8_t v6:1;, + uint8_t v4:1;) + }; + uint8_t flags; + }; -typedef struct ogs_pfcp_user_plane_ip_resource_information_s { -ED6(uint8_t spare1:1;, - uint8_t assosi:1;, - uint8_t assoni:1;, - uint8_t teidri:3;, - uint8_t v6:1;, - uint8_t v4:1;) + uint8_t teid_range; + uint32_t addr; + uint8_t addr6[OGS_IPV6_LEN]; + char network_instance[OGS_MAX_APN_LEN]; + ogs_pfcp_interface_t source_interface; +} __attribute__ ((packed)) ogs_pfcp_user_plane_ip_resource_info_t; - uint8_t teid_range:8; - uint32_t addr; - uint8_t addr6[OGS_IPV6_LEN]; - uint8_t network_instance; -ED2(uint8_t spare2:4;, - uint8_t source_interface:4; -) -} __attribute__ ((packed)) ogs_pfcp_user_plane_ip_resource_information_t; +int16_t ogs_pfcp_build_user_plane_ip_resource_info( + ogs_tlv_octet_t *octet, + ogs_pfcp_user_plane_ip_resource_info_t *info, + void *data, int data_len); +int16_t ogs_pfcp_parse_user_plane_ip_resource_info( + ogs_pfcp_user_plane_ip_resource_info_t *info, + ogs_tlv_octet_t *octet); + +/* + * 8.2.5 SDF Filter + * + * The SDF Filter IE type shall be encoded as shown in Figure 8.2.5-1. + * It contains an SDF Filter, i.e. a single IP flow packet filter. + * + * The following flags are coded within Octet 5: + * - Bit 1 – FD (Flow Description): If this bit is set to "1", + * then the Length of Flow Description and the Flow Description fields + * shall be present, otherwise they shall not be present. + * - Bit 2 – TTC (ToS Traffic Class): If this bit is set to "1", + * then the ToS Traffic Class field shall be present, + * otherwise the ToS Traffic Class field shall not be present. + * - Bit 3 – SPI (Security Parameter Index): If this bit is set to "1", + * then the Security Parameter Index field shall be present, + * otherwise the Security Parameter Index field shall not be present. + * - Bit 4 – FL (Flow Label): If this bit is set to "1", + * then the Flow Label field shall be present, otherwise the Flow Label field + * shall not be present. + * - Bit 5 – BID (Bidirectional SDF Filter): If this bit is set to "1", + * then the SDF Filter ID shall be present, otherwise the SDF Filter ID + * shall not be present. + * - Bit 6 to 8: Spare, for future use and set to 0. + * + * The Flow Description field, when present, shall be encoded as an OctetString + * as specified in clause 5.4.2 of 3GPP TS 29.212 [8]. + * + * The ToS Traffic Class field, when present, shall be encoded as an OctetString + * on two octets as specified in clause 5.3.15 of 3GPP TS 29.212 [8]. + * + * The Security Parameter Index field, when present, shall be encoded as + * an OctetString on four octets and shall contain the IPsec security parameter + * index (which is a 32-bit field), as specified in clause 5.3.51 + * of 3GPP TS 29.212 [8]. + * + * The Flow Label field, when present, shall be encoded as an OctetString + * on 3 octets as specified in clause 5.3.52 of 3GPP TS 29.212 [8] and + * shall contain an IPv6 flow label (which is a 20-bit field). + * + * The bits 8 to 5 of the octet "v" shall be spare and set to zero, and + * the remaining 20 bits shall contain the IPv6 flow label. + * + * An SDF Filter may: + * + * - be a pattern for matching the IP 5 tuple (source IP address or + * IPv6 network prefix, destination IP address or IPv6 network prefix, + * source port number, destination port number, protocol ID of the protocol + * above IP). In the pattern: + * - a value left unspecified in a filter matches any value of + * the corresponding information in a packet; + * - an IP address may be combined with a prefix mask; + * - port numbers may be specified as port ranges; + * - the pattern can be extended by the Type of Service (TOS) (IPv4) / + * Traffic class (IPv6) and Mask; + * + * - consist of the destination IP address and optional mask, protocol ID + * of the protocol above IP, the Type of Service (TOS) (IPv4) / + * Traffic class (IPv6) and Mask and the IPsec Security Parameter Index (SPI); + * + * - consist of the destination IP address and optional mask, + * the Type of Service (TOS) (IPv4) / Traffic class (IPv6) and Mask and + * the Flow Label (IPv6). + * + * NOTE 1: The details about the IPsec Security Parameter Index (SPI), + * the Type of Service (TOS) (IPv4) / Traffic class (IPv6) and Mask and + * the Flow Label (IPv6) are defined in 3GPP TS 23.060 [19] clause 15.3. + * + * - extend the packet inspection beyond the possibilities described above and + * look further into the packet. Such service data flow filters need + * to be predefined in the PGW-U, as specified in clause 5.11 + * of 3GPP TS 23.214 [2]. + * + * NOTE 2: Such filters may be used to support filtering with respect + * to a service data flow based on the transport and application + * protocols used above IP, e.g. for HTTP and WAP. Filtering + * for further application protocols and services can also be supported. + * + * The SDF Filter ID, when present, shall be encoded as + * an Unsigned32 binary integer value. It shall uniquely identify + * an SDF Filter among all the SDF Filters provisioned for a given PFCP Session. + * The source/destination IP address and port information, in a bidirectional + * SDF Filter, shall be set as for downlink IP flows. The SDF filter + * for the opposite direction has the same parameters, but having + * the source and destination address/port parameters swapped. When being + * provisioned with a bidirectional SDF filter in a PDR, + * the UP function shall apply the SDF filter as specified in clause 5.2.1A.2A. + */ + +#define OGS_PFCP_MAX_SDF_FILTER_LEN 256 +typedef struct ogs_pfcp_sdf_filter_s { + union { + struct { +ED6(uint8_t spare1:3;, + uint8_t bid:1;, + uint8_t fl:1;, + uint8_t spi:1;, + uint8_t ttc:1;, + uint8_t fd:1;) + }; + uint8_t flags; + }; + + uint8_t spare2; + uint16_t flow_description_len; + char *flow_description; + uint16_t tos_traffic_class; + uint32_t security_parameter_index; + uint32_t flow_label; + uint32_t sdf_filter_id; +} __attribute__ ((packed)) ogs_pfcp_sdf_filter_t; + +int16_t ogs_pfcp_build_sdf_filter( + ogs_tlv_octet_t *octet, ogs_pfcp_sdf_filter_t *info, + void *data, int data_len); +int16_t ogs_pfcp_parse_sdf_filter( + ogs_pfcp_sdf_filter_t *info, ogs_tlv_octet_t *octet); + +/* + * 8.2.8 MBR + * + * The UL/DL MBR fields shall be encoded as kilobits per second + * (1 kbps = 1000 bps) in binary value. The UL/DL MBR fields may require + * converting values in bits per second to kilobits per second + * when the UL/DL MBR values are received from an interface other than + * GTPv2 interface. If such conversions result in fractions, + * then the value of UL/DL MBR fields shall be rounded upwards. + * The range of UL/DL MBR is specified in 3GPP TS 36.413 [10]. + * + * NOTE: The encoding is aligned on the encoding specified + * in 3GPP TS 29.274 [9]. + */ + +#define OGS_PFCP_BITRATE_LEN 10 +typedef struct ogs_pfcp_bitrate_s { + uint64_t uplink; + uint64_t downlink; +} __attribute__ ((packed)) ogs_pfcp_bitrate_t; + +int16_t ogs_pfcp_build_bitrate(ogs_tlv_octet_t *octet, + ogs_pfcp_bitrate_t *bitrate, void *data, int data_len); +int16_t ogs_pfcp_parse_bitrate( + ogs_pfcp_bitrate_t *bitrate, ogs_tlv_octet_t *octet); + +#define OGS_PFCP_GATE_OPEN 0 +#define OGS_PFCP_GATE_CLOSE 1 +typedef struct ogs_pfcp_gate_status_s { + union { + struct { +ED3(uint8_t spare:4;, + uint8_t uplink:2;, + uint8_t downlink:2;) + }; + uint8_t value; + }; +} __attribute__ ((packed)) ogs_pfcp_gate_status_t; #ifdef __cplusplus } diff --git a/lib/pfcp/xact.c b/lib/pfcp/xact.c index 836984655..358b9509a 100644 --- a/lib/pfcp/xact.c +++ b/lib/pfcp/xact.c @@ -72,7 +72,7 @@ int ogs_pfcp_xact_final(void) return OGS_OK; } -ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *pnode, +ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *node, ogs_pfcp_header_t *hdesc, ogs_pkbuf_t *pkbuf, void (*cb)(ogs_pfcp_xact_t *xact, void *data), void *data) { @@ -80,7 +80,7 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *pnode, char buf[OGS_ADDRSTRLEN]; ogs_pfcp_xact_t *xact = NULL; - ogs_assert(pnode); + ogs_assert(node); ogs_pool_alloc(&pool, &xact); ogs_assert(xact); @@ -89,7 +89,7 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *pnode, xact->org = OGS_PFCP_LOCAL_ORIGINATOR; xact->xid = OGS_NEXT_ID(g_xact_id, PFCP_MIN_XACT_ID, PFCP_MAX_XACT_ID); - xact->pnode = pnode; + xact->node = node; xact->cb = cb; xact->data = data; @@ -102,11 +102,11 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *pnode, xact->holding_rcount = PFCP_T3_DUPLICATED_RETRY_COUNT; ogs_list_add(xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? - &xact->pnode->local_list : &xact->pnode->remote_list, xact); + &xact->node->local_list : &xact->node->remote_list, xact); rv = ogs_pfcp_xact_update_tx(xact, hdesc, pkbuf); if (rv != OGS_OK) { - ogs_error("ogs_pfcp_xact_update_tx() failed"); + ogs_error("ogs_pfcp_xact_update_tx(rv=%d) failed", (int)rv); ogs_pfcp_xact_delete(xact); return NULL; } @@ -114,19 +114,19 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *pnode, ogs_debug("[%d] %s Create peer [%s]:%d", xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&pnode->remote_addr, buf), - OGS_PORT(&pnode->remote_addr)); + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); return xact; } ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create( - ogs_pfcp_node_t *pnode, uint32_t sqn) + ogs_pfcp_node_t *node, uint32_t sqn) { char buf[OGS_ADDRSTRLEN]; ogs_pfcp_xact_t *xact = NULL; - ogs_assert(pnode); + ogs_assert(node); ogs_pool_alloc(&pool, &xact); ogs_assert(xact); @@ -135,7 +135,7 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create( xact->org = OGS_PFCP_REMOTE_ORIGINATOR; xact->xid = OGS_PFCP_SQN_TO_XID(sqn); - xact->pnode = pnode; + xact->node = node; xact->tm_response = ogs_timer_add(g_timer_mgr, response_timeout, xact); ogs_assert(xact->tm_response); @@ -146,24 +146,24 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create( xact->holding_rcount = PFCP_T3_DUPLICATED_RETRY_COUNT; ogs_list_add(xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? - &xact->pnode->local_list : &xact->pnode->remote_list, xact); + &xact->node->local_list : &xact->node->remote_list, xact); ogs_debug("[%d] %s Create peer [%s]:%d", xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&pnode->remote_addr, buf), - OGS_PORT(&pnode->remote_addr)); + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); return xact; } -void ogs_pfcp_xact_delete_all(ogs_pfcp_node_t *pnode) +void ogs_pfcp_xact_delete_all(ogs_pfcp_node_t *node) { ogs_pfcp_xact_t *xact = NULL, *next_xact = NULL; - ogs_list_for_each_safe(&pnode->local_list, next_xact, xact) + ogs_list_for_each_safe(&node->local_list, next_xact, xact) ogs_pfcp_xact_delete(xact); - ogs_list_for_each_safe(&pnode->remote_list, next_xact, xact) + ogs_list_for_each_safe(&node->remote_list, next_xact, xact) ogs_pfcp_xact_delete(xact); } @@ -173,9 +173,10 @@ int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact, char buf[OGS_ADDRSTRLEN]; ogs_pfcp_xact_stage_t stage; ogs_pfcp_header_t *h = NULL; + int pfcp_hlen = 0; ogs_assert(xact); - ogs_assert(xact->pnode); + ogs_assert(xact->node); ogs_assert(hdesc); ogs_assert(pkbuf); @@ -183,8 +184,8 @@ int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact, xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", hdesc->type, - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); stage = ogs_pfcp_xact_get_stage(hdesc->type, xact->xid); if (xact->org == OGS_PFCP_LOCAL_ORIGINATOR) { @@ -241,27 +242,28 @@ int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact, return OGS_ERROR; } - if (h->type >= OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE) - ogs_pkbuf_push(pkbuf, OGS_PFCP_HEADER_LEN); - else - ogs_pkbuf_push(pkbuf, OGS_PFCP_HEADER_LEN - OGS_PFCP_SEID_LEN); + if (hdesc->type >= OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE) { + pfcp_hlen = OGS_PFCP_HEADER_LEN; + } else { + pfcp_hlen = OGS_PFCP_HEADER_LEN - OGS_PFCP_SEID_LEN; + } + ogs_pkbuf_push(pkbuf, pfcp_hlen); h = (ogs_pfcp_header_t *)pkbuf->data; - ogs_assert(h); + memset(h, 0, pfcp_hlen); - memset(h, 0, sizeof(ogs_pfcp_header_t)); - h->version = 1; + h->version = OGS_PFCP_VERSION; h->type = hdesc->type; if (h->type >= OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE) { - h->seid_p = 1; + h->seid_presence = 1; h->seid = htobe64(hdesc->seid); h->sqn = OGS_PFCP_XID_TO_SQN(xact->xid); } else { - h->seid_p = 1; + h->seid_presence = 0; h->sqn_only = OGS_PFCP_XID_TO_SQN(xact->xid); } - h->length = htons(pkbuf->len - 4); + h->length = htobe16(pkbuf->len - 4); /* Save Message type and packet of this step */ xact->seq[xact->step].type = h->type; @@ -283,8 +285,8 @@ int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type) xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", type, - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); stage = ogs_pfcp_xact_get_stage(type, xact->xid); if (xact->org == OGS_PFCP_LOCAL_ORIGINATOR) { @@ -315,10 +317,10 @@ int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type) xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->pnode->remote_addr, + OGS_ADDR(&xact->node->addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); - rv = ogs_pfcp_sendto(xact->pnode, pkbuf); + OGS_PORT(&xact->node->addr)); + rv = ogs_pfcp_sendto(xact->node, pkbuf); ogs_expect(rv == OGS_OK); } else { ogs_warn("[%d] %s Request Duplicated. Discard!" @@ -327,9 +329,9 @@ int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type) xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->pnode->remote_addr, + OGS_ADDR(&xact->node->addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_PORT(&xact->node->addr)); } return OGS_RETRY; @@ -380,10 +382,10 @@ int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type) xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->pnode->remote_addr, + OGS_ADDR(&xact->node->addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); - rv = ogs_pfcp_sendto(xact->pnode, pkbuf); + OGS_PORT(&xact->node->addr)); + rv = ogs_pfcp_sendto(xact->node, pkbuf); ogs_expect(rv == OGS_OK); } else { ogs_warn("[%d] %s Request Duplicated. Discard!" @@ -392,9 +394,9 @@ int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type) xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, type, - OGS_ADDR(&xact->pnode->remote_addr, + OGS_ADDR(&xact->node->addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_PORT(&xact->node->addr)); } return OGS_RETRY; @@ -455,13 +457,13 @@ int ogs_pfcp_xact_commit(ogs_pfcp_xact_t *xact) ogs_pfcp_xact_stage_t stage; ogs_assert(xact); - ogs_assert(xact->pnode); + ogs_assert(xact->node); ogs_debug("[%d] %s Commit peer [%s]:%d", xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); type = xact->seq[xact->step-1].type; stage = ogs_pfcp_xact_get_stage(type, xact->xid); @@ -549,7 +551,7 @@ int ogs_pfcp_xact_commit(ogs_pfcp_xact_t *xact) pkbuf = xact->seq[xact->step-1].pkbuf; ogs_assert(pkbuf); - rv = ogs_pfcp_sendto(xact->pnode, pkbuf); + rv = ogs_pfcp_sendto(xact->node, pkbuf); ogs_expect(rv == OGS_OK); return OGS_OK; @@ -561,15 +563,15 @@ static void response_timeout(void *data) ogs_pfcp_xact_t *xact = data; ogs_assert(xact); - ogs_assert(xact->pnode); + ogs_assert(xact->node); ogs_debug("[%d] %s Response Timeout " "for step %d type %d peer [%s]:%d", xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); if (--xact->response_rcount > 0) { ogs_pkbuf_t *pkbuf = NULL; @@ -580,7 +582,7 @@ static void response_timeout(void *data) pkbuf = xact->seq[xact->step-1].pkbuf; ogs_assert(pkbuf); - if (ogs_pfcp_sendto(xact->pnode, pkbuf) != OGS_OK) { + if (ogs_pfcp_sendto(xact->node, pkbuf) != OGS_OK) { ogs_error("ogs_pfcp_sendto() failed"); goto out; } @@ -590,8 +592,8 @@ static void response_timeout(void *data) xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); if (xact->cb) xact->cb(xact, xact->data); @@ -611,15 +613,15 @@ static void holding_timeout(void *data) ogs_pfcp_xact_t *xact = data; ogs_assert(xact); - ogs_assert(xact->pnode); + ogs_assert(xact->node); ogs_debug("[%d] %s Holding Timeout " "for step %d type %d peer [%s]:%d", xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); if (--xact->holding_rcount > 0) { if (xact->tm_holding) @@ -630,44 +632,46 @@ static void holding_timeout(void *data) xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", xact->step, xact->seq[xact->step-1].type, - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); ogs_pfcp_xact_delete(xact); } } int ogs_pfcp_xact_receive( - ogs_pfcp_node_t *pnode, ogs_pfcp_header_t *h, ogs_pfcp_xact_t **xact) + ogs_pfcp_node_t *node, ogs_pfcp_header_t *h, ogs_pfcp_xact_t **xact) { char buf[OGS_ADDRSTRLEN]; int rv; ogs_pfcp_xact_t *new = NULL; - ogs_assert(pnode); + ogs_assert(node); ogs_assert(h); new = ogs_pfcp_xact_find_by_xid( - pnode, h->type, OGS_PFCP_SQN_TO_XID(h->sqn)); + node, h->type, OGS_PFCP_SQN_TO_XID(h->sqn)); if (!new) - new = ogs_pfcp_xact_remote_create(pnode, h->sqn); + new = ogs_pfcp_xact_remote_create(node, h->sqn); ogs_assert(new); ogs_debug("[%d] %s Receive peer [%s]:%d", new->xid, new->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&pnode->remote_addr, buf), - OGS_PORT(&pnode->remote_addr)); + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); rv = ogs_pfcp_xact_update_rx(new, h->type); - if (rv != OGS_OK) { + if (rv == OGS_ERROR) { ogs_error("ogs_pfcp_xact_update_rx() failed"); ogs_pfcp_xact_delete(new); return rv; + } else if (rv == OGS_RETRY) { + return rv; } *xact = new; - return OGS_OK; + return rv; } ogs_pfcp_xact_t *ogs_pfcp_xact_find(ogs_index_t index) @@ -710,27 +714,24 @@ static ogs_pfcp_xact_stage_t ogs_pfcp_xact_get_stage(uint8_t type, uint32_t xid) } ogs_pfcp_xact_t *ogs_pfcp_xact_find_by_xid( - ogs_pfcp_node_t *pnode, uint8_t type, uint32_t xid) + ogs_pfcp_node_t *node, uint8_t type, uint32_t xid) { char buf[OGS_ADDRSTRLEN]; ogs_list_t *list = NULL; ogs_pfcp_xact_t *xact = NULL; - ogs_assert(pnode); + ogs_assert(node); switch (ogs_pfcp_xact_get_stage(type, xid)) { case PFCP_XACT_INITIAL_STAGE: - list = &pnode->remote_list; + list = &node->remote_list; break; case PFCP_XACT_INTERMEDIATE_STAGE: - list = &pnode->local_list; + list = &node->local_list; break; case PFCP_XACT_FINAL_STAGE: - if (xid & PFCP_MAX_XACT_ID) - list = &pnode->remote_list; - else - list = &pnode->local_list; + list = &node->local_list; break; default: ogs_assert_if_reached(); @@ -743,8 +744,8 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_find_by_xid( ogs_debug("[%d] %s Find peer [%s]:%d", xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&pnode->remote_addr, buf), - OGS_PORT(&pnode->remote_addr)); + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); break; } } @@ -757,13 +758,13 @@ static int ogs_pfcp_xact_delete(ogs_pfcp_xact_t *xact) char buf[OGS_ADDRSTRLEN]; ogs_assert(xact); - ogs_assert(xact->pnode); + ogs_assert(xact->node); ogs_debug("[%d] %s Delete peer [%s]:%d", xact->xid, xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE", - OGS_ADDR(&xact->pnode->remote_addr, buf), - OGS_PORT(&xact->pnode->remote_addr)); + OGS_ADDR(&xact->node->addr, buf), + OGS_PORT(&xact->node->addr)); if (xact->seq[0].pkbuf) ogs_pkbuf_free(xact->seq[0].pkbuf); @@ -778,7 +779,7 @@ static int ogs_pfcp_xact_delete(ogs_pfcp_xact_t *xact) ogs_timer_delete(xact->tm_holding); ogs_list_remove(xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? - &xact->pnode->local_list : &xact->pnode->remote_list, xact); + &xact->node->local_list : &xact->node->remote_list, xact); ogs_pool_free(&pool, xact); return OGS_OK; diff --git a/lib/pfcp/xact.h b/lib/pfcp/xact.h index 2d68e0d53..4a34a6f75 100644 --- a/lib/pfcp/xact.h +++ b/lib/pfcp/xact.h @@ -32,7 +32,7 @@ extern "C" { * Transaction context */ typedef struct ogs_pfcp_xact_s { - ogs_lnode_t node; /**< A node of list */ + ogs_lnode_t lnode; /**< A node of list */ ogs_index_t index; #define OGS_PFCP_LOCAL_ORIGINATOR 0 @@ -41,7 +41,7 @@ typedef struct ogs_pfcp_xact_s { local or remote */ uint32_t xid; /**< Transaction ID */ - ogs_pfcp_node_t *pnode; /**< Relevant PFCP node context */ + ogs_pfcp_node_t *node; /**< Relevant PFCP node context */ void (*cb)(ogs_pfcp_xact_t *, void *); /**< Local timer expiration handler */ void *data; /**< Transaction Data */ @@ -59,17 +59,19 @@ typedef struct ogs_pfcp_xact_s { uint8_t response_rcount; ogs_timer_t *tm_holding; /**< Timer waiting for holding message */ uint8_t holding_rcount; + + void *assoc_xact; /**< Associated GTP transaction */ } ogs_pfcp_xact_t; int ogs_pfcp_xact_init(ogs_timer_mgr_t *timer_mgr, int size); int ogs_pfcp_xact_final(void); -ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *pnode, +ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *node, ogs_pfcp_header_t *hdesc, ogs_pkbuf_t *pkbuf, void (*cb)(ogs_pfcp_xact_t *xact, void *data), void *data); ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create( - ogs_pfcp_node_t *pnode, uint32_t sqn); -void ogs_pfcp_xact_delete_all(ogs_pfcp_node_t *pnode); + ogs_pfcp_node_t *node, uint32_t sqn); +void ogs_pfcp_xact_delete_all(ogs_pfcp_node_t *node); int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact, ogs_pfcp_header_t *hdesc, ogs_pkbuf_t *pkbuf); @@ -77,12 +79,12 @@ int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type); int ogs_pfcp_xact_commit(ogs_pfcp_xact_t *xact); -int ogs_pfcp_xact_receive(ogs_pfcp_node_t *pnode, +int ogs_pfcp_xact_receive(ogs_pfcp_node_t *node, ogs_pfcp_header_t *h, ogs_pfcp_xact_t **xact); ogs_pfcp_xact_t *ogs_pfcp_xact_find(ogs_index_t index); ogs_pfcp_xact_t *ogs_pfcp_xact_find_by_xid( - ogs_pfcp_node_t *pnode, uint8_t type, uint32_t xid); + ogs_pfcp_node_t *node, uint8_t type, uint32_t xid); #ifdef __cplusplus } diff --git a/lib/s1ap/message.h b/lib/s1ap/message.h index 05859d79d..a447e285b 100644 --- a/lib/s1ap/message.h +++ b/lib/s1ap/message.h @@ -32,8 +32,7 @@ extern "C" { #define OGS_S1AP_CLEAR_DATA(__dATA) \ do { \ ogs_assert((__dATA)); \ - if ((__dATA)->buf) \ - { \ + if ((__dATA)->buf) { \ FREEMEM((__dATA)->buf); \ (__dATA)->buf = NULL; \ (__dATA)->size = 0; \ diff --git a/lib/sctp/ogs-lksctp.c b/lib/sctp/ogs-lksctp.c index 526fd5156..023270b76 100644 --- a/lib/sctp/ogs-lksctp.c +++ b/lib/sctp/ogs-lksctp.c @@ -200,7 +200,7 @@ int ogs_sctp_sendmsg(ogs_sock_t *sock, const void *msg, size_t len, size = sctp_sendmsg(sock->fd, msg, len, to ? &to->sa : NULL, addrlen, - htonl(ppid), + htobe32(ppid), 0, /* flags */ stream_no, 0, /* timetolive */ @@ -244,7 +244,7 @@ int ogs_sctp_recvmsg(ogs_sock_t *sock, void *msg, size_t len, } if (sinfo) { - sinfo->ppid = ntohl(sndrcvinfo.sinfo_ppid); + sinfo->ppid = be32toh(sndrcvinfo.sinfo_ppid); sinfo->stream_no = sndrcvinfo.sinfo_stream; } diff --git a/lib/sctp/ogs-usrsctp.c b/lib/sctp/ogs-usrsctp.c index b860fb59a..9fce7c708 100644 --- a/lib/sctp/ogs-usrsctp.c +++ b/lib/sctp/ogs-usrsctp.c @@ -334,7 +334,7 @@ int ogs_sctp_sendmsg(ogs_sock_t *sock, const void *msg, size_t len, ogs_assert(socket); memset((void *)&sndinfo, 0, sizeof(struct sctp_sndinfo)); - sndinfo.snd_ppid = htonl(ppid); + sndinfo.snd_ppid = htobe32(ppid); sndinfo.snd_sid = stream_no; sent = usrsctp_sendv(socket, msg, len, to ? &to->sa : NULL, to ? 1 : 0, @@ -384,7 +384,7 @@ int ogs_sctp_recvmsg(ogs_sock_t *sock, void *msg, size_t len, } if (sinfo) { - sinfo->ppid = ntohl(rcv_info.rcv_ppid); + sinfo->ppid = be32toh(rcv_info.rcv_ppid); sinfo->stream_no = rcv_info.rcv_sid; } diff --git a/src/meson.build b/src/meson.build index 7f6eff3e2..2aa67023f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -26,3 +26,6 @@ subdir('hss') subdir('sgw') subdir('pgw') subdir('pcrf') + +subdir('smf') +subdir('upf') diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index 0b08d4b14..9d5f55c74 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -1512,7 +1512,7 @@ int mme_context_parse_config() selection_mode); } } - } else if (!strcmp(root_key, "pgw")) { + } else if (!strcmp(root_key, "pgw") || !strcmp(root_key, "smf")) { ogs_yaml_iter_t pgw_iter; ogs_yaml_iter_recurse(&root_iter, &pgw_iter); while (ogs_yaml_iter_next(&pgw_iter)) { @@ -1663,7 +1663,7 @@ mme_sgw_t *mme_sgw_find_by_addr(ogs_sockaddr_t *addr) ogs_list_for_each(&self.sgw_list, sgw) { ogs_assert(sgw->gnode); - if (ogs_sockaddr_is_equal(&sgw->gnode->remote_addr, addr) == true) + if (ogs_sockaddr_is_equal(&sgw->gnode->addr, addr) == true) break; } diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index 64a6f548f..d295bface 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -476,8 +476,12 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) case MME_EVT_S11_MESSAGE: pkbuf = e->pkbuf; ogs_assert(pkbuf); - rv = ogs_gtp_parse_msg(>p_message, pkbuf); - ogs_assert(rv == OGS_OK); + + if (ogs_gtp_parse_msg(>p_message, pkbuf) != OGS_OK) { + ogs_error("ogs_gtp_parse_msg() failed"); + ogs_pkbuf_free(pkbuf); + break; + } /* * 5.5.2 in spec 29.274 diff --git a/src/mme/s1ap-path.c b/src/mme/s1ap-path.c index 910093f93..3b94f5cc8 100644 --- a/src/mme/s1ap-path.c +++ b/src/mme/s1ap-path.c @@ -204,7 +204,7 @@ int s1ap_send_to_nas(enb_ue_t *enb_ue, ogs_pkbuf_pull(nasbuf, 6); break; default: - ogs_error("Not implemented(securiry header type:0x%x)", + ogs_error("Not implemented(security header type:0x%x)", sh->security_header_type); return OGS_ERROR; } diff --git a/src/pcrf/pcrf-context.c b/src/pcrf/pcrf-context.c index 2bd74c971..3f49a3af0 100644 --- a/src/pcrf/pcrf-context.c +++ b/src/pcrf/pcrf-context.c @@ -205,7 +205,8 @@ int pcrf_context_parse_config(void) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&conn_array)) break; - ogs_yaml_iter_recurse(&conn_array, &conn_iter); + ogs_yaml_iter_recurse( + &conn_array, &conn_iter); } else if (ogs_yaml_iter_type(&conn_array) == YAML_SCALAR_NODE) { break; @@ -439,7 +440,8 @@ int pcrf_db_qos_data(char *imsi_bcd, char *apn, ogs_assert(child3_key); pcc_rule_index = atoi(child3_key); - ogs_assert(pcc_rule_index < OGS_MAX_NUM_OF_PCC_RULE); + ogs_assert(pcc_rule_index < + OGS_MAX_NUM_OF_PCC_RULE); pcc_rule = &gx_message->pcc_rule[pcc_rule_index]; bson_iter_recurse(&child3_iter, &child4_iter); @@ -485,8 +487,8 @@ int pcrf_db_qos_data(char *imsi_bcd, char *apn, bson_iter_int32( &child6_iter); } else if (!strcmp(child6_key, - "pre_emption_vulnerability") && - BSON_ITER_HOLDS_INT32( + "pre_emption_vulnerability") + && BSON_ITER_HOLDS_INT32( &child6_iter)) { pcc_rule->qos.arp. pre_emption_vulnerability = @@ -568,7 +570,8 @@ int pcrf_db_qos_data(char *imsi_bcd, char *apn, while (bson_iter_next(&child6_iter)) { const char *child6_key = bson_iter_key(&child6_iter); - if (!strcmp(child6_key, "direction") && + if (!strcmp(child6_key, + "direction") && BSON_ITER_HOLDS_INT32( &child6_iter)) { flow->direction = diff --git a/src/pcrf/pcrf-gx-path.c b/src/pcrf/pcrf-gx-path.c index e42b3b2b3..fa83b59a8 100644 --- a/src/pcrf/pcrf-gx-path.c +++ b/src/pcrf/pcrf-gx-path.c @@ -349,7 +349,8 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, 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) { + if (hdr->avp_value->i32 != + OGS_DIAM_GX_SUBSCRIPTION_ID_TYPE_END_USER_IMSI) { ogs_error("Not implemented Subscription-Id-Type(%d)", hdr->avp_value->i32); result_code = OGS_DIAM_AVP_UNSUPPORTED; @@ -416,7 +417,8 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, ogs_pcc_rule_t *pcc_rule = &gx_message.pcc_rule[i]; if (pcc_rule->num_of_flow) { if (charging_rule == 0) { - ret = fd_msg_avp_new(ogs_diam_gx_charging_rule_install, 0, &avp); + ret = fd_msg_avp_new( + ogs_diam_gx_charging_rule_install, 0, &avp); ogs_assert(ret == 0); charging_rule = 1; @@ -438,8 +440,8 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, ogs_assert(ret == 0); if (gx_message.pdn.ambr.uplink) { - ret = fd_msg_avp_new(ogs_diam_gx_apn_aggregate_max_bitrate_ul, 0, - &avpch1); + ret = fd_msg_avp_new( + ogs_diam_gx_apn_aggregate_max_bitrate_ul, 0, &avpch1); ogs_assert(ret == 0); val.u32 = gx_message.pdn.ambr.uplink; ret = fd_msg_avp_setvalue (avpch1, &val); @@ -449,8 +451,8 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, } if (gx_message.pdn.ambr.downlink) { - ret = fd_msg_avp_new(ogs_diam_gx_apn_aggregate_max_bitrate_dl, 0, - &avpch1); + ret = fd_msg_avp_new( + ogs_diam_gx_apn_aggregate_max_bitrate_dl, 0, &avpch1); ogs_assert(ret == 0); val.u32 = gx_message.pdn.ambr.downlink; ret = fd_msg_avp_setvalue (avpch1, &val); @@ -475,7 +477,8 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, 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); + 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); @@ -530,7 +533,8 @@ static int pcrf_gx_ccr_cb( struct msg **msg, struct avp *avp, ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); ogs_assert(ret == 0); - } else if (cc_request_type == OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { + } else if (cc_request_type == + OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { struct rx_sess_state *rx_sess_data = NULL, *next_rx_sess_data = NULL; ogs_list_for_each_safe(&sess_data->rx_list, next_rx_sess_data, rx_sess_data) { @@ -590,7 +594,8 @@ out: } if (sess_data) { - if (cc_request_type != OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { + if (cc_request_type != + OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST) { /* Store this value in the session */ ret = fd_sess_state_store(pcrf_gx_reg, sess, &sess_data); ogs_assert(sess_data == NULL); @@ -838,7 +843,8 @@ int pcrf_gx_send_rar( pcc_rule->qos.gbr.uplink = db_pcc_rule->qos.gbr.uplink; if (charging_rule == 0) { - ret = fd_msg_avp_new(ogs_diam_gx_charging_rule_install, 0, &avp); + ret = fd_msg_avp_new( + ogs_diam_gx_charging_rule_install, 0, &avp); ogs_assert(ret == 0); charging_rule = 1; } @@ -852,7 +858,8 @@ int pcrf_gx_send_rar( ogs_assert(ret == 0); } - } else if (rx_message->cmd_code == OGS_DIAM_RX_CMD_CODE_SESSION_TERMINATION) { + } else if (rx_message->cmd_code == + OGS_DIAM_RX_CMD_CODE_SESSION_TERMINATION) { ogs_assert(rx_sess_data); for (i = 0; i < rx_sess_data->num_of_pcc_rule; i++) { @@ -1010,7 +1017,8 @@ static void pcrf_gx_raa_cb(void *data, struct msg **msg) 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); + 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); @@ -1242,7 +1250,8 @@ static int encode_pcc_rule_definition( ogs_assert(ret == 0); if (pcc_rule->qos.mbr.uplink) { - ret = fd_msg_avp_new(ogs_diam_gx_max_requested_bandwidth_ul, 0, &avpch3); + ret = fd_msg_avp_new( + ogs_diam_gx_max_requested_bandwidth_ul, 0, &avpch3); ogs_assert(ret == 0); val.u32 = pcc_rule->qos.mbr.uplink; ret = fd_msg_avp_setvalue (avpch3, &val); @@ -1252,7 +1261,8 @@ static int encode_pcc_rule_definition( } if (pcc_rule->qos.mbr.downlink) { - ret = fd_msg_avp_new(ogs_diam_gx_max_requested_bandwidth_dl, 0, &avpch3); + ret = fd_msg_avp_new( + ogs_diam_gx_max_requested_bandwidth_dl, 0, &avpch3); ogs_assert(ret == 0); val.u32 = pcc_rule->qos.mbr.downlink; ret = fd_msg_avp_setvalue (avpch3, &val); @@ -1405,8 +1415,8 @@ static int matched_flow(ogs_pcc_rule_t *pcc_rule, return matched; } -static int install_flow( - ogs_pcc_rule_t *pcc_rule, ogs_diam_rx_media_component_t *media_component) +static int install_flow(ogs_pcc_rule_t *pcc_rule, + ogs_diam_rx_media_component_t *media_component) { int rv; int i, j; @@ -1445,8 +1455,8 @@ static int install_flow( return OGS_OK; } -static int update_qos( - ogs_pcc_rule_t *pcc_rule, ogs_diam_rx_media_component_t *media_component) +static int update_qos(ogs_pcc_rule_t *pcc_rule, + ogs_diam_rx_media_component_t *media_component) { int rv; int i, j; diff --git a/src/pgw/meson.build b/src/pgw/meson.build index 258d818ee..e5ce833a4 100644 --- a/src/pgw/meson.build +++ b/src/pgw/meson.build @@ -15,8 +15,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -subdir('ipfw') - pgw_conf = configuration_data() pgw_headers = (''' @@ -41,9 +39,6 @@ endif configure_file(output : 'pgw-config.h', configuration : pgw_conf) libpgw_sources = files(''' - ogs-tun.h - ogs-tun.c - pgw-ipfw.h pgw-event.h pgw-context.h @@ -69,12 +64,12 @@ libpgw_sources = files(''' libpgw = static_library('pgw', sources : libpgw_sources, link_with : libipfw, - dependencies : [libapp_dep, libdiameter_gx_dep, libgtp_dep], + dependencies : [libapp_dep, libdiameter_gx_dep, libgtp_dep, libipfw_dep], install : false) libpgw_dep = declare_dependency( link_with : libpgw, - dependencies : [libapp_dep, libdiameter_gx_dep, libgtp_dep]) + dependencies : [libapp_dep, libdiameter_gx_dep, libgtp_dep, libipfw_dep]) pgw_sources = files(''' app-init.c diff --git a/src/pgw/pgw-context.c b/src/pgw/pgw-context.c index 4c68ef455..120ac1546 100644 --- a/src/pgw/pgw-context.c +++ b/src/pgw/pgw-context.c @@ -37,12 +37,14 @@ static int context_initiaized = 0; int num_sessions = 0; void stats_add_session(void) { num_sessions = num_sessions + 1; - ogs_info("Added a session. Number of active sessions is now %d", num_sessions); + ogs_info("Added a session. Number of active sessions is now %d", + num_sessions); } void stats_remove_session(void) { num_sessions = num_sessions - 1; - ogs_info("Removed a session. Number of active sessions is now %d", num_sessions); + ogs_info("Removed a session. Number of active sessions is now %d", + num_sessions); } void pgw_context_init(void) @@ -157,6 +159,11 @@ static int pgw_context_validation(void) ogs_config()->file); return OGS_ERROR; } + if (ogs_list_first(&self.subnet_list) == NULL) { + ogs_error("No pgw.pdn in '%s'", + ogs_config()->file); + return OGS_ERROR; + } if (self.dns[0] == NULL && self.dns6[0] == NULL) { ogs_error("No pgw.dns in '%s'", ogs_config()->file); @@ -249,7 +256,8 @@ int pgw_context_parse_config(void) conf = ogs_yaml_iter_value( &ext_iter); } else - ogs_warn("unknown key `%s`", ext_key); + ogs_warn("unknown key `%s`", + ext_key); } if (module) { @@ -302,7 +310,8 @@ int pgw_context_parse_config(void) ogs_yaml_iter_value(&conn_iter); if (v) port = atoi(v); } else - ogs_warn("unknown key `%s`", conn_key); + ogs_warn("unknown key `%s`", + conn_key); } if (identity && addr) { @@ -358,7 +367,8 @@ int pgw_context_parse_config(void) if (v) family = atoi(v); if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6) { - ogs_warn("Ignore family(%d) : AF_UNSPEC(%d), " + ogs_warn("Ignore family(%d) : " + "AF_UNSPEC(%d), " "AF_INET(%d), AF_INET6(%d) ", family, AF_UNSPEC, AF_INET, AF_INET6); family = AF_UNSPEC; @@ -366,7 +376,8 @@ int pgw_context_parse_config(void) } 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_yaml_iter_recurse(>pc_iter, + &hostname_iter); ogs_assert(ogs_yaml_iter_type(&hostname_iter) != YAML_MAPPING_NODE); @@ -473,7 +484,8 @@ int pgw_context_parse_config(void) if (v) family = atoi(v); if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6) { - ogs_warn("Ignore family(%d) : AF_UNSPEC(%d), " + ogs_warn("Ignore family(%d) : " + "AF_UNSPEC(%d), " "AF_INET(%d), AF_INET6(%d) ", family, AF_UNSPEC, AF_INET, AF_INET6); family = AF_UNSPEC; @@ -481,7 +493,8 @@ int pgw_context_parse_config(void) } else if (!strcmp(gtpu_key, "addr") || !strcmp(gtpu_key, "name")) { ogs_yaml_iter_t hostname_iter; - ogs_yaml_iter_recurse(>pu_iter, &hostname_iter); + ogs_yaml_iter_recurse(>pu_iter, + &hostname_iter); ogs_assert(ogs_yaml_iter_type(&hostname_iter) != YAML_MAPPING_NODE); @@ -550,9 +563,10 @@ int pgw_context_parse_config(void) NULL, self.gtpu_port); ogs_assert(rv == OGS_OK); } - } else if (!strcmp(pgw_key, "ue_pool")) { - ogs_yaml_iter_t ue_pool_array, ue_pool_iter; - ogs_yaml_iter_recurse(&pgw_iter, &ue_pool_array); + } else if (!strcmp(pgw_key, "pdn") || + !strcmp(pgw_key, "ue_pool")) { + ogs_yaml_iter_t pdn_array, pdn_iter; + ogs_yaml_iter_recurse(&pgw_iter, &pdn_array); do { pgw_subnet_t *subnet = NULL; const char *ipstr = NULL; @@ -563,43 +577,43 @@ int pgw_context_parse_config(void) const char *high[MAX_NUM_OF_SUBNET_RANGE]; int i, num = 0; - if (ogs_yaml_iter_type(&ue_pool_array) == + if (ogs_yaml_iter_type(&pdn_array) == YAML_MAPPING_NODE) { - memcpy(&ue_pool_iter, &ue_pool_array, + memcpy(&pdn_iter, &pdn_array, sizeof(ogs_yaml_iter_t)); - } else if (ogs_yaml_iter_type(&ue_pool_array) == + } else if (ogs_yaml_iter_type(&pdn_array) == YAML_SEQUENCE_NODE) { - if (!ogs_yaml_iter_next(&ue_pool_array)) + if (!ogs_yaml_iter_next(&pdn_array)) break; - ogs_yaml_iter_recurse(&ue_pool_array, - &ue_pool_iter); - } else if (ogs_yaml_iter_type(&ue_pool_array) == + ogs_yaml_iter_recurse(&pdn_array, + &pdn_iter); + } else if (ogs_yaml_iter_type(&pdn_array) == YAML_SCALAR_NODE) { break; } else ogs_assert_if_reached(); - while (ogs_yaml_iter_next(&ue_pool_iter)) { - const char *ue_pool_key = - ogs_yaml_iter_key(&ue_pool_iter); - ogs_assert(ue_pool_key); - if (!strcmp(ue_pool_key, "addr")) { + while (ogs_yaml_iter_next(&pdn_iter)) { + const char *pdn_key = + ogs_yaml_iter_key(&pdn_iter); + ogs_assert(pdn_key); + if (!strcmp(pdn_key, "addr")) { char *v = - (char *)ogs_yaml_iter_value(&ue_pool_iter); + (char *)ogs_yaml_iter_value(&pdn_iter); if (v) { ipstr = (const char *)strsep(&v, "/"); if (ipstr) { mask_or_numbits = (const char *)v; } } - } else if (!strcmp(ue_pool_key, "apn")) { - apn = ogs_yaml_iter_value(&ue_pool_iter); - } else if (!strcmp(ue_pool_key, "dev")) { - dev = ogs_yaml_iter_value(&ue_pool_iter); - } else if (!strcmp(ue_pool_key, "range")) { + } else if (!strcmp(pdn_key, "apn")) { + apn = ogs_yaml_iter_value(&pdn_iter); + } else if (!strcmp(pdn_key, "dev")) { + dev = ogs_yaml_iter_value(&pdn_iter); + } else if (!strcmp(pdn_key, "range")) { ogs_yaml_iter_t range_iter; ogs_yaml_iter_recurse( - &ue_pool_iter, &range_iter); + &pdn_iter, &range_iter); ogs_assert(ogs_yaml_iter_type(&range_iter) != YAML_MAPPING_NODE); do { @@ -631,7 +645,7 @@ int pgw_context_parse_config(void) ogs_yaml_iter_type(&range_iter) == YAML_SEQUENCE_NODE); } else - ogs_warn("unknown key `%s`", ue_pool_key); + ogs_warn("unknown key `%s`", pdn_key); } if (ipstr && mask_or_numbits) { @@ -649,7 +663,7 @@ int pgw_context_parse_config(void) ipstr, mask_or_numbits, apn); } - } while (ogs_yaml_iter_type(&ue_pool_array) == + } while (ogs_yaml_iter_type(&pdn_array) == YAML_SEQUENCE_NODE); } else if (!strcmp(pgw_key, "mtu")) { ogs_assert(ogs_yaml_iter_type(&pgw_iter) != @@ -790,14 +804,7 @@ pgw_sess_t *pgw_sess_add( /* Set APN */ ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); - ogs_list_init(&sess->bearer_list); - - ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); - - bearer = pgw_bearer_add(sess); - ogs_assert(bearer); - bearer->ebi = ebi; - + /* Set UE IP Address */ sess->pdn.paa.pdn_type = pdn_type; ogs_assert(pdn_type == paa->pdn_type); @@ -834,16 +841,22 @@ pgw_sess_t *pgw_sess_add( ogs_assert_if_reached(); ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]", - sess->imsi_bcd, - apn, - sess->ipv4 ? INET_NTOP(&sess->ipv4->addr, buf1) : "", - sess->ipv6 ? INET6_NTOP(&sess->ipv6->addr, buf2) : ""); + sess->imsi_bcd, apn, + sess->ipv4 ? INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? INET6_NTOP(&sess->ipv6->addr, buf2) : ""); - /* Generate Hash Key : IMSI + APN */ + /* Generate Hash Key : IMSI + APN */ sess_hash_keygen(sess->hash_keybuf, &sess->hash_keylen, imsi, imsi_len, apn); ogs_hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, sess); + /* Set Default Bearer */ + ogs_list_init(&sess->bearer_list); + + bearer = pgw_bearer_add(sess); + ogs_assert(bearer); + bearer->ebi = ebi; + ogs_list_add(&self.sess_list, sess); stats_add_session(); @@ -857,6 +870,10 @@ int pgw_sess_remove(pgw_sess_t *sess) ogs_list_remove(&self.sess_list, sess); + OGS_TLV_CLEAR_DATA(&sess->ue_pco); + OGS_TLV_CLEAR_DATA(&sess->user_location_information); + OGS_TLV_CLEAR_DATA(&sess->ue_timezone); + ogs_hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL); if (sess->ipv4) { @@ -1256,7 +1273,7 @@ int pgw_ue_pool_generate(void) rv = ogs_ipsubnet( &high, subnet->range[rangeindex].high, NULL); ogs_assert(rv == OGS_OK); - high.sub[lastindex] += htonl(1); + high.sub[lastindex] += htobe32(1); memcpy(end, high.sub, maxbytes); } else { memcpy(end, broadcast, maxbytes); @@ -1272,7 +1289,7 @@ int pgw_ue_pool_generate(void) ue_ip->subnet = subnet; memcpy(ue_ip->addr, start, maxbytes); - ue_ip->addr[lastindex] += htonl(inc); + ue_ip->addr[lastindex] += htobe32(inc); inc++; if (memcmp(ue_ip->addr, end, maxbytes) == 0) diff --git a/src/pgw/pgw-context.h b/src/pgw/pgw-context.h index a53ae3241..0bff25aaa 100644 --- a/src/pgw/pgw-context.h +++ b/src/pgw/pgw-context.h @@ -124,12 +124,8 @@ typedef struct pgw_subnet_s { #define MAX_NUM_OF_SUBNET_RANGE 16 struct { -#if 0 - ogs_ipsubnet_t low, high; -#else const char *low; const char *high; -#endif } range[MAX_NUM_OF_SUBNET_RANGE]; int num_of_range; @@ -159,14 +155,13 @@ typedef struct pgw_sess_s { pgw_ue_ip_t* ipv4; pgw_ue_ip_t* ipv6; - /* User Location Information */ - int uli_type; - ogs_tai_t tai; - ogs_e_cgi_t e_cgi; - uint8_t hash_keybuf[OGS_MAX_IMSI_LEN+OGS_MAX_APN_LEN+1]; int hash_keylen; + ogs_tlv_octet_t ue_pco; /* Save Protocol Configuration Options from UE */ + ogs_tlv_octet_t user_location_information; /* User Location Information */ + ogs_tlv_octet_t ue_timezone; /* UE Timezone */ + ogs_list_t bearer_list; /* Related Context */ @@ -295,7 +290,6 @@ pgw_subnet_t *pgw_subnet_next(pgw_subnet_t *subnet); int pgw_subnet_remove(pgw_subnet_t *subnet); void pgw_subnet_remove_all(void); pgw_subnet_t *pgw_subnet_first(void); -pgw_subnet_t *gw_subnet_next(pgw_subnet_t *subnet); void stats_add_session(void); void stats_remove_session(void); diff --git a/src/pgw/pgw-event.h b/src/pgw/pgw-event.h index 0953dfb6b..8aa19bf6d 100644 --- a/src/pgw/pgw-event.h +++ b/src/pgw/pgw-event.h @@ -42,8 +42,7 @@ typedef enum { typedef struct pgw_event_s { int id; - ogs_pkbuf_t *gtpbuf; - ogs_pkbuf_t *gxbuf; + ogs_pkbuf_t *pkbuf; ogs_gtp_node_t *gnode; ogs_gtp_xact_t *xact; diff --git a/src/pgw/pgw-fd-path.c b/src/pgw/pgw-fd-path.c index 03fdd2340..80d7e1e83 100644 --- a/src/pgw/pgw-fd-path.c +++ b/src/pgw/pgw-fd-path.c @@ -30,7 +30,6 @@ struct sess_state { #define MAX_CC_REQUEST_NUMBER 32 pgw_sess_t *sess; ogs_gtp_xact_t *xact[MAX_CC_REQUEST_NUMBER]; - ogs_pkbuf_t *gtpbuf[MAX_CC_REQUEST_NUMBER]; uint32_t cc_request_type; uint32_t cc_request_number; @@ -62,7 +61,7 @@ static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) } void pgw_gx_send_ccr(pgw_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_pkbuf_t *gtpbuf, uint32_t cc_request_type) + uint32_t cc_request_type) { int ret; @@ -73,14 +72,10 @@ void pgw_gx_send_ccr(pgw_sess_t *sess, ogs_gtp_xact_t *xact, struct sess_state *sess_data = NULL, *svg; struct session *session = NULL; int new; - ogs_gtp_message_t *message = NULL; ogs_paa_t paa; /* For changing Framed-IPv6-Prefix Length to 128 */ ogs_assert(sess); ogs_assert(sess->ipv4 || sess->ipv6); - ogs_assert(gtpbuf); - message = (ogs_gtp_message_t *)gtpbuf->data; - ogs_assert(message); ogs_debug("[Credit-Control-Request]"); @@ -162,7 +157,6 @@ void pgw_gx_send_ccr(pgw_sess_t *sess, ogs_gtp_xact_t *xact, /* Update session state */ sess_data->sess = sess; sess_data->xact[sess_data->cc_request_number] = xact; - sess_data->gtpbuf[sess_data->cc_request_number] = gtpbuf; /* Set Origin-Host & Origin-Realm */ ret = fd_msg_add_origin(req, 0); @@ -349,7 +343,8 @@ void pgw_gx_send_ccr(pgw_sess_t *sess, ogs_gtp_xact_t *xact, 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); + 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); @@ -383,35 +378,49 @@ void pgw_gx_send_ccr(pgw_sess_t *sess, ogs_gtp_xact_t *xact, ogs_assert(ret == 0); /* Set 3GPP-User-Location-Info */ - if (sess->uli_type) { - ogs_gtp_tlv_uli_t *user_location_information = - &message->create_session_request.user_location_information; + if (sess->user_location_information.presence) { + ogs_gtp_uli_t uli; + int16_t uli_len; + uint8_t uli_buf[OGS_GTP_MAX_ULI_LEN]; - ogs_assert(user_location_information->data); - ogs_assert(user_location_information->len); - memcpy(&uli_buf, user_location_information->data, - user_location_information->len); + uli_len = ogs_gtp_parse_uli(&uli, &sess->user_location_information); + ogs_assert(sess->user_location_information.len == uli_len); + + ogs_assert(sess->user_location_information.data); + ogs_assert(sess->user_location_information.len); + memcpy(&uli_buf, sess->user_location_information.data, + sess->user_location_information.len); /* Update Gx ULI Type */ - uli_buf[0] = sess->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; - 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 = 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); + 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->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 (message->create_session_request.ue_time_zone.presence) { + if (sess->ue_timezone.presence && + sess->ue_timezone.len && sess->ue_timezone.data) { ret = fd_msg_avp_new(ogs_diam_gx_3gpp_ms_timezone, 0, &avp); ogs_assert(ret == 0); - val.os.data = message->create_session_request.ue_time_zone.data; - val.os.len = message->create_session_request.ue_time_zone.len; + val.os.data = sess->ue_timezone.data; + val.os.len = sess->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); @@ -467,9 +476,9 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) pgw_event_t *e = NULL; ogs_gtp_xact_t *xact = NULL; pgw_sess_t *sess = NULL; - ogs_pkbuf_t *gxbuf = NULL, *gtpbuf = NULL; + ogs_pkbuf_t *pkbuf = NULL; ogs_diam_gx_message_t *gx_message = NULL; - uint16_t gxbuf_len = 0; + uint16_t pkbuf_len = 0; uint32_t cc_request_number = 0; ogs_debug("[Credit-Control-Answer]"); @@ -509,18 +518,16 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) ogs_assert(xact); sess = sess_data->sess; ogs_assert(sess); - gtpbuf = sess_data->gtpbuf[cc_request_number]; - ogs_assert(gtpbuf); - gxbuf_len = sizeof(ogs_diam_gx_message_t); - ogs_assert(gxbuf_len < 8192); - gxbuf = ogs_pkbuf_alloc(NULL, gxbuf_len); - ogs_pkbuf_put(gxbuf, gxbuf_len); - gx_message = (ogs_diam_gx_message_t *)gxbuf->data; + pkbuf_len = sizeof(ogs_diam_gx_message_t); + ogs_assert(pkbuf_len < 8192); + pkbuf = ogs_pkbuf_alloc(NULL, pkbuf_len); + ogs_pkbuf_put(pkbuf, pkbuf_len); + gx_message = (ogs_diam_gx_message_t *)pkbuf->data; ogs_assert(gx_message); /* Set Credit Control Command */ - memset(gx_message, 0, gxbuf_len); + memset(gx_message, 0, pkbuf_len); gx_message->cmd_code = OGS_DIAM_GX_CMD_CODE_CREDIT_CONTROL; /* Value of Result Code */ @@ -536,7 +543,8 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) 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); + 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); @@ -598,14 +606,16 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) 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); + 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->pdn.ambr.uplink = hdr->avp_value->u32; } - ret = fd_avp_search_avp(avp, ogs_diam_gx_apn_aggregate_max_bitrate_dl, &avpch1); + 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); @@ -625,7 +635,8 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) gx_message->pdn.qos.qci = hdr->avp_value->u32; } - ret = fd_avp_search_avp(avp, ogs_diam_gx_allocation_retention_priority, &avpch1); + 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); @@ -636,7 +647,8 @@ static void pgw_gx_cca_cb(void *data, struct msg **msg) gx_message->pdn.qos.arp.priority_level = hdr->avp_value->u32; } - ret = fd_avp_search_avp(avpch1, ogs_diam_gx_pre_emption_capability, &avpch2); + 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); @@ -719,23 +731,20 @@ out: ogs_assert(e); e->sess = sess; - e->gxbuf = gxbuf; + e->pkbuf = pkbuf; e->xact = xact; - e->gtpbuf = gtpbuf; rv = ogs_queue_push(pgw_self()->queue, e); if (rv != OGS_OK) { ogs_error("ogs_queue_push() failed:%d", (int)rv); ogs_diam_gx_message_free(gx_message); - ogs_pkbuf_free(e->gxbuf); - ogs_pkbuf_free(e->gtpbuf); + ogs_pkbuf_free(e->pkbuf); pgw_event_free(e); } else { ogs_pollset_notify(pgw_self()->pollset); } } else { ogs_diam_gx_message_free(gx_message); - ogs_pkbuf_free(gxbuf); - ogs_pkbuf_free(gtpbuf); + ogs_pkbuf_free(pkbuf); } /* Free the message */ @@ -777,7 +786,8 @@ out: 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 && + 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); @@ -817,8 +827,8 @@ static int pgw_gx_rar_cb( struct msg **msg, struct avp *avp, struct sess_state *sess_data = NULL; pgw_event_t *e = NULL; - uint16_t gxbuf_len = 0; - ogs_pkbuf_t *gxbuf = NULL; + uint16_t pkbuf_len = 0; + ogs_pkbuf_t *pkbuf = NULL; pgw_sess_t *sess = NULL; ogs_diam_gx_message_t *gx_message = NULL; @@ -828,15 +838,15 @@ static int pgw_gx_rar_cb( struct msg **msg, struct avp *avp, 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_pkbuf_put(gxbuf, gxbuf_len); - gx_message = (ogs_diam_gx_message_t *)gxbuf->data; + pkbuf_len = sizeof(ogs_diam_gx_message_t); + ogs_assert(pkbuf_len < 8192); + pkbuf = ogs_pkbuf_alloc(NULL, pkbuf_len); + ogs_pkbuf_put(pkbuf, pkbuf_len); + gx_message = (ogs_diam_gx_message_t *)pkbuf->data; ogs_assert(gx_message); /* Set Credit Control Command */ - memset(gx_message, 0, gxbuf_len); + memset(gx_message, 0, pkbuf_len); gx_message->cmd_code = OGS_DIAM_GX_CMD_RE_AUTH; /* Create answer header */ @@ -947,12 +957,12 @@ static int pgw_gx_rar_cb( struct msg **msg, struct avp *avp, ogs_assert(e); e->sess = sess; - e->gxbuf = gxbuf; + e->pkbuf = pkbuf; rv = ogs_queue_push(pgw_self()->queue, e); if (rv != OGS_OK) { ogs_error("ogs_queue_push() failed:%d", (int)rv); ogs_diam_gx_message_free(gx_message); - ogs_pkbuf_free(e->gxbuf); + ogs_pkbuf_free(e->pkbuf); pgw_event_free(e); } else { ogs_pollset_notify(pgw_self()->pollset); @@ -1008,7 +1018,7 @@ out: ogs_assert(ret == 0); ogs_diam_gx_message_free(gx_message); - ogs_pkbuf_free(gxbuf); + ogs_pkbuf_free(pkbuf); return 0; } @@ -1080,8 +1090,7 @@ static int decode_pcc_rule_definition( ogs_assert(ret == 0); switch (hdr->avp_code) { case OGS_DIAM_GX_AVP_CODE_CHARGING_RULE_NAME: - if (pcc_rule->name) - { + if (pcc_rule->name) { ogs_error("PCC Rule Name has already been defined"); ogs_free(pcc_rule->name); } @@ -1095,17 +1104,16 @@ static int decode_pcc_rule_definition( ret = fd_avp_search_avp(avpch2, ogs_diam_gx_flow_direction, &avpch3); ogs_assert(ret == 0); - if (avpch3) - { + 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); + ret = fd_avp_search_avp( + avpch2, ogs_diam_gx_flow_description, &avpch3); ogs_assert(ret == 0); - if (avpch3) - { + if (avpch3) { ret = fd_msg_avp_hdr(avpch3, &hdr); ogs_assert(ret == 0); flow->description = ogs_malloc(hdr->avp_value->os.len+1); @@ -1137,7 +1145,8 @@ static int decode_pcc_rule_definition( 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); + 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); diff --git a/src/pgw/pgw-fd-path.h b/src/pgw/pgw-fd-path.h index 8b2541673..110b27fba 100644 --- a/src/pgw/pgw-fd-path.h +++ b/src/pgw/pgw-fd-path.h @@ -32,7 +32,7 @@ int pgw_fd_init(void); void pgw_fd_final(void); void pgw_gx_send_ccr(pgw_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_pkbuf_t *gtpbuf, uint32_t cc_request_type); + uint32_t cc_request_type); #ifdef __cplusplus } diff --git a/src/pgw/pgw-gtp-path.c b/src/pgw/pgw-gtp-path.c index f5674dae0..8f853aae8 100644 --- a/src/pgw/pgw-gtp-path.c +++ b/src/pgw/pgw-gtp-path.c @@ -117,12 +117,12 @@ static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data) } ogs_assert(e); e->gnode = gnode; - e->gtpbuf = pkbuf; + e->pkbuf = pkbuf; rv = ogs_queue_push(pgw_self()->queue, e); if (rv != OGS_OK) { ogs_error("ogs_queue_push() failed:%d", (int)rv); - ogs_pkbuf_free(e->gtpbuf); + ogs_pkbuf_free(e->pkbuf); pgw_event_free(e); } } @@ -161,7 +161,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) gtp_h = (ogs_gtp_header_t *)pkbuf->data; if (gtp_h->flags & OGS_GTPU_FLAGS_S) len += 4; - teid = ntohl(gtp_h->teid); + teid = be32toh(gtp_h->teid); ogs_debug("[PGW] RECV GPU-U from SGW : TEID[0x%x]", teid); @@ -423,12 +423,12 @@ static int pgw_gtp_send_to_bearer(pgw_bearer_t *bearer, ogs_pkbuf_t *sendbuf) */ gtp_h->flags = 0x30; gtp_h->type = OGS_GTPU_MSGTYPE_GPDU; - gtp_h->length = htons(sendbuf->len - OGS_GTPV1U_HEADER_LEN); - gtp_h->teid = htonl(bearer->sgw_s5u_teid); + gtp_h->length = htobe16(sendbuf->len - OGS_GTPV1U_HEADER_LEN); + gtp_h->teid = htobe32(bearer->sgw_s5u_teid); /* Send to SGW */ ogs_debug("[PGW] SEND GPU-U to SGW[%s] : TEID[0x%x]", - OGS_ADDR(&bearer->gnode->remote_addr, buf), + OGS_ADDR(&bearer->gnode->addr, buf), bearer->sgw_s5u_teid); rv = ogs_gtp_sendto(bearer->gnode, sendbuf); @@ -486,7 +486,7 @@ static int pgw_gtp_send_router_advertisement( advert_h->nd_ra_code = 0; advert_h->nd_ra_curhoplimit = 64; advert_h->nd_ra_flags_reserved = 0; - advert_h->nd_ra_router_lifetime = htons(64800); /* 64800s */ + advert_h->nd_ra_router_lifetime = htobe16(64800); /* 64800s */ advert_h->nd_ra_reachable = 0; advert_h->nd_ra_retransmit = 0; @@ -495,13 +495,13 @@ static int pgw_gtp_send_router_advertisement( prefix->nd_opt_pi_prefix_len = subnet->prefixlen; prefix->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO; - prefix->nd_opt_pi_valid_time = htonl(0xffffffff); /* Infinite */ - prefix->nd_opt_pi_preferred_time = htonl(0xffffffff); /* Infinite */ + prefix->nd_opt_pi_valid_time = htobe32(0xffffffff); /* Infinite */ + prefix->nd_opt_pi_preferred_time = htobe32(0xffffffff); /* Infinite */ memcpy(prefix->nd_opt_pi_prefix.s6_addr, subnet->sub.sub, sizeof prefix->nd_opt_pi_prefix.s6_addr); /* For IPv6 Pseudo-Header */ - plen = htons(sizeof *advert_h + sizeof *prefix); + plen = htobe16(sizeof *advert_h + sizeof *prefix); nxt = IPPROTO_ICMPV6; memcpy(p, src_ipsub.sub, sizeof src_ipsub.sub); @@ -512,7 +512,7 @@ static int pgw_gtp_send_router_advertisement( p += 3; *p = nxt; p += 1; advert_h->nd_ra_cksum = in_cksum((uint16_t *)pkbuf->data, pkbuf->len); - ip6_h->ip6_flow = htonl(0x60000001); + ip6_h->ip6_flow = htobe32(0x60000001); ip6_h->ip6_plen = plen; ip6_h->ip6_nxt = nxt; /* ICMPv6 */ ip6_h->ip6_hlim = 0xff; diff --git a/src/pgw/pgw-gx-handler.c b/src/pgw/pgw-gx-handler.c index 2a15121c7..5ac95422a 100644 --- a/src/pgw/pgw-gx-handler.c +++ b/src/pgw/pgw-gx-handler.c @@ -62,7 +62,7 @@ static uint8_t gtp_cause_from_diameter( void pgw_gx_handle_cca_initial_request( pgw_sess_t *sess, ogs_diam_gx_message_t *gx_message, - ogs_gtp_xact_t *xact, ogs_gtp_create_session_request_t *req) + ogs_gtp_xact_t *xact) { int rv; ogs_gtp_header_t h; @@ -71,7 +71,6 @@ void pgw_gx_handle_cca_initial_request( ogs_assert(sess); ogs_assert(gx_message); ogs_assert(xact); - ogs_assert(req); ogs_debug("[PGW] Create Session Response"); ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", @@ -86,13 +85,12 @@ void pgw_gx_handle_cca_initial_request( return; } - /* Send Create Session Request with Creating Default Bearer */ memset(&h, 0, sizeof(ogs_gtp_header_t)); h.type = OGS_GTP_CREATE_SESSION_RESPONSE_TYPE; h.teid = sess->sgw_s5c_teid; pkbuf = pgw_s5c_build_create_session_response( - h.type, sess, gx_message, req); + h.type, sess, gx_message); ogs_expect_or_return(pkbuf); rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); @@ -106,7 +104,7 @@ void pgw_gx_handle_cca_initial_request( void pgw_gx_handle_cca_termination_request( pgw_sess_t *sess, ogs_diam_gx_message_t *gx_message, - ogs_gtp_xact_t *xact, ogs_gtp_delete_session_request_t *req) + ogs_gtp_xact_t *xact) { int rv; ogs_gtp_header_t h; @@ -116,7 +114,6 @@ void pgw_gx_handle_cca_termination_request( ogs_assert(xact); ogs_assert(sess); ogs_assert(gx_message); - ogs_assert(req); /* backup sgw_s5c_teid in session context */ sgw_s5c_teid = sess->sgw_s5c_teid; @@ -142,7 +139,7 @@ void pgw_gx_handle_cca_termination_request( h.teid = sgw_s5c_teid; pkbuf = pgw_s5c_build_delete_session_response( - h.type, gx_message, req); + h.type, sess, gx_message); ogs_expect_or_return(pkbuf); rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); @@ -330,7 +327,7 @@ static void bearer_binding(pgw_sess_t *sess, ogs_diam_gx_message_t *gx_message) /* Update QoS parameter */ memcpy(&bearer->qos, &pcc_rule->qos, sizeof(ogs_qos_t)); - /* Update Bearer Request will encode updated QoS parameter */ + /* Update Bearer Request encodes updated QoS parameter */ qos_presence = 1; } diff --git a/src/pgw/pgw-gx-handler.h b/src/pgw/pgw-gx-handler.h index 2688b2133..4f8fef7de 100644 --- a/src/pgw/pgw-gx-handler.h +++ b/src/pgw/pgw-gx-handler.h @@ -28,10 +28,10 @@ extern "C" { void pgw_gx_handle_cca_initial_request( pgw_sess_t *sess, ogs_diam_gx_message_t *gx_message, - ogs_gtp_xact_t *xact, ogs_gtp_create_session_request_t *req); + ogs_gtp_xact_t *xact); void pgw_gx_handle_cca_termination_request( pgw_sess_t *sess, ogs_diam_gx_message_t *gx_message, - ogs_gtp_xact_t *xact, ogs_gtp_delete_session_request_t *req); + ogs_gtp_xact_t *xact); void pgw_gx_handle_re_auth_request( pgw_sess_t *sess, ogs_diam_gx_message_t *gx_message); diff --git a/src/pgw/pgw-ipfw.c b/src/pgw/pgw-ipfw.c index fd5d7fa99..e13e271c7 100644 --- a/src/pgw/pgw-ipfw.c +++ b/src/pgw/pgw-ipfw.c @@ -175,7 +175,7 @@ static int decode_ipv6_header( nxt = ip6_h->ip6_nxt; p = (uint8_t *)ip6_h + sizeof(*ip6_h); - endp = p + ntohs(ip6_h->ip6_plen); + endp = p + be16toh(ip6_h->ip6_plen); jp = p + sizeof(struct ip6_hbh); while (p == endp) { /* Jumbo Frame */ @@ -186,7 +186,7 @@ static int decode_ipv6_header( jumbo = (struct ip6_opt_jumbo *)jp; memcpy(&jp_len, jumbo->ip6oj_jumbo_len, sizeof(jp_len)); - jp_len = ntohl(jp_len); + jp_len = be32toh(jp_len); switch (jumbo->ip6oj_type) { case IP6OPT_JUMBO: endp = p + jp_len; @@ -279,11 +279,11 @@ pgw_bearer_t *pgw_bearer_find_by_packet(ogs_pkbuf_t *pkt) ogs_error("Invalid IP version = %d", ip_h->ip_v); ogs_debug("[PGW] PROTO:%d SRC:%08x %08x %08x %08x", - proto, ntohl(src_addr[0]), ntohl(src_addr[1]), - ntohl(src_addr[2]), ntohl(src_addr[3])); + proto, be32toh(src_addr[0]), be32toh(src_addr[1]), + be32toh(src_addr[2]), be32toh(src_addr[3])); ogs_debug("[PGW] HLEN:%d DST:%08x %08x %08x %08x", - ip_hlen, ntohl(dst_addr[0]), ntohl(dst_addr[1]), - ntohl(dst_addr[2]), ntohl(dst_addr[3])); + ip_hlen, be32toh(dst_addr[0]), be32toh(dst_addr[1]), + be32toh(dst_addr[2]), be32toh(dst_addr[3])); if (sess) { pgw_bearer_t *default_bearer = NULL; @@ -325,23 +325,23 @@ pgw_bearer_t *pgw_bearer_find_by_packet(ogs_pkbuf_t *pkt) pf->rule.port.remote.low, pf->rule.port.remote.high); ogs_debug("SRC:%08x %08x %08x %08x/%08x %08x %08x %08x", - ntohl(pf->rule.ip.local.addr[0]), - ntohl(pf->rule.ip.local.addr[1]), - ntohl(pf->rule.ip.local.addr[2]), - ntohl(pf->rule.ip.local.addr[3]), - ntohl(pf->rule.ip.local.mask[0]), - ntohl(pf->rule.ip.local.mask[1]), - ntohl(pf->rule.ip.local.mask[2]), - ntohl(pf->rule.ip.local.mask[3])); + be32toh(pf->rule.ip.local.addr[0]), + be32toh(pf->rule.ip.local.addr[1]), + be32toh(pf->rule.ip.local.addr[2]), + be32toh(pf->rule.ip.local.addr[3]), + be32toh(pf->rule.ip.local.mask[0]), + be32toh(pf->rule.ip.local.mask[1]), + be32toh(pf->rule.ip.local.mask[2]), + be32toh(pf->rule.ip.local.mask[3])); ogs_debug("DST:%08x %08x %08x %08x/%08x %08x %08x %08x", - ntohl(pf->rule.ip.remote.addr[0]), - ntohl(pf->rule.ip.remote.addr[1]), - ntohl(pf->rule.ip.remote.addr[2]), - ntohl(pf->rule.ip.remote.addr[3]), - ntohl(pf->rule.ip.remote.mask[0]), - ntohl(pf->rule.ip.remote.mask[1]), - ntohl(pf->rule.ip.remote.mask[2]), - ntohl(pf->rule.ip.remote.mask[3])); + be32toh(pf->rule.ip.remote.addr[0]), + be32toh(pf->rule.ip.remote.addr[1]), + be32toh(pf->rule.ip.remote.addr[2]), + be32toh(pf->rule.ip.remote.addr[3]), + be32toh(pf->rule.ip.remote.mask[0]), + be32toh(pf->rule.ip.remote.mask[1]), + be32toh(pf->rule.ip.remote.mask[2]), + be32toh(pf->rule.ip.remote.mask[3])); if (pf->direction != 1) { continue; @@ -370,26 +370,26 @@ pgw_bearer_t *pgw_bearer_find_by_packet(ogs_pkbuf_t *pkt) /* Source port */ if (pf->rule.port.local.low && - ntohs(tcph->th_sport) < + be16toh(tcph->th_sport) < pf->rule.port.local.low) { continue; } if (pf->rule.port.local.high && - ntohs(tcph->th_sport) > + be16toh(tcph->th_sport) > pf->rule.port.local.high) { continue; } /* Dst Port*/ if (pf->rule.port.remote.low && - ntohs(tcph->th_dport) < + be16toh(tcph->th_dport) < pf->rule.port.remote.low) { continue; } if (pf->rule.port.remote.high && - ntohs(tcph->th_dport) > + be16toh(tcph->th_dport) > pf->rule.port.remote.high) { continue; } @@ -403,26 +403,26 @@ pgw_bearer_t *pgw_bearer_find_by_packet(ogs_pkbuf_t *pkt) /* Source port */ if (pf->rule.port.local.low && - ntohs(udph->uh_sport) < + be16toh(udph->uh_sport) < pf->rule.port.local.low) { continue; } if (pf->rule.port.local.high && - ntohs(udph->uh_sport) > + be16toh(udph->uh_sport) > pf->rule.port.local.high) { continue; } /* Dst Port*/ if (pf->rule.port.remote.low && - ntohs(udph->uh_dport) < + be16toh(udph->uh_dport) < pf->rule.port.remote.low) { continue; } if (pf->rule.port.remote.high && - ntohs(udph->uh_dport) > + be16toh(udph->uh_dport) > pf->rule.port.remote.high) { continue; } diff --git a/src/pgw/pgw-s5c-build.c b/src/pgw/pgw-s5c-build.c index 96cd1804c..4c9863287 100644 --- a/src/pgw/pgw-s5c-build.c +++ b/src/pgw/pgw-s5c-build.c @@ -26,8 +26,7 @@ static int16_t pgw_pco_build(uint8_t *pco_buf, ogs_gtp_tlv_pco_t *tlv_pco); ogs_pkbuf_t *pgw_s5c_build_create_session_response( uint8_t type, pgw_sess_t *sess, - ogs_diam_gx_message_t *gx_message, - ogs_gtp_create_session_request_t *req) + ogs_diam_gx_message_t *gx_message) { int rv; pgw_bearer_t *bearer = NULL; @@ -44,13 +43,12 @@ ogs_pkbuf_t *pgw_s5c_build_create_session_response( ogs_debug("[PGW] Create Session Response"); ogs_assert(sess); - ogs_assert(req); bearer = pgw_default_bearer_in_sess(sess); ogs_assert(bearer); ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", sess->sgw_s5c_teid, sess->pgw_s5c_teid); - ogs_debug(" SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]", + ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); rsp = >p_message.create_session_response; @@ -66,7 +64,7 @@ ogs_pkbuf_t *pgw_s5c_build_create_session_response( /* Control Plane(UL) : PGW-S5C */ memset(&pgw_s5c_teid, 0, sizeof(ogs_gtp_f_teid_t)); pgw_s5c_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_C; - pgw_s5c_teid.teid = htonl(sess->pgw_s5c_teid); + pgw_s5c_teid.teid = htobe32(sess->pgw_s5c_teid); rv = ogs_gtp_sockaddr_to_f_teid( pgw_self()->gtpc_addr, pgw_self()->gtpc_addr6, &pgw_s5c_teid, &len); ogs_assert(rv == OGS_OK); @@ -97,8 +95,8 @@ ogs_pkbuf_t *pgw_s5c_build_create_session_response( * if PCRF changes APN-AMBR, this should be included. */ /* PCO */ - if (req->protocol_configuration_options.presence == 1) { - pco_len = pgw_pco_build(pco_buf, &req->protocol_configuration_options); + if (sess->ue_pco.presence && sess->ue_pco.len && sess->ue_pco.data) { + pco_len = pgw_pco_build(pco_buf, &sess->ue_pco); ogs_assert(pco_len > 0); rsp->protocol_configuration_options.presence = 1; rsp->protocol_configuration_options.data = pco_buf; @@ -121,7 +119,7 @@ ogs_pkbuf_t *pgw_s5c_build_create_session_response( /* Data Plane(UL) : PGW-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 = htonl(bearer->pgw_s5u_teid); + pgw_s5u_teid.teid = htobe32(bearer->pgw_s5u_teid); rv = ogs_gtp_sockaddr_to_f_teid( pgw_self()->gtpu_addr, pgw_self()->gtpu_addr6, &pgw_s5u_teid, &len); ogs_assert(rv == OGS_OK); @@ -134,8 +132,8 @@ ogs_pkbuf_t *pgw_s5c_build_create_session_response( } ogs_pkbuf_t *pgw_s5c_build_delete_session_response( - uint8_t type, ogs_diam_gx_message_t *gx_message, - ogs_gtp_delete_session_request_t *req) + uint8_t type, pgw_sess_t *sess, + ogs_diam_gx_message_t *gx_message) { ogs_gtp_message_t gtp_message; ogs_gtp_delete_session_response_t *rsp = NULL; @@ -145,7 +143,6 @@ ogs_pkbuf_t *pgw_s5c_build_delete_session_response( int16_t pco_len; ogs_assert(gx_message); - ogs_assert(req); /* prepare cause */ memset(&cause, 0, sizeof(cause)); @@ -162,8 +159,8 @@ ogs_pkbuf_t *pgw_s5c_build_delete_session_response( /* Recovery */ /* PCO */ - if (req->protocol_configuration_options.presence == 1) { - pco_len = pgw_pco_build(pco_buf, &req->protocol_configuration_options); + if (sess->ue_pco.presence && sess->ue_pco.len && sess->ue_pco.data) { + pco_len = pgw_pco_build(pco_buf, &sess->ue_pco); ogs_assert(pco_len > 0); rsp->protocol_configuration_options.presence = 1; rsp->protocol_configuration_options.data = pco_buf; @@ -218,7 +215,7 @@ ogs_pkbuf_t *pgw_s5c_build_create_bearer_request( /* Data Plane(UL) : PGW_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 = htonl(bearer->pgw_s5u_teid); + pgw_s5u_teid.teid = htobe32(bearer->pgw_s5u_teid); rv = ogs_gtp_sockaddr_to_f_teid( pgw_self()->gtpu_addr, pgw_self()->gtpu_addr6, &pgw_s5u_teid, &len); ogs_assert(rv == OGS_OK); diff --git a/src/pgw/pgw-s5c-build.h b/src/pgw/pgw-s5c-build.h index d5f341872..f047fa6e3 100644 --- a/src/pgw/pgw-s5c-build.h +++ b/src/pgw/pgw-s5c-build.h @@ -28,11 +28,10 @@ extern "C" { ogs_pkbuf_t *pgw_s5c_build_create_session_response( uint8_t type, pgw_sess_t *sess, - ogs_diam_gx_message_t *gx_message, - ogs_gtp_create_session_request_t *req); + ogs_diam_gx_message_t *gx_message); ogs_pkbuf_t *pgw_s5c_build_delete_session_response( - uint8_t type, ogs_diam_gx_message_t *gx_message, - ogs_gtp_delete_session_request_t *req); + uint8_t type, pgw_sess_t *sess, + ogs_diam_gx_message_t *gx_message); ogs_pkbuf_t *pgw_s5c_build_create_bearer_request( uint8_t type, pgw_bearer_t *bearer, ogs_gtp_tft_t *tft); diff --git a/src/pgw/pgw-s5c-handler.c b/src/pgw/pgw-s5c-handler.c index 67711220a..0413e1fdd 100644 --- a/src/pgw/pgw-s5c-handler.c +++ b/src/pgw/pgw-s5c-handler.c @@ -46,7 +46,7 @@ void pgw_s5c_handle_echo_response( void pgw_s5c_handle_create_session_request( pgw_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_pkbuf_t *gtpbuf, ogs_gtp_create_session_request_t *req) + ogs_gtp_create_session_request_t *req) { int rv; uint8_t cause_value = 0; @@ -55,7 +55,6 @@ void pgw_s5c_handle_create_session_request( pgw_bearer_t *bearer = NULL; ogs_gtp_bearer_qos_t bearer_qos; ogs_gtp_ambr_t *ambr = NULL; - ogs_gtp_uli_t uli; uint16_t decoded = 0; ogs_assert(xact); @@ -103,7 +102,6 @@ void pgw_s5c_handle_create_session_request( if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value); - ogs_pkbuf_free(gtpbuf); return; } @@ -115,22 +113,22 @@ void pgw_s5c_handle_create_session_request( /* Control Plane(DL) : SGW-S5C */ sgw_s5c_teid = req->sender_f_teid_for_control_plane.data; ogs_assert(sgw_s5c_teid); - sess->sgw_s5c_teid = ntohl(sgw_s5c_teid->teid); + sess->sgw_s5c_teid = be32toh(sgw_s5c_teid->teid); /* Control 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 = ntohl(sgw_s5u_teid->teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", sess->sgw_s5c_teid, sess->pgw_s5c_teid); - ogs_debug(" SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]", + ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); sgw = ogs_gtp_node_find_by_f_teid(&pgw_self()->sgw_s5u_list, sgw_s5u_teid); if (!sgw) { - sgw = ogs_gtp_node_add(&pgw_self()->sgw_s5u_list, sgw_s5u_teid, - pgw_self()->gtpu_port, + sgw = ogs_gtp_node_add_by_f_teid( + &pgw_self()->sgw_s5u_list, sgw_s5u_teid, pgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); @@ -167,39 +165,30 @@ void pgw_s5c_handle_create_session_request( sess->pdn.ambr.downlink = be32toh(ambr->downlink) * 1000; sess->pdn.ambr.uplink = be32toh(ambr->uplink) * 1000; } - - /* Set User Location Information */ - if (req->user_location_information.presence) { - decoded = ogs_gtp_parse_uli(&uli, &req->user_location_information); - ogs_assert(req->user_location_information.len == decoded); - if (uli.flags.tai && uli.flags.e_cgi) - sess->uli_type = - OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI_AND_ECGI; - else if (uli.flags.tai) - sess->uli_type = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_TAI; - else if (uli.flags.e_cgi) - sess->uli_type = OGS_DIAM_GX_3GPP_USER_LOCATION_INFO_TYPE_ECGI; - - if (uli.flags.tai) { - memcpy(&sess->tai.plmn_id, &uli.tai.plmn_id, - sizeof(uli.tai.plmn_id)); - sess->tai.tac = uli.tai.tac; - } - if (uli.flags.e_cgi) { - memcpy(&sess->e_cgi.plmn_id, &uli.e_cgi.plmn_id, - sizeof(uli.e_cgi.plmn_id)); - sess->e_cgi.cell_id = uli.e_cgi.cell_id; - } + /* PCO */ + if (req->protocol_configuration_options.presence) { + OGS_TLV_STORE_DATA(&sess->ue_pco, &req->protocol_configuration_options); } - pgw_gx_send_ccr(sess, xact, gtpbuf, + /* Set User Location Information */ + if (req->user_location_information.presence) { + OGS_TLV_STORE_DATA(&sess->user_location_information, + &req->user_location_information); + } + + /* Set UE Timezone */ + if (req->ue_time_zone.presence) { + OGS_TLV_STORE_DATA(&sess->ue_timezone, &req->ue_time_zone); + } + + pgw_gx_send_ccr(sess, xact, OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST); } void pgw_s5c_handle_delete_session_request( pgw_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_pkbuf_t *gtpbuf, ogs_gtp_delete_session_request_t *req) + ogs_gtp_delete_session_request_t *req) { uint8_t cause_value = 0; @@ -223,14 +212,13 @@ void pgw_s5c_handle_delete_session_request( if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, OGS_GTP_DELETE_SESSION_RESPONSE_TYPE, cause_value); - ogs_pkbuf_free(gtpbuf); return; } ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", sess->sgw_s5c_teid, sess->pgw_s5c_teid); - pgw_gx_send_ccr(sess, xact, gtpbuf, + pgw_gx_send_ccr(sess, xact, OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST); } @@ -291,7 +279,7 @@ void pgw_s5c_handle_create_bearer_response( ogs_assert(pgw_s5u_teid); /* Find the Bearer by PGW-S5U-TEID */ - bearer = pgw_bearer_find_by_pgw_s5u_teid(ntohl(pgw_s5u_teid->teid)); + bearer = pgw_bearer_find_by_pgw_s5u_teid(be32toh(pgw_s5u_teid->teid)); ogs_assert(bearer); /* Set EBI */ @@ -299,11 +287,11 @@ void pgw_s5c_handle_create_bearer_response( /* Data Plane(DL) : SGW-S5U */ sgw_s5u_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data; - bearer->sgw_s5u_teid = ntohl(sgw_s5u_teid->teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); sgw = ogs_gtp_node_find_by_f_teid(&pgw_self()->sgw_s5u_list, sgw_s5u_teid); if (!sgw) { - sgw = ogs_gtp_node_add(&pgw_self()->sgw_s5u_list, sgw_s5u_teid, - pgw_self()->gtpu_port, + sgw = ogs_gtp_node_add_by_f_teid( + &pgw_self()->sgw_s5u_list, sgw_s5u_teid, pgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); diff --git a/src/pgw/pgw-s5c-handler.h b/src/pgw/pgw-s5c-handler.h index 6b858a87e..431bd3888 100644 --- a/src/pgw/pgw-s5c-handler.h +++ b/src/pgw/pgw-s5c-handler.h @@ -33,10 +33,10 @@ void pgw_s5c_handle_echo_response( void pgw_s5c_handle_create_session_request( pgw_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_pkbuf_t *gtpbuf, ogs_gtp_create_session_request_t *req); + ogs_gtp_create_session_request_t *req); void pgw_s5c_handle_delete_session_request( pgw_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_pkbuf_t *gtpbuf, ogs_gtp_delete_session_request_t *req); + ogs_gtp_delete_session_request_t *req); void pgw_s5c_handle_create_bearer_response( pgw_sess_t *sess, ogs_gtp_xact_t *xact, ogs_gtp_create_bearer_response_t *req); diff --git a/src/pgw/pgw-sm.c b/src/pgw/pgw-sm.c index 671848b3b..e81555e3c 100644 --- a/src/pgw/pgw-sm.c +++ b/src/pgw/pgw-sm.c @@ -45,14 +45,10 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) { int rv; ogs_pkbuf_t *recvbuf = NULL; - ogs_pkbuf_t *copybuf = NULL; - uint16_t copybuf_len = 0; ogs_gtp_xact_t *xact = NULL; - ogs_gtp_message_t *message = NULL; + ogs_gtp_message_t gtp_message; pgw_sess_t *sess = NULL; - ogs_pkbuf_t *gxbuf = NULL; ogs_diam_gx_message_t *gx_message = NULL; - ogs_pkbuf_t *gtpbuf = NULL; ogs_gtp_node_t *gnode = NULL; pgw_sm_debug(e); @@ -70,17 +66,14 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) break; case PGW_EVT_S5C_MESSAGE: ogs_assert(e); - recvbuf = e->gtpbuf; + recvbuf = e->pkbuf; ogs_assert(recvbuf); - copybuf_len = sizeof(ogs_gtp_message_t); - copybuf = ogs_pkbuf_alloc(NULL, copybuf_len); - ogs_pkbuf_put(copybuf, copybuf_len); - message = (ogs_gtp_message_t *)copybuf->data; - ogs_assert(message); - - rv = ogs_gtp_parse_msg(message, recvbuf); - ogs_assert(rv == OGS_OK); + if (ogs_gtp_parse_msg(>p_message, recvbuf) != OGS_OK) { + ogs_error("ogs_gtp_parse_msg() failed"); + ogs_pkbuf_free(recvbuf); + break; + } /* * 5.5.2 in spec 29.274 @@ -111,9 +104,9 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) * However in this case, the cause code shall not be set to * "Context not found". */ - if (message->h.teid_presence && message->h.teid != 0) { + if (gtp_message.h.teid_presence && gtp_message.h.teid != 0) { /* Cause is not "Context not found" */ - sess = pgw_sess_find_by_teid(message->h.teid); + sess = pgw_sess_find_by_teid(gtp_message.h.teid); } if (sess) { @@ -124,59 +117,51 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) ogs_assert(gnode); } - rv = ogs_gtp_xact_receive(gnode, &message->h, &xact); + rv = ogs_gtp_xact_receive(gnode, >p_message.h, &xact); if (rv != OGS_OK) { ogs_pkbuf_free(recvbuf); - ogs_pkbuf_free(copybuf); break; } - switch(message->h.type) { + switch(gtp_message.h.type) { case OGS_GTP_ECHO_REQUEST_TYPE: - pgw_s5c_handle_echo_request(xact, &message->echo_request); - ogs_pkbuf_free(copybuf); + pgw_s5c_handle_echo_request(xact, >p_message.echo_request); break; case OGS_GTP_ECHO_RESPONSE_TYPE: - pgw_s5c_handle_echo_response(xact, &message->echo_response); - ogs_pkbuf_free(copybuf); + pgw_s5c_handle_echo_response(xact, >p_message.echo_response); break; case OGS_GTP_CREATE_SESSION_REQUEST_TYPE: - if (message->h.teid == 0) { - ogs_assert(!sess); - sess = pgw_sess_add_by_message(message); + if (gtp_message.h.teid == 0) { + ogs_expect(!sess); + sess = pgw_sess_add_by_message(>p_message); if (sess) OGS_SETUP_GTP_NODE(sess, gnode); } pgw_s5c_handle_create_session_request( - sess, xact, copybuf, &message->create_session_request); + sess, xact, >p_message.create_session_request); break; case OGS_GTP_DELETE_SESSION_REQUEST_TYPE: pgw_s5c_handle_delete_session_request( - sess, xact, copybuf, &message->delete_session_request); + sess, xact, >p_message.delete_session_request); break; case OGS_GTP_CREATE_BEARER_RESPONSE_TYPE: pgw_s5c_handle_create_bearer_response( - sess, xact, &message->create_bearer_response); - ogs_pkbuf_free(copybuf); + sess, xact, >p_message.create_bearer_response); break; case OGS_GTP_UPDATE_BEARER_RESPONSE_TYPE: pgw_s5c_handle_update_bearer_response( - sess, xact, &message->update_bearer_response); - ogs_pkbuf_free(copybuf); + sess, xact, >p_message.update_bearer_response); break; case OGS_GTP_DELETE_BEARER_RESPONSE_TYPE: pgw_s5c_handle_delete_bearer_response( - sess, xact, &message->delete_bearer_response); - ogs_pkbuf_free(copybuf); + sess, xact, >p_message.delete_bearer_response); break; case OGS_GTP_BEARER_RESOURCE_COMMAND_TYPE: pgw_s5c_handle_bearer_resource_command( - sess, xact, &message->bearer_resource_command); - ogs_pkbuf_free(copybuf); + sess, xact, >p_message.bearer_resource_command); break; default: - ogs_warn("Not implmeneted(type:%d)", message->h.type); - ogs_pkbuf_free(copybuf); + ogs_warn("Not implmeneted(type:%d)", gtp_message.h.type); break; } ogs_pkbuf_free(recvbuf); @@ -185,9 +170,9 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) case PGW_EVT_GX_MESSAGE: ogs_assert(e); - gxbuf = e->gxbuf; - ogs_assert(gxbuf); - gx_message = (ogs_diam_gx_message_t *)gxbuf->data; + recvbuf = e->pkbuf; + ogs_assert(recvbuf); + gx_message = (ogs_diam_gx_message_t *)recvbuf->data; ogs_assert(gx_message); sess = e->sess; @@ -198,27 +183,20 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) xact = e->xact; ogs_assert(xact); - gtpbuf = e->gtpbuf; - ogs_assert(gtpbuf); - message = (ogs_gtp_message_t *)gtpbuf->data; - switch(gx_message->cc_request_type) { case OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST: pgw_gx_handle_cca_initial_request( - sess, gx_message, xact, - &message->create_session_request); + sess, gx_message, xact); break; case OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST: pgw_gx_handle_cca_termination_request( - sess, gx_message, xact, - &message->delete_session_request); + sess, gx_message, xact); break; default: - ogs_error("Not implemented(%d)", gx_message->cc_request_type); + ogs_error("Not implemented(%d)", + gx_message->cc_request_type); break; } - - ogs_pkbuf_free(gtpbuf); break; case OGS_DIAM_GX_CMD_RE_AUTH: pgw_gx_handle_re_auth_request(sess, gx_message); @@ -229,7 +207,7 @@ void pgw_state_operational(ogs_fsm_t *s, pgw_event_t *e) } ogs_diam_gx_message_free(gx_message); - ogs_pkbuf_free(gxbuf); + ogs_pkbuf_free(recvbuf); break; default: ogs_error("No handler for event %s", pgw_event_get_name(e)); diff --git a/src/sgw/sgw-context.h b/src/sgw/sgw-context.h index bf8619fc3..06705b2a7 100644 --- a/src/sgw/sgw-context.h +++ b/src/sgw/sgw-context.h @@ -104,7 +104,6 @@ typedef struct sgw_sess_s { * SGW-S5C-TEID = INDEX | 0x80000000 * INDEX = SGW-S5C-TEID & ~0x80000000 */ -#define SGW_S5C_TEID(__tEID) (__tEID & 0x80000000) #define SGW_S5C_TEID_TO_INDEX(__iNDEX) (__iNDEX & ~0x80000000) #define SGW_S5C_INDEX_TO_TEID(__iNDEX) (__iNDEX | 0x80000000) uint32_t sgw_s5c_teid; /* SGW-S5C-TEID is derived from INDEX */ diff --git a/src/sgw/sgw-gtp-path.c b/src/sgw/sgw-gtp-path.c index 724704793..79936c0f7 100644 --- a/src/sgw/sgw-gtp-path.c +++ b/src/sgw/sgw-gtp-path.c @@ -187,7 +187,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(s5u_tunnel->gnode); ogs_assert(s5u_tunnel->gnode->sock); ogs_debug("[SGW] SEND GPU-U to PGW[%s]: TEID[0x%x]", - OGS_ADDR(&s5u_tunnel->gnode->remote_addr, buf), + OGS_ADDR(&s5u_tunnel->gnode->addr, buf), s5u_tunnel->remote_teid); gtp_h->teid = htonl(s5u_tunnel->remote_teid); @@ -204,7 +204,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(indirect_tunnel->gnode); ogs_assert(indirect_tunnel->gnode->sock); ogs_debug("[SGW] SEND GPU-U to Indirect Tunnel[%s]: TEID[0x%x]", - OGS_ADDR(&indirect_tunnel->gnode->remote_addr, buf), + OGS_ADDR(&indirect_tunnel->gnode->addr, buf), indirect_tunnel->remote_teid); gtp_h->teid = htonl(indirect_tunnel->remote_teid); @@ -219,7 +219,7 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(s1u_tunnel->gnode); ogs_assert(s1u_tunnel->gnode->sock); ogs_debug("[SGW] SEND GPU-U to ENB[%s]: TEID[0x%x]", - OGS_ADDR(&s1u_tunnel->gnode->remote_addr, buf), + OGS_ADDR(&s1u_tunnel->gnode->addr, buf), s1u_tunnel->remote_teid); /* If there is buffered packet, send it first */ @@ -378,7 +378,7 @@ void sgw_gtp_send_end_marker(sgw_tunnel_t *s1u_tunnel) ogs_assert(s1u_tunnel->gnode->sock); ogs_debug("[SGW] SEND End Marker to ENB[%s]: TEID[0x%x]", - OGS_ADDR(&s1u_tunnel->gnode->remote_addr, buf), + OGS_ADDR(&s1u_tunnel->gnode->addr, buf), s1u_tunnel->remote_teid); pkbuf = ogs_pkbuf_alloc(NULL, diff --git a/src/sgw/sgw-s11-handler.c b/src/sgw/sgw-s11-handler.c index 691f331dd..c29a5a7ae 100644 --- a/src/sgw/sgw-s11-handler.c +++ b/src/sgw/sgw-s11-handler.c @@ -155,8 +155,8 @@ void sgw_s11_handle_create_session_request(ogs_gtp_xact_t *s11_xact, pgw = ogs_gtp_node_find_by_f_teid(&sgw_self()->pgw_s5c_list, pgw_s5c_teid); if (!pgw) { - pgw = ogs_gtp_node_add(&sgw_self()->pgw_s5c_list, pgw_s5c_teid, - sgw_self()->gtpc_port, + pgw = ogs_gtp_node_add_by_f_teid( + &sgw_self()->pgw_s5c_list, pgw_s5c_teid, sgw_self()->gtpc_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); @@ -286,8 +286,8 @@ void sgw_s11_handle_modify_bearer_request(ogs_gtp_xact_t *s11_xact, enb = ogs_gtp_node_find_by_f_teid( &sgw_self()->enb_s1u_list, enb_s1u_teid); if (!enb) { - enb = ogs_gtp_node_add(&sgw_self()->enb_s1u_list, enb_s1u_teid, - sgw_self()->gtpu_port, + enb = ogs_gtp_node_add_by_f_teid( + &sgw_self()->enb_s1u_list, enb_s1u_teid, sgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); @@ -347,7 +347,7 @@ void sgw_s11_handle_modify_bearer_request(ogs_gtp_xact_t *s11_xact, ogs_assert(s1u_tunnel->gnode->sock); ogs_debug("[SGW] SEND End Marker to ENB[%s]: TEID[0x%x]", - OGS_ADDR(&s1u_tunnel->gnode->remote_addr, buf), + OGS_ADDR(&s1u_tunnel->gnode->addr, buf), s1u_tunnel->remote_teid); sgw_gtp_send_end_marker(s1u_tunnel); } @@ -550,8 +550,8 @@ void sgw_s11_handle_create_bearer_response(ogs_gtp_xact_t *s11_xact, enb = ogs_gtp_node_find_by_f_teid(&sgw_self()->enb_s1u_list, enb_s1u_teid); if (!enb) { - enb = ogs_gtp_node_add(&sgw_self()->enb_s1u_list, enb_s1u_teid, - sgw_self()->gtpu_port, + enb = ogs_gtp_node_add_by_f_teid( + &sgw_self()->enb_s1u_list, enb_s1u_teid, sgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); @@ -1036,8 +1036,8 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request( enb = ogs_gtp_node_find_by_f_teid( &sgw_self()->enb_s1u_list, req_teid); if (!enb) { - enb = ogs_gtp_node_add(&sgw_self()->enb_s1u_list, req_teid, - sgw_self()->gtpu_port, + enb = ogs_gtp_node_add_by_f_teid( + &sgw_self()->enb_s1u_list, req_teid, sgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); @@ -1076,7 +1076,8 @@ void sgw_s11_handle_create_indirect_data_forwarding_tunnel_request( enb = ogs_gtp_node_find_by_f_teid( &sgw_self()->enb_s1u_list, req_teid); if (!enb) { - enb = ogs_gtp_node_add(&sgw_self()->enb_s1u_list, req_teid, + enb = ogs_gtp_node_add_by_f_teid( + &sgw_self()->enb_s1u_list, req_teid, sgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, diff --git a/src/sgw/sgw-s5c-handler.c b/src/sgw/sgw-s5c-handler.c index 4565b71ff..880a48160 100644 --- a/src/sgw/sgw-s5c-handler.c +++ b/src/sgw/sgw-s5c-handler.c @@ -178,8 +178,8 @@ void sgw_s5c_handle_create_session_response(ogs_gtp_xact_t *s5c_xact, pgw = ogs_gtp_node_find_by_f_teid(&sgw_self()->pgw_s5u_list, pgw_s5u_teid); if (!pgw) { - pgw = ogs_gtp_node_add(&sgw_self()->pgw_s5u_list, pgw_s5u_teid, - sgw_self()->gtpu_port, + pgw = ogs_gtp_node_add_by_f_teid( + &sgw_self()->pgw_s5u_list, pgw_s5u_teid, sgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); @@ -386,8 +386,8 @@ void sgw_s5c_handle_create_bearer_request(ogs_gtp_xact_t *s5c_xact, s5u_tunnel->remote_teid = ntohl(pgw_s5u_teid->teid); pgw = ogs_gtp_node_find_by_f_teid(&sgw_self()->pgw_s5u_list, pgw_s5u_teid); if (!pgw) { - pgw = ogs_gtp_node_add(&sgw_self()->pgw_s5u_list, pgw_s5u_teid, - sgw_self()->gtpu_port, + pgw = ogs_gtp_node_add_by_f_teid( + &sgw_self()->pgw_s5u_list, pgw_s5u_teid, sgw_self()->gtpu_port, ogs_config()->parameter.no_ipv4, ogs_config()->parameter.no_ipv6, ogs_config()->parameter.prefer_ipv4); diff --git a/src/sgw/sgw-sm.c b/src/sgw/sgw-sm.c index 7cb4f0ba1..e07bdcd10 100644 --- a/src/sgw/sgw-sm.c +++ b/src/sgw/sgw-sm.c @@ -89,8 +89,12 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e) ogs_assert(e); pkbuf = e->pkbuf; ogs_assert(pkbuf); - rv = ogs_gtp_parse_msg(&message, pkbuf); - ogs_assert(rv == OGS_OK); + + if (ogs_gtp_parse_msg(&message, pkbuf) != OGS_OK) { + ogs_error("ogs_gtp_parse_msg() failed"); + ogs_pkbuf_free(pkbuf); + break; + } if (message.h.teid_presence && message.h.teid != 0) { /* Cause is not "Context not found" */ @@ -120,7 +124,7 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e) break; case OGS_GTP_CREATE_SESSION_REQUEST_TYPE: if (message.h.teid == 0) { - ogs_assert(!sgw_ue); + ogs_expect(!sgw_ue); sgw_ue = sgw_ue_add_by_message(&message); if (sgw_ue) OGS_SETUP_GTP_NODE(sgw_ue, gnode); @@ -178,10 +182,13 @@ void sgw_state_operational(ogs_fsm_t *s, sgw_event_t *e) case SGW_EVT_S5C_MESSAGE: ogs_assert(e); pkbuf = e->pkbuf; - ogs_assert(pkbuf); - rv = ogs_gtp_parse_msg(&message, pkbuf); - ogs_assert(rv == OGS_OK); + + if (ogs_gtp_parse_msg(&message, pkbuf) != OGS_OK) { + ogs_error("ogs_gtp_parse_msg() failed"); + ogs_pkbuf_free(pkbuf); + break; + } if (message.h.teid_presence && message.h.teid != 0) { sess = sgw_sess_find_by_teid(message.h.teid); diff --git a/src/smf/app.c b/src/smf/app.c new file mode 100644 index 000000000..0f8a242ab --- /dev/null +++ b/src/smf/app.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-app.h" + +int app_initialize(const char *const argv[]) +{ + int rv; + + rv = smf_initialize(); + if (rv != OGS_OK) { + ogs_error("Failed to intialize SMF"); + return rv; + } + ogs_info("SMF initialize...done"); + + return OGS_OK; +} + +void app_terminate(void) +{ + smf_terminate(); + ogs_info("SMF terminate...done"); +} diff --git a/src/smf/bearer-binding.c b/src/smf/bearer-binding.c new file mode 100644 index 000000000..46afd49ec --- /dev/null +++ b/src/smf/bearer-binding.c @@ -0,0 +1,349 @@ +/* + * 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 "bearer-binding.h" +#include "s5c-build.h" + +#include "ipfw/ipfw2.h" + +static void timeout(ogs_gtp_xact_t *xact, void *data) +{ + smf_sess_t *sess = data; + uint8_t type = 0; + + ogs_assert(sess); + + type = xact->seq[0].type; + + ogs_debug("GTP Timeout : SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x] " + "Message-Type[%d]", sess->sgw_s5c_teid, sess->smf_n4_teid, type); +} + +static void encode_traffic_flow_template( + ogs_gtp_tft_t *tft, smf_bearer_t *bearer) +{ + int i, j, len; + smf_pf_t *pf = NULL; + + ogs_assert(tft); + ogs_assert(bearer); + + memset(tft, 0, sizeof(*tft)); + tft->code = OGS_GTP_TFT_CODE_CREATE_NEW_TFT; + + i = 0; + pf = smf_pf_first(bearer); + while (pf) { + tft->pf[i].direction = pf->direction; + tft->pf[i].identifier = pf->identifier - 1; + tft->pf[i].precedence = i+1; + + j = 0, len = 0; + if (pf->rule.proto) { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE; + tft->pf[i].component[j].proto = pf->rule.proto; + j++; len += 2; + } + + if (pf->rule.ipv4_local) { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE; + tft->pf[i].component[j].ipv4.addr = pf->rule.ip.local.addr[0]; + tft->pf[i].component[j].ipv4.mask = pf->rule.ip.local.mask[0]; + j++; len += 9; + } + + if (pf->rule.ipv4_remote) { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE; + tft->pf[i].component[j].ipv4.addr = pf->rule.ip.remote.addr[0]; + tft->pf[i].component[j].ipv4.mask = pf->rule.ip.remote.mask[0]; + j++; len += 9; + } + + if (pf->rule.ipv6_local) { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE; + memcpy(tft->pf[i].component[j].ipv6.addr, pf->rule.ip.local.addr, + sizeof pf->rule.ip.local.addr); + tft->pf[i].component[j].ipv6.prefixlen = + contigmask((uint8_t *)pf->rule.ip.local.mask, 128); + j++; len += 18; + } + + if (pf->rule.ipv6_remote) { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE; + memcpy(tft->pf[i].component[j].ipv6.addr, pf->rule.ip.remote.addr, + sizeof pf->rule.ip.remote.addr); + tft->pf[i].component[j].ipv6.prefixlen = + contigmask((uint8_t *)pf->rule.ip.remote.mask, 128); + j++; len += 18; + } + + if (pf->rule.port.local.low) { + if (pf->rule.port.local.low == pf->rule.port.local.high) + { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE; + tft->pf[i].component[j].port.low = pf->rule.port.local.low; + j++; len += 3; + } else { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE; + tft->pf[i].component[j].port.low = pf->rule.port.local.low; + tft->pf[i].component[j].port.high = pf->rule.port.local.high; + j++; len += 5; + } + } + + if (pf->rule.port.remote.low) { + if (pf->rule.port.remote.low == pf->rule.port.remote.high) { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE; + tft->pf[i].component[j].port.low = pf->rule.port.remote.low; + j++; len += 3; + } else { + tft->pf[i].component[j].type = + GTP_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE; + tft->pf[i].component[j].port.low = pf->rule.port.remote.low; + tft->pf[i].component[j].port.high = pf->rule.port.remote.high; + j++; len += 5; + } + } + + tft->pf[i].num_of_component = j; + tft->pf[i].length = len; + i++; + + pf = smf_pf_next(pf); + } + tft->num_of_packet_filter = i; +} + +void smf_bearer_binding(smf_sess_t *sess) +{ + int rv; + int i, j; + + ogs_assert(sess); + + for (i = 0; i < sess->num_of_pcc_rule; i++) { + ogs_gtp_xact_t *xact = NULL; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + smf_bearer_t *bearer = NULL; + + ogs_pcc_rule_t *pcc_rule = &sess->pcc_rule[i]; + int bearer_created = 0; + int qos_presence = 0; + ogs_gtp_tft_t tft; + + ogs_assert(pcc_rule); + if (pcc_rule->name == NULL) { + ogs_error("No PCC Rule Name"); + continue; + } + + if (pcc_rule->type == OGS_PCC_RULE_TYPE_INSTALL) { + ogs_pfcp_pdr_t *pdr = NULL; + + bearer = smf_bearer_find_by_qci_arp(sess, + pcc_rule->qos.qci, + pcc_rule->qos.arp.priority_level, + pcc_rule->qos.arp.pre_emption_capability, + pcc_rule->qos.arp.pre_emption_vulnerability); + if (!bearer) { + if (pcc_rule->num_of_flow == 0) { + /* TFT is mandatory in + * activate dedicated EPS bearer context request */ + ogs_error("No flow in PCC Rule"); + continue; + } + + bearer = smf_bearer_add(sess); + ogs_assert(bearer); + + /* Precedence is set to the order in which it was created */ + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) + pdr->precedence = pdr->id; + + bearer->name = ogs_strdup(pcc_rule->name); + ogs_assert(bearer->name); + + memcpy(&bearer->qos, &pcc_rule->qos, sizeof(ogs_qos_t)); + + bearer_created = 1; + } else { + ogs_assert(strcmp(bearer->name, pcc_rule->name) == 0); + + if (pcc_rule->num_of_flow) { + /* We'll use always 'Create new TFT'. + * Therefore, all previous flows are removed + * and replaced by the new flow */ + smf_pf_remove_all(bearer); + } + + if ((pcc_rule->qos.mbr.downlink && + bearer->qos.mbr.downlink != pcc_rule->qos.mbr.downlink) || + (pcc_rule->qos.mbr.uplink && + bearer->qos.mbr.uplink != pcc_rule->qos.mbr.uplink) || + (pcc_rule->qos.gbr.downlink && + bearer->qos.gbr.downlink != pcc_rule->qos.gbr.downlink) || + (pcc_rule->qos.gbr.uplink && + bearer->qos.gbr.uplink != pcc_rule->qos.gbr.uplink)) { + /* Update QoS parameter */ + memcpy(&bearer->qos, &pcc_rule->qos, sizeof(ogs_qos_t)); + + /* Update Bearer Request encodes updated QoS parameter */ + qos_presence = 1; + } + + if (pcc_rule->num_of_flow == 0 && qos_presence == 0) { + ogs_warn("No need to send 'Update Bearer Request'"); + ogs_warn(" - Both QoS and TFT are same as before"); + continue; + } + } + + for (j = 0; j < pcc_rule->num_of_flow; j++) { + ogs_flow_t *flow = &pcc_rule->flow[j]; + ogs_ipfw_rule_t rule; + smf_pf_t *pf = NULL; + char *tmp = NULL; + + ogs_expect_or_return(flow); + ogs_expect_or_return(flow->description); + + /* Find First Downlink/Uplink PDR in the Bearer */ + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) { + ogs_pfcp_far_t *far = NULL; + far = pdr->far; + ogs_assert(far); + if (flow->direction == OGS_FLOW_DOWNLINK_ONLY) { + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE && + far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { + pdr->flow_description[pdr->num_of_flow++] = + flow->description; + break; + } + + } else if (flow->direction == OGS_FLOW_UPLINK_ONLY) { + if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS && + far->dst_if == OGS_PFCP_INTERFACE_CORE) { + pdr->flow_description[pdr->num_of_flow++] = + flow->description; + break; + } + } else { + ogs_error("Flow Bidirectional is not supported[%d]", + flow->direction); + break; + } + + } + + tmp = ogs_strdup(flow->description); + rv = ogs_ipfw_compile_rule(&rule, tmp); + ogs_free(tmp); + ogs_expect_or_return(rv == OGS_OK); + + pf = smf_pf_add(bearer, pcc_rule->precedence); + ogs_expect_or_return(pf); + + memcpy(&pf->rule, &rule, sizeof(ogs_ipfw_rule_t)); + pf->direction = flow->direction; + } + + memset(&tft, 0, sizeof tft); + if (pcc_rule->num_of_flow) + encode_traffic_flow_template(&tft, bearer); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + if (bearer_created == 1) { + memset(&bearer->state, 0, sizeof(bearer->state)); + bearer->state.created = true; + + h.type = OGS_GTP_CREATE_BEARER_REQUEST_TYPE; + h.teid = sess->sgw_s5c_teid; + + /* TFT is mandatory in + * activate dedicated EPS bearer context request */ + ogs_assert(pcc_rule->num_of_flow); + + pkbuf = smf_s5c_build_create_bearer_request( + h.type, bearer, pcc_rule->num_of_flow ? &tft : NULL); + ogs_expect_or_return(pkbuf); + } else { + memset(&bearer->state, 0, sizeof(bearer->state)); + if (pcc_rule->num_of_flow) + bearer->state.tft_updated = true; + if (qos_presence) + bearer->state.qos_updated = true; + + h.type = OGS_GTP_UPDATE_BEARER_REQUEST_TYPE; + h.teid = sess->sgw_s5c_teid; + + pkbuf = smf_s5c_build_update_bearer_request( + h.type, bearer, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + pcc_rule->num_of_flow ? &tft : NULL, qos_presence); + ogs_expect_or_return(pkbuf); + } + + xact = ogs_gtp_xact_local_create( + sess->gnode, &h, pkbuf, timeout, sess); + ogs_expect_or_return(xact); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + } else if (pcc_rule->type == OGS_PCC_RULE_TYPE_REMOVE) { + bearer = smf_bearer_find_by_name(sess, pcc_rule->name); + ogs_assert(bearer); + + if (!bearer) { + ogs_warn("No need to send 'Delete Bearer Request'"); + ogs_warn(" - Bearer[Name:%s] has already been removed.", + pcc_rule->name); + return; + } + + memset(&bearer->state, 0, sizeof(bearer->state)); + bearer->state.removed = true; + + 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, timeout, sess); + ogs_expect_or_return(xact); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + } else { + ogs_error("Invalid Type[%d]", pcc_rule->type); + } + } +} diff --git a/src/smf/bearer-binding.h b/src/smf/bearer-binding.h new file mode 100644 index 000000000..09fa77e6b --- /dev/null +++ b/src/smf/bearer-binding.h @@ -0,0 +1,35 @@ +/* + * 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 SMF_BEARER_BINDING_H +#define SMF_BEARER_BINDING_H + +#include "context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void smf_bearer_binding(smf_sess_t *sess); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_BEARER_BINDING_H */ diff --git a/src/smf/context.c b/src/smf/context.c new file mode 100644 index 000000000..8e398b553 --- /dev/null +++ b/src/smf/context.c @@ -0,0 +1,1081 @@ +/* + * 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 "context.h" +#include "smf-sm.h" + +static smf_context_t self; +static ogs_diam_config_t g_diam_conf; + +int __smf_log_domain; + +static OGS_POOL(smf_sess_pool, smf_sess_t); +static OGS_POOL(smf_bearer_pool, smf_bearer_t); + +static OGS_POOL(smf_pf_pool, smf_pf_t); + +static int context_initiaized = 0; + +int num_sessions = 0; +void stats_add_session(void) { + num_sessions = num_sessions + 1; + ogs_info("Added a session. Number of active sessions is now %d", num_sessions); +} + +void stats_remove_session(void) { + num_sessions = num_sessions - 1; + ogs_info("Removed a session. Number of active sessions is now %d", num_sessions); +} + +void smf_context_init(void) +{ + ogs_assert(context_initiaized == 0); + + /* Initial FreeDiameter Config */ + memset(&g_diam_conf, 0, sizeof(ogs_diam_config_t)); + + /* Initialize SMF context */ + memset(&self, 0, sizeof(smf_context_t)); + self.diam_config = &g_diam_conf; + + ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level); + ogs_log_install_domain(&__ogs_diam_domain, "diam", ogs_core()->log.level); + ogs_log_install_domain(&__smf_log_domain, "smf", ogs_core()->log.level); + + ogs_gtp_node_init(512); + + ogs_list_init(&self.sess_list); + + ogs_list_init(&self.gtpc_list); + ogs_list_init(&self.gtpc_list6); + + ogs_list_init(&self.sgw_s5c_list); + + ogs_pool_init(&smf_sess_pool, ogs_config()->pool.sess); + ogs_pool_init(&smf_bearer_pool, ogs_config()->pool.bearer); + + ogs_pool_init(&smf_pf_pool, ogs_config()->pool.pf); + + self.sess_hash = ogs_hash_make(); + self.ipv4_hash = ogs_hash_make(); + self.ipv6_hash = ogs_hash_make(); + + context_initiaized = 1; +} + +void smf_context_final(void) +{ + ogs_assert(context_initiaized == 1); + + smf_sess_remove_all(); + + ogs_assert(self.sess_hash); + ogs_hash_destroy(self.sess_hash); + ogs_assert(self.ipv4_hash); + ogs_hash_destroy(self.ipv4_hash); + ogs_assert(self.ipv6_hash); + ogs_hash_destroy(self.ipv6_hash); + + ogs_pool_final(&smf_bearer_pool); + ogs_pool_final(&smf_sess_pool); + + ogs_pool_final(&smf_pf_pool); + + ogs_gtp_node_remove_all(&self.sgw_s5c_list); + + ogs_gtp_node_final(); + + context_initiaized = 0; +} + +smf_context_t *smf_self(void) +{ + return &self; +} + +static int smf_context_prepare(void) +{ + self.gtpc_port = OGS_GTPV2_C_UDP_PORT; + self.diam_config->cnf_port = DIAMETER_PORT; + self.diam_config->cnf_port_tls = DIAMETER_SECURE_PORT; + + return OGS_OK; +} + +static int smf_context_validation(void) +{ + if (self.diam_conf_path == NULL && + (self.diam_config->cnf_diamid == NULL || + self.diam_config->cnf_diamrlm == NULL || + self.diam_config->cnf_addr == NULL)) { + ogs_error("No smf.freeDiameter in '%s'", ogs_config()->file); + return OGS_ERROR; + } + if (ogs_list_first(&self.gtpc_list) == NULL && + ogs_list_first(&self.gtpc_list6) == NULL) { + ogs_error("No smf.gtpc in '%s'", ogs_config()->file); + return OGS_ERROR; + } + if (self.dns[0] == NULL && self.dns6[0] == NULL) { + ogs_error("No smf.dns in '%s'", ogs_config()->file); + return OGS_ERROR; + } + return OGS_OK; +} + +int smf_context_parse_config(void) +{ + int rv; + yaml_document_t *document = NULL; + ogs_yaml_iter_t root_iter; + + document = ogs_config()->document; + ogs_assert(document); + + rv = smf_context_prepare(); + if (rv != OGS_OK) return rv; + + ogs_yaml_iter_init(&root_iter, document); + while (ogs_yaml_iter_next(&root_iter)) { + const char *root_key = ogs_yaml_iter_key(&root_iter); + ogs_assert(root_key); + if (!strcmp(root_key, "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, "freeDiameter")) { + yaml_node_t *node = + yaml_document_get_node(document, smf_iter.pair->value); + ogs_assert(node); + if (node->type == YAML_SCALAR_NODE) { + self.diam_conf_path = ogs_yaml_iter_value(&smf_iter); + } else if (node->type == YAML_MAPPING_NODE) { + ogs_yaml_iter_t fd_iter; + ogs_yaml_iter_recurse(&smf_iter, &fd_iter); + + while (ogs_yaml_iter_next(&fd_iter)) { + const char *fd_key = ogs_yaml_iter_key(&fd_iter); + ogs_assert(fd_key); + if (!strcmp(fd_key, "identity")) { + self.diam_config->cnf_diamid = + ogs_yaml_iter_value(&fd_iter); + } else if (!strcmp(fd_key, "realm")) { + self.diam_config->cnf_diamrlm = + ogs_yaml_iter_value(&fd_iter); + } else if (!strcmp(fd_key, "port")) { + const char *v = ogs_yaml_iter_value(&fd_iter); + if (v) self.diam_config->cnf_port = atoi(v); + } else if (!strcmp(fd_key, "sec_port")) { + const char *v = ogs_yaml_iter_value(&fd_iter); + if (v) self.diam_config->cnf_port_tls = atoi(v); + } else if (!strcmp(fd_key, "listen_on")) { + self.diam_config->cnf_addr = + ogs_yaml_iter_value(&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); + do { + const char *module = NULL; + const char *conf = NULL; + + if (ogs_yaml_iter_type(&ext_array) == + YAML_MAPPING_NODE) { + memcpy(&ext_iter, &ext_array, + sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type(&ext_array) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&ext_array)) + break; + ogs_yaml_iter_recurse( + &ext_array, &ext_iter); + } else if (ogs_yaml_iter_type(&ext_array) == + YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + while (ogs_yaml_iter_next(&ext_iter)) { + const char *ext_key = + ogs_yaml_iter_key(&ext_iter); + ogs_assert(ext_key); + if (!strcmp(ext_key, "module")) { + module = ogs_yaml_iter_value( + &ext_iter); + } else if (!strcmp(ext_key, "conf")) { + conf = ogs_yaml_iter_value( + &ext_iter); + } else + ogs_warn("unknown key `%s`", + ext_key); + } + + if (module) { + self.diam_config-> + ext[self.diam_config->num_of_ext]. + module = module; + self.diam_config-> + ext[self.diam_config->num_of_ext]. + conf = conf; + self.diam_config->num_of_ext++; + } + } while (ogs_yaml_iter_type(&ext_array) == + YAML_SEQUENCE_NODE); + } else if (!strcmp(fd_key, "connect")) { + ogs_yaml_iter_t conn_array, conn_iter; + ogs_yaml_iter_recurse(&fd_iter, &conn_array); + do { + const char *identity = NULL; + const char *addr = NULL; + uint16_t port = 0; + + if (ogs_yaml_iter_type(&conn_array) == + YAML_MAPPING_NODE) { + memcpy(&conn_iter, &conn_array, + sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type( + &conn_array) == YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&conn_array)) + break; + ogs_yaml_iter_recurse(&conn_array, + &conn_iter); + } else if (ogs_yaml_iter_type( + &conn_array) == YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + while (ogs_yaml_iter_next(&conn_iter)) { + const char *conn_key = + ogs_yaml_iter_key(&conn_iter); + ogs_assert(conn_key); + if (!strcmp(conn_key, "identity")) { + identity = + ogs_yaml_iter_value(&conn_iter); + } else if (!strcmp(conn_key, "addr")) { + addr = + ogs_yaml_iter_value(&conn_iter); + } else if (!strcmp(conn_key, "port")) { + const char *v = + ogs_yaml_iter_value(&conn_iter); + if (v) port = atoi(v); + } else + ogs_warn("unknown key `%s`", + conn_key); + } + + if (identity && addr) { + self.diam_config-> + conn[self.diam_config->num_of_conn]. + identity = identity; + self.diam_config-> + conn[self.diam_config->num_of_conn]. + addr = addr; + self.diam_config-> + conn[self.diam_config->num_of_conn]. + port = port; + self.diam_config->num_of_conn++; + } + } while (ogs_yaml_iter_type(&conn_array) == + YAML_SEQUENCE_NODE); + } else + ogs_warn("unknown key `%s`", fd_key); + } + } + } else 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 = self.gtpc_port; + const char *dev = NULL; + 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); + self.gtpc_port = port; + } + } else if (!strcmp(gtpc_key, "dev")) { + dev = ogs_yaml_iter_value(>pc_iter); + } else if (!strcmp(gtpc_key, "apn")) { + /* Skip */ + } 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); + } + + if (addr) { + if (ogs_config()->parameter.no_ipv4 == 0) + ogs_socknode_add( + &self.gtpc_list, AF_INET, addr); + if (ogs_config()->parameter.no_ipv6 == 0) + ogs_socknode_add( + &self.gtpc_list6, AF_INET6, addr); + ogs_freeaddrinfo(addr); + } + + if (dev) { + rv = ogs_socknode_probe( + ogs_config()->parameter.no_ipv4 ? + NULL : &self.gtpc_list, + ogs_config()->parameter.no_ipv6 ? + NULL : &self.gtpc_list6, + dev, self.gtpc_port); + ogs_assert(rv == OGS_OK); + } + + } while (ogs_yaml_iter_type(>pc_array) == + YAML_SEQUENCE_NODE); + + if (ogs_list_first(&self.gtpc_list) == NULL && + ogs_list_first(&self.gtpc_list6) == NULL) { + rv = ogs_socknode_probe( + ogs_config()->parameter.no_ipv4 ? + NULL : &self.gtpc_list, + ogs_config()->parameter.no_ipv6 ? + NULL : &self.gtpc_list6, + NULL, self.gtpc_port); + ogs_assert(rv == OGS_OK); + } + } else if (!strcmp(smf_key, "pfcp")) { + /* handle config in pfcp library */ + } else if (!strcmp(smf_key, "pdn")) { + /* handle config in pfcp library */ + } else if (!strcmp(smf_key, "dns")) { + ogs_yaml_iter_t dns_iter; + ogs_yaml_iter_recurse(&smf_iter, &dns_iter); + ogs_assert(ogs_yaml_iter_type(&dns_iter) != + YAML_MAPPING_NODE); + + do { + const char *v = NULL; + + if (ogs_yaml_iter_type(&dns_iter) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&dns_iter)) + break; + } + + v = ogs_yaml_iter_value(&dns_iter); + if (v && strlen(v)) { + ogs_ipsubnet_t ipsub; + rv = ogs_ipsubnet(&ipsub, v, NULL); + ogs_assert(rv == OGS_OK); + + if (ipsub.family == AF_INET) { + if (self.dns[0] && self.dns[1]) + ogs_warn("Ignore DNS : %s", v); + else if (self.dns[0]) self.dns[1] = v; + else self.dns[0] = v; + } + else if (ipsub.family == AF_INET6) { + if (self.dns6[0] && self.dns6[1]) + ogs_warn("Ignore DNS : %s", v); + else if (self.dns6[0]) self.dns6[1] = v; + else self.dns6[0] = v; + } else + ogs_warn("Ignore DNS : %s", v); + } + + } while ( + ogs_yaml_iter_type(&dns_iter) == + YAML_SEQUENCE_NODE); + } else if (!strcmp(smf_key, "mtu")) { + ogs_assert(ogs_yaml_iter_type(&smf_iter) != + YAML_SCALAR_NODE); + self.mtu = atoi(ogs_yaml_iter_value(&smf_iter)); + ogs_assert(self.mtu); + } else if (!strcmp(smf_key, "p-cscf")) { + ogs_yaml_iter_t dns_iter; + ogs_yaml_iter_recurse(&smf_iter, &dns_iter); + ogs_assert(ogs_yaml_iter_type(&dns_iter) != + YAML_MAPPING_NODE); + + self.num_of_p_cscf = 0; + self.num_of_p_cscf6 = 0; + do { + const char *v = NULL; + + if (ogs_yaml_iter_type(&dns_iter) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(&dns_iter)) + break; + } + + v = ogs_yaml_iter_value(&dns_iter); + if (v) { + ogs_ipsubnet_t ipsub; + rv = ogs_ipsubnet(&ipsub, v, NULL); + ogs_assert(rv == OGS_OK); + + if (ipsub.family == AF_INET) { + if (self.num_of_p_cscf >= MAX_NUM_OF_P_CSCF) + ogs_warn("Ignore P-CSCF : %s", v); + else self.p_cscf[self.num_of_p_cscf++] = v; + } + else if (ipsub.family == AF_INET6) { + if (self.num_of_p_cscf6 >= MAX_NUM_OF_P_CSCF) + ogs_warn("Ignore P-CSCF : %s", v); + else self.p_cscf6[self.num_of_p_cscf6++] = v; + } else + ogs_warn("Ignore P-CSCF : %s", v); + } + + } while ( + ogs_yaml_iter_type(&dns_iter) == + YAML_SEQUENCE_NODE); + } + else + ogs_warn("unknown key `%s`", smf_key); + } + } + } + + rv = smf_context_validation(); + if (rv != OGS_OK) return rv; + + return OGS_OK; +} + +static void *sess_hash_keygen(uint8_t *out, int *out_len, + uint8_t *imsi, int imsi_len, char *apn) +{ + memcpy(out, imsi, imsi_len); + ogs_cpystrn((char*)(out+imsi_len), apn, OGS_MAX_APN_LEN+1); + *out_len = imsi_len+strlen((char*)(out+imsi_len)); + + return out; +} + +smf_sess_t *smf_sess_add( + uint8_t *imsi, int imsi_len, char *apn, + uint8_t pdn_type, uint8_t ebi, ogs_paa_t *paa) +{ + char buf1[OGS_ADDRSTRLEN]; + char buf2[OGS_ADDRSTRLEN]; + smf_sess_t *sess = NULL; + smf_bearer_t *bearer = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_subnet_t *subnet6 = NULL; + + ogs_assert(imsi); + ogs_assert(apn); + ogs_assert(paa); + + ogs_pool_alloc(&smf_sess_pool, &sess); + ogs_assert(sess); + memset(sess, 0, sizeof *sess); + + sess->index = ogs_pool_index(&smf_sess_pool, sess); + ogs_assert(sess->index > 0 && sess->index <= ogs_config()->pool.sess); + + /* Set TEID & SEID */ + sess->smf_n4_teid = sess->index; + sess->smf_n4_seid = sess->index; + + /* Set IMSI */ + sess->imsi_len = imsi_len; + memcpy(sess->imsi, imsi, sess->imsi_len); + ogs_buffer_to_bcd(sess->imsi, sess->imsi_len, sess->imsi_bcd); + + /* Set APN */ + ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); + + /* UE IP Address */ + sess->pdn.paa.pdn_type = pdn_type; + ogs_expect(pdn_type == paa->pdn_type); + + if (pdn_type == OGS_GTP_PDN_TYPE_IPV4) { + sess->ipv4 = ogs_pfcp_ue_ip_alloc( + AF_INET, apn, (uint8_t *)&(paa->addr)); + ogs_assert(sess->ipv4); + sess->pdn.paa.addr = sess->ipv4->addr[0]; + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); + } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV6) { + sess->ipv6 = ogs_pfcp_ue_ip_alloc( + AF_INET6, apn, (paa->addr6)); + ogs_assert(sess->ipv6); + + subnet6 = sess->ipv6->subnet; + ogs_assert(subnet6); + + sess->pdn.paa.len = subnet6->prefixlen; + memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, OGS_IPV6_LEN); + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); + } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { + sess->ipv4 = ogs_pfcp_ue_ip_alloc( + AF_INET, apn, (uint8_t *)&(paa->both.addr)); + ogs_assert(sess->ipv4); + sess->ipv6 = ogs_pfcp_ue_ip_alloc( + AF_INET6, apn, (paa->both.addr6)); + ogs_assert(sess->ipv6); + + subnet6 = sess->ipv6->subnet; + ogs_assert(subnet6); + + sess->pdn.paa.both.addr = sess->ipv4->addr[0]; + sess->pdn.paa.both.len = subnet6->prefixlen; + memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, OGS_IPV6_LEN); + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); + } else + ogs_assert_if_reached(); + + ogs_info("UE IMSI:[%s] APN:[%s] IPv4:[%s] IPv6:[%s]", + sess->imsi_bcd, apn, + sess->ipv4 ? INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? INET6_NTOP(&sess->ipv6->addr, buf2) : ""); + + /* Generate Hash Key : IMSI + APN */ + sess_hash_keygen(sess->hash_keybuf, &sess->hash_keylen, + imsi, imsi_len, apn); + ogs_hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, sess); + + /* Select UPF with round-robin manner */ + if (ogs_pfcp_self()->node == NULL) + ogs_pfcp_self()->node = ogs_list_first(&ogs_pfcp_self()->n4_list); + + for (; ogs_pfcp_self()->node; + ogs_pfcp_self()->node = ogs_list_next(ogs_pfcp_self()->node)) { + if (OGS_FSM_CHECK( + &ogs_pfcp_self()->node->sm, smf_pfcp_state_associated)) { + OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->node); + break; + } + } + + /* Set Default Bearer */ + ogs_list_init(&sess->bearer_list); + + bearer = smf_bearer_add(sess); + ogs_assert(bearer); + + bearer->ebi = ebi; + + /* Default PDRs is set to lowest precedence(highest precedence value). */ + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) + pdr->precedence = 0xffffffff; + + ogs_list_add(&self.sess_list, sess); + + stats_add_session(); + + return sess; +} + +int smf_sess_remove(smf_sess_t *sess) +{ + int i; + + ogs_assert(sess); + + ogs_list_remove(&self.sess_list, sess); + + OGS_TLV_CLEAR_DATA(&sess->ue_pco); + OGS_TLV_CLEAR_DATA(&sess->user_location_information); + OGS_TLV_CLEAR_DATA(&sess->ue_timezone); + + for (i = 0; i < sess->num_of_pcc_rule; i++) + OGS_PCC_RULE_FREE(&sess->pcc_rule[i]); + sess->num_of_pcc_rule = 0; + + ogs_hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL); + + if (sess->ipv4) { + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, NULL); + ogs_pfcp_ue_ip_free(sess->ipv4); + } + if (sess->ipv6) { + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, NULL); + ogs_pfcp_ue_ip_free(sess->ipv6); + } + + smf_bearer_remove_all(sess); + + ogs_pool_free(&smf_sess_pool, sess); + + stats_remove_session(); + + return OGS_OK; +} + +void smf_sess_remove_all(void) +{ + smf_sess_t *sess = NULL, *next = NULL;; + + ogs_list_for_each_safe(&self.sess_list, next, sess) + smf_sess_remove(sess); +} + +smf_sess_t *smf_sess_find(uint32_t index) +{ + ogs_assert(index); + return ogs_pool_find(&smf_sess_pool, index); +} + +smf_sess_t *smf_sess_find_by_teid(uint32_t teid) +{ + return smf_sess_find(teid); +} + +smf_sess_t *smf_sess_find_by_seid(uint64_t seid) +{ + return smf_sess_find(seid); +} + +smf_sess_t *smf_sess_find_by_imsi_apn( + uint8_t *imsi, int imsi_len, char *apn) +{ + uint8_t keybuf[OGS_MAX_IMSI_LEN+OGS_MAX_APN_LEN+1]; + int keylen = 0; + + ogs_assert(self.sess_hash); + + sess_hash_keygen(keybuf, &keylen, imsi, imsi_len, apn); + return (smf_sess_t *)ogs_hash_get(self.sess_hash, keybuf, keylen); +} + +smf_sess_t *smf_sess_find_by_ipv4(uint32_t addr) +{ + ogs_assert(self.ipv4_hash); + return (smf_sess_t *)ogs_hash_get(self.ipv4_hash, &addr, OGS_IPV4_LEN); +} + +smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6) +{ + ogs_assert(self.ipv6_hash); + ogs_assert(addr6); + return (smf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN); +} + +smf_sess_t *smf_sess_add_by_message(ogs_gtp_message_t *message) +{ + smf_sess_t *sess = NULL; + ogs_paa_t *paa = NULL; + char apn[OGS_MAX_APN_LEN]; + + ogs_gtp_create_session_request_t *req = &message->create_session_request; + + if (req->imsi.presence == 0) { + ogs_error("No IMSI"); + return NULL; + } + if (req->access_point_name.presence == 0) { + ogs_error("No APN"); + return NULL; + } + if (req->bearer_contexts_to_be_created.presence == 0) { + ogs_error("No Bearer"); + return NULL; + } + if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + return NULL; + } + if (req->pdn_type.presence == 0) { + ogs_error("No PDN Type"); + return NULL; + } + + if (req->pdn_address_allocation.presence == 0) { + ogs_error("No PAA Type"); + return NULL; + } + + ogs_fqdn_parse(apn, + req->access_point_name.data, req->access_point_name.len); + + ogs_trace("smf_sess_add_by_message() [APN:%s, PDN:%d, EDI:%d]", + apn, req->pdn_type.u8, + req->bearer_contexts_to_be_created.eps_bearer_id.u8); + + paa = (ogs_paa_t *)req->pdn_address_allocation.data; + + /* + * 7.2.1 in 3GPP TS 29.274 Release 15 + * + * If the new Create Session Request received by the SMF collides with + * an existing PDN connection context (the existing PDN connection context + * is identified with the triplet [IMSI, EPS Bearer ID, Interface type], + * where applicable Interface type here is S2a TWAN GTP-C interface or + * S2b ePDG GTP-C interface or S5/S8 SGW GTP-C interface, and where IMSI + * shall be replaced by TAC and SNR part of ME Identity for emergency + * attached UE without UICC or authenticated IMSI), this Create Session + * Request shall be treated as a request for a new session. Before creating + * the new session, the SMF should delete: + * + * - the existing PDN connection context, if the Create Session Request + * collides with the default bearer of an existing PDN connection context; + * - the existing dedicated bearer context, if the Create Session Request + * collides with a dedicated bearer of an existing PDN connection context. + */ + sess = smf_sess_find_by_imsi_apn(req->imsi.data, req->imsi.len, apn); + if (sess) { + ogs_warn("OLD Session Release [IMSI:%s,APN:%s]", + sess->imsi_bcd, sess->pdn.apn); + smf_sess_remove(sess); + } + sess = smf_sess_add(req->imsi.data, req->imsi.len, apn, + req->pdn_type.u8, + req->bearer_contexts_to_be_created.eps_bearer_id.u8, paa); + return sess; +} + +smf_bearer_t *smf_bearer_add(smf_sess_t *sess) +{ + smf_bearer_t *bearer = NULL; + ogs_pfcp_gtpu_resource_t *resource = NULL; + + ogs_pfcp_pdr_t *dl_pdr = NULL; + ogs_pfcp_pdr_t *ul_pdr = NULL; + ogs_pfcp_far_t *dl_far = NULL; + ogs_pfcp_far_t *ul_far = NULL; + + ogs_assert(sess); + + ogs_pool_alloc(&smf_bearer_pool, &bearer); + ogs_assert(bearer); + memset(bearer, 0, sizeof *bearer); + + bearer->index = ogs_pool_index(&smf_bearer_pool, bearer); + ogs_assert(bearer->index > 0 && bearer->index <= + ogs_config()->pool.bearer); + + ogs_list_init(&bearer->pf_list); + + dl_pdr = ogs_pfcp_pdr_add(&bearer->pfcp); + ogs_assert(dl_pdr); + dl_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1); + dl_pdr->src_if = OGS_PFCP_INTERFACE_CORE; + + ul_pdr = ogs_pfcp_pdr_add(&bearer->pfcp); + ogs_assert(ul_pdr); + ul_pdr->id = OGS_NEXT_ID(sess->pdr_id, 1, OGS_MAX_NUM_OF_PDR+1); + ul_pdr->src_if = OGS_PFCP_INTERFACE_ACCESS; + + dl_far = ogs_pfcp_far_add(&bearer->pfcp); + ogs_assert(dl_far); + dl_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1); + dl_far->dst_if = OGS_PFCP_INTERFACE_ACCESS; + ogs_pfcp_pdr_associate_far(dl_pdr, dl_far); + + ul_far = ogs_pfcp_far_add(&bearer->pfcp); + ogs_assert(ul_far); + ul_far->id = OGS_NEXT_ID(sess->far_id, 1, OGS_MAX_NUM_OF_FAR+1); + ul_far->dst_if = OGS_PFCP_INTERFACE_CORE; + ogs_pfcp_pdr_associate_far(ul_pdr, ul_far); + + resource = ogs_pfcp_gtpu_resource_find( + &sess->pfcp_node->gtpu_resource_list, + sess->pdn.apn, OGS_PFCP_INTERFACE_ACCESS); + if (resource) { + ogs_pfcp_user_plane_ip_resource_info_to_sockaddr(&resource->info, + &bearer->upf_addr, &bearer->upf_addr6); + ogs_assert(bearer->upf_addr || bearer->upf_addr6); + if (resource->info.teidri) + bearer->upf_n3_teid = UPF_S5U_INDEX_TO_TEID( + bearer->index, resource->info.teidri, + resource->info.teid_range); + else + bearer->upf_n3_teid = bearer->index; + } else { + if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) + ogs_copyaddrinfo(&bearer->upf_addr, &sess->pfcp_node->addr); + else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) + ogs_copyaddrinfo(&bearer->upf_addr6, &sess->pfcp_node->addr); + else + ogs_assert_if_reached(); + ogs_assert(bearer->upf_addr || bearer->upf_addr6); + + bearer->upf_n3_teid = bearer->index; + } + + bearer->sess = sess; + + ogs_list_add(&sess->bearer_list, bearer); + + return bearer; +} + +int smf_bearer_remove(smf_bearer_t *bearer) +{ + ogs_assert(bearer); + ogs_assert(bearer->sess); + + ogs_list_remove(&bearer->sess->bearer_list, bearer); + ogs_pfcp_sess_clear(&bearer->pfcp); + + if (bearer->name) + ogs_free(bearer->name); + if (bearer->upf_addr) + ogs_freeaddrinfo(bearer->upf_addr); + if (bearer->upf_addr6) + ogs_freeaddrinfo(bearer->upf_addr6); + + smf_pf_remove_all(bearer); + + ogs_pool_free(&smf_bearer_pool, bearer); + + return OGS_OK; +} + +void smf_bearer_remove_all(smf_sess_t *sess) +{ + smf_bearer_t *bearer = NULL, *next_bearer = NULL; + + ogs_assert(sess); + ogs_list_for_each_safe(&sess->bearer_list, next_bearer, bearer) + smf_bearer_remove(bearer); +} + +smf_bearer_t *smf_bearer_find(uint32_t index) +{ + ogs_assert(index); + return ogs_pool_find(&smf_bearer_pool, index); +} + +smf_bearer_t *smf_bearer_find_by_smf_s5u_teid(uint32_t smf_s5u_teid) +{ + return smf_bearer_find(smf_s5u_teid); +} + +smf_bearer_t *smf_bearer_find_by_ebi(smf_sess_t *sess, uint8_t ebi) +{ + smf_bearer_t *bearer = NULL; + + ogs_assert(sess); + + bearer = smf_bearer_first(sess); + while (bearer) { + if (bearer->ebi == ebi) + break; + + bearer = smf_bearer_next(bearer); + } + + return bearer; +} + +smf_bearer_t *smf_bearer_find_by_name(smf_sess_t *sess, char *name) +{ + smf_bearer_t *bearer = NULL; + + ogs_assert(sess); + ogs_assert(name); + + bearer = smf_bearer_first(sess); + while (bearer) { + if (bearer->name && strcmp(bearer->name, name) == 0) + return bearer; + + bearer = smf_bearer_next(bearer); + } + + return NULL; +} + +smf_bearer_t *smf_bearer_find_by_qci_arp(smf_sess_t *sess, + uint8_t qci, + uint8_t priority_level, + uint8_t pre_emption_capability, + uint8_t pre_emption_vulnerability) +{ + smf_bearer_t *bearer = NULL; + + ogs_assert(sess); + + bearer = smf_default_bearer_in_sess(sess); + if (!bearer) return NULL; + + if (sess->pdn.qos.qci == qci && + sess->pdn.qos.arp.priority_level == priority_level && + sess->pdn.qos.arp.pre_emption_capability == + pre_emption_capability && + sess->pdn.qos.arp.pre_emption_vulnerability == + pre_emption_vulnerability) { + return bearer; + } + + bearer = smf_bearer_next(bearer); + while (bearer) { + if (bearer->qos.qci == qci && + bearer->qos.arp.priority_level == priority_level && + bearer->qos.arp.pre_emption_capability == + pre_emption_capability && + bearer->qos.arp.pre_emption_vulnerability == + pre_emption_vulnerability) { + return bearer; + } + bearer = smf_bearer_next(bearer); + } + + return NULL; +} + +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->ebi == default_bearer->ebi; +} + +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_pf_t *smf_pf_add(smf_bearer_t *bearer, uint32_t precedence) +{ + smf_pf_t *pf = NULL; + + ogs_assert(bearer); + + ogs_pool_alloc(&smf_pf_pool, &pf); + ogs_assert(pf); + memset(pf, 0, sizeof *pf); + + pf->identifier = OGS_NEXT_ID(bearer->pf_identifier, 1, 15); + pf->bearer = bearer; + + ogs_list_add(&bearer->pf_list, pf); + + return pf; +} + +int smf_pf_remove(smf_pf_t *pf) +{ + ogs_assert(pf); + ogs_assert(pf->bearer); + + ogs_list_remove(&pf->bearer->pf_list, pf); + ogs_pool_free(&smf_pf_pool, pf); + + return OGS_OK; +} + +void smf_pf_remove_all(smf_bearer_t *bearer) +{ + smf_pf_t *pf = NULL, *next_pf = NULL; + + ogs_assert(bearer); + ogs_list_for_each_safe(&bearer->pf_list, next_pf, pf) + smf_pf_remove(pf); +} + +smf_pf_t *smf_pf_find_by_id(smf_bearer_t *bearer, uint8_t id) +{ + smf_pf_t *pf = NULL; + + ogs_list_for_each(&bearer->pf_list, pf) { + if (pf->identifier == id) return pf; + } + + return NULL; +} + +smf_pf_t *smf_pf_first(smf_bearer_t *bearer) +{ + return ogs_list_first(&bearer->pf_list); +} + +smf_pf_t *smf_pf_next(smf_pf_t *pf) +{ + return ogs_list_next(pf); +} diff --git a/src/smf/context.h b/src/smf/context.h new file mode 100644 index 000000000..51634946f --- /dev/null +++ b/src/smf/context.h @@ -0,0 +1,236 @@ +/* + * 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 SMF_CONTEXT_H +#define SMF_CONTEXT_H + +#include "smf-config.h" + +#if HAVE_NET_IF_H +#include +#endif + +#include "ogs-gtp.h" +#include "ogs-diameter-gx.h" +#include "ogs-pfcp.h" +#include "ogs-app.h" +#include "ipfw/ogs-ipfw.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int __smf_log_domain; + +#undef OGS_LOG_DOMAIN +#define OGS_LOG_DOMAIN __smf_log_domain + +typedef struct smf_context_s { + const char* diam_conf_path; /* SMF Diameter conf path */ + ogs_diam_config_t *diam_config; /* SMF Diameter config */ + + uint32_t gtpc_port; /* Default: SMF GTP-C local port */ + + ogs_list_t gtpc_list; /* SMF GTPC IPv4 Server List */ + ogs_list_t gtpc_list6; /* SMF GTPC IPv6 Server List */ + ogs_sock_t *gtpc_sock; /* SMF GTPC IPv4 Socket */ + ogs_sock_t *gtpc_sock6; /* SMF GTPC IPv6 Socket */ + ogs_sockaddr_t *gtpc_addr; /* SMF GTPC IPv4 Address */ + ogs_sockaddr_t *gtpc_addr6; /* SMF GTPC IPv6 Address */ + + uint8_t function_features; /* CP Function Features */ + + ogs_queue_t *queue; /* Queue for processing SMF control */ + ogs_timer_mgr_t *timer_mgr; /* Timer Manager */ + ogs_pollset_t *pollset; /* Poll Set for I/O Multiplexing */ + +#define MAX_NUM_OF_DNS 2 + const char *dns[MAX_NUM_OF_DNS]; + const char *dns6[MAX_NUM_OF_DNS]; + +#define MAX_NUM_OF_P_CSCF 16 + const char *p_cscf[MAX_NUM_OF_P_CSCF]; + int num_of_p_cscf; + int p_cscf_index; + const char *p_cscf6[MAX_NUM_OF_P_CSCF]; + int num_of_p_cscf6; + int p_cscf6_index; + + ogs_list_t sgw_s5c_list; /* SGW GTPC Node List */ + ogs_list_t ip_pool_list; + + ogs_hash_t *sess_hash; /* hash table (IMSI+APN) */ + ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */ + ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */ + + uint16_t mtu; /* MTU to advertise in PCO */ + + ogs_list_t sess_list; +} smf_context_t; + +typedef struct smf_sess_s { + ogs_lnode_t lnode; + uint32_t index; /**< An index of this node */ + + uint32_t smf_n4_teid; /* SMF-N4-TEID is derived from INDEX */ + uint32_t sgw_s5c_teid; /* SGW-S5C-TEID is received from SGW */ + + uint64_t smf_n4_seid; /* SMF SEID is dervied from INDEX */ + uint64_t upf_n4_seid; /* UPF SEID is received from Peer */ + + char *gx_sid; /* Gx Session ID */ + + ogs_pfcp_pdr_id_t pdr_id; /* ID Generator(1~MAX_NUM_OF_PDR) */ + ogs_pfcp_far_id_t far_id; /* ID Generator(1~MAX_NUM_OF_FAR) */ + ogs_pfcp_urr_id_t urr_id; /* ID Generator(1~MAX_NUM_OF_URR) */ + ogs_pfcp_qer_id_t qer_id; /* ID Generator(1~MAX_NUM_OF_URR) */ + ogs_pfcp_bar_id_t bar_id; /* ID Generator(1~MAX_NUM_OF_BAR) */ + + /* IMSI */ + uint8_t imsi[OGS_MAX_IMSI_LEN]; + int imsi_len; + char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; + + /* APN Configuration */ + ogs_pdn_t pdn; + ogs_pfcp_ue_ip_t *ipv4; + ogs_pfcp_ue_ip_t *ipv6; + + uint8_t hash_keybuf[OGS_MAX_IMSI_LEN+OGS_MAX_APN_LEN+1]; + int hash_keylen; + + ogs_tlv_octet_t ue_pco; /* Saved from S5-C */ + ogs_tlv_octet_t user_location_information; /* Saved from S5-C */ + ogs_tlv_octet_t ue_timezone; /* Saved from S5-C */ + + ogs_pcc_rule_t pcc_rule[OGS_MAX_NUM_OF_PCC_RULE]; /* Saved from Gx */ + int num_of_pcc_rule; + + ogs_list_t bearer_list; + + /* Related Context */ + ogs_gtp_node_t *gnode; + ogs_pfcp_node_t *pfcp_node; +} smf_sess_t; + +#define SMF_BEARER(pfcp_sess) ogs_container_of(pfcp_sess, smf_bearer_t, pfcp) +typedef struct smf_bearer_s { + ogs_lnode_t lnode; /**< A node of list_t */ + uint32_t index; + + ogs_pfcp_sess_t pfcp; /* PFCP session context */ + + uint8_t ebi; + /* + * UPF-S5U-TEID = INDEX | TEID_RANGE + * INDEX = UPF-S5U-TEID & ~TEID_RANGE + */ +#define UPF_S5U_TEID_TO_INDEX(__tEID, __iND, __rANGE) \ + (__tEID & ~(__rANGE << (32 - __iND))) +#define UPF_S5U_INDEX_TO_TEID(__iNDEX, __iND, __rANGE) \ + (__iNDEX | (__rANGE << (32 - __iND))) + uint32_t upf_n3_teid; /* UPF_N3 TEID */ + ogs_sockaddr_t *upf_addr; /* UPF_N3 IPv4 */ + ogs_sockaddr_t *upf_addr6; /* UPF_N3 IPv6 */ + + uint32_t gnb_n3_teid; /* gNB_N3 TEID */ + ogs_ip_t gnb_ip; /* gNB_N3 IP */ + + char *name; /* PCC Rule Name */ + ogs_qos_t qos; /* QoS Infomration */ + + /* Packet Filter Identifier Generator(1~15) */ + uint8_t pf_identifier; + /* Packet Filter List */ + ogs_list_t pf_list; + + struct { + bool created; + bool tft_updated; + bool qos_updated; + bool removed; + } state; + + smf_sess_t *sess; +} smf_bearer_t; + +typedef struct smf_pf_s { + ogs_lnode_t lnode; + +ED3(uint8_t spare:2;, + uint8_t direction:2;, + uint8_t identifier:4;) + ogs_ipfw_rule_t rule; + + smf_bearer_t *bearer; +} smf_pf_t; + +void smf_context_init(void); +void smf_context_final(void); +smf_context_t *smf_self(void); + +int smf_context_parse_config(void); + +smf_sess_t *smf_sess_add_by_message(ogs_gtp_message_t *message); + +smf_sess_t *smf_sess_add( + uint8_t *imsi, int imsi_len, char *apn, + uint8_t pdn_type, uint8_t ebi, ogs_paa_t *addr); + +int smf_sess_remove(smf_sess_t *sess); +void smf_sess_remove_all(void); +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_imsi_apn(uint8_t *imsi, int imsi_len, char *apn); +smf_sess_t *smf_sess_find_by_ipv4(uint32_t addr); +smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6); + +smf_bearer_t *smf_bearer_add(smf_sess_t *sess); +int smf_bearer_remove(smf_bearer_t *bearer); +void smf_bearer_remove_all(smf_sess_t *sess); +smf_bearer_t *smf_bearer_find(uint32_t index); +smf_bearer_t *smf_bearer_find_by_smf_s5u_teid(uint32_t smf_s5u_teid); +smf_bearer_t *smf_bearer_find_by_ebi(smf_sess_t *sess, uint8_t ebi); +smf_bearer_t *smf_bearer_find_by_name(smf_sess_t *sess, char *name); +smf_bearer_t *smf_bearer_find_by_qci_arp(smf_sess_t *sess, + uint8_t qci, + uint8_t priority_level, + uint8_t pre_emption_capability, + uint8_t pre_emption_vulnerability); +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_pf_t *smf_pf_add(smf_bearer_t *bearer, uint32_t precedence); +int smf_pf_remove(smf_pf_t *pf); +void smf_pf_remove_all(smf_bearer_t *bearer); +smf_pf_t *smf_pf_find_by_id(smf_bearer_t *smf_bearer, uint8_t id); +smf_pf_t *smf_pf_first(smf_bearer_t *bearer); +smf_pf_t *smf_pf_next(smf_pf_t *pf); + +void stats_add_session(void); +void stats_remove_session(void); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_CONTEXT_H */ diff --git a/src/smf/event.c b/src/smf/event.c new file mode 100644 index 000000000..1e9e43376 --- /dev/null +++ b/src/smf/event.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 "event.h" +#include "context.h" + +#define EVENT_POOL 32 /* FIXME : 32 */ +static OGS_POOL(pool, smf_event_t); + +void smf_event_init(void) +{ + ogs_pool_init(&pool, EVENT_POOL); + + smf_self()->queue = ogs_queue_create(EVENT_POOL); + ogs_assert(smf_self()->queue); + smf_self()->timer_mgr = ogs_timer_mgr_create(); + ogs_assert(smf_self()->timer_mgr); + smf_self()->pollset = ogs_pollset_create(); + ogs_assert(smf_self()->pollset); +} + +void smf_event_term(void) +{ + ogs_queue_term(smf_self()->queue); + ogs_pollset_notify(smf_self()->pollset); +} + +void smf_event_final(void) +{ + if (smf_self()->pollset) + ogs_pollset_destroy(smf_self()->pollset); + if (smf_self()->timer_mgr) + ogs_timer_mgr_destroy(smf_self()->timer_mgr); + if (smf_self()->queue) + ogs_queue_destroy(smf_self()->queue); + + ogs_pool_final(&pool); +} + +smf_event_t *smf_event_new(smf_event_e id) +{ + smf_event_t *e = NULL; + + ogs_pool_alloc(&pool, &e); + ogs_assert(e); + e->id = id; + + return e; +} + +void smf_event_free(smf_event_t *e) +{ + ogs_assert(e); + ogs_pool_free(&pool, e); +} + +const char *smf_event_get_name(smf_event_t *e) +{ + if (e == NULL) + return OGS_FSM_NAME_INIT_SIG; + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + return OGS_FSM_NAME_ENTRY_SIG; + case OGS_FSM_EXIT_SIG: + return OGS_FSM_NAME_EXIT_SIG; + + case SMF_EVT_S5C_MESSAGE: + return "SMF_EVT_S5C_MESSAGE"; + case SMF_EVT_GX_MESSAGE: + return "SMF_EVT_GX_MESSAGE"; + case SMF_EVT_N4_MESSAGE: + return "SMF_EVT_N4_MESSAGE"; + case SMF_EVT_N4_TIMER: + return "SMF_EVT_N4_TIMER"; + case SMF_EVT_N4_NO_HEARTBEAT: + return "SMF_EVT_N4_NO_HEARTBEAT"; + + default: + break; + } + + return "UNKNOWN_EVENT"; +} diff --git a/src/smf/event.h b/src/smf/event.h new file mode 100644 index 000000000..8afc5c749 --- /dev/null +++ b/src/smf/event.h @@ -0,0 +1,79 @@ +/* + * 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 SMF_EVENT_H +#define SMF_EVENT_H + +#include "ogs-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ogs_gtp_node_s ogs_gtp_node_t; +typedef struct ogs_gtp_xact_s ogs_gtp_xact_t; +typedef struct ogs_pfcp_node_s ogs_pfcp_node_t; +typedef struct ogs_pfcp_xact_s ogs_pfcp_xact_t; +typedef struct ogs_pfcp_message_s ogs_pfcp_message_t; +typedef struct smf_sess_s smf_sess_t; +typedef struct smf_upf_s smf_upf_t; + +typedef enum { + SMF_EVT_BASE = OGS_FSM_USER_SIG, + + SMF_EVT_S5C_MESSAGE, + SMF_EVT_GX_MESSAGE, + + SMF_EVT_N4_MESSAGE, + SMF_EVT_N4_TIMER, + SMF_EVT_N4_NO_HEARTBEAT, + + SMF_EVT_TOP, + +} smf_event_e; + +typedef struct smf_event_s { + int id; + ogs_pkbuf_t *pkbuf; + int timer_id; + + ogs_gtp_node_t *gnode; + ogs_gtp_xact_t *gtp_xact; + + ogs_pfcp_node_t *pfcp_node; + ogs_pfcp_xact_t *pfcp_xact; + ogs_pfcp_message_t *pfcp_message; + + smf_sess_t *sess; +} smf_event_t; + +void smf_event_init(void); +void smf_event_term(void); +void smf_event_final(void); + +smf_event_t *smf_event_new(smf_event_e id); +void smf_event_free(smf_event_t *e); + +const char *smf_event_get_name(smf_event_t *e); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_EVENT_H */ diff --git a/src/smf/fd-path.c b/src/smf/fd-path.c new file mode 100644 index 000000000..6574c1bf2 --- /dev/null +++ b/src/smf/fd-path.c @@ -0,0 +1,1232 @@ +/* + * 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 "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 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; + + new = ogs_calloc(1, sizeof(*new)); + new->gx_sid = (os0_t)ogs_strdup((char *)sid); + ogs_assert(new->gx_sid); + + 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_free(sess_data); +} + +void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, + uint32_t cc_request_type) +{ + int ret; + + 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); + + 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 *)sess->imsi_bcd; + val.os.len = strlen(sess->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->pdn.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->pdn.ambr.downlink || sess->pdn.ambr.uplink) { + ret = fd_msg_avp_new(ogs_diam_gx_qos_information, 0, &avp); + ogs_assert(ret == 0); + + if (sess->pdn.ambr.uplink) { + ret = fd_msg_avp_new(ogs_diam_gx_apn_aggregate_max_bitrate_ul, + 0, &avpch1); + ogs_assert(ret == 0); + val.u32 = sess->pdn.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->pdn.ambr.downlink) { + ret = fd_msg_avp_new( + ogs_diam_gx_apn_aggregate_max_bitrate_dl, 0, &avpch1); + ogs_assert(ret == 0); + val.u32 = sess->pdn.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->pdn.qos.qci; + 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->pdn.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->pdn.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->pdn.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->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->user_location_information); + ogs_assert(sess->user_location_information.len == uli_len); + + ogs_assert(sess->user_location_information.data); + ogs_assert(sess->user_location_information.len); + memcpy(&uli_buf, sess->user_location_information.data, + sess->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->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->ue_timezone.presence && + sess->ue_timezone.len && sess->ue_timezone.data) { + ret = fd_msg_avp_new(ogs_diam_gx_3gpp_ms_timezone, 0, &avp); + ogs_assert(ret == 0); + val.os.data = sess->ue_timezone.data; + val.os.len = sess->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); + val.os.data = (uint8_t*)sess->pdn.apn; + val.os.len = strlen(sess->pdn.apn); + 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_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_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->pdn.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->pdn.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->pdn.qos.qci = 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->pdn.qos.arp.priority_level = hdr->avp_value->u32; + } + + 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->pdn.qos.arp.pre_emption_capability = + hdr->avp_value->u32; + } + + 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->pdn.qos.arp.pre_emption_vulnerability = + hdr->avp_value->u32; + } + } + } + + 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: + { + ogs_pcc_rule_t *pcc_rule = &gx_message->pcc_rule + [gx_message->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->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(smf_self()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + ogs_diam_gx_message_free(gx_message); + ogs_pkbuf_free(e->pkbuf); + smf_event_free(e); + } else { + ogs_pollset_notify(smf_self()->pollset); + } + } else { + ogs_diam_gx_message_free(gx_message); + 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; + + 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_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: + { + ogs_pcc_rule_t *pcc_rule = &gx_message->pcc_rule + [gx_message->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->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: + { + ogs_pcc_rule_t *pcc_rule = &gx_message->pcc_rule + [gx_message->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->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(smf_self()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + ogs_diam_gx_message_free(gx_message); + ogs_pkbuf_free(e->pkbuf); + smf_event_free(e); + } else { + ogs_pollset_notify(smf_self()->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_diam_gx_message_free(gx_message); + ogs_pkbuf_free(gxbuf); + + return 0; +} + +int smf_fd_init(void) +{ + int ret; + struct disp_when data; + + ret = ogs_diam_init(FD_MODE_CLIENT|FD_MODE_SERVER, + smf_self()->diam_conf_path, smf_self()->diam_config); + ogs_assert(ret == 0); + + /* 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); + + return OGS_OK; +} + +void smf_fd_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_diam_final(); +} + +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) { + 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: + { + ogs_flow_t *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_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.qci = 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++; + } + + 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 { + ogs_error("no_Preemption-Capability"); + error++; + } + + 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 { + ogs_error("no_Preemption-Vulnerability"); + error++; + } + } 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 new file mode 100644 index 000000000..0f5000e64 --- /dev/null +++ b/src/smf/fd-path.h @@ -0,0 +1,42 @@ +/* + * 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 SMF_FD_PATH_H +#define SMF_FD_PATH_H + +#include "context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct gtp_xact_s gtp_xact_t; + +int smf_fd_init(void); +void smf_fd_final(void); + +void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, + uint32_t cc_request_type); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_FD_PATH_H */ + diff --git a/src/smf/gtp-path.c b/src/smf/gtp-path.c new file mode 100644 index 000000000..e15fd7783 --- /dev/null +++ b/src/smf/gtp-path.c @@ -0,0 +1,156 @@ +/* + * 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 "context.h" + +#include "event.h" +#include "gtp-path.h" +#include "s5c-build.h" + +#define SMF_GTP_HANDLED 1 + +static void _gtpv2_c_recv_cb(short when, ogs_socket_t fd, void *data) +{ + smf_event_t *e = NULL; + int rv; + ssize_t size; + ogs_pkbuf_t *pkbuf = NULL; + ogs_sockaddr_t from; + ogs_gtp_node_t *gnode = NULL; + + ogs_assert(fd != INVALID_SOCKET); + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); + + size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from); + if (size <= 0) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "ogs_recvfrom() failed"); + ogs_pkbuf_free(pkbuf); + return; + } + + ogs_pkbuf_trim(pkbuf, size); + + e = smf_event_new(SMF_EVT_S5C_MESSAGE); + gnode = ogs_gtp_node_find_by_addr(&smf_self()->sgw_s5c_list, &from); + if (!gnode) { + gnode = ogs_gtp_node_add_by_addr(&smf_self()->sgw_s5c_list, &from); + ogs_assert(gnode); + gnode->sock = data; + } + ogs_assert(e); + e->gnode = gnode; + e->pkbuf = pkbuf; + + rv = ogs_queue_push(smf_self()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + ogs_pkbuf_free(e->pkbuf); + smf_event_free(e); + } +} + +int smf_gtp_open(void) +{ + ogs_socknode_t *node = NULL; + ogs_sock_t *sock = NULL; + + ogs_list_for_each(&smf_self()->gtpc_list, node) { + sock = ogs_gtp_server(node); + ogs_assert(sock); + + node->poll = ogs_pollset_add(smf_self()->pollset, + OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); + } + ogs_list_for_each(&smf_self()->gtpc_list6, node) { + sock = ogs_gtp_server(node); + ogs_assert(sock); + + node->poll = ogs_pollset_add(smf_self()->pollset, + OGS_POLLIN, sock->fd, _gtpv2_c_recv_cb, sock); + } + + smf_self()->gtpc_sock = ogs_socknode_sock_first(&smf_self()->gtpc_list); + if (smf_self()->gtpc_sock) + smf_self()->gtpc_addr = &smf_self()->gtpc_sock->local_addr; + + smf_self()->gtpc_sock6 = ogs_socknode_sock_first(&smf_self()->gtpc_list6); + if (smf_self()->gtpc_sock6) + smf_self()->gtpc_addr6 = &smf_self()->gtpc_sock6->local_addr; + + ogs_assert(smf_self()->gtpc_addr || smf_self()->gtpc_addr6); + + return OGS_OK; +} + +void smf_gtp_close(void) +{ + ogs_socknode_remove_all(&smf_self()->gtpc_list); + ogs_socknode_remove_all(&smf_self()->gtpc_list6); +} + +void smf_gtp_send_create_session_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact) +{ + int rv; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(sess); + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_CREATE_SESSION_RESPONSE_TYPE; + h.teid = sess->sgw_s5c_teid; + + pkbuf = smf_s5c_build_create_session_response(h.type, sess); + 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); +} + +void smf_gtp_send_delete_session_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact) +{ + int rv; + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(xact); + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.type = OGS_GTP_DELETE_SESSION_RESPONSE_TYPE; + h.teid = sess->sgw_s5c_teid; + + pkbuf = smf_s5c_build_delete_session_response(h.type, sess); + 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); +} diff --git a/src/smf/gtp-path.h b/src/smf/gtp-path.h new file mode 100644 index 000000000..b45e43cc3 --- /dev/null +++ b/src/smf/gtp-path.h @@ -0,0 +1,42 @@ +/* + * 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 SMF_GTP_PATH_H +#define SMF_GTP_PATH_H + +#include "ogs-tun.h" +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int smf_gtp_open(void); +void smf_gtp_close(void); + +void smf_gtp_send_create_session_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact); +void smf_gtp_send_delete_session_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_GTP_PATH_H */ diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c new file mode 100644 index 000000000..52a4ac8a5 --- /dev/null +++ b/src/smf/gx-handler.c @@ -0,0 +1,119 @@ +/* + * 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 "context.h" +#include "gtp-path.h" +#include "pfcp-path.h" +#include "gx-handler.h" +#include "bearer-binding.h" + +static uint8_t gtp_cause_from_diameter( + const uint32_t *dia_err, const uint32_t *dia_exp_err) +{ + if (dia_exp_err) { + } + if (dia_err) { + switch (*dia_err) { + case OGS_DIAM_UNKNOWN_SESSION_ID: + return OGS_GTP_CAUSE_APN_ACCESS_DENIED_NO_SUBSCRIPTION; + } + } + + ogs_error("Unexpected Diameter Result Code %d/%d, defaulting to severe " + "network failure", + dia_err ? *dia_err : -1, dia_exp_err ? *dia_exp_err : -1); + return OGS_GTP_CAUSE_UE_NOT_AUTHORISED_BY_OCS_OR_EXTERNAL_AAA_SERVER; +} + +void smf_gx_handle_cca_initial_request( + smf_sess_t *sess, ogs_diam_gx_message_t *gx_message, + ogs_gtp_xact_t *gtp_xact) +{ + int i; + ogs_assert(sess); + ogs_assert(gx_message); + ogs_assert(gtp_xact); + + ogs_debug("[PGW] Create Session Response"); + ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + if (gx_message->result_code != ER_DIAMETER_SUCCESS) { + uint8_t cause_value = gtp_cause_from_diameter( + gx_message->err, gx_message->exp_err); + + ogs_gtp_send_error_message(gtp_xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value); + return; + } + + if (sess->pdn.ambr.downlink || sess->pdn.ambr.uplink) { + smf_bearer_t *bearer = smf_default_bearer_in_sess(sess); + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_qer_t *qer = NULL; + ogs_assert(bearer); + + /* Only 1 QER is used per bearer */ + qer = ogs_list_first(&bearer->pfcp.qer_list); + if (!qer) { + qer = ogs_pfcp_qer_add(&bearer->pfcp); + ogs_assert(qer); + qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1); + } + + qer->mbr.uplink = sess->pdn.ambr.uplink; + qer->mbr.downlink = sess->pdn.ambr.downlink; + + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) + ogs_pfcp_pdr_associate_qer(pdr, qer); + } + + sess->num_of_pcc_rule = gx_message->num_of_pcc_rule; + for (i = 0; i < gx_message->num_of_pcc_rule; i++) + OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]); + + smf_pfcp_send_session_establishment_request(sess, gtp_xact); +} + +void smf_gx_handle_cca_termination_request( + smf_sess_t *sess, ogs_diam_gx_message_t *gx_message, + ogs_gtp_xact_t *gtp_xact) +{ + ogs_assert(sess); + ogs_assert(gx_message); + ogs_assert(gtp_xact); + + ogs_debug("[SMF] Delete Session Response"); + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + smf_pfcp_send_session_deletion_request(sess, gtp_xact); +} + +void smf_gx_handle_re_auth_request( + smf_sess_t *sess, ogs_diam_gx_message_t *gx_message) +{ + int i; + + sess->num_of_pcc_rule = gx_message->num_of_pcc_rule; + for (i = 0; i < gx_message->num_of_pcc_rule; i++) + OGS_STORE_PCC_RULE(&sess->pcc_rule[i], &gx_message->pcc_rule[i]); + + smf_bearer_binding(sess); +} diff --git a/src/smf/gx-handler.h b/src/smf/gx-handler.h new file mode 100644 index 000000000..30b165da0 --- /dev/null +++ b/src/smf/gx-handler.h @@ -0,0 +1,42 @@ +/* + * 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 SMF_GX_HANDLER_H +#define SMF_GX_HANDLER_H + +#include "context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void smf_gx_handle_cca_initial_request( + smf_sess_t *sess, ogs_diam_gx_message_t *gx_message, + ogs_gtp_xact_t *gtp_xact); +void smf_gx_handle_cca_termination_request( + smf_sess_t *sess, ogs_diam_gx_message_t *gx_message, + ogs_gtp_xact_t *gtp_xact); +void smf_gx_handle_re_auth_request( + smf_sess_t *sess, ogs_diam_gx_message_t *gx_message); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_GX_HANDLER_H */ diff --git a/src/smf/init.c b/src/smf/init.c new file mode 100644 index 000000000..7f0e2dddc --- /dev/null +++ b/src/smf/init.c @@ -0,0 +1,145 @@ +/* + * 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 "context.h" +#include "event.h" +#include "smf-sm.h" + +#include "fd-path.h" + +static ogs_thread_t *thread; +static void smf_main(void *data); + +static int initialized = 0; + +int smf_initialize() +{ + int rv; + + ogs_pfcp_context_init(ogs_config()->max.upf * OGS_MAX_NUM_OF_GTPU_RESOURCE); + smf_context_init(); + smf_event_init(); + + rv = ogs_gtp_xact_init(smf_self()->timer_mgr, 512); + if (rv != OGS_OK) return rv; + + rv = ogs_pfcp_xact_init(smf_self()->timer_mgr, 512); + if (rv != OGS_OK) return rv; + + rv = ogs_pfcp_context_parse_config("smf", "upf"); + if (rv != OGS_OK) return rv; + + rv = smf_context_parse_config(); + if (rv != OGS_OK) return rv; + + rv = ogs_log_config_domain( + ogs_config()->logger.domain, ogs_config()->logger.level); + if (rv != OGS_OK) return rv; + + rv = ogs_pfcp_ue_pool_generate(); + if (rv != OGS_OK) return rv; + + rv = smf_fd_init(); + if (rv != 0) return OGS_ERROR; + + thread = ogs_thread_create(smf_main, NULL); + if (!thread) return OGS_ERROR; + + initialized = 1; + + return OGS_OK; +} + +void smf_terminate(void) +{ + if (!initialized) return; + + smf_event_term(); + + ogs_thread_destroy(thread); + + smf_fd_final(); + + smf_context_final(); + ogs_pfcp_context_final(); + + ogs_pfcp_xact_final(); + ogs_gtp_xact_final(); + + smf_event_final(); +} + +static void smf_main(void *data) +{ + ogs_fsm_t smf_sm; + int rv; + + ogs_fsm_create(&smf_sm, smf_state_initial, smf_state_final); + ogs_fsm_init(&smf_sm, 0); + + for ( ;; ) { + ogs_pollset_poll(smf_self()->pollset, + ogs_timer_mgr_next(smf_self()->timer_mgr)); + + /* Process the MESSAGE FIRST. + * + * For example, if UE Context Release Complete is received, + * the MME_TIMER_UE_CONTEXT_RELEASE is first stopped */ + for ( ;; ) { + smf_event_t *e = NULL; + + rv = ogs_queue_trypop(smf_self()->queue, (void**)&e); + ogs_assert(rv != OGS_ERROR); + + if (rv == OGS_DONE) + goto done; + + if (rv == OGS_RETRY) + break; + + ogs_assert(e); + ogs_fsm_dispatch(&smf_sm, e); + smf_event_free(e); + } + + ogs_timer_mgr_expire(smf_self()->timer_mgr); + + /* AND THEN, process the TIMER. */ + for ( ;; ) { + smf_event_t *e = NULL; + + rv = ogs_queue_trypop(smf_self()->queue, (void**)&e); + ogs_assert(rv != OGS_ERROR); + + if (rv == OGS_DONE) + goto done; + + if (rv == OGS_RETRY) + break; + + ogs_assert(e); + ogs_fsm_dispatch(&smf_sm, e); + smf_event_free(e); + } + } +done: + + ogs_fsm_fini(&smf_sm, 0); + ogs_fsm_delete(&smf_sm); +} diff --git a/src/smf/meson.build b/src/smf/meson.build new file mode 100644 index 000000000..b596ede57 --- /dev/null +++ b/src/smf/meson.build @@ -0,0 +1,90 @@ +# 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 . + +smf_conf = configuration_data() + +smf_headers = (''' + net/if.h +'''.split()) + +foreach h : smf_headers + if cc.has_header(h) + define = 'HAVE_' + h.underscorify().to_upper() + smf_conf.set(define, 1) + endif +endforeach + +configure_file(output : 'smf-config.h', configuration : smf_conf) + +libsmf_sources = files(''' + event.h + timer.h + context.h + smf-sm.h + gtp-path.h + s5c-build.h + s5c-handler.h + fd-path.h + gx-handler.h + pfcp-path.h + n4-build.h + n4-handler.h + bearer-binding.h + + init.c + event.c + timer.c + context.c + smf-sm.c + pfcp-sm.c + gtp-path.c + s5c-build.c + s5c-handler.c + fd-path.c + gx-handler.c + pfcp-path.c + n4-build.c + n4-handler.c + bearer-binding.c +'''.split()) + +libsmf = static_library('smf', + sources : libsmf_sources, + link_with : libipfw, + dependencies : [ + libapp_dep, libdiameter_gx_dep, libgtp_dep, libpfcp_dep, libipfw_dep + ], + install : false) + +libsmf_dep = declare_dependency( + link_with : libsmf, + dependencies : [ + libapp_dep, libdiameter_gx_dep, libgtp_dep, libpfcp_dep, libipfw_dep + ]) + +smf_sources = files(''' + app.c + ../main.c +'''.split()) + +executable('open5gs-smfd', + sources : smf_sources, + c_args : '-DDEFAULT_CONFIG_FILENAME="@0@/smf.yaml"'.format(open5gs_sysconfdir), + include_directories : srcinc, + dependencies : libsmf_dep, + install_rpath : libdir, + install : true) diff --git a/src/smf/n4-build.c b/src/smf/n4-build.c new file mode 100644 index 000000000..ebbe03375 --- /dev/null +++ b/src/smf/n4-build.c @@ -0,0 +1,534 @@ +/* + * 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 "context.h" +#include "n4-build.h" + +ogs_pkbuf_t *smf_n4_build_association_setup_request(uint8_t type) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_association_setup_request_t *req = NULL; + + ogs_pfcp_node_id_t node_id; + int node_id_len = 0; + + ogs_debug("[SMF] Association Setup Request"); + + req = &pfcp_message.pfcp_association_setup_request; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + ogs_pfcp_sockaddr_to_node_id( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + ogs_config()->parameter.prefer_ipv4, + &node_id, &node_id_len); + req->node_id.presence = 1; + req->node_id.data = &node_id; + req->node_id.len = node_id_len; + + req->recovery_time_stamp.presence = 1; + req->recovery_time_stamp.u32 = ogs_pfcp_self()->pfcp_started; + + req->cp_function_features.presence = 1; + req->cp_function_features.u8 = smf_self()->function_features; + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} + +ogs_pkbuf_t *smf_n4_build_association_setup_response(uint8_t type, + uint8_t cause) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_association_setup_response_t *rsp = NULL; + + ogs_pfcp_node_id_t node_id; + int node_id_len = 0; + + ogs_debug("[SMF] Association Setup Response"); + + rsp = &pfcp_message.pfcp_association_setup_response; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + ogs_pfcp_sockaddr_to_node_id( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + ogs_config()->parameter.prefer_ipv4, + &node_id, &node_id_len); + rsp->node_id.presence = 1; + rsp->node_id.data = &node_id; + rsp->node_id.len = node_id_len; + + rsp->cause.presence = 1; + rsp->cause.u8 = cause; + + rsp->recovery_time_stamp.presence = 1; + rsp->recovery_time_stamp.u32 = ogs_pfcp_self()->pfcp_started; + + rsp->cp_function_features.presence = 1; + rsp->cp_function_features.u8 = smf_self()->function_features; + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} + +static struct { + ogs_pfcp_ue_ip_addr_t addr; + ogs_pfcp_outer_header_removal_t outer_header_removal; + ogs_pfcp_f_teid_t f_teid; + char apn[OGS_MAX_APN_LEN]; + char *sdf_filter[OGS_MAX_NUM_OF_RULE]; +} create_pdr_buf[OGS_MAX_NUM_OF_PDR]; + +static void create_pdr_buf_init(void) +{ + memset(create_pdr_buf, 0, sizeof(create_pdr_buf)); +} +static void create_pdr_buf_clear(void) +{ + int i, j; + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + for (j = 0; j < OGS_MAX_NUM_OF_RULE; j++) { + if (create_pdr_buf[i].sdf_filter[j]) + ogs_free(create_pdr_buf[i].sdf_filter[j]); + } + } +} + +static void build_create_pdr( + ogs_pfcp_tlv_create_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr) +{ + ogs_pfcp_far_t *far = NULL; + ogs_pfcp_sess_t *pfcp_sess = NULL; + smf_sess_t *sess = NULL; + smf_bearer_t *bearer = NULL; + int j = 0; + int len = 0; + + ogs_assert(message); + + ogs_assert(pdr); + pfcp_sess = pdr->sess; + ogs_assert(pfcp_sess); + bearer = SMF_BEARER(pfcp_sess); + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + far = pdr->far; + ogs_assert(far); + + message->presence = 1; + message->pdr_id.presence = 1; + message->pdr_id.u16 = pdr->id; + + message->precedence.presence = 1; + message->precedence.u32 = pdr->precedence; + + message->pdi.presence = 1; + message->pdi.source_interface.presence = 1; + message->pdi.source_interface.u8 = pdr->src_if; + + message->pdi.network_instance.presence = 1; + message->pdi.network_instance.len = ogs_fqdn_build( + create_pdr_buf[i].apn, sess->pdn.apn, strlen(sess->pdn.apn)); + message->pdi.network_instance.data = create_pdr_buf[i].apn; + + for (j = 0; j < pdr->num_of_flow; j++) { + ogs_pfcp_sdf_filter_t pfcp_sdf_filter[OGS_MAX_NUM_OF_RULE]; + pfcp_sdf_filter[j].fd = 1; + pfcp_sdf_filter[j].flow_description_len = + strlen(pdr->flow_description[j]); + pfcp_sdf_filter[j].flow_description = pdr->flow_description[j]; + len = sizeof(ogs_pfcp_sdf_filter_t) + + pfcp_sdf_filter[j].flow_description_len; + + message->pdi.sdf_filter[j].presence = 1; + create_pdr_buf[i].sdf_filter[j] = ogs_calloc(1, len); + ogs_pfcp_build_sdf_filter(&message->pdi.sdf_filter[j], + &pfcp_sdf_filter[j], create_pdr_buf[i].sdf_filter[j], len); + } + + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE && + far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Dowklink */ + if (smf_bearer_is_default(bearer)) { /* Default Bearer */ + ogs_pfcp_paa_to_ue_ip_addr(&sess->pdn.paa, + &create_pdr_buf[i].addr, &len); + create_pdr_buf[i].addr.sd = OGS_PFCP_UE_IP_DST; + + message->pdi.ue_ip_address.presence = 1; + message->pdi.ue_ip_address.data = &create_pdr_buf[i].addr; + message->pdi.ue_ip_address.len = len; + } + + } else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS && + far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */ + ogs_pfcp_sockaddr_to_f_teid( + bearer->upf_addr, bearer->upf_addr6, + &create_pdr_buf[i].f_teid, &len); + create_pdr_buf[i].f_teid.teid = htobe32(bearer->upf_n3_teid); + + message->pdi.local_f_teid.presence = 1; + message->pdi.local_f_teid.data = &create_pdr_buf[i].f_teid; + message->pdi.local_f_teid.len = len; + + if (sess->pdn.paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4) { + create_pdr_buf[i].outer_header_removal.description = + OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV4; + } else if (sess->pdn.paa.pdn_type == OGS_GTP_PDN_TYPE_IPV6) { + create_pdr_buf[i].outer_header_removal.description = + OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IPV6; + } else if (sess->pdn.paa.pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { + create_pdr_buf[i].outer_header_removal.description = + OGS_PFCP_OUTER_HEADER_REMOVAL_GTPU_UDP_IP; + } else + ogs_assert_if_reached(); + + message->outer_header_removal.presence = 1; + message->outer_header_removal.data = + &create_pdr_buf[i].outer_header_removal.description; + message->outer_header_removal.len = 1; + } + + if (pdr->far) { + message->far_id.presence = 1; + message->far_id.u32 = pdr->far->id; + } + + if (pdr->urr) { + message->urr_id.presence = 1; + message->urr_id.u32 = pdr->urr->id; + } + + if (pdr->qer) { + message->qer_id.presence = 1; + message->qer_id.u32 = pdr->qer->id; + } +} + +static struct { + ogs_pfcp_outer_header_creation_t outer_header_creation; +} create_far_buf[OGS_MAX_NUM_OF_FAR]; + +static void build_create_far( + ogs_pfcp_tlv_create_far_t *message, int i, ogs_pfcp_far_t *far) +{ + ogs_pfcp_sess_t *pfcp_sess = NULL; + smf_bearer_t *bearer = NULL; + int len; + + ogs_assert(message); + ogs_assert(far); + pfcp_sess = far->sess; + ogs_assert(pfcp_sess); + bearer = SMF_BEARER(pfcp_sess); + ogs_assert(bearer); + + message->presence = 1; + message->far_id.presence = 1; + message->far_id.u32 = far->id; + + message->apply_action.presence = 1; + message->apply_action.u8 = far->apply_action; + + message->forwarding_parameters.presence = 1; + message->forwarding_parameters.destination_interface.presence = 1; + message->forwarding_parameters.destination_interface.u8 = far->dst_if; + + if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */ + ogs_pfcp_ip_to_outer_header_creation(&bearer->gnb_ip, + &create_far_buf[i].outer_header_creation, &len); + create_far_buf[i].outer_header_creation.teid = + htobe32(bearer->gnb_n3_teid); + + message->forwarding_parameters.outer_header_creation.presence = 1; + message->forwarding_parameters.outer_header_creation.data = + &create_far_buf[i].outer_header_creation; + message->forwarding_parameters.outer_header_creation.len = len; + } +} + +static void build_create_urr( + ogs_pfcp_tlv_create_urr_t *message, int i, ogs_pfcp_urr_t *urr) +{ + ogs_assert(message); + ogs_assert(urr); + + message->presence = 1; + message->urr_id.presence = 1; + message->urr_id.u32 = urr->id; +} + +static struct { + char mbr[OGS_PFCP_BITRATE_LEN]; + char gbr[OGS_PFCP_BITRATE_LEN]; +} create_qer_buf[OGS_MAX_NUM_OF_QER], update_qer_buf[OGS_MAX_NUM_OF_QER]; + +static void build_create_qer( + ogs_pfcp_tlv_create_qer_t *message, int i, ogs_pfcp_qer_t *qer) +{ + ogs_assert(message); + ogs_assert(qer); + + message->presence = 1; + message->qer_id.presence = 1; + message->qer_id.u32 = qer->id; + + message->gate_status.presence = 1; + message->gate_status.u8 = qer->gate_status.value; + + if (qer->mbr.uplink || qer->mbr.downlink) { + message->maximum_bitrate.presence = 1; + ogs_pfcp_build_bitrate( + &message->maximum_bitrate, + &qer->mbr, create_qer_buf[i].mbr, OGS_PFCP_BITRATE_LEN); + } + if (qer->gbr.uplink || qer->gbr.downlink) { + message->guaranteed_bitrate.presence = 1; + ogs_pfcp_build_bitrate( + &message->guaranteed_bitrate, + &qer->gbr, create_qer_buf[i].gbr, OGS_PFCP_BITRATE_LEN); + } +} + +static void build_update_qer( + ogs_pfcp_tlv_update_qer_t *message, int i, ogs_pfcp_qer_t *qer) +{ + ogs_assert(message); + ogs_assert(qer); + + message->presence = 1; + message->qer_id.presence = 1; + message->qer_id.u32 = qer->id; + + if (qer->mbr.uplink || qer->mbr.downlink) { + message->maximum_bitrate.presence = 1; + ogs_pfcp_build_bitrate( + &message->maximum_bitrate, + &qer->mbr, update_qer_buf[i].mbr, OGS_PFCP_BITRATE_LEN); + } + if (qer->gbr.uplink || qer->gbr.downlink) { + message->guaranteed_bitrate.presence = 1; + ogs_pfcp_build_bitrate( + &message->guaranteed_bitrate, + &qer->gbr, update_qer_buf[i].gbr, OGS_PFCP_BITRATE_LEN); + } +} + +ogs_pkbuf_t *smf_n4_build_session_establishment_request( + uint8_t type, smf_sess_t *sess) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_session_establishment_request_t *req = NULL; + ogs_pkbuf_t *pkbuf = NULL; + + smf_bearer_t *bearer = NULL; + + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; + ogs_pfcp_urr_t *urr = NULL; + ogs_pfcp_qer_t *qer = NULL; + int i; + + ogs_pfcp_node_id_t node_id; + ogs_pfcp_f_seid_t f_seid; + int len; + + ogs_debug("[SMF] Session Establishment Request"); + ogs_assert(sess); + + req = &pfcp_message.pfcp_session_establishment_request; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + /* Node ID */ + ogs_pfcp_sockaddr_to_node_id( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + ogs_config()->parameter.prefer_ipv4, + &node_id, &len); + req->node_id.presence = 1; + req->node_id.data = &node_id; + req->node_id.len = len; + + /* F-SEID */ + ogs_pfcp_sockaddr_to_f_seid( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + &f_seid, &len); + f_seid.seid = htobe64(sess->smf_n4_seid); + req->cp_f_seid.presence = 1; + req->cp_f_seid.data = &f_seid; + req->cp_f_seid.len = len; + + create_pdr_buf_init(); + + /* Create PDR */ + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) { + build_create_pdr(&req->create_pdr[i], i, pdr); + i++; + } + } + + /* Create FAR */ + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_list_for_each(&bearer->pfcp.far_list, far) { + build_create_far(&req->create_far[i], i, far); + i++; + } + } + + /* Create URR */ + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_list_for_each(&bearer->pfcp.urr_list, urr) { + build_create_urr(&req->create_urr[i], i, urr); + i++; + } + } + + /* Create QER */ + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_list_for_each(&bearer->pfcp.qer_list, qer) { + build_create_qer(&req->create_qer[i], i, qer); + i++; + } + } + + /* PDN Type */ + req->pdn_type.presence = 1; + req->pdn_type.u8 = sess->pdn.paa.pdn_type; + + pfcp_message.h.type = type; + pkbuf = ogs_pfcp_build_msg(&pfcp_message); + + create_pdr_buf_clear(); + + return pkbuf; +} + +ogs_pkbuf_t *smf_n4_build_session_modification_request( + uint8_t type, smf_bearer_t *bearer) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_session_modification_request_t *req = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; + ogs_pfcp_qer_t *qer = NULL; + ogs_pkbuf_t *pkbuf = NULL; + int i; + + smf_sess_t *sess = NULL; + + ogs_debug("[SMF] Session Modification Request"); + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + req = &pfcp_message.pfcp_session_modification_request; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + if (bearer->state.removed) { + /* Remove PDR */ + i = 0; + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) { + ogs_pfcp_tlv_remove_pdr_t *message = &req->remove_pdr[i]; + + message->presence = 1; + message->pdr_id.presence = 1; + message->pdr_id.u16 = pdr->id; + i++; + } + + /* Remove FAR */ + i = 0; + ogs_list_for_each(&bearer->pfcp.far_list, far) { + ogs_pfcp_tlv_remove_far_t *message = &req->remove_far[i]; + + message->presence = 1; + message->far_id.presence = 1; + message->far_id.u32 = far->id; + i++; + } + + /* Remove QER */ + i = 0; + ogs_list_for_each(&bearer->pfcp.qer_list, qer) { + ogs_pfcp_tlv_remove_qer_t *message = &req->remove_qer[i]; + + message->presence = 1; + message->qer_id.presence = 1; + message->qer_id.u32 = qer->id; + i++; + } + } else { + if (bearer->state.created) { + create_pdr_buf_init(); + + /* Create PDR */ + i = 0; + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) { + build_create_pdr(&req->create_pdr[i], i, pdr); + i++; + } + + /* Create FAR */ + i = 0; + ogs_list_for_each(&bearer->pfcp.far_list, far) { + build_create_far(&req->create_far[i], i, far); + i++; + } + + /* Create QER */ + i = 0; + ogs_list_for_each(&bearer->pfcp.qer_list, qer) { + build_create_qer(&req->create_qer[i], i, qer); + i++; + } + } + if (bearer->state.qos_updated) { + /* Update QER */ + i = 0; + ogs_list_for_each(&bearer->pfcp.qer_list, qer) { + build_update_qer(&req->update_qer[i], i, qer); + i++; + } + } + } + + pfcp_message.h.type = type; + pkbuf = ogs_pfcp_build_msg(&pfcp_message); + + if (bearer->state.created) { + create_pdr_buf_clear(); + } + + return pkbuf; +} + +ogs_pkbuf_t *smf_n4_build_session_deletion_request( + uint8_t type, smf_sess_t *sess) +{ + ogs_pfcp_message_t pfcp_message; + + ogs_debug("[SMF] Session Deletion Request"); + ogs_assert(sess); + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} diff --git a/src/smf/n4-build.h b/src/smf/n4-build.h new file mode 100644 index 000000000..7c5cf5325 --- /dev/null +++ b/src/smf/n4-build.h @@ -0,0 +1,44 @@ +/* + * 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 SMF_N4_BUILD_H +#define SMF_N4_BUILD_H + +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ogs_pkbuf_t *smf_n4_build_association_setup_request(uint8_t type); +ogs_pkbuf_t *smf_n4_build_association_setup_response(uint8_t type, + uint8_t cause); + +ogs_pkbuf_t *smf_n4_build_session_establishment_request( + uint8_t type, smf_sess_t *sess); +ogs_pkbuf_t *smf_n4_build_session_modification_request( + uint8_t type, smf_bearer_t *bearer); +ogs_pkbuf_t *smf_n4_build_session_deletion_request( + uint8_t type, smf_sess_t *sess); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_N4_BUILD_H */ diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c new file mode 100644 index 000000000..80cdc62b2 --- /dev/null +++ b/src/smf/n4-handler.c @@ -0,0 +1,257 @@ +/* + * 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 "context.h" +#include "timer.h" +#include "pfcp-path.h" +#include "gtp-path.h" +#include "n4-handler.h" +#include "bearer-binding.h" + +static uint8_t gtp_cause_from_pfcp(uint8_t pfcp_cause) +{ + switch (pfcp_cause) { + case OGS_PFCP_CAUSE_REQUEST_ACCEPTED: + return OGS_GTP_CAUSE_REQUEST_ACCEPTED; + case OGS_PFCP_CAUSE_REQUEST_REJECTED: + return OGS_GTP_CAUSE_REQUEST_REJECTED_REASON_NOT_SPECIFIED; + case OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND: + return OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; + case OGS_PFCP_CAUSE_MANDATORY_IE_MISSING: + return OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + case OGS_PFCP_CAUSE_CONDITIONAL_IE_MISSING: + return OGS_GTP_CAUSE_CONDITIONAL_IE_MISSING; + case OGS_PFCP_CAUSE_INVALID_LENGTH: + return OGS_GTP_CAUSE_INVALID_LENGTH; + case OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT: + return OGS_GTP_CAUSE_MANDATORY_IE_INCORRECT; + case OGS_PFCP_CAUSE_INVALID_FORWARDING_POLICY: + case OGS_PFCP_CAUSE_INVALID_F_TEID_ALLOCATION_OPTION: + return OGS_GTP_CAUSE_INVALID_MESSAGE_FORMAT; + case OGS_PFCP_CAUSE_NO_ESTABLISHED_PFCP_ASSOCIATION: + return OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + case OGS_PFCP_CAUSE_RULE_CREATION_MODIFICATION_FAILURE: + return OGS_GTP_CAUSE_SEMANTIC_ERROR_IN_THE_TFT_OPERATION; + case OGS_PFCP_CAUSE_PFCP_ENTITY_IN_CONGESTION: + return OGS_GTP_CAUSE_GTP_C_ENTITY_CONGESTION; + case OGS_PFCP_CAUSE_NO_RESOURCES_AVAILABLE: + return OGS_GTP_CAUSE_NO_RESOURCES_AVAILABLE; + case OGS_PFCP_CAUSE_SERVICE_NOT_SUPPORTED: + return OGS_GTP_CAUSE_SERVICE_NOT_SUPPORTED; + case OGS_PFCP_CAUSE_SYSTEM_FAILURE: + return OGS_GTP_CAUSE_SYSTEM_FAILURE; + default: + return OGS_GTP_CAUSE_SYSTEM_FAILURE; + } + + return OGS_GTP_CAUSE_SYSTEM_FAILURE; +} + +void smf_n4_handle_association_setup_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_request_t *req) +{ + int i; + + ogs_assert(xact); + ogs_assert(node); + ogs_assert(req); + + smf_pfcp_send_association_setup_response( + xact, OGS_PFCP_CAUSE_REQUEST_ACCEPTED); + + ogs_pfcp_gtpu_resource_remove_all(&node->gtpu_resource_list); + + for (i = 0; i < OGS_MAX_NUM_OF_GTPU_RESOURCE; i++) { + ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = + &req->user_plane_ip_resource_information[i]; + ogs_pfcp_user_plane_ip_resource_info_t info; + + if (message->presence == 0) + break; + + ogs_pfcp_parse_user_plane_ip_resource_info(&info, message); + ogs_pfcp_gtpu_resource_add(&node->gtpu_resource_list, &info); + } +} + +void smf_n4_handle_association_setup_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_response_t *rsp) +{ + int i; + + ogs_assert(xact); + ogs_pfcp_xact_commit(xact); + + ogs_assert(node); + ogs_assert(rsp); + + ogs_pfcp_gtpu_resource_remove_all(&node->gtpu_resource_list); + + for (i = 0; i < OGS_MAX_NUM_OF_GTPU_RESOURCE; i++) { + ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = + &rsp->user_plane_ip_resource_information[i]; + ogs_pfcp_user_plane_ip_resource_info_t info; + + if (message->presence == 0) + break; + + ogs_pfcp_parse_user_plane_ip_resource_info(&info, message); + ogs_pfcp_gtpu_resource_add(&node->gtpu_resource_list, &info); + } +} + +void smf_n4_handle_heartbeat_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_request_t *req) +{ + ogs_assert(xact); + ogs_pfcp_send_heartbeat_response(xact); +} + +void smf_n4_handle_heartbeat_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_response_t *rsp) +{ + ogs_assert(xact); + ogs_pfcp_xact_commit(xact); + + ogs_timer_start(node->t_heartbeat, + smf_timer_cfg(SMF_TIMER_HEARTBEAT)->duration); +} + +void smf_n4_handle_session_establishment_response( + smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_establishment_response_t *rsp) +{ + uint8_t cause_value = 0; + ogs_gtp_xact_t *gtp_xact = NULL; + ogs_pfcp_f_seid_t *up_f_seid = NULL; + + ogs_assert(xact); + ogs_assert(rsp); + + gtp_xact = xact->assoc_xact; + ogs_assert(gtp_xact); + + ogs_pfcp_xact_commit(xact); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_warn("No Context"); + cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; + } + + if (rsp->up_f_seid.presence == 0) { + ogs_error("No UP F-SEID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + if (rsp->cause.presence) { + if (rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { + ogs_warn("Cause[%d] : No Accepted", rsp->cause.u8); + cause_value = gtp_cause_from_pfcp(rsp->cause.u8); + } + } 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(gtp_xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value); + return; + } + + ogs_assert(sess); + + /* UP F-SEID */ + up_f_seid = rsp->up_f_seid.data; + ogs_assert(up_f_seid); + sess->upf_n4_seid = be64toh(up_f_seid->seid); + + smf_gtp_send_create_session_response(sess, gtp_xact); + + smf_bearer_binding(sess); +} + +void smf_n4_handle_session_modification_response( + smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_modification_response_t *rsp) +{ + smf_bearer_t *bearer = NULL; + + ogs_assert(xact); + ogs_assert(rsp); + + bearer = xact->data; + ogs_assert(bearer); + + ogs_pfcp_xact_commit(xact); + + if (bearer->state.removed) + smf_bearer_remove(bearer); +} + +void smf_n4_handle_session_deletion_response( + smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_deletion_response_t *rsp) +{ + uint8_t cause_value = 0; + ogs_gtp_xact_t *gtp_xact = NULL; + + ogs_assert(xact); + ogs_assert(rsp); + + gtp_xact = xact->assoc_xact; + ogs_assert(gtp_xact); + + ogs_pfcp_xact_commit(xact); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_warn("No Context"); + cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; + } + + if (rsp->cause.presence) { + if (rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { + ogs_warn("Cause[%d] : No Accepted", rsp->cause.u8); + cause_value = gtp_cause_from_pfcp(rsp->cause.u8); + } + } 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(gtp_xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_DELETE_SESSION_RESPONSE_TYPE, cause_value); + return; + } + + ogs_assert(sess); + + smf_gtp_send_delete_session_response(sess, gtp_xact); + + smf_sess_remove(sess); +} diff --git a/src/smf/n4-handler.h b/src/smf/n4-handler.h new file mode 100644 index 000000000..8176d6162 --- /dev/null +++ b/src/smf/n4-handler.h @@ -0,0 +1,56 @@ +/* + * 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 UPF_N4_HANDLER_H +#define UPF_N4_HANDLER_H + +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void smf_n4_handle_association_setup_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_request_t *req); +void smf_n4_handle_association_setup_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_response_t *req); +void smf_n4_handle_heartbeat_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_request_t *req); +void smf_n4_handle_heartbeat_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_response_t *req); + +void smf_n4_handle_session_establishment_response( + smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_establishment_response_t *rsp); +void smf_n4_handle_session_modification_response( + smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_modification_response_t *rsp); +void smf_n4_handle_session_deletion_response( + smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_deletion_response_t *rsp); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_N4_HANDLER_H */ diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c new file mode 100644 index 000000000..dcf0b98e3 --- /dev/null +++ b/src/smf/pfcp-path.c @@ -0,0 +1,305 @@ +/* + * 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 "context.h" + +#include "event.h" +#include "smf-sm.h" + +#include "pfcp-path.h" +#include "n4-build.h" + +static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data) +{ + int rv; + + ssize_t size; + smf_event_t *e = NULL; + ogs_pkbuf_t *pkbuf = NULL; + ogs_sockaddr_t from; + ogs_pfcp_node_t *node = NULL; + ogs_pfcp_header_t *h = NULL; + + ogs_assert(fd != INVALID_SOCKET); + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); + + size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from); + if (size <= 0) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "ogs_recvfrom() failed"); + ogs_pkbuf_free(pkbuf); + return; + } + + ogs_pkbuf_trim(pkbuf, size); + + h = (ogs_pfcp_header_t *)pkbuf->data; + if (h->version > OGS_PFCP_VERSION) { + ogs_pfcp_header_t rsp; + + ogs_error("Not supported version[%d]", h->version); + + memset(&rsp, 0, sizeof rsp); + rsp.flags = (OGS_PFCP_VERSION << 5); + rsp.type = OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE; + rsp.length = htobe16(4); + rsp.sqn_only = h->sqn_only; + ogs_sendto(fd, &rsp, 8, 0, &from); + ogs_pkbuf_free(pkbuf); + + return; + } + + e = smf_event_new(SMF_EVT_N4_MESSAGE); + node = ogs_pfcp_node_find(&ogs_pfcp_self()->n4_list, &from); + if (!node) { + node = ogs_pfcp_node_add(&ogs_pfcp_self()->n4_list, &from); + ogs_assert(node); + node->sock = data; + } + ogs_assert(e); + e->pfcp_node = node; + e->pkbuf = pkbuf; + + rv = ogs_queue_push(smf_self()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + ogs_pkbuf_free(e->pkbuf); + smf_event_free(e); + } +} + +int smf_pfcp_open(void) +{ + ogs_socknode_t *node = NULL; + ogs_sock_t *sock = NULL; + + /* PFCP Server */ + ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) { + sock = ogs_pfcp_server(node); + ogs_assert(sock); + + node->poll = ogs_pollset_add(smf_self()->pollset, + OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); + } + ogs_list_for_each(&ogs_pfcp_self()->pfcp_list6, node) { + sock = ogs_pfcp_server(node); + ogs_assert(sock); + + node->poll = ogs_pollset_add(smf_self()->pollset, + OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); + } + + ogs_pfcp_self()->pfcp_sock = + ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list); + if (ogs_pfcp_self()->pfcp_sock) + ogs_pfcp_self()->pfcp_addr = &ogs_pfcp_self()->pfcp_sock->local_addr; + + ogs_pfcp_self()->pfcp_sock6 = + ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list6); + if (ogs_pfcp_self()->pfcp_sock6) + ogs_pfcp_self()->pfcp_addr6 = &ogs_pfcp_self()->pfcp_sock6->local_addr; + + ogs_assert(ogs_pfcp_self()->pfcp_addr || ogs_pfcp_self()->pfcp_addr6); + + return OGS_OK; +} + +void smf_pfcp_close(void) +{ + ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); + ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list6); +} + +static void timeout(ogs_pfcp_xact_t *xact, void *data) +{ + int rv; + + smf_event_t *e = NULL; + uint8_t type; + + ogs_assert(xact); + type = xact->seq[0].type; + + switch (type) { + case OGS_PFCP_HEARTBEAT_REQUEST_TYPE: + ogs_assert(data); + + e = smf_event_new(SMF_EVT_N4_NO_HEARTBEAT); + e->pfcp_node = data; + + rv = ogs_queue_push(smf_self()->queue, e); + if (rv != OGS_OK) { + ogs_warn("ogs_queue_push() failed:%d", (int)rv); + smf_event_free(e); + } + break; + default: + break; + } +} + +void smf_pfcp_send_association_setup_request(ogs_pfcp_node_t *node) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(node); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE; + h.seid = 0; + + n4buf = smf_n4_build_association_setup_request(h.type); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create(node, &h, n4buf, timeout, node); + ogs_expect_or_return(xact); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void smf_pfcp_send_association_setup_response(ogs_pfcp_xact_t *xact, + uint8_t cause) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE; + h.seid = 0; + + n4buf = smf_n4_build_association_setup_response(h.type, cause); + ogs_expect_or_return(n4buf); + + rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void smf_pfcp_send_heartbeat_request(ogs_pfcp_node_t *node) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(node); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_HEARTBEAT_REQUEST_TYPE; + h.seid = 0; + + n4buf = ogs_pfcp_n4_build_heartbeat_request(h.type); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create(node, &h, n4buf, timeout, node); + ogs_expect_or_return(xact); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void smf_pfcp_send_session_establishment_request( + smf_sess_t *sess, void *gtp_xact) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + + n4buf = smf_n4_build_session_establishment_request(h.type, sess); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create( + sess->pfcp_node, &h, n4buf, timeout, sess); + ogs_expect_or_return(xact); + xact->assoc_xact = gtp_xact; + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void smf_pfcp_send_session_modification_request(smf_bearer_t *bearer) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + smf_sess_t *sess = NULL; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + + n4buf = smf_n4_build_session_modification_request(h.type, bearer); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create( + sess->pfcp_node, &h, n4buf, timeout, bearer); + ogs_expect_or_return(xact); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void smf_pfcp_send_session_deletion_request(smf_sess_t *sess, void *gtp_xact) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_DELETION_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + + n4buf = smf_n4_build_session_deletion_request(h.type, sess); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create( + sess->pfcp_node, &h, n4buf, timeout, sess); + ogs_expect_or_return(xact); + xact->assoc_xact = gtp_xact; + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} diff --git a/src/smf/pfcp-path.h b/src/smf/pfcp-path.h new file mode 100644 index 000000000..255a04e39 --- /dev/null +++ b/src/smf/pfcp-path.h @@ -0,0 +1,47 @@ +/* + * 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 SMF_PFCP_PATH_H +#define SMF_PFCP_PATH_H + +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int smf_pfcp_open(void); +void smf_pfcp_close(void); + +void smf_pfcp_send_association_setup_request(ogs_pfcp_node_t *node); +void smf_pfcp_send_association_setup_response(ogs_pfcp_xact_t *xact, + uint8_t cause); +void smf_pfcp_send_heartbeat_request(ogs_pfcp_node_t *node); + +void smf_pfcp_send_session_establishment_request( + smf_sess_t *sess, void *gtp_xact); +void smf_pfcp_send_session_modification_request(smf_bearer_t *bearer); +void smf_pfcp_send_session_deletion_request( + smf_sess_t *sess, void *gtp_xact); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_PFCP_PATH_H */ diff --git a/src/smf/pfcp-sm.c b/src/smf/pfcp-sm.c new file mode 100644 index 000000000..0b5bfb605 --- /dev/null +++ b/src/smf/pfcp-sm.c @@ -0,0 +1,268 @@ +/* + * 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 "context.h" +#include "event.h" +#include "timer.h" +#include "smf-sm.h" + +#include "pfcp-path.h" +#include "n4-handler.h" + +void smf_pfcp_state_initial(ogs_fsm_t *s, smf_event_t *e) +{ + int rv; + ogs_pfcp_node_t *node = NULL; + + ogs_assert(s); + ogs_assert(e); + + smf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + + rv = ogs_pfcp_connect( + ogs_pfcp_self()->pfcp_sock, ogs_pfcp_self()->pfcp_sock6, node); + ogs_assert(rv == OGS_OK); + + node->t_association = ogs_timer_add(smf_self()->timer_mgr, + smf_timer_association, node); + ogs_assert(node->t_association); + node->t_heartbeat = ogs_timer_add(smf_self()->timer_mgr, + smf_timer_heartbeat, node); + ogs_assert(node->t_heartbeat); + + OGS_FSM_TRAN(s, &smf_pfcp_state_will_associate); +} + +void smf_pfcp_state_final(ogs_fsm_t *s, smf_event_t *e) +{ + ogs_pfcp_node_t *node = NULL; + ogs_assert(s); + ogs_assert(e); + + smf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + + ogs_timer_delete(node->t_association); + ogs_timer_delete(node->t_heartbeat); +} + +void smf_pfcp_state_will_associate(ogs_fsm_t *s, smf_event_t *e) +{ + char buf[OGS_ADDRSTRLEN]; + + ogs_pfcp_node_t *node = NULL; + ogs_pfcp_xact_t *xact = NULL; + ogs_pfcp_message_t *message = NULL; + + ogs_sockaddr_t *addr = NULL; + + ogs_assert(s); + ogs_assert(e); + + smf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + addr = node->sa_list; + ogs_assert(addr); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + ogs_timer_start(node->t_association, + smf_timer_cfg(SMF_TIMER_ASSOCIATION)->duration); + + smf_pfcp_send_association_setup_request(node); + break; + case OGS_FSM_EXIT_SIG: + ogs_timer_stop(node->t_association); + break; + case SMF_EVT_N4_TIMER: + switch(e->timer_id) { + case SMF_TIMER_ASSOCIATION: + node = e->pfcp_node; + ogs_assert(node); + + ogs_warn("Retry to association with peer [%s]:%d failed", + OGS_ADDR(addr, buf), OGS_PORT(addr)); + + ogs_timer_start(node->t_association, + smf_timer_cfg(SMF_TIMER_ASSOCIATION)->duration); + + smf_pfcp_send_association_setup_request(node); + break; + default: + ogs_error("Unknown timer[%s:%d]", + smf_timer_get_name(e->timer_id), e->timer_id); + break; + } + break; + case SMF_EVT_N4_MESSAGE: + message = e->pfcp_message; + ogs_assert(message); + xact = e->pfcp_xact; + ogs_assert(xact); + + switch (message->h.type) { + case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: + smf_n4_handle_association_setup_request(node, xact, + &message->pfcp_association_setup_request); + OGS_FSM_TRAN(s, smf_pfcp_state_associated); + break; + case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE: + smf_n4_handle_association_setup_response(node, xact, + &message->pfcp_association_setup_response); + OGS_FSM_TRAN(s, smf_pfcp_state_associated); + break; + default: + ogs_error("cannot handle PFCP message type[%d]", + message->h.type); + break; + } + break; + default: + ogs_error("Unknown event %s", smf_event_get_name(e)); + break; + } +} + +void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) +{ + char buf[OGS_ADDRSTRLEN]; + + ogs_pfcp_node_t *node = NULL; + ogs_pfcp_xact_t *xact = NULL; + ogs_pfcp_message_t *message = NULL; + + ogs_sockaddr_t *addr = NULL; + smf_sess_t *sess = NULL; + + ogs_assert(s); + ogs_assert(e); + + smf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + addr = node->sa_list; + ogs_assert(addr); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + ogs_info("PFCP associated"); + ogs_timer_start(node->t_heartbeat, + smf_timer_cfg(SMF_TIMER_HEARTBEAT)->duration); + break; + case OGS_FSM_EXIT_SIG: + ogs_info("PFCP de-associated"); + ogs_timer_stop(node->t_heartbeat); + break; + case SMF_EVT_N4_MESSAGE: + message = e->pfcp_message; + ogs_assert(message); + xact = e->pfcp_xact; + ogs_assert(xact); + + if (message->h.seid_presence && message->h.seid != 0) + sess = smf_sess_find_by_seid(message->h.seid); + + switch (message->h.type) { + case OGS_PFCP_HEARTBEAT_REQUEST_TYPE: + smf_n4_handle_heartbeat_request(node, xact, + &message->pfcp_heartbeat_request); + break; + case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE: + smf_n4_handle_heartbeat_response(node, xact, + &message->pfcp_heartbeat_response); + break; + case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: + ogs_warn("PFCP[REQ] has already been associated"); + smf_n4_handle_association_setup_request(node, xact, + &message->pfcp_association_setup_request); + break; + case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE: + ogs_warn("PFCP[RSP] has already been associated"); + smf_n4_handle_association_setup_response(node, xact, + &message->pfcp_association_setup_response); + break; + case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE: + smf_n4_handle_session_establishment_response( + sess, xact, &message->pfcp_session_establishment_response); + break; + case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE: + smf_n4_handle_session_modification_response( + sess, xact, &message->pfcp_session_modification_response); + break; + case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE: + smf_n4_handle_session_deletion_response( + sess, xact, &message->pfcp_session_deletion_response); + break; + default: + ogs_error("Not implemented PFCP message type[%d]", + message->h.type); + break; + } + + break; + case SMF_EVT_N4_TIMER: + switch(e->timer_id) { + case SMF_TIMER_HEARTBEAT: + node = e->pfcp_node; + ogs_assert(node); + + smf_pfcp_send_heartbeat_request(node); + break; + default: + ogs_error("Unknown timer[%s:%d]", + smf_timer_get_name(e->timer_id), e->timer_id); + break; + } + break; + case SMF_EVT_N4_NO_HEARTBEAT: + ogs_warn("No Heartbeat from UPF [%s]:%d", + OGS_ADDR(addr, buf), OGS_PORT(addr)); + OGS_FSM_TRAN(s, smf_pfcp_state_will_associate); + break; + default: + ogs_error("Unknown event %s", smf_event_get_name(e)); + break; + } +} + +void smf_pfcp_state_exception(ogs_fsm_t *s, smf_event_t *e) +{ + ogs_assert(s); + ogs_assert(e); + + smf_sm_debug(e); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + break; + case OGS_FSM_EXIT_SIG: + break; + default: + ogs_error("Unknown event %s", smf_event_get_name(e)); + break; + } +} diff --git a/src/smf/s5c-build.c b/src/smf/s5c-build.c new file mode 100644 index 000000000..1cc962e01 --- /dev/null +++ b/src/smf/s5c-build.c @@ -0,0 +1,535 @@ +/* + * 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 "context.h" +#include "s5c-build.h" + +#include "ipfw/ipfw2.h" + +static int16_t smf_pco_build(uint8_t *pco_buf, ogs_gtp_tlv_pco_t *tlv_pco); + +ogs_pkbuf_t *smf_s5c_build_create_session_response( + uint8_t type, smf_sess_t *sess) +{ + int rv; + smf_bearer_t *bearer = NULL; + + ogs_gtp_message_t gtp_message; + ogs_gtp_create_session_response_t *rsp = NULL; + + ogs_gtp_cause_t cause; + ogs_gtp_f_teid_t smf_s5c_teid, upf_n3_teid; + int len; + uint8_t pco_buf[OGS_MAX_PCO_LEN]; + int16_t pco_len; + + ogs_debug("[SMF] Create Session Response"); + + ogs_assert(sess); + bearer = smf_default_bearer_in_sess(sess); + ogs_assert(bearer); + + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]", + bearer->gnb_n3_teid, bearer->upf_n3_teid); + + rsp = >p_message.create_session_response; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + /* Set Cause */ + memset(&cause, 0, sizeof(cause)); + cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + rsp->cause.presence = 1; + rsp->cause.len = sizeof(cause); + rsp->cause.data = &cause; + + /* 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; + smf_s5c_teid.teid = htobe32(sess->smf_n4_teid); + rv = ogs_gtp_sockaddr_to_f_teid( + smf_self()->gtpc_addr, smf_self()->gtpc_addr6, &smf_s5c_teid, &len); + ogs_assert(rv == OGS_OK); + rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface. + presence = 1; + rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface. + data = &smf_s5c_teid; + rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface. + len = len; + + /* PDN Address Allocation */ + rsp->pdn_address_allocation.data = &sess->pdn.paa; + if (sess->ipv4 && sess->ipv6) + rsp->pdn_address_allocation.len = OGS_PAA_IPV4V6_LEN; + else if (sess->ipv4) + rsp->pdn_address_allocation.len = OGS_PAA_IPV4_LEN; + else if (sess->ipv6) + rsp->pdn_address_allocation.len = OGS_PAA_IPV6_LEN; + else + ogs_assert_if_reached(); + rsp->pdn_address_allocation.presence = 1; + + /* APN Restriction */ + rsp->apn_restriction.presence = 1; + rsp->apn_restriction.u8 = OGS_GTP_APN_NO_RESTRICTION; + + /* TODO : APN-AMBR + * if PCRF changes APN-AMBR, this should be included. */ + + /* PCO */ + if (sess->ue_pco.presence && sess->ue_pco.len && sess->ue_pco.data) { + pco_len = smf_pco_build(pco_buf, &sess->ue_pco); + ogs_assert(pco_len > 0); + rsp->protocol_configuration_options.presence = 1; + rsp->protocol_configuration_options.data = pco_buf; + rsp->protocol_configuration_options.len = pco_len; + } + + /* Bearer EBI */ + rsp->bearer_contexts_created.presence = 1; + rsp->bearer_contexts_created.eps_bearer_id.presence = 1; + rsp->bearer_contexts_created.eps_bearer_id.u8 = bearer->ebi; + + /* Bearer Cause */ + rsp->bearer_contexts_created.cause.presence = 1; + rsp->bearer_contexts_created.cause.len = sizeof(cause); + rsp->bearer_contexts_created.cause.data = &cause; + + /* TODO : Bearer QoS + * if PCRF changes Bearer QoS, this should be included. */ + + /* Data Plane(UL) : SMF-S5U */ + memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t)); + upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; + upf_n3_teid.teid = htobe32(bearer->upf_n3_teid); + rv = ogs_gtp_sockaddr_to_f_teid( + bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len); + ogs_assert(rv == OGS_OK); + rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence = 1; + rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &upf_n3_teid; + rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.len = len; + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + +ogs_pkbuf_t *smf_s5c_build_delete_session_response( + uint8_t type, smf_sess_t *sess) +{ + ogs_gtp_message_t gtp_message; + ogs_gtp_delete_session_response_t *rsp = NULL; + + ogs_gtp_cause_t cause; + uint8_t pco_buf[OGS_MAX_PCO_LEN]; + int16_t pco_len; + + /* prepare cause */ + memset(&cause, 0, sizeof(cause)); + cause.value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + rsp = >p_message.delete_session_response; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + /* Cause */ + rsp->cause.presence = 1; + rsp->cause.len = sizeof(cause); + rsp->cause.data = &cause; + + /* Recovery */ + + /* PCO */ + if (sess->ue_pco.presence && sess->ue_pco.len && sess->ue_pco.data) { + pco_len = smf_pco_build(pco_buf, &sess->ue_pco); + ogs_assert(pco_len > 0); + rsp->protocol_configuration_options.presence = 1; + rsp->protocol_configuration_options.data = pco_buf; + rsp->protocol_configuration_options.len = pco_len; + } + + /* Private Extension */ + + /* 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) +{ + int rv; + smf_sess_t *sess = NULL; + smf_bearer_t *linked_bearer = NULL; + + ogs_gtp_message_t gtp_message; + ogs_gtp_create_bearer_request_t *req = NULL; + + ogs_gtp_f_teid_t upf_n3_teid; + ogs_gtp_bearer_qos_t bearer_qos; + char bearer_qos_buf[GTP_BEARER_QOS_LEN]; + int len; + char tft_buf[OGS_GTP_MAX_TRAFFIC_FLOW_TEMPLATE]; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + linked_bearer = smf_default_bearer_in_sess(sess); + ogs_assert(linked_bearer); + + ogs_debug("[SMF] Create Bearer Request"); + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + req = >p_message.create_bearer_request; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + /* Linked EBI */ + req->linked_eps_bearer_id.presence = 1; + req->linked_eps_bearer_id.u8 = linked_bearer->ebi; + + /* Bearer EBI */ + req->bearer_contexts.presence = 1; + req->bearer_contexts.eps_bearer_id.presence = 1; + req->bearer_contexts.eps_bearer_id.u8 = bearer->ebi; + + /* Data Plane(UL) : SMF_S5U */ + memset(&upf_n3_teid, 0, sizeof(ogs_gtp_f_teid_t)); + upf_n3_teid.interface_type = OGS_GTP_F_TEID_S5_S8_PGW_GTP_U; + upf_n3_teid.teid = htobe32(bearer->upf_n3_teid); + rv = ogs_gtp_sockaddr_to_f_teid( + bearer->upf_addr, bearer->upf_addr6, &upf_n3_teid, &len); + ogs_assert(rv == OGS_OK); + req->bearer_contexts.s5_s8_u_sgw_f_teid.presence = 1; + req->bearer_contexts.s5_s8_u_sgw_f_teid.data = &upf_n3_teid; + req->bearer_contexts.s5_s8_u_sgw_f_teid.len = len; + + /* Bearer QoS */ + memset(&bearer_qos, 0, sizeof(bearer_qos)); + bearer_qos.qci = bearer->qos.qci; + bearer_qos.priority_level = bearer->qos.arp.priority_level; + bearer_qos.pre_emption_capability = + bearer->qos.arp.pre_emption_capability; + bearer_qos.pre_emption_vulnerability = + bearer->qos.arp.pre_emption_vulnerability; + bearer_qos.dl_mbr = bearer->qos.mbr.downlink; + bearer_qos.ul_mbr = bearer->qos.mbr.uplink; + bearer_qos.dl_gbr = bearer->qos.gbr.downlink; + bearer_qos.ul_gbr = bearer->qos.gbr.uplink; + + req->bearer_contexts.bearer_level_qos.presence = 1; + ogs_gtp_build_bearer_qos(&req->bearer_contexts.bearer_level_qos, + &bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN); + + /* Bearer TFT */ + if (tft && tft->num_of_packet_filter) { + req->bearer_contexts.tft.presence = 1; + ogs_gtp_build_tft(&req->bearer_contexts.tft, + tft, tft_buf, OGS_GTP_MAX_TRAFFIC_FLOW_TEMPLATE); + } + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + +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) +{ + smf_sess_t *sess = NULL; + + ogs_gtp_message_t gtp_message; + ogs_gtp_update_bearer_request_t *req = NULL; + + ogs_gtp_ambr_t ambr; + ogs_gtp_bearer_qos_t bearer_qos; + char bearer_qos_buf[GTP_BEARER_QOS_LEN]; + char tft_buf[OGS_GTP_MAX_TRAFFIC_FLOW_TEMPLATE]; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + + ogs_debug("[SMF] Update Bearer Request"); + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + req = >p_message.update_bearer_request; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + /* Bearer EBI */ + req->bearer_contexts.presence = 1; + req->bearer_contexts.eps_bearer_id.presence = 1; + req->bearer_contexts.eps_bearer_id.u8 = bearer->ebi; + + if (sess->pdn.ambr.uplink || sess->pdn.ambr.downlink) { + /* + * Ch 8.7. Aggregate Maximum Bit Rate(AMBR) in TS 29.274 V15.9.0 + * + * AMBR is defined in clause 9.9.4.2 of 3GPP TS 24.301 [23], + * but it shall be encoded as shown in Figure 8.7-1 as + * Unsigned32 binary integer values in kbps (1000 bits per second). + */ + memset(&ambr, 0, sizeof(ogs_gtp_ambr_t)); + ambr.uplink = htobe32(sess->pdn.ambr.uplink / 1000); + ambr.downlink = htobe32(sess->pdn.ambr.downlink / 1000); + req->aggregate_maximum_bit_rate.presence = 1; + req->aggregate_maximum_bit_rate.data = &ambr; + req->aggregate_maximum_bit_rate.len = sizeof(ambr); + } + + /* PTI */ + if (pti) { + req->procedure_transaction_id.presence = 1; + req->procedure_transaction_id.u8 = pti; + } + + /* Bearer QoS */ + if (qos_presence == 1) { + memset(&bearer_qos, 0, sizeof(bearer_qos)); + bearer_qos.qci = bearer->qos.qci; + bearer_qos.priority_level = bearer->qos.arp.priority_level; + bearer_qos.pre_emption_capability = + bearer->qos.arp.pre_emption_capability; + bearer_qos.pre_emption_vulnerability = + bearer->qos.arp.pre_emption_vulnerability; + bearer_qos.dl_mbr = bearer->qos.mbr.downlink; + bearer_qos.ul_mbr = bearer->qos.mbr.uplink; + bearer_qos.dl_gbr = bearer->qos.gbr.downlink; + bearer_qos.ul_gbr = bearer->qos.gbr.uplink; + + req->bearer_contexts.bearer_level_qos.presence = 1; + ogs_gtp_build_bearer_qos(&req->bearer_contexts.bearer_level_qos, + &bearer_qos, bearer_qos_buf, GTP_BEARER_QOS_LEN); + } + + /* Bearer TFT */ + if (tft && tft->num_of_packet_filter) { + req->bearer_contexts.tft.presence = 1; + ogs_gtp_build_tft(&req->bearer_contexts.tft, + tft, tft_buf, OGS_GTP_MAX_TRAFFIC_FLOW_TEMPLATE); + } + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + +ogs_pkbuf_t *smf_s5c_build_delete_bearer_request( + uint8_t type, smf_bearer_t *bearer, uint8_t pti) +{ + smf_sess_t *sess = NULL; + smf_bearer_t *linked_bearer = NULL; + + ogs_gtp_message_t gtp_message; + ogs_gtp_delete_bearer_request_t *req = NULL; + + ogs_assert(bearer); + sess = bearer->sess; + ogs_assert(sess); + linked_bearer = smf_default_bearer_in_sess(sess); + ogs_assert(linked_bearer); + + ogs_debug("[SMF] Delete Bearer Request"); + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + req = >p_message.delete_bearer_request; + memset(>p_message, 0, sizeof(ogs_gtp_message_t)); + + if (bearer->ebi == linked_bearer->ebi) { + /* Linked EBI */ + req->linked_eps_bearer_id.presence = 1; + req->linked_eps_bearer_id.u8 = bearer->ebi; + } else { + /* Bearer EBI */ + req->eps_bearer_ids.presence = 1; + req->eps_bearer_ids.u8 = bearer->ebi; + } + + if (pti) { + req->procedure_transaction_id.presence = 1; + req->procedure_transaction_id.u8 = pti; + } + + gtp_message.h.type = type; + return ogs_gtp_build_msg(>p_message); +} + +static int16_t smf_pco_build(uint8_t *pco_buf, ogs_gtp_tlv_pco_t *tlv_pco) +{ + int rv; + ogs_pco_t ue, smf; + ogs_pco_ipcp_t pco_ipcp; + ogs_ipsubnet_t dns_primary, dns_secondary, dns6_primary, dns6_secondary; + ogs_ipsubnet_t p_cscf, p_cscf6; + int size = 0; + int i = 0; + uint16_t mtu = 0; + + ogs_assert(pco_buf); + ogs_assert(tlv_pco); + + size = ogs_pco_parse(&ue, tlv_pco->data, tlv_pco->len); + ogs_assert(size); + + memset(&smf, 0, sizeof(ogs_pco_t)); + smf.ext = ue.ext; + smf.configuration_protocol = ue.configuration_protocol; + + for (i = 0; i < ue.num_of_id; i++) { + uint8_t *data = ue.ids[i].data; + switch(ue.ids[i].id) { + case OGS_PCO_ID_CHALLENGE_HANDSHAKE_AUTHENTICATION_PROTOCOL: + if (data[0] == 2) { /* Code : Response */ + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = 4; + smf.ids[smf.num_of_id].data = + (uint8_t *)"\x03\x00\x00\x04"; /* Code : Success */ + smf.num_of_id++; + } + break; + case OGS_PCO_ID_INTERNET_PROTOCOL_CONTROL_PROTOCOL: + if (data[0] == 1) { /* Code : Configuration Request */ + uint16_t len = 0; + + ogs_assert(smf_self()->dns[0] || smf_self()->dns[1]); + + memset(&pco_ipcp, 0, sizeof(ogs_pco_ipcp_t)); + pco_ipcp.code = 2; /* Code : Configuration Ack */ + pco_ipcp.len = htobe16(len); + + len = 4; + /* Primary DNS Server IP Address */ + if (smf_self()->dns[0]) { + rv = ogs_ipsubnet( + &dns_primary, smf_self()->dns[0], NULL); + ogs_assert(rv == OGS_OK); + pco_ipcp.options[0].type = 129; + pco_ipcp.options[0].len = 6; + pco_ipcp.options[0].addr = dns_primary.sub[0]; + len += 6; + } + + /* Secondary DNS Server IP Address */ + if (smf_self()->dns[1]) { + rv = ogs_ipsubnet( + &dns_secondary, smf_self()->dns[1], NULL); + ogs_assert(rv == OGS_OK); + pco_ipcp.options[1].type = 131; + pco_ipcp.options[1].len = 6; + pco_ipcp.options[1].addr = dns_secondary.sub[0]; + len += 6; + } + + pco_ipcp.len = htobe16(len); + + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = len; + smf.ids[smf.num_of_id].data = (uint8_t *)&pco_ipcp; + + smf.num_of_id++; + } + break; + case OGS_PCO_ID_DNS_SERVER_IPV4_ADDRESS_REQUEST: + if (smf_self()->dns[0]) { + rv = ogs_ipsubnet( + &dns_primary, smf_self()->dns[0], NULL); + ogs_assert(rv == OGS_OK); + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = OGS_IPV4_LEN; + smf.ids[smf.num_of_id].data = dns_primary.sub; + smf.num_of_id++; + } + + if (smf_self()->dns[1]) { + rv = ogs_ipsubnet( + &dns_secondary, smf_self()->dns[1], NULL); + ogs_assert(rv == OGS_OK); + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = OGS_IPV4_LEN; + smf.ids[smf.num_of_id].data = dns_secondary.sub; + smf.num_of_id++; + } + break; + case OGS_PCO_ID_DNS_SERVER_IPV6_ADDRESS_REQUEST: + if (smf_self()->dns6[0]) { + rv = ogs_ipsubnet( + &dns6_primary, smf_self()->dns6[0], NULL); + ogs_assert(rv == OGS_OK); + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = OGS_IPV6_LEN; + smf.ids[smf.num_of_id].data = dns6_primary.sub; + smf.num_of_id++; + } + + if (smf_self()->dns6[1]) { + rv = ogs_ipsubnet( + &dns6_secondary, smf_self()->dns6[1], NULL); + ogs_assert(rv == OGS_OK); + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = OGS_IPV6_LEN; + smf.ids[smf.num_of_id].data = dns6_secondary.sub; + smf.num_of_id++; + } + break; + case OGS_PCO_ID_P_CSCF_IPV4_ADDRESS_REQUEST: + if (smf_self()->num_of_p_cscf) { + rv = ogs_ipsubnet(&p_cscf, + smf_self()->p_cscf[smf_self()->p_cscf_index], NULL); + ogs_assert(rv == OGS_OK); + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = OGS_IPV4_LEN; + smf.ids[smf.num_of_id].data = p_cscf.sub; + smf.num_of_id++; + + smf_self()->p_cscf_index++; + smf_self()->p_cscf_index %= smf_self()->num_of_p_cscf; + } + break; + case OGS_PCO_ID_P_CSCF_IPV6_ADDRESS_REQUEST: + if (smf_self()->num_of_p_cscf6) { + rv = ogs_ipsubnet(&p_cscf6, + smf_self()->p_cscf6[smf_self()->p_cscf6_index], NULL); + ogs_assert(rv == OGS_OK); + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = OGS_IPV6_LEN; + smf.ids[smf.num_of_id].data = p_cscf6.sub; + smf.num_of_id++; + + smf_self()->p_cscf6_index++; + smf_self()->p_cscf6_index %= smf_self()->num_of_p_cscf6; + } + break; + case OGS_PCO_ID_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING: + /* TODO */ + break; + case OGS_PCO_ID_IPV4_LINK_MTU_REQUEST: + if (smf_self()->mtu) { + mtu = htons(smf_self()->mtu); + smf.ids[smf.num_of_id].id = ue.ids[i].id; + smf.ids[smf.num_of_id].len = sizeof(uint16_t); + smf.ids[smf.num_of_id].data = &mtu; + smf.num_of_id++; + } + break; + default: + ogs_warn("Unknown PCO ID:(0x%x)", ue.ids[i].id); + } + } + + size = ogs_pco_build(pco_buf, OGS_MAX_PCO_LEN, &smf); + return size; +} diff --git a/src/smf/s5c-build.h b/src/smf/s5c-build.h new file mode 100644 index 000000000..4fd54f973 --- /dev/null +++ b/src/smf/s5c-build.h @@ -0,0 +1,45 @@ +/* + * 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 SMF_S5C_BUILD_H +#define SMF_S5C_BUILD_H + +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ogs_pkbuf_t *smf_s5c_build_create_session_response( + uint8_t type, smf_sess_t *sess); +ogs_pkbuf_t *smf_s5c_build_delete_session_response( + uint8_t type, smf_sess_t *sess); + +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); +#ifdef __cplusplus +} +#endif + +#endif /* SMF_S5C_BUILD_H */ diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c new file mode 100644 index 000000000..9f90b2f19 --- /dev/null +++ b/src/smf/s5c-handler.c @@ -0,0 +1,689 @@ +/* + * 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 "event.h" +#include "context.h" +#include "gtp-path.h" +#include "fd-path.h" +#include "s5c-build.h" +#include "s5c-handler.h" +#include "pfcp-path.h" + +#include "ipfw/ipfw2.h" + +void smf_s5c_handle_echo_request( + ogs_gtp_xact_t *xact, ogs_gtp_echo_request_t *req) +{ + ogs_assert(xact); + ogs_assert(req); + + ogs_debug("[PGW] Receiving Echo Request"); + /* FIXME : Before implementing recovery counter correctly, + * I'll re-use the recovery value in request message */ + ogs_gtp_send_echo_response(xact, req->recovery.u8, 0); +} + +void smf_s5c_handle_echo_response( + ogs_gtp_xact_t *xact, ogs_gtp_echo_response_t *req) +{ + /* Not Implemented */ +} + +void smf_s5c_handle_create_session_request( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_create_session_request_t *req) +{ + int rv; + uint8_t cause_value = 0; + ogs_gtp_f_teid_t *sgw_s5c_teid, *gnb_n3_teid; + smf_bearer_t *bearer = NULL; + ogs_gtp_bearer_qos_t bearer_qos; + ogs_gtp_ambr_t *ambr = NULL; + uint16_t decoded = 0; + + ogs_assert(xact); + ogs_assert(req); + + ogs_debug("[SMF] Create Session Reqeust"); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + if (sess) { + bearer = smf_default_bearer_in_sess(sess); + ogs_assert(bearer); + } + if (!bearer) { + ogs_warn("No Context"); + cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; + } + + if (req->imsi.presence == 0) { + ogs_error("No IMSI"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (req->sender_f_teid_for_control_plane.presence == 0) { + ogs_error("No TEID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (req->bearer_contexts_to_be_created.presence == 0) { + ogs_error("No Bearer"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (req->bearer_contexts_to_be_created.bearer_level_qos.presence == 0) { + 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 (!ogs_diam_peer_connected()) { + ogs_error("No Diameter Peer"); + cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + } + + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_CREATE_SESSION_RESPONSE_TYPE, cause_value); + return; + } + + /* Set IMSI */ + sess->imsi_len = req->imsi.len; + memcpy(sess->imsi, req->imsi.data, sess->imsi_len); + ogs_buffer_to_bcd(sess->imsi, sess->imsi_len, sess->imsi_bcd); + + /* Control Plane(DL) : SGW-S5C */ + 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) : gNB-N3 */ + gnb_n3_teid = req->bearer_contexts_to_be_created.s5_s8_u_sgw_f_teid.data; + ogs_assert(gnb_n3_teid); + bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid); + rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_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); + ogs_debug(" gNB_N3_TEID[0x%x] UPF_N3_TEID[0x%x]", + bearer->gnb_n3_teid, bearer->upf_n3_teid); + + decoded = ogs_gtp_parse_bearer_qos(&bearer_qos, + &req->bearer_contexts_to_be_created.bearer_level_qos); + ogs_assert(req->bearer_contexts_to_be_created.bearer_level_qos.len == + decoded); + sess->pdn.qos.qci = bearer_qos.qci; + sess->pdn.qos.arp.priority_level = bearer_qos.priority_level; + sess->pdn.qos.arp.pre_emption_capability = + bearer_qos.pre_emption_capability; + sess->pdn.qos.arp.pre_emption_vulnerability = + bearer_qos.pre_emption_vulnerability; + + /* Set AMBR if available */ + if (req->aggregate_maximum_bit_rate.presence) { + /* + * Ch 8.7. Aggregate Maximum Bit Rate(AMBR) in TS 29.274 V15.9.0 + * + * AMBR is defined in clause 9.9.4.2 of 3GPP TS 24.301 [23], + * but it shall be encoded as shown in Figure 8.7-1 as + * Unsigned32 binary integer values in kbps (1000 bits per second). + */ + ambr = req->aggregate_maximum_bit_rate.data; + sess->pdn.ambr.downlink = be32toh(ambr->downlink) * 1000; + sess->pdn.ambr.uplink = be32toh(ambr->uplink) * 1000; + } + + /* PCO */ + if (req->protocol_configuration_options.presence) { + OGS_TLV_STORE_DATA(&sess->ue_pco, &req->protocol_configuration_options); + } + + /* Set User Location Information */ + if (req->user_location_information.presence) { + OGS_TLV_STORE_DATA(&sess->user_location_information, + &req->user_location_information); + } + + /* Set UE Timezone */ + if (req->ue_time_zone.presence) { + OGS_TLV_STORE_DATA(&sess->ue_timezone, &req->ue_time_zone); + } + + smf_gx_send_ccr(sess, xact, + OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST); +} + +void smf_s5c_handle_delete_session_request( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_delete_session_request_t *req) +{ + uint8_t cause_value = 0; + + ogs_debug("[SMF] Delete Session 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 (!ogs_diam_peer_connected()) { + ogs_error("No Diameter Peer"); + cause_value = OGS_GTP_CAUSE_REMOTE_PEER_NOT_RESPONDING; + } + + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_DELETE_SESSION_RESPONSE_TYPE, cause_value); + return; + } + + 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); +} + +void smf_s5c_handle_create_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_create_bearer_response_t *rsp) +{ + int rv; + ogs_gtp_f_teid_t *gnb_n3_teid, *smf_s5u_teid; + smf_bearer_t *bearer = NULL; + + ogs_assert(xact); + ogs_assert(rsp); + + ogs_debug("[SMF] Create Bearer Response"); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + if (!sess) { + ogs_warn("No Context in TEID"); + return; + } + + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_warn("GTP Failed [CAUSE:%d]", cause->value); + return; + } + } + + if (rsp->bearer_contexts.presence == 0) { + ogs_error("No Bearer"); + return; + } + if (rsp->bearer_contexts.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + return; + } + if (rsp->bearer_contexts.s5_s8_u_pgw_f_teid.presence == 0) { + ogs_error("No SMF TEID"); + return; + } + if (rsp->bearer_contexts.s5_s8_u_sgw_f_teid.presence == 0) { + ogs_error("No SGW TEID"); + return; + } + + /* Correlate with SMF-S5U-TEID */ + smf_s5u_teid = rsp->bearer_contexts.s5_s8_u_pgw_f_teid.data; + ogs_assert(smf_s5u_teid); + + /* Find the Bearer by SMF-S5U-TEID */ + bearer = smf_bearer_find_by_smf_s5u_teid(be32toh(smf_s5u_teid->teid)); + ogs_assert(bearer); + + /* Set EBI */ + bearer->ebi = rsp->bearer_contexts.eps_bearer_id.u8; + + /* Data Plane(DL) : gNB-N3 */ + gnb_n3_teid = rsp->bearer_contexts.s5_s8_u_sgw_f_teid.data; + ogs_assert(gnb_n3_teid); + bearer->gnb_n3_teid = be32toh(gnb_n3_teid->teid); + rv = ogs_gtp_f_teid_to_ip(gnb_n3_teid, &bearer->gnb_ip); + ogs_assert(rv == OGS_OK); + + ogs_debug("[SMF] Create Bearer Response : SGW[0x%x] --> SMF[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink || + bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) { + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_qer_t *qer = NULL; + + /* Only 1 QER is used per bearer */ + qer = ogs_list_first(&bearer->pfcp.qer_list); + if (!qer) { + qer = ogs_pfcp_qer_add(&bearer->pfcp); + ogs_assert(qer); + qer->id = OGS_NEXT_ID(sess->qer_id, 1, OGS_MAX_NUM_OF_QER+1); + } + + ogs_list_for_each(&bearer->pfcp.pdr_list, pdr) + ogs_pfcp_pdr_associate_qer(pdr, qer); + + qer->mbr.uplink = bearer->qos.mbr.uplink; + qer->mbr.downlink = bearer->qos.mbr.downlink; + qer->gbr.uplink = bearer->qos.gbr.uplink; + qer->gbr.downlink = bearer->qos.gbr.downlink; + } + + smf_pfcp_send_session_modification_request(bearer); +} + +void smf_s5c_handle_update_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_update_bearer_response_t *rsp) +{ + int rv; + smf_bearer_t *bearer = NULL; + + ogs_assert(xact); + ogs_assert(rsp); + + ogs_debug("[SMF] Update Bearer Response"); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + if (!sess) { + ogs_warn("No Context in TEID"); + return; + } + + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_warn("GTP Failed [CAUSE:%d]", cause->value); + return; + } + } + + if (rsp->bearer_contexts.presence == 0) { + ogs_error("No Bearer"); + return; + } + if (rsp->bearer_contexts.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + return; + } + + bearer = smf_bearer_find_by_ebi( + sess, rsp->bearer_contexts.eps_bearer_id.u8); + ogs_assert(bearer); + + ogs_debug("[SMF] Update Bearer Response : SGW[0x%x] --> SMF[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + if (bearer->state.qos_updated) { + ogs_pfcp_qer_t *qer = NULL; + + /* Only 1 QER is used per bearer */ + qer = ogs_list_first(&bearer->pfcp.qer_list); + if (qer) { + qer->mbr.uplink = bearer->qos.mbr.uplink; + qer->mbr.downlink = bearer->qos.mbr.downlink; + qer->gbr.uplink = bearer->qos.gbr.uplink; + qer->gbr.downlink = bearer->qos.gbr.downlink; + + } + } + + if (bearer->state.tft_updated) + ogs_warn("Not Implemented"); + +#if 0 /* FIXME */ + if (bearer->state.qos_updated || bearer->state.tft_updated) { +#else + if (bearer->state.qos_updated) { +#endif + smf_pfcp_send_session_modification_request(bearer); + } +} + +void smf_s5c_handle_delete_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_delete_bearer_response_t *rsp) +{ + int rv; + smf_bearer_t *bearer = NULL; + + ogs_assert(xact); + ogs_assert(rsp); + + ogs_debug("[SMF] Delete Bearer Response"); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + if (!sess) { + ogs_warn("No Context in TEID"); + return; + } + + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + if (rsp->cause.presence) { + ogs_gtp_cause_t *cause = rsp->cause.data; + ogs_assert(cause); + + if (cause->value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_warn("GTP Failed [CAUSE:%d]", cause->value); + return; + } + } + + if (rsp->bearer_contexts.presence == 0) { + ogs_error("No Bearer"); + return; + } + if (rsp->bearer_contexts.eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + return; + } + + bearer = smf_bearer_find_by_ebi( + sess, rsp->bearer_contexts.eps_bearer_id.u8); + ogs_assert(bearer); + + ogs_debug("[SMF] Delete Bearer Response : SGW[0x%x] --> SMF[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + smf_pfcp_send_session_modification_request(bearer); +} + +static int reconfigure_packet_filter(smf_pf_t *pf, ogs_gtp_tft_t *tft, int i) +{ + int j; + + for (j = 0; j < tft->pf[i].num_of_component; j++) { + switch(tft->pf[i].component[j].type) { + case GTP_PACKET_FILTER_PROTOCOL_IDENTIFIER_NEXT_HEADER_TYPE: + pf->rule.proto = tft->pf[i].component[j].proto; + break; + case GTP_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE: + pf->rule.ipv4_remote = 1; + pf->rule.ip.remote.addr[0] = tft->pf[i].component[j].ipv4.addr; + pf->rule.ip.remote.mask[0] = tft->pf[i].component[j].ipv4.mask; + break; + case GTP_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE: + pf->rule.ipv4_local = 1; + pf->rule.ip.local.addr[0] = tft->pf[i].component[j].ipv4.addr; + pf->rule.ip.local.mask[0] = tft->pf[i].component[j].ipv4.mask; + break; + case GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE: + pf->rule.ipv6_remote = 1; + memcpy(pf->rule.ip.remote.addr, + tft->pf[i].component[j].ipv6_mask.addr, + sizeof(pf->rule.ip.remote.addr)); + memcpy(pf->rule.ip.remote.mask, + tft->pf[i].component[j].ipv6_mask.mask, + sizeof(pf->rule.ip.remote.mask)); + break; + case GTP_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE: + pf->rule.ipv6_remote = 1; + memcpy(pf->rule.ip.remote.addr, + tft->pf[i].component[j].ipv6_mask.addr, + sizeof(pf->rule.ip.remote.addr)); + n2mask((struct in6_addr *)pf->rule.ip.remote.mask, + tft->pf[i].component[j].ipv6.prefixlen); + break; + case GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_TYPE: + pf->rule.ipv6_local = 1; + memcpy(pf->rule.ip.local.addr, + tft->pf[i].component[j].ipv6_mask.addr, + sizeof(pf->rule.ip.local.addr)); + memcpy(pf->rule.ip.local.mask, + tft->pf[i].component[j].ipv6_mask.mask, + sizeof(pf->rule.ip.local.mask)); + break; + case GTP_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE: + pf->rule.ipv6_local = 1; + memcpy(pf->rule.ip.local.addr, + tft->pf[i].component[j].ipv6_mask.addr, + sizeof(pf->rule.ip.local.addr)); + n2mask((struct in6_addr *)pf->rule.ip.local.mask, + tft->pf[i].component[j].ipv6.prefixlen); + break; + case GTP_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE: + pf->rule.port.local.low = pf->rule.port.local.high = + tft->pf[i].component[j].port.low; + break; + case GTP_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE: + pf->rule.port.remote.low = pf->rule.port.remote.high = + tft->pf[i].component[j].port.low; + break; + case GTP_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE: + pf->rule.port.local.low = tft->pf[i].component[j].port.low; + pf->rule.port.local.high = tft->pf[i].component[j].port.high; + break; + case GTP_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE: + pf->rule.port.remote.low = tft->pf[i].component[j].port.low; + pf->rule.port.remote.high = tft->pf[i].component[j].port.high; + break; + default: + ogs_error("Unknown Packet Filter Type(%d)", + tft->pf[i].component[j].type); + return OGS_ERROR; + } + } + + return j; +} + +void smf_s5c_handle_bearer_resource_command( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_bearer_resource_command_t *cmd) +{ + int rv; + uint8_t cause_value = 0; + int i; + + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + + smf_bearer_t *bearer = NULL; + smf_pf_t *pf = NULL; + + int16_t decoded; + ogs_gtp_tft_t tft; + + int tft_update = 0; + int qos_update = 0; + int tft_delete = 0; + + ogs_assert(xact); + ogs_assert(sess); + ogs_assert(cmd); + + ogs_debug("[PGW] Bearer Resource Command"); + ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", + sess->sgw_s5c_teid, sess->smf_n4_teid); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + if (cmd->linked_eps_bearer_id.presence == 0) { + ogs_error("No Linked EPS Bearer ID"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } else { + bearer = smf_bearer_find_by_ebi( + sess, cmd->linked_eps_bearer_id.u8); + if (!bearer) { + ogs_error("No Context for Linked EPS Bearer ID[%d]", + cmd->linked_eps_bearer_id.u8); + cause_value = OGS_GTP_CAUSE_CONTEXT_NOT_FOUND; + } + } + + if (cmd->procedure_transaction_id.presence == 0) { + ogs_error("No PTI"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + if (cmd->traffic_aggregate_description.presence == 0) { + ogs_error("No Traffic aggregate description(TAD)"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_BEARER_RESOURCE_FAILURE_INDICATION_TYPE, cause_value); + return; + } + + ogs_assert(bearer); + + decoded = ogs_gtp_parse_tft(&tft, &cmd->traffic_aggregate_description); + ogs_assert(cmd->traffic_aggregate_description.len == decoded); + + if (tft.code == OGS_GTP_TFT_CODE_NO_TFT_OPERATION) { + /* No operation */ + } else if (tft.code == OGS_GTP_TFT_CODE_DELETE_EXISTING_TFT) { + smf_pf_remove_all(bearer); + tft_delete = 1; + } else if (tft.code == + OGS_GTP_TFT_CODE_REPLACE_PACKET_FILTERS_IN_EXISTING) { + for (i = 0; i < tft.num_of_packet_filter; i++) { + pf = smf_pf_find_by_id(bearer, tft.pf[i].identifier+1); + if (pf) { + if (reconfigure_packet_filter(pf, &tft, i) < 0) { + ogs_gtp_send_error_message( + xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_BEARER_RESOURCE_FAILURE_INDICATION_TYPE, + OGS_GTP_CAUSE_SEMANTIC_ERROR_IN_THE_TAD_OPERATION); + return; + } + } + + tft_update = 1; + } + } else if (tft.code == + OGS_GTP_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT || + tft.code == OGS_GTP_TFT_CODE_CREATE_NEW_TFT) { + if (tft.code == OGS_GTP_TFT_CODE_CREATE_NEW_TFT) + smf_pf_remove_all(bearer); + + for (i = 0; i < tft.num_of_packet_filter; i++) { + pf = smf_pf_find_by_id(bearer, tft.pf[i].identifier+1); + if (!pf) + pf = smf_pf_add(bearer, tft.pf[i].precedence); + ogs_assert(pf); + + if (reconfigure_packet_filter(pf, &tft, i) < 0) { + ogs_gtp_send_error_message( + xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_BEARER_RESOURCE_FAILURE_INDICATION_TYPE, + OGS_GTP_CAUSE_SEMANTIC_ERROR_IN_THE_TAD_OPERATION); + return; + } + + tft_update = 1; + } + } else if (tft.code == + OGS_GTP_TFT_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING) { + for (i = 0; i < tft.num_of_packet_filter; i++) { + pf = smf_pf_find_by_id(bearer, tft.pf[i].identifier+1); + if (pf) + smf_pf_remove(pf); + + if (ogs_list_count(&bearer->pf_list)) + tft_update = 1; + else + tft_delete = 1; + } + } + + if (cmd->flow_quality_of_service.presence) { + ogs_gtp_flow_qos_t flow_qos; + + decoded = ogs_gtp_parse_flow_qos( + &flow_qos, &cmd->flow_quality_of_service); + ogs_assert(cmd->flow_quality_of_service.len == decoded); + + bearer->qos.mbr.uplink = flow_qos.ul_mbr; + bearer->qos.mbr.downlink = flow_qos.dl_mbr; + bearer->qos.gbr.uplink = flow_qos.ul_gbr; + bearer->qos.gbr.downlink = flow_qos.dl_gbr; + + qos_update = 1; + } + + if (tft_update == 0 && tft_delete == 0 && qos_update == 0) { + /* No modification */ + ogs_gtp_send_error_message(xact, sess ? sess->sgw_s5c_teid : 0, + OGS_GTP_BEARER_RESOURCE_FAILURE_INDICATION_TYPE, + OGS_GTP_CAUSE_SERVICE_NOT_SUPPORTED); + return; + } + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.teid = sess->sgw_s5c_teid; + + if (tft_delete) { + memset(&bearer->state, 0, sizeof(bearer->state)); + bearer->state.removed = true; + + h.type = OGS_GTP_DELETE_BEARER_REQUEST_TYPE; + pkbuf = smf_s5c_build_delete_bearer_request( + h.type, bearer, cmd->procedure_transaction_id.u8); + ogs_expect_or_return(pkbuf); + } else { + memset(&bearer->state, 0, sizeof(bearer->state)); + if (tft_update) + bearer->state.tft_updated = true; + if (qos_update) + bearer->state.qos_updated = true; + + h.type = OGS_GTP_UPDATE_BEARER_REQUEST_TYPE; + pkbuf = smf_s5c_build_update_bearer_request( + h.type, bearer, cmd->procedure_transaction_id.u8, + tft_update ? &tft : NULL, qos_update); + 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); +} diff --git a/src/smf/s5c-handler.h b/src/smf/s5c-handler.h new file mode 100644 index 000000000..e321665c7 --- /dev/null +++ b/src/smf/s5c-handler.h @@ -0,0 +1,57 @@ +/* + * 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 SMF_S5C_HANDLER_H +#define SMF_S5C_HANDLER_H + +#include "context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void smf_s5c_handle_echo_request( + ogs_gtp_xact_t *xact, ogs_gtp_echo_request_t *req); +void smf_s5c_handle_echo_response( + ogs_gtp_xact_t *xact, ogs_gtp_echo_response_t *req); + +void smf_s5c_handle_create_session_request( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_create_session_request_t *req); +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_create_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_create_bearer_response_t *req); +void smf_s5c_handle_update_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_update_bearer_response_t *req); +void smf_s5c_handle_delete_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_delete_bearer_response_t *req); +void smf_s5c_handle_bearer_resource_command( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp_bearer_resource_command_t *cmd); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_S5C_HANDLER_H */ diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c new file mode 100644 index 000000000..0d0a385e7 --- /dev/null +++ b/src/smf/smf-sm.c @@ -0,0 +1,255 @@ +/* + * 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 "smf-sm.h" +#include "context.h" +#include "event.h" +#include "gtp-path.h" +#include "fd-path.h" +#include "pfcp-path.h" +#include "s5c-handler.h" +#include "gx-handler.h" + +void smf_state_initial(ogs_fsm_t *s, smf_event_t *e) +{ + smf_sm_debug(e); + + ogs_assert(s); + + OGS_FSM_TRAN(s, &smf_state_operational); +} + +void smf_state_final(ogs_fsm_t *s, smf_event_t *e) +{ + smf_sm_debug(e); + + ogs_assert(s); +} + +void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) +{ + int rv; + ogs_pkbuf_t *recvbuf = NULL; + smf_sess_t *sess = NULL; + + ogs_gtp_node_t *gnode = NULL; + ogs_gtp_xact_t *gtp_xact = NULL; + ogs_gtp_message_t gtp_message; + + ogs_diam_gx_message_t *gx_message = NULL; + + ogs_pfcp_node_t *pfcp_node = NULL; + ogs_pfcp_xact_t *pfcp_xact = NULL; + ogs_pfcp_message_t pfcp_message; + + smf_sm_debug(e); + + ogs_assert(s); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + rv = smf_gtp_open(); + if (rv != OGS_OK) { + ogs_fatal("Can't establish S11-GTP path"); + } + + rv = smf_pfcp_open(); + if (rv != OGS_OK) { + ogs_fatal("Can't establish N4-PFCP path"); + } + + ogs_list_for_each(&ogs_pfcp_self()->n4_list, pfcp_node) { + smf_event_t e; + e.pfcp_node = pfcp_node; + + ogs_fsm_create(&pfcp_node->sm, + smf_pfcp_state_initial, smf_pfcp_state_final); + ogs_fsm_init(&pfcp_node->sm, &e); + } + break; + case OGS_FSM_EXIT_SIG: + ogs_list_for_each(&ogs_pfcp_self()->n4_list, pfcp_node) { + smf_event_t e; + e.pfcp_node = pfcp_node; + + ogs_fsm_fini(&pfcp_node->sm, &e); + ogs_fsm_delete(&pfcp_node->sm); + } + + smf_gtp_close(); + smf_pfcp_close(); + break; + case SMF_EVT_S5C_MESSAGE: + ogs_assert(e); + recvbuf = e->pkbuf; + ogs_assert(recvbuf); + + if (ogs_gtp_parse_msg(>p_message, recvbuf) != OGS_OK) { + ogs_error("ogs_gtp_parse_msg() failed"); + ogs_pkbuf_free(recvbuf); + break; + } + + if (gtp_message.h.teid != 0) { + sess = smf_sess_find_by_teid(gtp_message.h.teid); + } + + if (sess) { + gnode = sess->gnode; + ogs_assert(gnode); + } else { + gnode = e->gnode; + ogs_assert(gnode); + } + + rv = ogs_gtp_xact_receive(gnode, >p_message.h, >p_xact); + if (rv != OGS_OK) { + ogs_pkbuf_free(recvbuf); + break; + } + + switch(gtp_message.h.type) { + case OGS_GTP_ECHO_REQUEST_TYPE: + smf_s5c_handle_echo_request(gtp_xact, >p_message.echo_request); + break; + case OGS_GTP_ECHO_RESPONSE_TYPE: + smf_s5c_handle_echo_response(gtp_xact, >p_message.echo_response); + break; + case OGS_GTP_CREATE_SESSION_REQUEST_TYPE: + if (gtp_message.h.teid == 0) { + ogs_expect(!sess); + sess = smf_sess_add_by_message(>p_message); + if (sess) + OGS_SETUP_GTP_NODE(sess, gnode); + } + smf_s5c_handle_create_session_request( + sess, gtp_xact, >p_message.create_session_request); + break; + case OGS_GTP_DELETE_SESSION_REQUEST_TYPE: + smf_s5c_handle_delete_session_request( + sess, gtp_xact, >p_message.delete_session_request); + break; + case OGS_GTP_CREATE_BEARER_RESPONSE_TYPE: + smf_s5c_handle_create_bearer_response( + sess, gtp_xact, >p_message.create_bearer_response); + break; + case OGS_GTP_UPDATE_BEARER_RESPONSE_TYPE: + smf_s5c_handle_update_bearer_response( + sess, gtp_xact, >p_message.update_bearer_response); + break; + case OGS_GTP_DELETE_BEARER_RESPONSE_TYPE: + smf_s5c_handle_delete_bearer_response( + sess, gtp_xact, >p_message.delete_bearer_response); + break; + case OGS_GTP_BEARER_RESOURCE_COMMAND_TYPE: + smf_s5c_handle_bearer_resource_command( + sess, gtp_xact, >p_message.bearer_resource_command); + break; + default: + ogs_warn("Not implmeneted(type:%d)", gtp_message.h.type); + break; + } + ogs_pkbuf_free(recvbuf); + break; + + case SMF_EVT_GX_MESSAGE: + ogs_assert(e); + + recvbuf = e->pkbuf; + ogs_assert(recvbuf); + gx_message = (ogs_diam_gx_message_t *)recvbuf->data; + ogs_assert(gx_message); + + sess = e->sess; + ogs_assert(sess); + + switch(gx_message->cmd_code) { + case OGS_DIAM_GX_CMD_CODE_CREDIT_CONTROL: + gtp_xact = e->gtp_xact; + ogs_assert(gtp_xact); + + switch(gx_message->cc_request_type) { + case OGS_DIAM_GX_CC_REQUEST_TYPE_INITIAL_REQUEST: + smf_gx_handle_cca_initial_request( + sess, gx_message, gtp_xact); + break; + case OGS_DIAM_GX_CC_REQUEST_TYPE_TERMINATION_REQUEST: + smf_gx_handle_cca_termination_request( + sess, gx_message, gtp_xact); + break; + default: + ogs_error("Not implemented(%d)", + gx_message->cc_request_type); + break; + } + + break; + case OGS_DIAM_GX_CMD_RE_AUTH: + smf_gx_handle_re_auth_request(sess, gx_message); + break; + default: + ogs_error("Invalid type(%d)", gx_message->cmd_code); + break; + } + + ogs_diam_gx_message_free(gx_message); + ogs_pkbuf_free(recvbuf); + break; + case SMF_EVT_N4_MESSAGE: + ogs_assert(e); + recvbuf = e->pkbuf; + ogs_assert(recvbuf); + pfcp_node = e->pfcp_node; + ogs_assert(pfcp_node); + + if (ogs_pfcp_parse_msg(&pfcp_message, recvbuf) != OGS_OK) { + ogs_error("ogs_pfcp_parse_msg() failed"); + ogs_pkbuf_free(recvbuf); + break; + } + + rv = ogs_pfcp_xact_receive(pfcp_node, &pfcp_message.h, &pfcp_xact); + if (rv != OGS_OK) { + ogs_pkbuf_free(recvbuf); + break; + } + + e->pfcp_message = &pfcp_message; + e->pfcp_xact = pfcp_xact; + ogs_fsm_dispatch(&pfcp_node->sm, e); + if (OGS_FSM_CHECK(&pfcp_node->sm, smf_pfcp_state_exception)) { + ogs_error("PFCP state machine exception"); + break; + } + + ogs_pkbuf_free(recvbuf); + break; + case SMF_EVT_N4_TIMER: + case SMF_EVT_N4_NO_HEARTBEAT: + pfcp_node = e->pfcp_node; + ogs_assert(pfcp_node); + ogs_assert(OGS_FSM_STATE(&pfcp_node->sm)); + + ogs_fsm_dispatch(&pfcp_node->sm, e); + break; + default: + ogs_error("No handler for event %s", smf_event_get_name(e)); + break; + } +} diff --git a/src/smf/smf-sm.h b/src/smf/smf-sm.h new file mode 100644 index 000000000..7b80e4478 --- /dev/null +++ b/src/smf/smf-sm.h @@ -0,0 +1,47 @@ +/* + * 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 SMF_SM_H +#define SMF_SM_H + +#include "event.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void smf_state_initial(ogs_fsm_t *s, smf_event_t *e); +void smf_state_final(ogs_fsm_t *s, smf_event_t *e); +void smf_state_operational(ogs_fsm_t *s, smf_event_t *e); +void smf_state_exception(ogs_fsm_t *s, smf_event_t *e); + +void smf_pfcp_state_initial(ogs_fsm_t *s, smf_event_t *e); +void smf_pfcp_state_final(ogs_fsm_t *s, smf_event_t *e); +void smf_pfcp_state_will_associate(ogs_fsm_t *s, smf_event_t *e); +void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e); +void smf_pfcp_state_exception(ogs_fsm_t *s, smf_event_t *e); + +#define smf_sm_debug(__pe) \ + ogs_debug("%s(): %s", __func__, smf_event_get_name(__pe)) + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_SM_H */ diff --git a/src/smf/timer.c b/src/smf/timer.c new file mode 100644 index 000000000..02030790c --- /dev/null +++ b/src/smf/timer.c @@ -0,0 +1,76 @@ +/* + * 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 "timer.h" +#include "event.h" +#include "context.h" + +static smf_timer_cfg_t g_smf_timer_cfg[MAX_NUM_OF_SMF_TIMER] = { + [SMF_TIMER_ASSOCIATION] = + { .duration = ogs_time_from_sec(12) }, + [SMF_TIMER_HEARTBEAT] = + { .duration = ogs_time_from_sec(12) }, +}; + +smf_timer_cfg_t *smf_timer_cfg(smf_timer_e id) +{ + ogs_assert(id < MAX_NUM_OF_SMF_TIMER); + return &g_smf_timer_cfg[id]; +} + +const char *smf_timer_get_name(smf_timer_e id) +{ + switch (id) { + case SMF_TIMER_ASSOCIATION: + return "SMF_TIMER_ASSOCIATION"; + case SMF_TIMER_HEARTBEAT: + return "SMF_TIMER_HEARTBEAT"; + default: + break; + } + + return "UNKNOWN_TIMER"; +} + +static void timer_send_event(int timer_id, void *data) +{ + int rv; + smf_event_t *e = NULL; + ogs_assert(data); + + e = smf_event_new(SMF_EVT_N4_TIMER); + e->timer_id = timer_id; + e->pfcp_node = data; + + rv = ogs_queue_push(smf_self()->queue, e); + if (rv != OGS_OK) { + ogs_warn("ogs_queue_push() failed:%d", (int)rv); + smf_event_free(e); + } +} + +void smf_timer_association(void *data) +{ + timer_send_event(SMF_TIMER_ASSOCIATION, data); +} + +void smf_timer_heartbeat(void *data) +{ + timer_send_event(SMF_TIMER_HEARTBEAT, data); +} diff --git a/src/smf/timer.h b/src/smf/timer.h new file mode 100644 index 000000000..852480e23 --- /dev/null +++ b/src/smf/timer.h @@ -0,0 +1,56 @@ +/* + * 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 SMF_TIMER_H +#define SMF_TIMER_H + +#include "ogs-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* forward declaration */ +typedef enum { + SMF_TIMER_BASE = 0, + + SMF_TIMER_ASSOCIATION, + SMF_TIMER_HEARTBEAT, + + MAX_NUM_OF_SMF_TIMER, + +} smf_timer_e; + +typedef struct smf_timer_cfg_s { + int max_count; + ogs_time_t duration; +} smf_timer_cfg_t; + +smf_timer_cfg_t *smf_timer_cfg(smf_timer_e id); + +const char *smf_timer_get_name(smf_timer_e id); + +void smf_timer_association(void *data); +void smf_timer_heartbeat(void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* SMF_TIMER_H */ diff --git a/src/upf/app.c b/src/upf/app.c new file mode 100644 index 000000000..026bf876e --- /dev/null +++ b/src/upf/app.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-app.h" + +int app_initialize(const char *const argv[]) +{ + int rv; + + rv = upf_initialize(); + if (rv != OGS_OK) { + ogs_error("Failed to intialize UPF"); + return rv; + } + ogs_info("UPF initialize...done"); + + return OGS_OK; +} + +void app_terminate(void) +{ + upf_terminate(); + ogs_info("UPF terminate...done"); +} diff --git a/src/upf/context.c b/src/upf/context.c new file mode 100644 index 000000000..0731285e5 --- /dev/null +++ b/src/upf/context.c @@ -0,0 +1,685 @@ +/* + * 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 "context.h" + +static upf_context_t self; + +int __upf_log_domain; + +static OGS_POOL(upf_sess_pool, upf_sess_t); +static OGS_POOL(upf_sdf_filter_pool, upf_sdf_filter_t); + +static int context_initiaized = 0; + +int num_sessions = 0; +void stats_add_session(void) { + num_sessions = num_sessions + 1; + ogs_info("Added a session. Number of active sessions is now %d", + num_sessions); +} + +void stats_remove_session(void) { + num_sessions = num_sessions - 1; + ogs_info("Removed a session. Number of active sessions is now %d", + num_sessions); +} + +void upf_context_init(void) +{ + ogs_assert(context_initiaized == 0); + + /* Initialize UPF context */ + memset(&self, 0, sizeof(upf_context_t)); + + ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level); + ogs_log_install_domain(&__upf_log_domain, "upf", ogs_core()->log.level); + + ogs_gtp_node_init(512); + + ogs_list_init(&self.sess_list); + + ogs_list_init(&self.gtpu_list); + ogs_list_init(&self.gtpu_resource_list); + + ogs_list_init(&self.gnb_n3_list); + + ogs_pool_init(&upf_sess_pool, ogs_config()->pool.sess); + ogs_pool_init(&upf_sdf_filter_pool, + ogs_config()->pool.sess * OGS_MAX_NUM_OF_RULE); + + self.sess_hash = ogs_hash_make(); + self.ipv4_hash = ogs_hash_make(); + self.ipv6_hash = ogs_hash_make(); + + context_initiaized = 1; +} + +void upf_context_final(void) +{ + ogs_assert(context_initiaized == 1); + + upf_sess_remove_all(); + + ogs_assert(self.sess_hash); + ogs_hash_destroy(self.sess_hash); + ogs_assert(self.ipv4_hash); + ogs_hash_destroy(self.ipv4_hash); + ogs_assert(self.ipv6_hash); + ogs_hash_destroy(self.ipv6_hash); + + ogs_pool_final(&upf_sess_pool); + ogs_pool_final(&upf_sdf_filter_pool); + + ogs_gtp_node_remove_all(&self.gnb_n3_list); + + ogs_gtp_node_final(); + ogs_pfcp_gtpu_resource_remove_all(&self.gtpu_resource_list); + + context_initiaized = 0; +} + +upf_context_t *upf_self(void) +{ + return &self; +} + +static int upf_context_prepare(void) +{ + self.gtpu_port = OGS_GTPV1_U_UDP_PORT; + + return OGS_OK; +} + +static int upf_context_validation(void) +{ + if (ogs_list_first(&self.gtpu_list) == NULL) { + ogs_error("No upf.gtpu in '%s'", ogs_config()->file); + return OGS_ERROR; + } + return OGS_OK; +} + +int upf_context_parse_config(void) +{ + int rv; + yaml_document_t *document = NULL; + ogs_yaml_iter_t root_iter; + + document = ogs_config()->document; + ogs_assert(document); + + rv = upf_context_prepare(); + if (rv != OGS_OK) return rv; + + ogs_yaml_iter_init(&root_iter, document); + while (ogs_yaml_iter_next(&root_iter)) { + const char *root_key = ogs_yaml_iter_key(&root_iter); + ogs_assert(root_key); + if (!strcmp(root_key, "upf")) { + ogs_yaml_iter_t upf_iter; + ogs_yaml_iter_recurse(&root_iter, &upf_iter); + while (ogs_yaml_iter_next(&upf_iter)) { + const char *upf_key = ogs_yaml_iter_key(&upf_iter); + ogs_assert(upf_key); + if (!strcmp(upf_key, "gtpu")) { + ogs_list_t list, list6; + ogs_socknode_t *node = NULL, *node6 = NULL; + ogs_socknode_t *iter = NULL, *next_iter = NULL; + + ogs_yaml_iter_t gtpu_array, gtpu_iter; + ogs_yaml_iter_recurse(&upf_iter, >pu_array); + + do { + int family = AF_UNSPEC; + int i, num = 0; + const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; + uint16_t port = self.gtpu_port; + const char *dev = NULL; + ogs_sockaddr_t *addr = NULL; + const char *teid_range_indication = NULL; + const char *teid_range = NULL; + const char *network_instance = NULL; + const char *source_interface = NULL; + + if (ogs_yaml_iter_type(>pu_array) == + YAML_MAPPING_NODE) { + memcpy(>pu_iter, >pu_array, + sizeof(ogs_yaml_iter_t)); + } else if (ogs_yaml_iter_type(>pu_array) == + YAML_SEQUENCE_NODE) { + if (!ogs_yaml_iter_next(>pu_array)) + break; + ogs_yaml_iter_recurse(>pu_array, >pu_iter); + } else if (ogs_yaml_iter_type(>pu_array) == + YAML_SCALAR_NODE) { + break; + } else + ogs_assert_if_reached(); + + while (ogs_yaml_iter_next(>pu_iter)) { + const char *gtpu_key = + ogs_yaml_iter_key(>pu_iter); + ogs_assert(gtpu_key); + + if (ogs_list_count( + &self.gtpu_resource_list) >= + OGS_MAX_NUM_OF_GTPU_RESOURCE) { + ogs_warn("[Overflow]: Number of User Plane " + "IP Resource <= %d", + OGS_MAX_NUM_OF_GTPU_RESOURCE); + break; + } + + if (!strcmp(gtpu_key, "family")) { + const char *v = ogs_yaml_iter_value(>pu_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(gtpu_key, "addr") || + !strcmp(gtpu_key, "name")) { + ogs_yaml_iter_t hostname_iter; + ogs_yaml_iter_recurse( + >pu_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(gtpu_key, "port")) { + const char *v = ogs_yaml_iter_value(>pu_iter); + if (v) { + port = atoi(v); + self.gtpu_port = port; + } + } else if (!strcmp(gtpu_key, "dev")) { + dev = ogs_yaml_iter_value(>pu_iter); + } else if (!strcmp(gtpu_key, + "teid_range_indication")) { + teid_range_indication = + ogs_yaml_iter_value(>pu_iter); + } else if (!strcmp(gtpu_key, + "teid_range")) { + teid_range = ogs_yaml_iter_value(>pu_iter); + } else if (!strcmp(gtpu_key, + "network_instance")) { + network_instance = + ogs_yaml_iter_value(>pu_iter); + } else if (!strcmp(gtpu_key, + "source_interface")) { + source_interface = + ogs_yaml_iter_value(>pu_iter); + } else + ogs_warn("unknown key `%s`", gtpu_key); + } + + addr = NULL; + for (i = 0; i < num; i++) { + rv = ogs_addaddrinfo(&addr, + family, hostname[i], port, 0); + ogs_assert(rv == OGS_OK); + } + + ogs_list_init(&list); + ogs_list_init(&list6); + + if (addr) { + if (ogs_config()->parameter.no_ipv4 == 0) + ogs_socknode_add(&list, AF_INET, addr); + if (ogs_config()->parameter.no_ipv6 == 0) + ogs_socknode_add(&list6, AF_INET6, addr); + ogs_freeaddrinfo(addr); + } + + if (dev) { + rv = ogs_socknode_probe( + ogs_config()->parameter.no_ipv4 ? NULL : &list, + ogs_config()->parameter.no_ipv6 ? NULL : &list6, + dev, self.gtpu_port); + ogs_assert(rv == OGS_OK); + } + + /* Find first IPv4/IPv6 address in the list. + * + * In the following configuration, + * 127.0.0.4, 127.0.0.5 and cafe::1 are ignored + * on PFCP Assocation Response message's + * user plane IP resource information. + * + * gtpu: + * - addr: + * - 127.0.0.3 + * - ::1 + * - 127.0.0.4 + * - 127.0.0.5 + * - cafe::1 + * + * To include all user plane IP resource information, + * configure as below: + * + * gtpu: + * - addr: + * - 127.0.0.3 + * - ::1 + * - addr: 127.0.0.4 + * - addr + * - 127.0.0.5 + * - cafe::1 + */ + node = ogs_list_first(&list); + node6 = ogs_list_first(&list6); + if (node || node6) { + ogs_pfcp_user_plane_ip_resource_info_t info; + + memset(&info, 0, sizeof(info)); + ogs_pfcp_sockaddr_to_user_plane_ip_resource_info( + node ? node->addr : NULL, + node6 ? node6->addr : NULL, + &info); + + if (teid_range_indication) { + info.teidri = atoi(teid_range_indication); + if (teid_range) { + info.teid_range = atoi(teid_range); + } + } + if (network_instance) { + info.assoni = 1; + ogs_cpystrn(info.network_instance, + network_instance, OGS_MAX_APN_LEN+1); + } + if (source_interface) { + info.assosi = 1; + info.source_interface = atoi(source_interface); + } + + ogs_pfcp_gtpu_resource_add( + &self.gtpu_resource_list, &info); + } + + ogs_list_for_each_safe(&list, next_iter, iter) + ogs_list_add(&self.gtpu_list, iter); + ogs_list_for_each_safe(&list6, next_iter, iter) + ogs_list_add(&self.gtpu_list, iter); + + } while (ogs_yaml_iter_type(>pu_array) == + YAML_SEQUENCE_NODE); + + if (ogs_list_first(&self.gtpu_list) == NULL) { + ogs_list_init(&list); + ogs_list_init(&list6); + + rv = ogs_socknode_probe( + ogs_config()->parameter.no_ipv4 ? NULL : &list, + ogs_config()->parameter.no_ipv6 ? NULL : &list6, + NULL, self.gtpu_port); + ogs_assert(rv == OGS_OK); + + /* + * The first tuple IPv4/IPv6 are added + * in User Plane IP resource information. + * + * TEID Range, Network Instance, Source Interface + * cannot be configured in automatic IP detection. + */ + node = ogs_list_first(&list); + node6 = ogs_list_first(&list6); + if (node || node6) { + ogs_pfcp_user_plane_ip_resource_info_t info; + + memset(&info, 0, sizeof(info)); + ogs_pfcp_sockaddr_to_user_plane_ip_resource_info( + node ? node->addr : NULL, + node6 ? node6->addr : NULL, + &info); + + ogs_pfcp_gtpu_resource_add( + &self.gtpu_resource_list, &info); + } + + ogs_list_for_each_safe(&list, next_iter, iter) + ogs_list_add(&self.gtpu_list, iter); + ogs_list_for_each_safe(&list6, next_iter, iter) + ogs_list_add(&self.gtpu_list, iter); + } + } else if (!strcmp(upf_key, "pdn")) { + /* handle config in pfcp library */ + } + } + } + } + + rv = upf_context_validation(); + if (rv != OGS_OK) return rv; + + return OGS_OK; +} + +upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *cp_f_seid, + const char *apn, uint8_t pdn_type, ogs_pfcp_ue_ip_addr_t *ue_ip, + ogs_pfcp_pdr_id_t default_pdr_id) +{ + char buf1[OGS_ADDRSTRLEN]; + char buf2[OGS_ADDRSTRLEN]; + upf_sess_t *sess = NULL; + + ogs_assert(cp_f_seid); + ogs_assert(apn); + ogs_assert(ue_ip); + + ogs_pool_alloc(&upf_sess_pool, &sess); + ogs_assert(sess); + memset(sess, 0, sizeof *sess); + + sess->index = ogs_pool_index(&upf_sess_pool, sess); + ogs_assert(sess->index > 0 && sess->index <= ogs_config()->pool.sess); + + sess->upf_n4_seid = sess->index; + sess->smf_n4_seid = cp_f_seid->seid; + ogs_hash_set(self.sess_hash, &sess->smf_n4_seid, + sizeof(sess->smf_n4_seid), sess); + + /* Set APN */ + ogs_cpystrn(sess->pdn.apn, apn, OGS_MAX_APN_LEN+1); + + /* Set PDN-Type and UE IP Address */ + sess->pdn.pdn_type = pdn_type; + if (pdn_type == OGS_GTP_PDN_TYPE_IPV4) { + if (ue_ip->ipv4 == 0) { + ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6); + goto cleanup; + } + sess->ipv4 = ogs_pfcp_ue_ip_alloc( + AF_INET, apn, (uint8_t *)&(ue_ip->addr)); + ogs_assert(sess->ipv4); + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); + } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV6) { + if (ue_ip->ipv6 == 0) { + ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6); + goto cleanup; + } + sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, apn, ue_ip->addr6); + ogs_assert(sess->ipv6); + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); + } else if (pdn_type == OGS_GTP_PDN_TYPE_IPV4V6) { + if (ue_ip->ipv4 == 0 || ue_ip->ipv6 == 0) { + ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6); + goto cleanup; + } + sess->ipv4 = ogs_pfcp_ue_ip_alloc( + AF_INET, apn, (uint8_t *)&(ue_ip->both.addr)); + ogs_assert(sess->ipv4); + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, sess); + + sess->ipv6 = ogs_pfcp_ue_ip_alloc(AF_INET6, apn, ue_ip->both.addr6); + ogs_assert(sess->ipv6); + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, sess); + } else { + ogs_error("Cannot support PDN-Type[%d] != [IPv4:%d, IPv6:%d]", + pdn_type, ue_ip->ipv4, ue_ip->ipv6); + goto cleanup; + } + + /* Set Default PDR */ + OGS_SETUP_DEFAULT_PDR(&sess->pfcp, + ogs_pfcp_pdr_find_or_add(&sess->pfcp, default_pdr_id)); + + ogs_info("UE F-SEID[CP:%ld,UP:%ld] " + "APN[%s] PDN-Type[%d] IPv4[%s] IPv6[%s], Default PDR ID[%d]", + (long)sess->upf_n4_seid, (long)sess->smf_n4_seid, + apn, pdn_type, + sess->ipv4 ? INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? INET6_NTOP(&sess->ipv6->addr, buf2) : "", + sess->pfcp.default_pdr->id); + + ogs_list_add(&self.sess_list, sess); + + stats_add_session(); + + return sess; + +cleanup: + ogs_pool_free(&upf_sess_pool, sess); + return NULL; +} + +int upf_sess_remove(upf_sess_t *sess) +{ + ogs_assert(sess); + + ogs_list_remove(&self.sess_list, sess); + ogs_pfcp_sess_clear(&sess->pfcp); + upf_sdf_filter_remove_all(sess); + + ogs_hash_set(self.sess_hash, &sess->smf_n4_seid, + sizeof(sess->smf_n4_seid), NULL); + + if (sess->ipv4) { + ogs_hash_set(self.ipv4_hash, sess->ipv4->addr, OGS_IPV4_LEN, NULL); + ogs_pfcp_ue_ip_free(sess->ipv4); + } + if (sess->ipv6) { + ogs_hash_set(self.ipv6_hash, sess->ipv6->addr, OGS_IPV6_LEN, NULL); + ogs_pfcp_ue_ip_free(sess->ipv6); + } + + ogs_pool_free(&upf_sess_pool, sess); + + stats_remove_session(); + + return OGS_OK; +} + +void upf_sess_remove_all(void) +{ + upf_sess_t *sess = NULL, *next = NULL;; + + ogs_list_for_each_safe(&self.sess_list, next, sess) { + upf_sess_remove(sess); + } +} + +upf_sess_t *upf_sess_find(uint32_t index) +{ + ogs_assert(index); + return ogs_pool_find(&upf_sess_pool, index); +} + +upf_sess_t *upf_sess_find_by_cp_seid(uint64_t seid) +{ + return (upf_sess_t *)ogs_hash_get(self.sess_hash, &seid, sizeof(seid)); +} + +upf_sess_t *upf_sess_find_by_up_seid(uint64_t seid) +{ + return upf_sess_find(seid); +} + +upf_sess_t *upf_sess_find_by_ipv4(uint32_t addr) +{ + ogs_assert(self.ipv4_hash); + return (upf_sess_t *)ogs_hash_get(self.ipv4_hash, &addr, OGS_IPV4_LEN); +} + +upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6) +{ + ogs_assert(self.ipv6_hash); + ogs_assert(addr6); + return (upf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN); +} + +upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message) +{ + upf_sess_t *sess = NULL; + + ogs_pfcp_f_seid_t *f_seid = NULL; + char apn[OGS_MAX_APN_LEN]; + ogs_pfcp_ue_ip_addr_t *addr = NULL; + bool default_pdr_found = false; + ogs_pfcp_pdr_id_t default_pdr_id; + + ogs_pfcp_session_establishment_request_t *req = + &message->pfcp_session_establishment_request;; + int i; + + f_seid = req->cp_f_seid.data; + if (req->cp_f_seid.presence == 0 || f_seid == NULL) { + ogs_error("No CP F-SEID"); + return NULL; + } + f_seid->seid = be64toh(f_seid->seid); + + if (req->pdn_type.presence == 0) { + ogs_error("No PDN Type"); + return NULL; + } + + /* Find the Default PDR : + * - PDR ID is existed + * - SDF Filter is NOT existed + * - APN(Network Instance) is existed + * - UE IP Address is existed + * - Downlink PDR + */ + memset(apn, 0, sizeof(apn)); + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + ogs_pfcp_tlv_create_pdr_t *message = &req->create_pdr[i]; + ogs_assert(message); + if (message->presence == 0) + continue; + if (message->pdr_id.presence == 0) + continue; + if (message->pdi.presence == 0) + continue; + if (message->pdi.sdf_filter[0].presence) /* No SDF Filter */ + continue; + if (message->pdi.network_instance.presence == 0) + continue; + if (message->pdi.ue_ip_address.presence == 0) + continue; + if (message->pdi.source_interface.presence == 0) + continue; + if (message->pdi.source_interface.u8 != OGS_PFCP_INTERFACE_CORE) + continue; + + default_pdr_id = message->pdr_id.u16; + ogs_fqdn_parse(apn, + message->pdi.network_instance.data, + message->pdi.network_instance.len); + addr = message->pdi.ue_ip_address.data; + + default_pdr_found = true; + break; + } + + if (!default_pdr_found) { + ogs_error("Cannot find Default PDR"); + return NULL; + } + + if (strlen(apn) == 0) { + ogs_error("No APN in PDR"); + return NULL; + } + + if (!addr) { + ogs_error("No UE IP Address in PDR"); + return NULL; + } + + sess = upf_sess_find_by_cp_seid(f_seid->seid); + if (!sess) { + sess = upf_sess_add( + f_seid, apn, req->pdn_type.u8, addr, default_pdr_id); + if (!sess) return NULL; + } + ogs_assert(sess); + + return sess; +} + +upf_sdf_filter_t *upf_sdf_filter_add(ogs_pfcp_pdr_t *pdr) +{ + upf_sdf_filter_t *sdf_filter = NULL; + ogs_pfcp_sess_t *pfcp = NULL; + upf_sess_t *sess = NULL; + + ogs_assert(pdr); + pfcp = pdr->sess; + ogs_assert(pfcp); + sess = UPF_SESS(pfcp); + ogs_assert(sess); + + ogs_pool_alloc(&upf_sdf_filter_pool, &sdf_filter); + ogs_assert(sdf_filter); + memset(sdf_filter, 0, sizeof *sdf_filter); + + sdf_filter->pdr = pdr; + ogs_list_add(&sess->sdf_filter_list, sdf_filter); + + return sdf_filter; +} + +void upf_sdf_filter_remove(upf_sdf_filter_t *sdf_filter) +{ + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_sess_t *pfcp = NULL; + upf_sess_t *sess = NULL; + + ogs_assert(sdf_filter); + pdr = sdf_filter->pdr; + ogs_assert(pdr); + pfcp = pdr->sess; + ogs_assert(pfcp); + sess = UPF_SESS(pfcp); + ogs_assert(sess); + + ogs_list_remove(&sess->sdf_filter_list, sdf_filter); + ogs_pool_free(&upf_sdf_filter_pool, sdf_filter); +} + +void upf_sdf_filter_remove_all(upf_sess_t *sess) +{ + upf_sdf_filter_t *sdf_filter = NULL, *next_sdf_filter = NULL; + + ogs_assert(sess); + + ogs_list_for_each_safe(&sess->sdf_filter_list, next_sdf_filter, sdf_filter) + upf_sdf_filter_remove(sdf_filter); +} diff --git a/src/upf/context.h b/src/upf/context.h new file mode 100644 index 000000000..08eaf2929 --- /dev/null +++ b/src/upf/context.h @@ -0,0 +1,127 @@ +/* + * 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 UPF_CONTEXT_H +#define UPF_CONTEXT_H + +#include "upf-config.h" + +#if HAVE_NET_IF_H +#include +#endif + +#include "ogs-gtp.h" +#include "ogs-diameter-gx.h" +#include "ogs-pfcp.h" +#include "ogs-app.h" + +#include "ipfw/ogs-ipfw.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern int __upf_log_domain; + +#undef OGS_LOG_DOMAIN +#define OGS_LOG_DOMAIN __upf_log_domain + +typedef struct upf_context_s { + uint32_t gtpu_port; /* Default: UPF GTP-U local port */ + + ogs_list_t gtpu_list; /* UPF GTPU Server List */ + ogs_sock_t *gtpu_sock; /* UPF GTPU IPv4 Socket */ + ogs_sock_t *gtpu_sock6; /* UPF GTPU IPv6 Socket */ + ogs_list_t gtpu_resource_list; /* UP IP Resource List */ + uint16_t function_features; /* UP Function Features */ + + ogs_queue_t *queue; /* Queue for processing UPF control */ + ogs_timer_mgr_t *timer_mgr; /* Timer Manager */ + ogs_pollset_t *pollset; /* Poll Set for I/O Multiplexing */ + + ogs_list_t gnb_n3_list; /* gNB N3 Node List */ + ogs_list_t ip_pool_list; + + ogs_hash_t *sess_hash; /* hash table (F-SEID) */ + ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */ + ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */ + + ogs_list_t sess_list; +} upf_context_t; + +#define UPF_SESS(pfcp_sess) ogs_container_of(pfcp_sess, upf_sess_t, pfcp) +typedef struct upf_sess_s { + ogs_lnode_t lnode; + uint32_t index; /**< An index of this node */ + + ogs_pfcp_sess_t pfcp; + ogs_list_t sdf_filter_list; /* SDF Filter List */ + + uint64_t upf_n4_seid; /* UPF SEID is dervied from INDEX */ + uint64_t smf_n4_seid; /* SMF SEID is received from Peer */ + + /* APN Configuration */ + ogs_pdn_t pdn; + ogs_pfcp_ue_ip_t *ipv4; + ogs_pfcp_ue_ip_t *ipv6; + + char *gx_sid; /* Gx Session ID */ + ogs_pfcp_node_t *pfcp_node; +} upf_sess_t; + +typedef struct upf_sdf_filter_s { + ogs_lnode_t lnode; + + ogs_ipfw_rule_t rule; + + /* Related Context */ + ogs_pfcp_pdr_t *pdr; +} upf_sdf_filter_t; + +void upf_context_init(void); +void upf_context_final(void); +upf_context_t *upf_self(void); + +int upf_context_parse_config(void); + +upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message); + +upf_sess_t *upf_sess_add(ogs_pfcp_f_seid_t *f_seid, + const char *apn, uint8_t pdn_type, ogs_pfcp_ue_ip_addr_t *ue_ip, + ogs_pfcp_pdr_id_t default_pdr_id); +int upf_sess_remove(upf_sess_t *sess); +void upf_sess_remove_all(void); +upf_sess_t *upf_sess_find(uint32_t index); +upf_sess_t *upf_sess_find_by_cp_seid(uint64_t seid); +upf_sess_t *upf_sess_find_by_up_seid(uint64_t seid); +upf_sess_t *upf_sess_find_by_ipv4(uint32_t addr); +upf_sess_t *upf_sess_find_by_ipv6(uint32_t *addr6); + +upf_sdf_filter_t *upf_sdf_filter_add(ogs_pfcp_pdr_t *pdr); +void upf_sdf_filter_remove(upf_sdf_filter_t *sdf_filter); +void upf_sdf_filter_remove_all(upf_sess_t *sess); + +void stats_add_session(void); +void stats_remove_session(void); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_CONTEXT_H */ diff --git a/src/upf/event.c b/src/upf/event.c new file mode 100644 index 000000000..284c17775 --- /dev/null +++ b/src/upf/event.c @@ -0,0 +1,96 @@ +/* + * 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 "event.h" +#include "context.h" + +#define EVENT_POOL 32 /* FIXME : 32 */ +static OGS_POOL(pool, upf_event_t); + +void upf_event_init(void) +{ + ogs_pool_init(&pool, EVENT_POOL); + + upf_self()->queue = ogs_queue_create(EVENT_POOL); + ogs_assert(upf_self()->queue); + upf_self()->timer_mgr = ogs_timer_mgr_create(); + ogs_assert(upf_self()->timer_mgr); + upf_self()->pollset = ogs_pollset_create(); + ogs_assert(upf_self()->pollset); +} + +void upf_event_term(void) +{ + ogs_queue_term(upf_self()->queue); + ogs_pollset_notify(upf_self()->pollset); +} + +void upf_event_final(void) +{ + if (upf_self()->pollset) + ogs_pollset_destroy(upf_self()->pollset); + if (upf_self()->timer_mgr) + ogs_timer_mgr_destroy(upf_self()->timer_mgr); + if (upf_self()->queue) + ogs_queue_destroy(upf_self()->queue); + + ogs_pool_final(&pool); +} + +upf_event_t *upf_event_new(upf_event_e id) +{ + upf_event_t *e = NULL; + + ogs_pool_alloc(&pool, &e); + ogs_assert(e); + e->id = id; + + return e; +} + +void upf_event_free(upf_event_t *e) +{ + ogs_assert(e); + ogs_pool_free(&pool, e); +} + +const char *upf_event_get_name(upf_event_t *e) +{ + if (e == NULL) + return OGS_FSM_NAME_INIT_SIG; + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + return OGS_FSM_NAME_ENTRY_SIG; + case OGS_FSM_EXIT_SIG: + return OGS_FSM_NAME_EXIT_SIG; + + case UPF_EVT_N4_MESSAGE: + return "UPF_EVT_N4_MESSAGE"; + case UPF_EVT_N4_TIMER: + return "UPF_EVT_N4_TIMER"; + case UPF_EVT_N4_NO_HEARTBEAT: + return "UPF_EVT_N4_NO_HEARTBEAT"; + + default: + break; + } + + return "UNKNOWN_EVENT"; +} diff --git a/src/upf/event.h b/src/upf/event.h new file mode 100644 index 000000000..ba12d1ed6 --- /dev/null +++ b/src/upf/event.h @@ -0,0 +1,69 @@ +/* + * 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 UPF_EVENT_H +#define UPF_EVENT_H + +#include "ogs-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ogs_pfcp_node_s ogs_pfcp_node_t; +typedef struct ogs_pfcp_xact_s ogs_pfcp_xact_t; +typedef struct ogs_pfcp_message_s ogs_pfcp_message_t; +typedef struct upf_sess_s upf_sess_t; +typedef struct upf_upf_s upf_upf_t; + +typedef enum { + UPF_EVT_BASE = OGS_FSM_USER_SIG, + + UPF_EVT_N4_MESSAGE, + UPF_EVT_N4_TIMER, + UPF_EVT_N4_NO_HEARTBEAT, + + UPF_EVT_TOP, + +} upf_event_e; + +typedef struct upf_event_s { + int id; + ogs_pkbuf_t *pkbuf; + int timer_id; + + ogs_pfcp_node_t *pfcp_node; + ogs_pfcp_xact_t *pfcp_xact; + ogs_pfcp_message_t *pfcp_message; +} upf_event_t; + +void upf_event_init(void); +void upf_event_term(void); +void upf_event_final(void); + +upf_event_t *upf_event_new(upf_event_e id); +void upf_event_free(upf_event_t *e); + +const char *upf_event_get_name(upf_event_t *e); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_EVENT_H */ diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c new file mode 100644 index 000000000..0a555e7ed --- /dev/null +++ b/src/upf/gtp-path.c @@ -0,0 +1,501 @@ +/* + * 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 "context.h" + +#if HAVE_NETINET_IP_H +#include +#endif + +#if HAVE_NETINET_IP6_H +#include +#endif + +#if HAVE_NETINET_IP_ICMP_H +#include +#endif + +#if HAVE_NETINET_ICMP6_H +#include +#endif + +#include "event.h" +#include "gtp-path.h" +#include "rule-match.h" + +#define UPF_GTP_HANDLED 1 + +uint16_t in_cksum(uint16_t *addr, int len); +static int upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf); +static int upf_gtp_handle_slaac(upf_sess_t *sess, ogs_pkbuf_t *recvbuf); +static void upf_gtp_send_to_far(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf); +static void upf_gtp_send_to_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf); +static int upf_gtp_send_router_advertisement( + upf_sess_t *sess, uint8_t *ip6_dst); + +static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data) +{ + ogs_pkbuf_t *recvbuf = NULL; + int n; + ogs_pfcp_pdr_t *pdr = NULL; + + recvbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_pkbuf_reserve(recvbuf, OGS_GTPV1U_HEADER_LEN); + ogs_pkbuf_put(recvbuf, OGS_MAX_SDU_LEN-OGS_GTPV1U_HEADER_LEN); + + n = ogs_read(fd, recvbuf->data, recvbuf->len); + if (n <= 0) { + ogs_log_message(OGS_LOG_WARN, ogs_socket_errno, "ogs_read() failed"); + ogs_pkbuf_free(recvbuf); + return; + } + + ogs_pkbuf_trim(recvbuf, n); + + /* Find the PDR by packet filter */ + pdr = upf_pdr_find_by_packet(recvbuf); + if (pdr) { + /* Unicast */ + upf_gtp_send_to_pdr(pdr, recvbuf); + } else { + if (ogs_config()->parameter.multicast) { + upf_gtp_handle_multicast(recvbuf); + } + } + + ogs_pkbuf_free(recvbuf); +} + +static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) +{ + int rv; + ssize_t size; + ogs_pkbuf_t *pkbuf = NULL; + uint32_t len = OGS_GTPV1U_HEADER_LEN; + ogs_gtp_header_t *gtp_h = NULL; + struct ip *ip_h = NULL; + + uint32_t teid; + ogs_pfcp_pdr_t *pdr = NULL; + upf_sess_t *sess = NULL; + ogs_pfcp_subnet_t *subnet = NULL; + ogs_pfcp_dev_t *dev = NULL; + + ogs_assert(fd != INVALID_SOCKET); + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); + + size = ogs_recv(fd, pkbuf->data, pkbuf->len, 0); + if (size <= 0) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "ogs_recv() failed"); + goto cleanup; + } + + ogs_pkbuf_trim(pkbuf, size); + + ogs_assert(pkbuf); + ogs_assert(pkbuf->len); + + gtp_h = (ogs_gtp_header_t *)pkbuf->data; + if (gtp_h->flags & OGS_GTPU_FLAGS_S) len += 4; + teid = be32toh(gtp_h->teid); + + ogs_debug("[UPF] RECV GPU-U from SGW : TEID[0x%x]", teid); + + /* Remove GTP header and send packets to TUN interface */ + ogs_assert(ogs_pkbuf_pull(pkbuf, len)); + + ip_h = (struct ip *)pkbuf->data; + ogs_assert(ip_h); + + pdr = ogs_pfcp_pdr_find_by_teid(teid); + if (!pdr) { + ogs_warn("[DROP] Cannot find PDR : UPF-N3-TEID[0x%x]", teid); + goto cleanup; + } + ogs_assert(pdr->sess); + sess = UPF_SESS(pdr->sess); + ogs_assert(sess); + + if (ip_h->ip_v == 4 && sess->ipv4) + subnet = sess->ipv4->subnet; + else if (ip_h->ip_v == 6 && sess->ipv6) + subnet = sess->ipv6->subnet; + + if (!subnet) { + ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data, pkbuf->len); + ogs_error("[DROP] Cannot find subnet V:%d, IPv4:%p, IPv6:%p", + ip_h->ip_v, sess->ipv4, sess->ipv6); + goto cleanup; + } + + /* Check IPv6 */ + if (ogs_config()->parameter.no_slaac == 0 && ip_h->ip_v == 6) { + rv = upf_gtp_handle_slaac(sess, pkbuf); + if (rv == UPF_GTP_HANDLED) { + goto cleanup; + } + ogs_assert(rv == OGS_OK); + } + + dev = subnet->dev; + ogs_assert(dev); + if (ogs_write(dev->fd, pkbuf->data, pkbuf->len) <= 0) + ogs_error("ogs_write() failed"); + +cleanup: + ogs_pkbuf_free(pkbuf); +} + +int upf_gtp_open(void) +{ + ogs_pfcp_dev_t *dev = NULL; + ogs_pfcp_subnet_t *subnet = NULL; + ogs_socknode_t *node = NULL; + ogs_sock_t *sock = NULL; + int rc; + + ogs_list_for_each(&upf_self()->gtpu_list, node) { + sock = ogs_gtp_server(node); + ogs_assert(sock); + + if (sock->family == AF_INET) + upf_self()->gtpu_sock = sock; + else if (sock->family == AF_INET6) + upf_self()->gtpu_sock6 = sock; + + node->poll = ogs_pollset_add(upf_self()->pollset, + OGS_POLLIN, sock->fd, _gtpv1_u_recv_cb, sock); + } + + ogs_assert(upf_self()->gtpu_sock || upf_self()->gtpu_sock6); + + /* NOTE : tun device can be created via following command. + * + * $ sudo ip tuntap add name ogstun mode tun + * + * Also, before running upf, assign the one IP from IP pool of UE + * to ogstun. The IP should not be assigned to UE + * + * $ sudo ifconfig ogstun 45.45.0.1/16 up + * + */ + + /* Open Tun interface */ + ogs_list_for_each(&ogs_pfcp_self()->dev_list, dev) { + dev->fd = ogs_tun_open(dev->ifname, OGS_MAX_IFNAME_LEN, 0); + if (dev->fd == INVALID_SOCKET) { + ogs_error("tun_open(dev:%s) failed", dev->ifname); + return OGS_ERROR; + } + + dev->poll = ogs_pollset_add(upf_self()->pollset, + OGS_POLLIN, dev->fd, _gtpv1_tun_recv_cb, NULL); + ogs_assert(dev->poll); + } + + /* + * On Linux, it is possible to create a persistent tun/tap + * interface which will continue to exist even if open5gs quit, + * although this is normally not required. + * It can be useful to set up a tun/tap interface owned + * by a non-root user, so open5gs can be started without + * needing any root privileges at all. + */ + + /* Set P-to-P IP address with Netmask + * Note that Linux will skip this configuration */ + ogs_list_for_each(&ogs_pfcp_self()->subnet_list, subnet) { + ogs_assert(subnet->dev); + rc = ogs_tun_set_ip(subnet->dev->ifname, &subnet->gw, &subnet->sub); + if (rc != OGS_OK) { + ogs_error("ogs_tun_set_ip(dev:%s) failed", subnet->dev->ifname); + return OGS_ERROR; + } + } + + /* Link-Local Address for UPF_TUN */ + ogs_list_for_each(&ogs_pfcp_self()->dev_list, dev) + dev->link_local_addr = ogs_link_local_addr_by_dev(dev->ifname); + + return OGS_OK; +} + +void upf_gtp_close(void) +{ + ogs_pfcp_dev_t *dev = NULL; + + ogs_socknode_remove_all(&upf_self()->gtpu_list); + + ogs_list_for_each(&ogs_pfcp_self()->dev_list, dev) { + if (dev->poll) + ogs_pollset_remove(dev->poll); + ogs_closesocket(dev->fd); + } +} + +static int upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf) +{ + struct ip *ip_h = NULL; + struct ip6_hdr *ip6_h = NULL; + + ip_h = (struct ip *)recvbuf->data; + if (ip_h->ip_v == 6) { +#if COMPILE_ERROR_IN_MAC_OS_X /* Compiler error in Mac OS X platform */ + ip6_h = (struct ip6_hdr *)recvbuf->data; + if (IN6_IS_ADDR_MULTICAST(&ip6_h->ip6_dst)) +#else + struct in6_addr ip6_dst; + ip6_h = (struct ip6_hdr *)recvbuf->data; + memcpy(&ip6_dst, &ip6_h->ip6_dst, sizeof(struct in6_addr)); + if (IN6_IS_ADDR_MULTICAST(&ip6_dst)) +#endif + { + upf_sess_t *sess = NULL; + + /* IPv6 Multicast */ + ogs_list_for_each(&upf_self()->sess_list, sess) { + if (sess->ipv6) { + /* PDN IPv6 is avaiable */ + ogs_pfcp_pdr_t *pdr = NULL; + + pdr = ogs_pfcp_sess_default_pdr(&sess->pfcp); + ogs_assert(pdr); + upf_gtp_send_to_pdr(pdr, recvbuf); + + return UPF_GTP_HANDLED; + } + } + } + } + + return OGS_OK; +} + +static int upf_gtp_handle_slaac(upf_sess_t *sess, ogs_pkbuf_t *recvbuf) +{ + int rv; + struct ip *ip_h = NULL; + + ogs_assert(sess); + ogs_assert(recvbuf); + ogs_assert(recvbuf->len); + ip_h = (struct ip *)recvbuf->data; + if (ip_h->ip_v == 6) { + struct ip6_hdr *ip6_h = (struct ip6_hdr *)recvbuf->data; + if (ip6_h->ip6_nxt == IPPROTO_ICMPV6) { + struct icmp6_hdr *icmp_h = + (struct icmp6_hdr *)(recvbuf->data + sizeof(struct ip6_hdr)); + if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT) { + ogs_debug("[UPF] Router Solict"); + if (sess->ipv6) { + rv = upf_gtp_send_router_advertisement( + sess, ip6_h->ip6_src.s6_addr); + ogs_assert(rv == OGS_OK); + } + return UPF_GTP_HANDLED; + } + } + } + + return OGS_OK; +} + +static void upf_gtp_send_to_far(ogs_pfcp_far_t *far, ogs_pkbuf_t *sendbuf) +{ + char buf[OGS_ADDRSTRLEN]; + int rv; + ogs_gtp_header_t *gtp_h = NULL; + ogs_gtp_node_t *gnode = NULL; + + ogs_assert(far); + + if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) { + ogs_error("FAR is NOT Downlink"); + return; + } + + gnode = far->gnode; + ogs_assert(gnode); + ogs_assert(gnode->sock); + ogs_assert(sendbuf); + + /* Add GTP-U header */ + ogs_assert(ogs_pkbuf_push(sendbuf, OGS_GTPV1U_HEADER_LEN)); + gtp_h = (ogs_gtp_header_t *)sendbuf->data; + /* Bits 8 7 6 5 4 3 2 1 + * +--+--+--+--+--+--+--+--+ + * |version |PT| 1| E| S|PN| + * +--+--+--+--+--+--+--+--+ + * 0 0 1 1 0 0 0 0 + */ + gtp_h->flags = 0x30; + gtp_h->type = OGS_GTPU_MSGTYPE_GPDU; + gtp_h->length = htobe16(sendbuf->len - OGS_GTPV1U_HEADER_LEN); + gtp_h->teid = htobe32(far->outer_header_creation.teid); + + /* Send to SGW */ + ogs_debug("[UPF] SEND GPU-U to gNB[%s] : TEID[0x%x]", + OGS_ADDR(&gnode->addr, buf), far->outer_header_creation.teid); + rv = ogs_gtp_sendto(gnode, sendbuf); + if (rv != OGS_OK) + ogs_error("ogs_gtp_sendto() failed"); +} + +static void upf_gtp_send_to_pdr(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf) +{ + ogs_pfcp_far_t *far = NULL; + + ogs_assert(sendbuf); + ogs_assert(pdr); + + if (pdr->src_if != OGS_PFCP_INTERFACE_CORE) { + ogs_error("PDR is NOT Downlink"); + return; + } + + far = pdr->far; + ogs_assert(far); + + upf_gtp_send_to_far(far, sendbuf); +} + +static int upf_gtp_send_router_advertisement( + upf_sess_t *sess, uint8_t *ip6_dst) +{ + int rv; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; + ogs_pfcp_ue_ip_t *ue_ip = NULL; + ogs_pfcp_subnet_t *subnet = NULL; + ogs_pfcp_dev_t *dev = NULL; + + ogs_ipsubnet_t src_ipsub; + uint16_t plen = 0; + uint8_t nxt = 0; + uint8_t *p = NULL; + struct ip6_hdr *ip6_h = NULL; + struct nd_router_advert *advert_h = NULL; + struct nd_opt_prefix_info *prefix = NULL; + + ogs_assert(sess); + pdr = ogs_pfcp_sess_default_pdr(&sess->pfcp); + ogs_assert(pdr); + far = pdr->far; + ogs_assert(far); + ue_ip = sess->ipv6; + ogs_assert(ue_ip); + subnet = ue_ip->subnet; + ogs_assert(subnet); + dev = subnet->dev; + ogs_assert(dev); + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_GTPV1U_HEADER_LEN+200); + ogs_pkbuf_reserve(pkbuf, OGS_GTPV1U_HEADER_LEN); + ogs_pkbuf_put(pkbuf, 200); + pkbuf->len = sizeof *ip6_h + sizeof *advert_h + sizeof *prefix; + memset(pkbuf->data, 0, pkbuf->len); + + p = (uint8_t *)pkbuf->data; + ip6_h = (struct ip6_hdr *)p; + advert_h = (struct nd_router_advert *)((uint8_t *)ip6_h + sizeof *ip6_h); + prefix = (struct nd_opt_prefix_info *) + ((uint8_t*)advert_h + sizeof *advert_h); + + rv = ogs_ipsubnet(&src_ipsub, "fe80::1", NULL); + ogs_assert(rv == OGS_OK); + if (dev->link_local_addr) + memcpy(src_ipsub.sub, dev->link_local_addr->sin6.sin6_addr.s6_addr, + sizeof src_ipsub.sub); + + advert_h->nd_ra_type = ND_ROUTER_ADVERT; + advert_h->nd_ra_code = 0; + advert_h->nd_ra_curhoplimit = 64; + advert_h->nd_ra_flags_reserved = 0; + advert_h->nd_ra_router_lifetime = htobe16(64800); /* 64800s */ + advert_h->nd_ra_reachable = 0; + advert_h->nd_ra_retransmit = 0; + + prefix->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; + prefix->nd_opt_pi_len = 4; /* 32bytes */ + prefix->nd_opt_pi_prefix_len = subnet->prefixlen; + prefix->nd_opt_pi_flags_reserved = + ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO; + prefix->nd_opt_pi_valid_time = htobe32(0xffffffff); /* Infinite */ + prefix->nd_opt_pi_preferred_time = htobe32(0xffffffff); /* Infinite */ + memcpy(prefix->nd_opt_pi_prefix.s6_addr, + subnet->sub.sub, sizeof prefix->nd_opt_pi_prefix.s6_addr); + + /* For IPv6 Pseudo-Header */ + plen = htobe16(sizeof *advert_h + sizeof *prefix); + nxt = IPPROTO_ICMPV6; + + memcpy(p, src_ipsub.sub, sizeof src_ipsub.sub); + p += sizeof src_ipsub.sub; + memcpy(p, ip6_dst, OGS_IPV6_LEN); + p += OGS_IPV6_LEN; + p += 2; memcpy(p, &plen, 2); p += 2; + p += 3; *p = nxt; p += 1; + advert_h->nd_ra_cksum = in_cksum((uint16_t *)pkbuf->data, pkbuf->len); + + ip6_h->ip6_flow = htobe32(0x60000001); + ip6_h->ip6_plen = plen; + ip6_h->ip6_nxt = nxt; /* ICMPv6 */ + ip6_h->ip6_hlim = 0xff; + memcpy(ip6_h->ip6_src.s6_addr, src_ipsub.sub, sizeof src_ipsub.sub); + memcpy(ip6_h->ip6_dst.s6_addr, ip6_dst, OGS_IPV6_LEN); + + upf_gtp_send_to_pdr(pdr, pkbuf); + + ogs_debug("[UPF] Router Advertisement"); + + ogs_pkbuf_free(pkbuf); + return rv; +} + +uint16_t in_cksum(uint16_t *addr, int len) +{ + int nleft = len; + uint32_t sum = 0; + uint16_t *w = addr; + uint16_t answer = 0; + + // Adding 16 bits sequentially in sum + while (nleft > 1) { + sum += *w; + nleft -= 2; + w++; + } + + // If an odd byte is left + if (nleft == 1) { + *(uint8_t *) (&answer) = *(uint8_t *) w; + sum += answer; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + answer = ~sum; + + return answer; +} diff --git a/src/upf/gtp-path.h b/src/upf/gtp-path.h new file mode 100644 index 000000000..45e35b2a9 --- /dev/null +++ b/src/upf/gtp-path.h @@ -0,0 +1,37 @@ +/* + * 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 UPF_GTP_PATH_H +#define UPF_GTP_PATH_H + +#include "ogs-tun.h" +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int upf_gtp_open(void); +void upf_gtp_close(void); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_GTP_PATH_H */ diff --git a/src/upf/init.c b/src/upf/init.c new file mode 100644 index 000000000..dc17ef809 --- /dev/null +++ b/src/upf/init.c @@ -0,0 +1,134 @@ +/* + * 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 "context.h" +#include "event.h" +#include "upf-sm.h" + +static ogs_thread_t *thread; +static void upf_main(void *data); + +static int initialized = 0; + +int upf_initialize() +{ + int rv; + + ogs_pfcp_context_init(OGS_MAX_NUM_OF_GTPU_RESOURCE); + upf_context_init(); + upf_event_init(); + + rv = ogs_pfcp_xact_init(upf_self()->timer_mgr, 512); + if (rv != OGS_OK) return rv; + + rv = ogs_pfcp_context_parse_config("upf", "smf"); + if (rv != OGS_OK) return rv; + + rv = upf_context_parse_config(); + if (rv != OGS_OK) return rv; + + rv = ogs_log_config_domain( + ogs_config()->logger.domain, ogs_config()->logger.level); + if (rv != OGS_OK) return rv; + + rv = ogs_pfcp_ue_pool_generate(); + if (rv != OGS_OK) return rv; + + thread = ogs_thread_create(upf_main, NULL); + if (!thread) return OGS_ERROR; + + initialized = 1; + + return OGS_OK; +} + +void upf_terminate(void) +{ + if (!initialized) return; + + upf_event_term(); + + ogs_thread_destroy(thread); + + upf_context_final(); + ogs_pfcp_context_final(); + + ogs_pfcp_xact_final(); + + upf_event_final(); +} + +static void upf_main(void *data) +{ + ogs_fsm_t upf_sm; + int rv; + + ogs_fsm_create(&upf_sm, upf_state_initial, upf_state_final); + ogs_fsm_init(&upf_sm, 0); + + for ( ;; ) { + ogs_pollset_poll(upf_self()->pollset, + ogs_timer_mgr_next(upf_self()->timer_mgr)); + + /* Process the MESSAGE FIRST. + * + * For example, if UE Context Release Complete is received, + * the MME_TIMER_UE_CONTEXT_RELEASE is first stopped */ + for ( ;; ) { + upf_event_t *e = NULL; + + rv = ogs_queue_trypop(upf_self()->queue, (void**)&e); + ogs_assert(rv != OGS_ERROR); + + if (rv == OGS_DONE) + goto done; + + if (rv == OGS_RETRY) + break; + + ogs_assert(e); + ogs_fsm_dispatch(&upf_sm, e); + upf_event_free(e); + } + + ogs_timer_mgr_expire(upf_self()->timer_mgr); + + /* AND THEN, process the TIMER. */ + for ( ;; ) { + upf_event_t *e = NULL; + + rv = ogs_queue_trypop(upf_self()->queue, (void**)&e); + ogs_assert(rv != OGS_ERROR); + + if (rv == OGS_DONE) + goto done; + + if (rv == OGS_RETRY) + break; + + ogs_assert(e); + ogs_fsm_dispatch(&upf_sm, e); + upf_event_free(e); + } + } +done: + + ogs_fsm_fini(&upf_sm, 0); + ogs_fsm_delete(&upf_sm); +} diff --git a/src/upf/meson.build b/src/upf/meson.build new file mode 100644 index 000000000..05cdfa846 --- /dev/null +++ b/src/upf/meson.build @@ -0,0 +1,90 @@ +# 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 . + +upf_conf = configuration_data() + +upf_headers = (''' + net/if.h + netinet/ip.h + netinet/ip6.h + netinet/ip_icmp.h + netinet/icmp6.h +'''.split()) + +foreach h : upf_headers + if cc.has_header(h) + define = 'HAVE_' + h.underscorify().to_upper() + upf_conf.set(define, 1) + endif +endforeach + +if have_func_kqueue + upf_conf.set('HAVE_KQUEUE', 1) +endif + +configure_file(output : 'upf-config.h', configuration : upf_conf) + +libupf_sources = files(''' + rule-match.h + event.h + timer.h + context.h + upf-sm.h + gtp-path.h + pfcp-path.h + n4-build.h + n4-handler.h + + rule-match.c + init.c + event.c + timer.c + context.c + upf-sm.c + pfcp-sm.c + gtp-path.c + pfcp-path.c + n4-build.c + n4-handler.c +'''.split()) + +libupf = static_library('upf', + sources : libupf_sources, + link_with : libipfw, + dependencies : [ + libapp_dep, libdiameter_gx_dep, libgtp_dep, libpfcp_dep, libipfw_dep + ], + install : false) + +libupf_dep = declare_dependency( + link_with : libupf, + dependencies : [ + libapp_dep, libdiameter_gx_dep, libgtp_dep, libpfcp_dep, libipfw_dep + ]) + +upf_sources = files(''' + app.c + ../main.c +'''.split()) + +executable('open5gs-upfd', + sources : upf_sources, + c_args : '-DDEFAULT_CONFIG_FILENAME="@0@/upf.yaml"'.format(open5gs_sysconfdir), + include_directories : srcinc, + dependencies : libupf_dep, + install_rpath : libdir, + install : true) diff --git a/src/upf/n4-build.c b/src/upf/n4-build.c new file mode 100644 index 000000000..d03c92fd4 --- /dev/null +++ b/src/upf/n4-build.c @@ -0,0 +1,228 @@ +/* + * 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 "context.h" +#include "n4-build.h" + +ogs_pkbuf_t *upf_n4_build_association_setup_request(uint8_t type) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_association_setup_request_t *req = NULL; + + ogs_pfcp_node_id_t node_id; + int node_id_len = 0; + + ogs_pfcp_gtpu_resource_t *resource = NULL; + char infobuf[OGS_MAX_NUM_OF_GTPU_RESOURCE] + [OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; + int i = 0; + + ogs_debug("[UPF] Association Setup Request"); + + req = &pfcp_message.pfcp_association_setup_request; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + ogs_pfcp_sockaddr_to_node_id( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + ogs_config()->parameter.prefer_ipv4, + &node_id, &node_id_len); + req->node_id.presence = 1; + req->node_id.data = &node_id; + req->node_id.len = node_id_len; + + req->recovery_time_stamp.presence = 1; + req->recovery_time_stamp.u32 = ogs_pfcp_self()->pfcp_started; + + req->up_function_features.presence = 1; + req->up_function_features.u16 = htobe16(upf_self()->function_features); + + i = 0; + ogs_list_for_each(&upf_self()->gtpu_resource_list, resource) { + ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE); + ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = + &req->user_plane_ip_resource_information[i]; + ogs_assert(message); + + message->presence = 1; + ogs_pfcp_build_user_plane_ip_resource_info( + message, &resource->info, infobuf[i], + OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); + i++; + } + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} + +ogs_pkbuf_t *upf_n4_build_association_setup_response(uint8_t type, + uint8_t cause) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_association_setup_response_t *rsp = NULL; + + ogs_pfcp_node_id_t node_id; + int node_id_len = 0; + + ogs_pfcp_gtpu_resource_t *resource = NULL; + char infobuf[OGS_MAX_NUM_OF_GTPU_RESOURCE] + [OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN]; + int i = 0; + + ogs_debug("[UPF] Association Setup Response"); + + rsp = &pfcp_message.pfcp_association_setup_response; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + ogs_pfcp_sockaddr_to_node_id( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + ogs_config()->parameter.prefer_ipv4, + &node_id, &node_id_len); + rsp->node_id.presence = 1; + rsp->node_id.data = &node_id; + rsp->node_id.len = node_id_len; + + rsp->cause.presence = 1; + rsp->cause.u8 = cause; + + rsp->recovery_time_stamp.presence = 1; + rsp->recovery_time_stamp.u32 = ogs_pfcp_self()->pfcp_started; + + rsp->up_function_features.presence = 1; + rsp->up_function_features.u16 = htobe16(upf_self()->function_features); + + i = 0; + ogs_list_for_each(&upf_self()->gtpu_resource_list, resource) { + ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE); + ogs_pfcp_tlv_user_plane_ip_resource_information_t *message = + &rsp->user_plane_ip_resource_information[i]; + ogs_assert(message); + + message->presence = 1; + ogs_pfcp_build_user_plane_ip_resource_info( + message, &resource->info, infobuf[i], + OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN); + i++; + } + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} + +ogs_pkbuf_t *upf_n4_build_session_establishment_response(uint8_t type, + upf_sess_t *sess, ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_session_establishment_response_t *rsp = NULL; + + int i = 0; + + ogs_pfcp_node_id_t node_id; + ogs_pfcp_f_seid_t f_seid; + int len = 0; + + ogs_debug("[UPF] Session Establishment Response"); + + rsp = &pfcp_message.pfcp_session_establishment_response; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + /* Node ID */ + ogs_pfcp_sockaddr_to_node_id( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + ogs_config()->parameter.prefer_ipv4, + &node_id, &len); + rsp->node_id.presence = 1; + rsp->node_id.data = &node_id; + rsp->node_id.len = len; + + /* Cause */ + rsp->cause.presence = 1; + rsp->cause.u8 = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + + /* F-SEID */ + ogs_pfcp_sockaddr_to_f_seid( + ogs_pfcp_self()->pfcp_addr, ogs_pfcp_self()->pfcp_addr6, + &f_seid, &len); + f_seid.seid = htobe64(sess->upf_n4_seid); + rsp->up_f_seid.presence = 1; + rsp->up_f_seid.data = &f_seid; + rsp->up_f_seid.len = len; + + /* Created PDR */ + for (i = 0; i < num_of_created_pdr; i++) { + ogs_pfcp_tlv_created_pdr_t *message = &rsp->created_pdr[i]; + ogs_assert(message); + + message->presence = 1; + message->pdr_id.presence = 1; + message->pdr_id.u16 = created_pdr[i]->id; + } + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} + +ogs_pkbuf_t *upf_n4_build_session_modification_response(uint8_t type, + upf_sess_t *sess, ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_session_modification_response_t *rsp = NULL; + + int i = 0; + + ogs_debug("[UPF] Session Modification Response"); + + rsp = &pfcp_message.pfcp_session_modification_response; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + /* Cause */ + rsp->cause.presence = 1; + rsp->cause.u8 = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + + /* Created PDR */ + for (i = 0; i < num_of_created_pdr; i++) { + ogs_pfcp_tlv_created_pdr_t *message = &rsp->created_pdr[i]; + ogs_assert(message); + + message->presence = 1; + message->pdr_id.presence = 1; + message->pdr_id.u16 = created_pdr[i]->id; + } + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} + +ogs_pkbuf_t *upf_n4_build_session_deletion_response(uint8_t type, + upf_sess_t *sess) +{ + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_session_deletion_response_t *rsp = NULL; + + ogs_debug("[UPF] Session Deletion Response"); + + rsp = &pfcp_message.pfcp_session_deletion_response; + memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); + + /* Cause */ + rsp->cause.presence = 1; + rsp->cause.u8 = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + + pfcp_message.h.type = type; + return ogs_pfcp_build_msg(&pfcp_message); +} diff --git a/src/upf/n4-build.h b/src/upf/n4-build.h new file mode 100644 index 000000000..ec6325baa --- /dev/null +++ b/src/upf/n4-build.h @@ -0,0 +1,44 @@ +/* + * 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 UPF_N4_BUILD_H +#define UPF_N4_BUILD_H + +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ogs_pkbuf_t *upf_n4_build_association_setup_request(uint8_t type); +ogs_pkbuf_t *upf_n4_build_association_setup_response(uint8_t type, + uint8_t cause); + +ogs_pkbuf_t *upf_n4_build_session_establishment_response(uint8_t type, + upf_sess_t *sess, ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr); +ogs_pkbuf_t *upf_n4_build_session_modification_response(uint8_t type, + upf_sess_t *sess, ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr); +ogs_pkbuf_t *upf_n4_build_session_deletion_response(uint8_t type, + upf_sess_t *sess); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_N4_BUILD_H */ diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c new file mode 100644 index 000000000..543b5ede0 --- /dev/null +++ b/src/upf/n4-handler.c @@ -0,0 +1,640 @@ +/* + * 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 "context.h" +#include "timer.h" +#include "pfcp-path.h" +#include "n4-handler.h" + +void upf_n4_handle_association_setup_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_request_t *req) +{ + ogs_assert(xact); + upf_pfcp_send_association_setup_response( + xact, OGS_PFCP_CAUSE_REQUEST_ACCEPTED); +} + +void upf_n4_handle_association_setup_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_response_t *rsp) +{ + ogs_assert(xact); + ogs_pfcp_xact_commit(xact); +} + +void upf_n4_handle_heartbeat_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_request_t *req) +{ + ogs_assert(xact); + ogs_pfcp_send_heartbeat_response(xact); +} + +void upf_n4_handle_heartbeat_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_response_t *rsp) +{ + ogs_assert(xact); + ogs_pfcp_xact_commit(xact); + + ogs_timer_start(node->t_heartbeat, + upf_timer_cfg(UPF_TIMER_HEARTBEAT)->duration); +} + +static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_create_pdr_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; + ogs_pfcp_qer_t *qer = NULL; + int i, len; + int rv; + + ogs_assert(sess); + ogs_assert(message); + + if (message->presence == 0) + return NULL; + + if (message->pdr_id.presence == 0) { + ogs_warn("No PDR-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_PDR_ID_TYPE; + return NULL; + } + + if (message->precedence.presence == 0) { + ogs_warn("No Presence in PDR"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_PRECEDENCE_TYPE; + return NULL; + } + + pdr = ogs_pfcp_pdr_find_or_add(sess, message->pdr_id.u16); + ogs_assert(pdr); + ogs_pfcp_pdr_reorder_by_precedence(pdr, message->precedence.u32); + + if (message->pdi.presence == 0) { + ogs_warn("No PDI in PDR"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_PDI_TYPE; + return NULL; + } + + if (message->pdi.source_interface.presence == 0) { + ogs_warn("No Source Interface in PDI"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_SOURCE_INTERFACE_TYPE; + return NULL; + } + + pdr->precedence = message->precedence.u32; + pdr->src_if = message->pdi.source_interface.u8; + + for (i = 0; i < OGS_MAX_NUM_OF_RULE; i++) { + ogs_pfcp_sdf_filter_t sdf_filter_in_message; + if (message->pdi.sdf_filter[i].presence == 0) + break; + + len = ogs_pfcp_parse_sdf_filter( + &sdf_filter_in_message, &message->pdi.sdf_filter[i]); + ogs_assert(message->pdi.sdf_filter[i].len == len); + if (sdf_filter_in_message.fd) { + upf_sdf_filter_t *sdf_filter = NULL; + char *flow_description = NULL; + + flow_description = ogs_malloc( + sdf_filter_in_message.flow_description_len+1); + ogs_cpystrn(flow_description, + sdf_filter_in_message.flow_description, + sdf_filter_in_message.flow_description_len+1); + + sdf_filter = upf_sdf_filter_add(pdr); + ogs_assert(sdf_filter); + rv = ogs_ipfw_compile_rule(&sdf_filter->rule, flow_description); + ogs_assert(rv == OGS_OK); + sdf_filter->pdr = pdr; + + ogs_free(flow_description); + } + } + + /* APN(Network Instance) and UE IP Address + * has already been processed in upf_sess_add() */ + + if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */ + + /* Nothing */ + + } else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */ + if (message->pdi.local_f_teid.presence == 0) { + ogs_warn("No F-TEID in PDI"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_F_TEID_TYPE; + return NULL; + } + + if (message->outer_header_removal.presence == 0) { + ogs_warn("No Outer Header Removal in PDI"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_OUTER_HEADER_REMOVAL_TYPE; + return NULL; + } + + memcpy(&pdr->f_teid, message->pdi.local_f_teid.data, + message->pdi.local_f_teid.len); + pdr->f_teid.teid = be32toh(pdr->f_teid.teid); + memcpy(&pdr->outer_header_removal, + message->outer_header_removal.data, + message->outer_header_removal.len); + + /* Setup UPF-N3-TEID */ + ogs_hash_set(ogs_pfcp_self()->pdr_hash, &pdr->f_teid.teid, + sizeof(pdr->f_teid.teid), pdr); + } else { + ogs_error("Invalid Source Interface[%d] in PDR", pdr->src_if); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_SOURCE_INTERFACE_TYPE; + return NULL; + } + + if (message->far_id.presence) { + far = ogs_pfcp_far_find_or_add(sess, message->far_id.u32); + ogs_assert(far); + ogs_pfcp_pdr_associate_far(pdr, far); + } + + if (message->qer_id.presence) { + qer = ogs_pfcp_qer_find_or_add(sess, message->qer_id.u32); + ogs_assert(qer); + ogs_pfcp_pdr_associate_qer(pdr, qer); + } + + return pdr; +} + +static bool handle_remove_pdr(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_remove_pdr_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_assert(sess); + ogs_assert(message); + + if (message->presence == 0) + return false; + + if (message->pdr_id.presence == 0) { + ogs_warn("No PDR-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_PDR_ID_TYPE; + return false; + } + + pdr = ogs_pfcp_pdr_find(sess, message->pdr_id.u16); + if (!pdr) { + ogs_error("Unknown PDR-ID[%d]", message->pdr_id.u16); + *cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + return false; + } + + ogs_pfcp_pdr_remove(pdr); + + return true; +} + +static ogs_pfcp_far_t *handle_create_far(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_create_far_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_far_t *far = NULL; + + ogs_assert(message); + ogs_assert(sess); + + if (message->presence == 0) + return NULL; + + if (message->far_id.presence == 0) { + ogs_warn("No FAR-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_FAR_ID_TYPE; + return NULL; + } + + far = ogs_pfcp_far_find(sess, message->far_id.u32); + if (!far) { + ogs_error("Cannot find FAR-ID[%d] in PDR", message->far_id.u32); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_FAR_ID_TYPE; + return NULL; + } + + if (message->apply_action.presence == 0) { + ogs_warn("No Apply Action"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_APPLY_ACTION_TYPE; + return NULL; + } + if (message->forwarding_parameters. + destination_interface.presence == 0) { + ogs_warn("No Destination Interface"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_DESTINATION_INTERFACE_TYPE; + return NULL; + } + + far->apply_action = message->apply_action.u8; + far->dst_if = message->forwarding_parameters.destination_interface.u8; + + if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */ + int rv; + ogs_ip_t ip; + ogs_gtp_node_t *gnode = NULL; + + if (message->forwarding_parameters. + outer_header_creation.presence == 0) { + ogs_warn("No Outer Header Creation in PDI"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_OUTER_HEADER_CREATION_TYPE; + return NULL; + } + + memcpy(&far->outer_header_creation, + message->forwarding_parameters.outer_header_creation.data, + message->forwarding_parameters.outer_header_creation.len); + far->outer_header_creation.teid = + be32toh(far->outer_header_creation.teid); + + /* Setup GTP Node */ + rv = ogs_pfcp_outer_header_creation_to_ip( + &far->outer_header_creation, &ip); + ogs_assert(rv == OGS_OK); + + gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip); + if (!gnode) { + gnode = ogs_gtp_node_add_by_ip( + &upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port, + ogs_config()->parameter.no_ipv4, + ogs_config()->parameter.no_ipv6, + ogs_config()->parameter.prefer_ipv4); + ogs_assert(gnode); + + rv = ogs_gtp_connect( + upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode); + ogs_assert(rv == OGS_OK); + } + OGS_SETUP_GTP_NODE(far, gnode); + } else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */ + + /* Nothing */ + + } else { + ogs_error("Invalid Destination Interface[%d] in FAR", far->dst_if); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_DESTINATION_INTERFACE_TYPE; + return NULL; + } + + return far; +} + +static bool handle_remove_far(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_remove_far_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_far_t *far = NULL; + + ogs_assert(sess); + ogs_assert(message); + + if (message->presence == 0) + return false; + + if (message->far_id.presence == 0) { + ogs_warn("No FAR-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_FAR_ID_TYPE; + return false; + } + + far = ogs_pfcp_far_find(sess, message->far_id.u32); + if (!far) { + ogs_error("Unknown FAR-ID[%d]", message->far_id.u32); + *cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + return false; + } + + ogs_pfcp_far_remove(far); + + return true; +} + +static ogs_pfcp_qer_t *handle_create_qer(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_create_qer_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_qer_t *qer = NULL; + + ogs_assert(message); + ogs_assert(sess); + + if (message->presence == 0) + return NULL; + + if (message->qer_id.presence == 0) { + ogs_warn("No QER-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_FAR_ID_TYPE; + return NULL; + } + + qer = ogs_pfcp_qer_find(sess, message->qer_id.u32); + if (!qer) { + ogs_error("Cannot find QER-ID[%d] in PDR", message->qer_id.u32); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_FAR_ID_TYPE; + return NULL; + } + + if (message->gate_status.presence == 0) { + ogs_warn("No Gate Status"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_APPLY_ACTION_TYPE; + return NULL; + } + + qer->gate_status.value = message->gate_status.u8; + + if (message->maximum_bitrate.presence) + ogs_pfcp_parse_bitrate(&qer->mbr, &message->maximum_bitrate); + if (message->guaranteed_bitrate.presence) + ogs_pfcp_parse_bitrate(&qer->gbr, &message->guaranteed_bitrate); + + return qer; +} + +static ogs_pfcp_qer_t *handle_update_qer(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_update_qer_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_qer_t *qer = NULL; + + ogs_assert(message); + ogs_assert(sess); + + if (message->presence == 0) + return NULL; + + if (message->qer_id.presence == 0) { + ogs_warn("No QER-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_FAR_ID_TYPE; + return NULL; + } + + qer = ogs_pfcp_qer_find(sess, message->qer_id.u32); + if (!qer) { + ogs_error("Cannot find QER-ID[%d] in PDR", message->qer_id.u32); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT; + *offending_ie_value = OGS_PFCP_FAR_ID_TYPE; + return NULL; + } + + if (message->maximum_bitrate.presence) + ogs_pfcp_parse_bitrate(&qer->mbr, &message->maximum_bitrate); + if (message->guaranteed_bitrate.presence) + ogs_pfcp_parse_bitrate(&qer->gbr, &message->guaranteed_bitrate); + + return qer; +} + +static bool handle_remove_qer(ogs_pfcp_sess_t *sess, + ogs_pfcp_tlv_remove_qer_t *message, + uint8_t *cause_value, uint8_t *offending_ie_value) +{ + ogs_pfcp_qer_t *qer = NULL; + + ogs_assert(sess); + ogs_assert(message); + + if (message->presence == 0) + return false; + + if (message->qer_id.presence == 0) { + ogs_warn("No QER-ID"); + *cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + *offending_ie_value = OGS_PFCP_QER_ID_TYPE; + return false; + } + + qer = ogs_pfcp_qer_find(sess, message->qer_id.u32); + if (!qer) { + ogs_error("Unknown QER-ID[%d]", message->qer_id.u32); + *cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + return false; + } + + ogs_pfcp_qer_remove(qer); + + return true; +} + +void upf_n4_handle_session_establishment_request( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_establishment_request_t *req) +{ + ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR]; + int num_of_created_pdr = 0; + uint8_t cause_value = 0; + uint8_t offending_ie_value = 0; + int i; + + ogs_assert(xact); + ogs_assert(req); + + ogs_debug("[UPF] Session Establishment Request"); + + cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_warn("No Context"); + ogs_pfcp_send_error_message(xact, 0, + OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE, + OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0); + return; + } + + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + created_pdr[i] = handle_create_pdr(&sess->pfcp, + &req->create_pdr[i], &cause_value, &offending_ie_value); + if (created_pdr[i] == NULL) + break; + } + num_of_created_pdr = i; + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_FAR; i++) { + if (handle_create_far(&sess->pfcp, &req->create_far[i], + &cause_value, &offending_ie_value) == NULL) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_QER; i++) { + if (handle_create_qer(&sess->pfcp, &req->create_qer[i], + &cause_value, &offending_ie_value) == NULL) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + upf_pfcp_send_session_establishment_response( + xact, sess, created_pdr, num_of_created_pdr); + return; + +cleanup: + ogs_pfcp_sess_clear(&sess->pfcp); + ogs_pfcp_send_error_message(xact, sess ? sess->smf_n4_seid : 0, + OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE, + cause_value, offending_ie_value); +} + +void upf_n4_handle_session_modification_request( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_modification_request_t *req) +{ + ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR]; + int num_of_created_pdr = 0; + uint8_t cause_value = 0; + uint8_t offending_ie_value = 0; + int i; + + ogs_assert(xact); + ogs_assert(req); + + ogs_debug("[UPF] Session Modification Request"); + + cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_warn("No Context"); + ogs_pfcp_send_error_message(xact, 0, + OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE, + OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0); + return; + } + + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + created_pdr[i] = handle_create_pdr(&sess->pfcp, + &req->create_pdr[i], &cause_value, &offending_ie_value); + if (created_pdr[i] == NULL) + break; + } + num_of_created_pdr = i; + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + if (handle_remove_pdr(&sess->pfcp, &req->remove_pdr[i], + &cause_value, &offending_ie_value) == false) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_FAR; i++) { + if (handle_create_far(&sess->pfcp, &req->create_far[i], + &cause_value, &offending_ie_value) == NULL) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + if (handle_remove_far(&sess->pfcp, &req->remove_far[i], + &cause_value, &offending_ie_value) == false) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_QER; i++) { + if (handle_create_qer(&sess->pfcp, &req->create_qer[i], + &cause_value, &offending_ie_value) == NULL) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_QER; i++) { + if (handle_update_qer(&sess->pfcp, &req->update_qer[i], + &cause_value, &offending_ie_value) == NULL) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { + if (handle_remove_qer(&sess->pfcp, &req->remove_qer[i], + &cause_value, &offending_ie_value) == false) + break; + } + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) + goto cleanup; + + upf_pfcp_send_session_modification_response( + xact, sess, created_pdr, num_of_created_pdr); + return; + +cleanup: + ogs_pfcp_sess_clear(&sess->pfcp); + ogs_pfcp_send_error_message(xact, sess ? sess->smf_n4_seid : 0, + OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE, + cause_value, offending_ie_value); +} + +void upf_n4_handle_session_deletion_request( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_deletion_request_t *req) +{ + ogs_assert(xact); + ogs_assert(req); + + ogs_debug("[UPF] Session Deletion Request"); + + if (!sess) { + ogs_warn("No Context"); + ogs_pfcp_send_error_message(xact, 0, + OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE, + OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0); + return; + } + + ogs_assert(sess); + + upf_pfcp_send_session_deletion_response(xact, sess); + + upf_sess_remove(sess); +} diff --git a/src/upf/n4-handler.h b/src/upf/n4-handler.h new file mode 100644 index 000000000..5dd46264e --- /dev/null +++ b/src/upf/n4-handler.h @@ -0,0 +1,56 @@ +/* + * 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 UPF_N4_HANDLER_H +#define UPF_N4_HANDLER_H + +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void upf_n4_handle_association_setup_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_request_t *req); +void upf_n4_handle_association_setup_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_association_setup_response_t *req); +void upf_n4_handle_heartbeat_request( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_request_t *req); +void upf_n4_handle_heartbeat_response( + ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact, + ogs_pfcp_heartbeat_response_t *req); + +void upf_n4_handle_session_establishment_request( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_establishment_request_t *req); +void upf_n4_handle_session_modification_request( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_modification_request_t *req); +void upf_n4_handle_session_deletion_request( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_deletion_request_t *req); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_N4_HANDLER_H */ diff --git a/src/upf/pfcp-path.c b/src/upf/pfcp-path.c new file mode 100644 index 000000000..cb88b6799 --- /dev/null +++ b/src/upf/pfcp-path.c @@ -0,0 +1,301 @@ +/* + * 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 "context.h" + +#include "event.h" +#include "upf-sm.h" + +#include "pfcp-path.h" +#include "n4-build.h" + +static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data) +{ + int rv; + + ssize_t size; + upf_event_t *e = NULL; + ogs_pkbuf_t *pkbuf = NULL; + ogs_sockaddr_t from; + ogs_pfcp_node_t *node = NULL; + ogs_pfcp_header_t *h = NULL; + + ogs_assert(fd != INVALID_SOCKET); + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); + + size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from); + if (size <= 0) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "ogs_recvfrom() failed"); + ogs_pkbuf_free(pkbuf); + return; + } + + ogs_pkbuf_trim(pkbuf, size); + + h = (ogs_pfcp_header_t *)pkbuf->data; + if (h->version > OGS_PFCP_VERSION) { + ogs_pfcp_header_t rsp; + + ogs_error("Not supported version[%d]", h->version); + + memset(&rsp, 0, sizeof rsp); + rsp.flags = (OGS_PFCP_VERSION << 5); + rsp.type = OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE; + rsp.length = htobe16(4); + rsp.sqn_only = h->sqn_only; + ogs_sendto(fd, &rsp, 8, 0, &from); + ogs_pkbuf_free(pkbuf); + + return; + } + + e = upf_event_new(UPF_EVT_N4_MESSAGE); + node = ogs_pfcp_node_find(&ogs_pfcp_self()->n4_list, &from); + if (!node) { + node = ogs_pfcp_node_add(&ogs_pfcp_self()->n4_list, &from); + ogs_assert(node); + node->sock = data; + } + ogs_assert(e); + e->pfcp_node = node; + e->pkbuf = pkbuf; + + rv = ogs_queue_push(upf_self()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + ogs_pkbuf_free(e->pkbuf); + upf_event_free(e); + } +} + +int upf_pfcp_open(void) +{ + ogs_socknode_t *node = NULL; + ogs_sock_t *sock = NULL; + + /* PFCP Server */ + ogs_list_for_each(&ogs_pfcp_self()->pfcp_list, node) { + sock = ogs_pfcp_server(node); + ogs_assert(sock); + + node->poll = ogs_pollset_add(upf_self()->pollset, + OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); + } + ogs_list_for_each(&ogs_pfcp_self()->pfcp_list6, node) { + sock = ogs_pfcp_server(node); + ogs_assert(sock); + + node->poll = ogs_pollset_add(upf_self()->pollset, + OGS_POLLIN, sock->fd, pfcp_recv_cb, sock); + } + + ogs_pfcp_self()->pfcp_sock = + ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list); + if (ogs_pfcp_self()->pfcp_sock) + ogs_pfcp_self()->pfcp_addr = &ogs_pfcp_self()->pfcp_sock->local_addr; + + ogs_pfcp_self()->pfcp_sock6 = + ogs_socknode_sock_first(&ogs_pfcp_self()->pfcp_list6); + if (ogs_pfcp_self()->pfcp_sock6) + ogs_pfcp_self()->pfcp_addr6 = &ogs_pfcp_self()->pfcp_sock6->local_addr; + + ogs_assert(ogs_pfcp_self()->pfcp_addr || ogs_pfcp_self()->pfcp_addr6); + + return OGS_OK; +} + +void upf_pfcp_close(void) +{ + ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list); + ogs_socknode_remove_all(&ogs_pfcp_self()->pfcp_list6); +} + +static void timeout(ogs_pfcp_xact_t *xact, void *data) +{ + int rv; + + upf_event_t *e = NULL; + uint8_t type; + + ogs_assert(xact); + type = xact->seq[0].type; + + switch (type) { + case OGS_PFCP_HEARTBEAT_REQUEST_TYPE: + ogs_assert(data); + + e = upf_event_new(UPF_EVT_N4_NO_HEARTBEAT); + e->pfcp_node = data; + + rv = ogs_queue_push(upf_self()->queue, e); + if (rv != OGS_OK) { + ogs_warn("ogs_queue_push() failed:%d", (int)rv); + upf_event_free(e); + } + break; + default: + break; + } +} + +void upf_pfcp_send_association_setup_request(ogs_pfcp_node_t *node) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(node); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE; + h.seid = 0; + + n4buf = upf_n4_build_association_setup_request(h.type); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create(node, &h, n4buf, timeout, node); + ogs_expect_or_return(xact); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void upf_pfcp_send_association_setup_response(ogs_pfcp_xact_t *xact, + uint8_t cause) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE; + h.seid = 0; + + n4buf = upf_n4_build_association_setup_response(h.type, cause); + ogs_expect_or_return(n4buf); + + rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void upf_pfcp_send_heartbeat_request(ogs_pfcp_node_t *node) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(node); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_HEARTBEAT_REQUEST_TYPE; + h.seid = 0; + + n4buf = ogs_pfcp_n4_build_heartbeat_request(h.type); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create(node, &h, n4buf, timeout, node); + ogs_expect_or_return(xact); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void upf_pfcp_send_session_establishment_response( + ogs_pfcp_xact_t *xact, upf_sess_t *sess, + ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE; + h.seid = sess->smf_n4_seid; + + n4buf = upf_n4_build_session_establishment_response( + h.type, sess, created_pdr, num_of_created_pdr); + ogs_expect_or_return(n4buf); + + rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void upf_pfcp_send_session_modification_response( + ogs_pfcp_xact_t *xact, upf_sess_t *sess, + ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(xact); + ogs_assert(created_pdr); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE; + h.seid = sess->smf_n4_seid; + + n4buf = upf_n4_build_session_modification_response( + h.type, sess, created_pdr, num_of_created_pdr); + ogs_expect_or_return(n4buf); + + rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} + +void upf_pfcp_send_session_deletion_response(ogs_pfcp_xact_t *xact, + upf_sess_t *sess) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE; + h.seid = sess->smf_n4_seid; + + n4buf = upf_n4_build_session_deletion_response(h.type, sess); + ogs_expect_or_return(n4buf); + + rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} diff --git a/src/upf/pfcp-path.h b/src/upf/pfcp-path.h new file mode 100644 index 000000000..8a8016471 --- /dev/null +++ b/src/upf/pfcp-path.h @@ -0,0 +1,50 @@ +/* + * 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 UPF_PFCP_PATH_H +#define UPF_PFCP_PATH_H + +#include "ogs-gtp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int upf_pfcp_open(void); +void upf_pfcp_close(void); + +void upf_pfcp_send_association_setup_request(ogs_pfcp_node_t *node); +void upf_pfcp_send_association_setup_response(ogs_pfcp_xact_t *xact, + uint8_t cause); +void upf_pfcp_send_heartbeat_request(ogs_pfcp_node_t *node); + +void upf_pfcp_send_session_establishment_response( + ogs_pfcp_xact_t *xact, upf_sess_t *sess, + ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr); +void upf_pfcp_send_session_modification_response( + ogs_pfcp_xact_t *xact, upf_sess_t *sess, + ogs_pfcp_pdr_t *created_pdr[], int num_of_created_pdr); +void upf_pfcp_send_session_deletion_response(ogs_pfcp_xact_t *xact, + upf_sess_t *sess); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_PFCP_PATH_H */ diff --git a/src/upf/pfcp-sm.c b/src/upf/pfcp-sm.c new file mode 100644 index 000000000..d10df0e93 --- /dev/null +++ b/src/upf/pfcp-sm.c @@ -0,0 +1,273 @@ +/* + * 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 "context.h" +#include "event.h" +#include "timer.h" +#include "upf-sm.h" + +#include "pfcp-path.h" +#include "n4-handler.h" + +void upf_pfcp_state_initial(ogs_fsm_t *s, upf_event_t *e) +{ + int rv; + ogs_pfcp_node_t *node = NULL; + + ogs_assert(s); + ogs_assert(e); + + upf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + + rv = ogs_pfcp_connect( + ogs_pfcp_self()->pfcp_sock, ogs_pfcp_self()->pfcp_sock6, node); + ogs_assert(rv == OGS_OK); + + node->t_association = ogs_timer_add(upf_self()->timer_mgr, + upf_timer_association, node); + ogs_assert(node->t_association); + node->t_heartbeat = ogs_timer_add(upf_self()->timer_mgr, + upf_timer_heartbeat, node); + ogs_assert(node->t_heartbeat); + + OGS_FSM_TRAN(s, &upf_pfcp_state_will_associate); +} + +void upf_pfcp_state_final(ogs_fsm_t *s, upf_event_t *e) +{ + ogs_pfcp_node_t *node = NULL; + ogs_assert(s); + ogs_assert(e); + + upf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + + ogs_timer_delete(node->t_association); + ogs_timer_delete(node->t_heartbeat); +} + +void upf_pfcp_state_will_associate(ogs_fsm_t *s, upf_event_t *e) +{ + char buf[OGS_ADDRSTRLEN]; + + ogs_pfcp_node_t *node = NULL; + ogs_pfcp_xact_t *xact = NULL; + ogs_pfcp_message_t *message = NULL; + ogs_sockaddr_t *addr = NULL; + ogs_assert(s); + ogs_assert(e); + + upf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + ogs_timer_start(node->t_association, + upf_timer_cfg(UPF_TIMER_ASSOCIATION)->duration); + + upf_pfcp_send_association_setup_request(node); + break; + case OGS_FSM_EXIT_SIG: + ogs_timer_stop(node->t_association); + break; + case UPF_EVT_N4_TIMER: + switch(e->timer_id) { + case UPF_TIMER_ASSOCIATION: + addr = node->sa_list; + ogs_assert(addr); + + ogs_warn("Retry to association with peer [%s]:%d failed", + OGS_ADDR(addr, buf), OGS_PORT(addr)); + + ogs_timer_start(node->t_association, + upf_timer_cfg(UPF_TIMER_ASSOCIATION)->duration); + + upf_pfcp_send_association_setup_request(node); + break; + default: + ogs_error("Unknown timer[%s:%d]", + upf_timer_get_name(e->timer_id), e->timer_id); + break; + } + break; + case UPF_EVT_N4_MESSAGE: + message = e->pfcp_message; + ogs_assert(message); + xact = e->pfcp_xact; + ogs_assert(xact); + + switch (message->h.type) { + case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: + upf_n4_handle_association_setup_request(node, xact, + &message->pfcp_association_setup_request); + OGS_FSM_TRAN(s, upf_pfcp_state_associated); + break; + case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE: + upf_n4_handle_association_setup_response(node, xact, + &message->pfcp_association_setup_response); + OGS_FSM_TRAN(s, upf_pfcp_state_associated); + break; + default: + ogs_error("cannot handle PFCP message type[%d]", + message->h.type); + break; + } + break; + default: + ogs_error("Unknown event %s", upf_event_get_name(e)); + break; + } +} + +void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e) +{ + char buf[OGS_ADDRSTRLEN]; + + ogs_pfcp_node_t *node = NULL; + ogs_pfcp_xact_t *xact = NULL; + ogs_pfcp_message_t *message = NULL; + + ogs_sockaddr_t *addr = NULL; + upf_sess_t *sess = NULL; + + ogs_assert(s); + ogs_assert(e); + + upf_sm_debug(e); + + node = e->pfcp_node; + ogs_assert(node); + addr = node->sa_list; + ogs_assert(addr); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + ogs_info("PFCP associated"); + ogs_timer_start(node->t_heartbeat, + upf_timer_cfg(UPF_TIMER_HEARTBEAT)->duration); + break; + case OGS_FSM_EXIT_SIG: + ogs_info("PFCP de-associated"); + ogs_timer_stop(node->t_heartbeat); + break; + case UPF_EVT_N4_MESSAGE: + message = e->pfcp_message; + ogs_assert(message); + xact = e->pfcp_xact; + ogs_assert(xact); + + xact = e->pfcp_xact; + ogs_assert(xact); + + if (message->h.seid_presence && message->h.seid != 0) + sess = upf_sess_find_by_up_seid(message->h.seid); + + switch (message->h.type) { + case OGS_PFCP_HEARTBEAT_REQUEST_TYPE: + upf_n4_handle_heartbeat_request(node, xact, + &message->pfcp_heartbeat_request); + break; + case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE: + upf_n4_handle_heartbeat_response(node, xact, + &message->pfcp_heartbeat_response); + break; + case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: + ogs_warn("PFCP[REQ] has already been associated"); + upf_n4_handle_association_setup_request(node, xact, + &message->pfcp_association_setup_request); + break; + case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE: + ogs_warn("PFCP[RSP] has already been associated"); + upf_n4_handle_association_setup_response(node, xact, + &message->pfcp_association_setup_response); + break; + case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE: + if (message->h.seid_presence && message->h.seid == 0) { + ogs_expect(!sess); + sess = upf_sess_add_by_message(message); + if (sess) + OGS_SETUP_PFCP_NODE(sess, node); + } + upf_n4_handle_session_establishment_request( + sess, xact, &message->pfcp_session_establishment_request); + break; + case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE: + upf_n4_handle_session_modification_request( + sess, xact, &message->pfcp_session_modification_request); + break; + case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE: + upf_n4_handle_session_deletion_request( + sess, xact, &message->pfcp_session_deletion_request); + break; + default: + ogs_error("Not implemented PFCP message type[%d]", + message->h.type); + break; + } + + break; + case UPF_EVT_N4_TIMER: + switch(e->timer_id) { + case UPF_TIMER_HEARTBEAT: + node = e->pfcp_node; + ogs_assert(node); + + upf_pfcp_send_heartbeat_request(node); + break; + default: + ogs_error("Unknown timer[%s:%d]", + upf_timer_get_name(e->timer_id), e->timer_id); + break; + } + break; + case UPF_EVT_N4_NO_HEARTBEAT: + ogs_warn("No Heartbeat from UPF [%s]:%d", + OGS_ADDR(addr, buf), OGS_PORT(addr)); + OGS_FSM_TRAN(s, upf_pfcp_state_will_associate); + break; + default: + ogs_error("Unknown event %s", upf_event_get_name(e)); + break; + } +} + +void upf_pfcp_state_exception(ogs_fsm_t *s, upf_event_t *e) +{ + ogs_assert(s); + ogs_assert(e); + + upf_sm_debug(e); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + break; + case OGS_FSM_EXIT_SIG: + break; + default: + ogs_error("Unknown event %s", upf_event_get_name(e)); + break; + } +} diff --git a/src/upf/rule-match.c b/src/upf/rule-match.c new file mode 100644 index 000000000..7ba1f2570 --- /dev/null +++ b/src/upf/rule-match.c @@ -0,0 +1,320 @@ +/* + * 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 . + */ + +#define _DEFAULT_SOURCE 1 +#define _BSD_SOURCE 1 + +#include +#include +#include +#include +#include + +#include "rule-match.h" + +static int decode_ipv6_header( + struct ip6_hdr *ip6_h, uint8_t *proto, uint16_t *hlen) +{ + int done = 0; + uint8_t *p, *jp, *endp; + uint8_t nxt; /* Next Header */ + + ogs_assert(ip6_h); + ogs_assert(proto); + ogs_assert(hlen); + + nxt = ip6_h->ip6_nxt; + p = (uint8_t *)ip6_h + sizeof(*ip6_h); + endp = p + be16toh(ip6_h->ip6_plen); + + jp = p + sizeof(struct ip6_hbh); + while (p == endp) { /* Jumbo Frame */ + uint32_t jp_len = 0; + struct ip6_opt_jumbo *jumbo = NULL; + + ogs_assert(nxt == 0); + + jumbo = (struct ip6_opt_jumbo *)jp; + memcpy(&jp_len, jumbo->ip6oj_jumbo_len, sizeof(jp_len)); + jp_len = be32toh(jp_len); + switch (jumbo->ip6oj_type) { + case IP6OPT_JUMBO: + endp = p + jp_len; + break; + case 0: + jp++; + break; + default: + jp += (sizeof(struct ip6_opt) + jp_len); + break; + } + } + + while (p < endp) { + struct ip6_ext *ext = (struct ip6_ext *)p; + switch (nxt) { + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: + case 135: /* mobility */ + case 139: /* host identity, experimental */ + case 140: /* shim6 */ + case 253: /* testing, experimental */ + case 254: /* testing, experimental */ + p += ((ext->ip6e_len << 3) + 8); + break; + case IPPROTO_FRAGMENT: + p += sizeof(struct ip6_frag); + break; + case IPPROTO_AH: + p += ((ext->ip6e_len + 2) << 2); + break; + default: /* Upper Layer */ + done = 1; + break; + + } + if (done) + break; + + nxt = ext->ip6e_nxt; + } + + *proto = nxt; + *hlen = p - (uint8_t *)ip6_h; + + return OGS_OK; +} + +ogs_pfcp_pdr_t *upf_pdr_find_by_packet(ogs_pkbuf_t *pkt) +{ + struct ip *ip_h = NULL; + struct ip6_hdr *ip6_h = NULL; + uint32_t *src_addr = NULL; + uint32_t *dst_addr = NULL; + int addr_len = 0; + uint8_t proto = 0; + uint16_t ip_hlen = 0; + char buf[OGS_ADDRSTRLEN]; + upf_sess_t *sess = NULL; + + ogs_assert(pkt); + ogs_assert(pkt->len); + + ip_h = (struct ip *)pkt->data; + if (ip_h->ip_v == 4) { + ip_h = (struct ip *)pkt->data; + ip6_h = NULL; + + proto = ip_h->ip_p; + ip_hlen = (ip_h->ip_hl)*4; + + src_addr = &ip_h->ip_src.s_addr; + dst_addr = &ip_h->ip_dst.s_addr; + addr_len = OGS_IPV4_LEN; + + sess = upf_sess_find_by_ipv4(dst_addr[0]); + } else if (ip_h->ip_v == 6) { + ip_h = NULL; + ip6_h = (struct ip6_hdr *)pkt->data; + + decode_ipv6_header(ip6_h, &proto, &ip_hlen); + + src_addr = (uint32_t *)ip6_h->ip6_src.s6_addr; + dst_addr = (uint32_t *)ip6_h->ip6_dst.s6_addr; + addr_len = OGS_IPV6_LEN; + + sess = upf_sess_find_by_ipv6(dst_addr); + } else + ogs_error("Invalid IP version = %d", ip_h->ip_v); + + ogs_debug("[UPF] PROTO:%d SRC:%08x %08x %08x %08x", + proto, be32toh(src_addr[0]), be32toh(src_addr[1]), + be32toh(src_addr[2]), be32toh(src_addr[3])); + ogs_debug("[UPF] HLEN:%d DST:%08x %08x %08x %08x", + ip_hlen, be32toh(dst_addr[0]), be32toh(dst_addr[1]), + be32toh(dst_addr[2]), be32toh(dst_addr[3])); + + + if (sess) { + ogs_pfcp_pdr_t *default_pdr = NULL; + upf_sdf_filter_t *sdf_filter = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pfcp_far_t *far = NULL; + + if (ip_h && sess->ipv4) + ogs_debug("[UPF] PAA IPv4:%s", + INET_NTOP(&sess->ipv4->addr, buf)); + if (ip6_h && sess->ipv6) + ogs_debug("[UPF] PAA IPv6:%s", + INET6_NTOP(&sess->ipv6->addr, buf)); + + /* Save the default PDR */ + default_pdr = ogs_pfcp_sess_default_pdr(&sess->pfcp); + ogs_assert(default_pdr); + + /* Found */ + ogs_debug("[UPF] Found Session : Default PDR-ID[%d]", default_pdr->id); + + ogs_list_for_each(&sess->sdf_filter_list, sdf_filter) { + int k; + uint32_t src_mask[4]; + uint32_t dst_mask[4]; + ogs_ipfw_rule_t *rule = NULL; + + pdr = sdf_filter->pdr; + ogs_assert(pdr); + far = pdr->far; + ogs_assert(far); + rule = &sdf_filter->rule; + ogs_assert(rule); + + /* Skip if PDR is default */ + if (pdr->id == default_pdr->id) + continue; + + /* Check if PDR is Downlink */ + if (pdr->src_if != OGS_PFCP_INTERFACE_CORE) + continue; + + /* Check if FAR is Downlink */ + if (far->dst_if != OGS_PFCP_INTERFACE_ACCESS) + continue; + + /* Check if Create Bearer Response is received */ + if (far->outer_header_creation.teid == 0) + continue; + + ogs_debug("PROTO:%d SRC:%d-%d DST:%d-%d", + rule->proto, + rule->port.local.low, + rule->port.local.high, + rule->port.remote.low, + rule->port.remote.high); + ogs_debug("SRC:%08x %08x %08x %08x/%08x %08x %08x %08x", + be32toh(rule->ip.local.addr[0]), + be32toh(rule->ip.local.addr[1]), + be32toh(rule->ip.local.addr[2]), + be32toh(rule->ip.local.addr[3]), + be32toh(rule->ip.local.mask[0]), + be32toh(rule->ip.local.mask[1]), + be32toh(rule->ip.local.mask[2]), + be32toh(rule->ip.local.mask[3])); + ogs_debug("DST:%08x %08x %08x %08x/%08x %08x %08x %08x", + be32toh(rule->ip.remote.addr[0]), + be32toh(rule->ip.remote.addr[1]), + be32toh(rule->ip.remote.addr[2]), + be32toh(rule->ip.remote.addr[3]), + be32toh(rule->ip.remote.mask[0]), + be32toh(rule->ip.remote.mask[1]), + be32toh(rule->ip.remote.mask[2]), + be32toh(rule->ip.remote.mask[3])); + + for (k = 0; k < 4; k++) { + src_mask[k] = src_addr[k] & rule->ip.local.mask[k]; + dst_mask[k] = dst_addr[k] & rule->ip.remote.mask[k]; + } + + if (memcmp(src_mask, rule->ip.local.addr, addr_len) == 0 && + memcmp(dst_mask, rule->ip.remote.addr, addr_len) == 0) { + /* Protocol match */ + if (rule->proto == 0) { /* IP */ + /* No need to match port */ + break; + } + + if (rule->proto == proto) { + if (rule->proto == IPPROTO_TCP) { + struct tcphdr *tcph = + (struct tcphdr *)((char *)pkt->data + ip_hlen); + + /* Source port */ + if (rule->port.local.low && + be16toh(tcph->th_sport) < rule->port.local.low) { + continue; + } + + if (rule->port.local.high && + be16toh(tcph->th_sport) > rule->port.local.high) { + continue; + } + + /* Dst Port*/ + if (rule->port.remote.low && + be16toh(tcph->th_dport) < rule->port.remote.low) { + continue; + } + + if (rule->port.remote.high && + be16toh(tcph->th_dport) > + rule->port.remote.high) { + continue; + } + + /* Matched */ + break; + } else if (rule->proto == IPPROTO_UDP) { + struct udphdr *udph = + (struct udphdr *)((char *)pkt->data + ip_hlen); + + /* Source port */ + if (rule->port.local.low && + be16toh(udph->uh_sport) < rule->port.local.low) { + continue; + } + + if (rule->port.local.high && + be16toh(udph->uh_sport) > rule->port.local.high) { + continue; + } + + /* Dst Port*/ + if (rule->port.remote.low && + be16toh(udph->uh_dport) < rule->port.remote.low) { + continue; + } + + if (rule->port.remote.high && + be16toh(udph->uh_dport) > + rule->port.remote.high) { + continue; + } + + /* Matched */ + break; + } else { + /* No need to match port */ + break; + } + } + } + } + + if (sdf_filter) { + ogs_debug("Found Dedicated PDR : PDR ID[%d]", pdr->id); + return pdr; + } + + return default_pdr; + } else { + ogs_debug("[UPF] No Session"); + } + + return NULL; +} diff --git a/src/upf/rule-match.h b/src/upf/rule-match.h new file mode 100644 index 000000000..639784f9f --- /dev/null +++ b/src/upf/rule-match.h @@ -0,0 +1,35 @@ +/* + * 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 UPF_RULE_MATCH_H +#define UPF_RULE_MATCH_H + +#include "context.h" + +#ifdef __cplusplus +extern "C" { +#endif + +ogs_pfcp_pdr_t *upf_pdr_find_by_packet(ogs_pkbuf_t *pkt); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_RULE_MATCH_H */ diff --git a/src/upf/timer.c b/src/upf/timer.c new file mode 100644 index 000000000..0ef7f946c --- /dev/null +++ b/src/upf/timer.c @@ -0,0 +1,76 @@ +/* + * 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 "timer.h" +#include "event.h" +#include "context.h" + +static upf_timer_cfg_t g_upf_timer_cfg[MAX_NUM_OF_UPF_TIMER] = { + [UPF_TIMER_ASSOCIATION] = + { .duration = ogs_time_from_sec(12) }, + [UPF_TIMER_HEARTBEAT] = + { .duration = ogs_time_from_sec(12) }, +}; + +upf_timer_cfg_t *upf_timer_cfg(upf_timer_e id) +{ + ogs_assert(id < MAX_NUM_OF_UPF_TIMER); + return &g_upf_timer_cfg[id]; +} + +const char *upf_timer_get_name(upf_timer_e id) +{ + switch (id) { + case UPF_TIMER_ASSOCIATION: + return "UPF_TIMER_ASSOCIATION"; + case UPF_TIMER_HEARTBEAT: + return "UPF_TIMER_HEARTBEAT"; + default: + break; + } + + return "UNKNOWN_TIMER"; +} + +static void timer_send_event(int timer_id, void *data) +{ + int rv; + upf_event_t *e = NULL; + ogs_assert(data); + + e = upf_event_new(UPF_EVT_N4_TIMER); + e->timer_id = timer_id; + e->pfcp_node = data; + + rv = ogs_queue_push(upf_self()->queue, e); + if (rv != OGS_OK) { + ogs_warn("ogs_queue_push() failed:%d", (int)rv); + upf_event_free(e); + } +} + +void upf_timer_association(void *data) +{ + timer_send_event(UPF_TIMER_ASSOCIATION, data); +} + +void upf_timer_heartbeat(void *data) +{ + timer_send_event(UPF_TIMER_HEARTBEAT, data); +} diff --git a/src/upf/timer.h b/src/upf/timer.h new file mode 100644 index 000000000..b865f0b1b --- /dev/null +++ b/src/upf/timer.h @@ -0,0 +1,56 @@ +/* + * 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 UPF_TIMER_H +#define UPF_TIMER_H + +#include "ogs-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* forward declaration */ +typedef enum { + UPF_TIMER_BASE = 0, + + UPF_TIMER_ASSOCIATION, + UPF_TIMER_HEARTBEAT, + + MAX_NUM_OF_UPF_TIMER, + +} upf_timer_e; + +typedef struct upf_timer_cfg_s { + int max_count; + ogs_time_t duration; +} upf_timer_cfg_t; + +upf_timer_cfg_t *upf_timer_cfg(upf_timer_e id); + +const char *upf_timer_get_name(upf_timer_e id); + +void upf_timer_association(void *data); +void upf_timer_heartbeat(void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_TIMER_H */ diff --git a/src/upf/upf-sm.c b/src/upf/upf-sm.c new file mode 100644 index 000000000..d589dc044 --- /dev/null +++ b/src/upf/upf-sm.c @@ -0,0 +1,128 @@ +/* + * 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 "upf-sm.h" +#include "context.h" +#include "event.h" +#include "pfcp-path.h" +#include "gtp-path.h" + +void upf_state_initial(ogs_fsm_t *s, upf_event_t *e) +{ + upf_sm_debug(e); + + ogs_assert(s); + + OGS_FSM_TRAN(s, &upf_state_operational); +} + +void upf_state_final(ogs_fsm_t *s, upf_event_t *e) +{ + upf_sm_debug(e); + + ogs_assert(s); +} + +void upf_state_operational(ogs_fsm_t *s, upf_event_t *e) +{ + int rv; + ogs_pkbuf_t *recvbuf = NULL; + + ogs_pfcp_message_t pfcp_message; + ogs_pfcp_node_t *node = NULL; + ogs_pfcp_xact_t *xact = NULL; + + upf_sm_debug(e); + + ogs_assert(s); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + rv = upf_pfcp_open(); + if (rv != OGS_OK) { + ogs_fatal("Can't establish N4-PFCP path"); + } + rv = upf_gtp_open(); + if (rv != OGS_OK) { + ogs_fatal("Can't establish GTP-U path"); + } + + ogs_list_for_each(&ogs_pfcp_self()->n4_list, node) { + upf_event_t e; + e.pfcp_node = node; + + ogs_fsm_create(&node->sm, + upf_pfcp_state_initial, upf_pfcp_state_final); + ogs_fsm_init(&node->sm, &e); + } + break; + case OGS_FSM_EXIT_SIG: + ogs_list_for_each(&ogs_pfcp_self()->n4_list, node) { + upf_event_t e; + e.pfcp_node = node; + + ogs_fsm_fini(&node->sm, &e); + ogs_fsm_delete(&node->sm); + } + + upf_pfcp_close(); + upf_gtp_close(); + break; + case UPF_EVT_N4_MESSAGE: + ogs_assert(e); + recvbuf = e->pkbuf; + ogs_assert(recvbuf); + node = e->pfcp_node; + ogs_assert(node); + + if (ogs_pfcp_parse_msg(&pfcp_message, recvbuf) != OGS_OK) { + ogs_error("ogs_pfcp_parse_msg() failed"); + ogs_pkbuf_free(recvbuf); + break; + } + + rv = ogs_pfcp_xact_receive(node, &pfcp_message.h, &xact); + if (rv != OGS_OK) { + ogs_pkbuf_free(recvbuf); + break; + } + + e->pfcp_message = &pfcp_message; + e->pfcp_xact = xact; + ogs_fsm_dispatch(&node->sm, e); + if (OGS_FSM_CHECK(&node->sm, upf_pfcp_state_exception)) { + ogs_error("PFCP state machine exception"); + break; + } + + ogs_pkbuf_free(recvbuf); + break; + case UPF_EVT_N4_TIMER: + case UPF_EVT_N4_NO_HEARTBEAT: + node = e->pfcp_node; + ogs_assert(node); + ogs_assert(OGS_FSM_STATE(&node->sm)); + + ogs_fsm_dispatch(&node->sm, e); + break; + default: + ogs_error("No handler for event %s", upf_event_get_name(e)); + break; + } +} diff --git a/src/upf/upf-sm.h b/src/upf/upf-sm.h new file mode 100644 index 000000000..18b68b04b --- /dev/null +++ b/src/upf/upf-sm.h @@ -0,0 +1,47 @@ +/* + * 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 UPF_SM_H +#define UPF_SM_H + +#include "event.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void upf_state_initial(ogs_fsm_t *s, upf_event_t *e); +void upf_state_final(ogs_fsm_t *s, upf_event_t *e); +void upf_state_operational(ogs_fsm_t *s, upf_event_t *e); +void upf_state_exception(ogs_fsm_t *s, upf_event_t *e); + +void upf_pfcp_state_initial(ogs_fsm_t *s, upf_event_t *e); +void upf_pfcp_state_final(ogs_fsm_t *s, upf_event_t *e); +void upf_pfcp_state_will_associate(ogs_fsm_t *s, upf_event_t *e); +void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e); +void upf_pfcp_state_exception(ogs_fsm_t *s, upf_event_t *e); + +#define upf_sm_debug(__pe) \ + ogs_debug("%s(): %s", __func__, upf_event_get_name(__pe)) + +#ifdef __cplusplus +} +#endif + +#endif /* UPF_SM_H */ diff --git a/tests/app/test-packet.c b/tests/app/test-packet.c index 8ef42a82e..0783e515b 100644 --- a/tests/app/test-packet.c +++ b/tests/app/test-packet.c @@ -160,6 +160,8 @@ ogs_pkbuf_t *testenb_gtpu_read(ogs_socknode_t *node) return recvbuf; } +bool test_no_mme_self = 0; + int testenb_gtpu_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf) { int rv; @@ -174,28 +176,33 @@ int testenb_gtpu_send(ogs_socknode_t *node, ogs_pkbuf_t *sendbuf) ogs_assert(node); ogs_assert(node->sock); - mme_ue = ogs_list_first(&mme_self()->mme_ue_list); - ogs_assert(mme_ue); - sess = mme_sess_first(mme_ue); - ogs_assert(sess); - bearer = mme_bearer_first(sess); - ogs_assert(bearer); - memset(&sgw, 0, sizeof(ogs_sockaddr_t)); sgw.ogs_sin_port = htons(OGS_GTPV1_U_UDP_PORT); - if (bearer->sgw_s1u_ip.ipv6) { - sgw.ogs_sa_family = AF_INET6; - if (bearer->sgw_s1u_ip.ipv4) - memcpy(sgw.sin6.sin6_addr.s6_addr, - bearer->sgw_s1u_ip.both.addr6, OGS_IPV6_LEN); - else - memcpy(sgw.sin6.sin6_addr.s6_addr, - bearer->sgw_s1u_ip.addr6, OGS_IPV6_LEN); - rv = ogs_socknode_fill_scope_id_in_local(&sgw); - ogs_assert(rv == OGS_OK); - } else { + if (test_no_mme_self) { sgw.ogs_sa_family = AF_INET; - sgw.sin.sin_addr.s_addr = bearer->sgw_s1u_ip.addr; + sgw.sin.sin_addr.s_addr = inet_addr("127.0.0.2"); + } else { + mme_ue = ogs_list_first(&mme_self()->mme_ue_list); + ogs_assert(mme_ue); + sess = mme_sess_first(mme_ue); + ogs_assert(sess); + bearer = mme_bearer_first(sess); + ogs_assert(bearer); + + if (bearer->sgw_s1u_ip.ipv6) { + sgw.ogs_sa_family = AF_INET6; + if (bearer->sgw_s1u_ip.ipv4) + memcpy(sgw.sin6.sin6_addr.s6_addr, + bearer->sgw_s1u_ip.both.addr6, OGS_IPV6_LEN); + else + memcpy(sgw.sin6.sin6_addr.s6_addr, + bearer->sgw_s1u_ip.addr6, OGS_IPV6_LEN); + rv = ogs_socknode_fill_scope_id_in_local(&sgw); + ogs_assert(rv == OGS_OK); + } else { + sgw.ogs_sa_family = AF_INET; + sgw.sin.sin_addr.s_addr = bearer->sgw_s1u_ip.addr; + } } sent = ogs_sendto(node->sock->fd, sendbuf->data, sendbuf->len, 0, &sgw); @@ -3519,8 +3526,8 @@ int tests1ap_build_uplink_nas_transport(ogs_pkbuf_t **pkbuf, int i) uint16_t in_cksum(uint16_t *addr, int len); /* from pgw_gtp_path.c */ -int testgtpu_build_ping( - ogs_pkbuf_t **sendbuf, const char *src_ip, const char *dst_ip) +int testgtpu_build_ping(ogs_pkbuf_t **sendbuf, + const uint32_t teid, const char *src_ip, const char *dst_ip) { int rv; ogs_pkbuf_t *pkbuf = NULL; @@ -3542,7 +3549,7 @@ int testgtpu_build_ping( gtp_h = (ogs_gtp_header_t *)pkbuf->data; gtp_h->flags = 0x30; gtp_h->type = OGS_GTPU_MSGTYPE_GPDU; - gtp_h->teid = htonl(1); + gtp_h->teid = htonl(teid); if (dst_ipsub.family == AF_INET) { struct ip *ip_h = NULL; diff --git a/tests/app/test-packet.h b/tests/app/test-packet.h index 7bc215993..39f04e3bb 100644 --- a/tests/app/test-packet.h +++ b/tests/app/test-packet.h @@ -28,6 +28,8 @@ extern "C" { #endif +extern bool test_no_mme_self; + ogs_socknode_t *testsctp_server(const char *ipstr); ogs_socknode_t *testsctp_client(const char *ipstr); ogs_pkbuf_t *testsctp_read(ogs_socknode_t *node, int type); @@ -144,7 +146,7 @@ int tests1ap_build_s1_reset(ogs_pkbuf_t **pkbuf, int i); int tests1ap_build_uplink_nas_transport(ogs_pkbuf_t **pkbuf, int i); int testgtpu_build_ping(ogs_pkbuf_t **sendbuf, - const char *src_ip, const char *dst_ip); + const uint32_t teid, const char *src_ip, const char *dst_ip); int testgtpu_build_slacc_rs(ogs_pkbuf_t **sendbuf, int i); int testsgsap_location_update_accept(ogs_pkbuf_t **pkbuf, int i); diff --git a/tests/core/list-test.c b/tests/core/list-test.c index c80fb2281..a97f721b9 100644 --- a/tests/core/list-test.c +++ b/tests/core/list-test.c @@ -25,11 +25,21 @@ typedef struct { int m1; } lt_type1; +int lttype1_compare(lt_type1 *pnode1, lt_type1 *pnode2) +{ + if (pnode1->m1 == pnode2->m1) + return 0; + else if (pnode1->m1 < pnode2->m1) + return -1; + else + return 1; +} + #define SIZE_OF_lt_type1 16 static OGS_LIST(tlist1); -static void test_basic(abts_case *tc, void *data) +static void list_test1(abts_case *tc, void *data) { int i; lt_type1 *iter, *tmp, node[SIZE_OF_lt_type1]; @@ -37,7 +47,6 @@ static void test_basic(abts_case *tc, void *data) for (i = 0; i < SIZE_OF_lt_type1; i++) node[i].m1 = i; - ogs_list_init(&tlist1); ABTS_TRUE(tc, ogs_list_empty(&tlist1)); ABTS_INT_EQUAL(tc, 0, ogs_list_count(&tlist1)); @@ -67,11 +76,254 @@ static void test_basic(abts_case *tc, void *data) ABTS_TRUE(tc, ogs_list_empty(&tlist1)); } +static void list_test2(abts_case *tc, void *data) +{ + int i; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + /* Initialize head of list */ + ogs_list_init(&tlist1); + + /* Check list is empty */ + ABTS_TRUE(tc, ogs_list_empty(&tlist1)); + + /* Confirm that any node can't be get */ + iter = ogs_list_first(&tlist1); + ABTS_PTR_EQUAL(tc, NULL, iter); + + /* Add a node */ + ogs_list_prepend(&tlist1, &node[0]); + + /* Iterate from the first. And check the pointers */ + iter = ogs_list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); + + /* Iterate from the last. And check the pointers */ + iter = ogs_list_last(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_prev(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); + + /* Add two nodes */ + ogs_list_prepend(&tlist1, &node[1]); + ogs_list_prepend(&tlist1, &node[2]); + + /* Iterate from the first. And check the pointers */ + iter = ogs_list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); + + /* Iterate from the last. And check the pointers */ + iter = ogs_list_last(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_prev(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = ogs_list_prev(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = ogs_list_prev(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); + + /* Remove all nodes */ + ogs_list_remove(&tlist1, &node[2]); + ogs_list_remove(&tlist1, &node[1]); + ogs_list_remove(&tlist1, &node[0]); + + /* Check list is empty */ + ABTS_TRUE(tc, ogs_list_empty(&tlist1)); +} + +static void list_test3(abts_case *tc, void *data) +{ + int i; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + /* Initialize head of list */ + ogs_list_init(&tlist1); + + /* Add three nodes */ + for (i = 0; i < 3; i++) + ogs_list_add(&tlist1, &node[i]); + + /* Iterate from the first. And check the pointers */ + i = 0; iter = ogs_list_first(&tlist1); + while (iter) { + ABTS_PTR_EQUAL(tc, &node[i++], iter); + iter = ogs_list_next(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Iterate from the last. And check the pointers */ + i = 0; iter = ogs_list_last(&tlist1); + while (iter) { + ABTS_PTR_EQUAL(tc, &node[3 - (++i)], iter); + iter = ogs_list_prev(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Insert three nodes by ogs_list_insert_prev() */ + ogs_list_insert_prev(&tlist1, &node[0], &node[3]); + ogs_list_insert_prev(&tlist1, &node[1], &node[4]); + ogs_list_insert_prev(&tlist1, &node[2], &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = ogs_list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[3], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[4], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[5], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); + + /* Remove three nodes inserted by ogs_list_insert_prev() */ + ogs_list_remove(&tlist1, &node[3]); + ogs_list_remove(&tlist1, &node[4]); + ogs_list_remove(&tlist1, &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = ogs_list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); +} + +static void list_test4(abts_case *tc, void *data) +{ + int i; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + /* Initialize head of list */ + ogs_list_init(&tlist1); + + /* Add three nodes */ + for (i = 0; i < 3; i++) + ogs_list_add(&tlist1, &node[i]); + + /* Iterate from the first. And check the pointers */ + i = 0; iter = ogs_list_first(&tlist1); + while (iter) { + ABTS_PTR_EQUAL(tc, &node[i++], iter); + iter = ogs_list_next(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Iterate from the last. And check the pointers */ + i = 0; iter = ogs_list_last(&tlist1); + while (iter) { + ABTS_PTR_EQUAL(tc, &node[3 - (++i)], iter); + iter = ogs_list_prev(iter); + } + ABTS_INT_EQUAL(tc, 3, i); + + /* Insert three nodes by ogs_list_insert_next() */ + ogs_list_insert_next(&tlist1, &node[0], &node[3]); + ogs_list_insert_next(&tlist1, &node[1], &node[4]); + ogs_list_insert_next(&tlist1, &node[2], &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = ogs_list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[3], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[4], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[5], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); + + /* Remove three nodes inserted by ogs_list_insert_next() */ + ogs_list_remove(&tlist1, &node[3]); + ogs_list_remove(&tlist1, &node[4]); + ogs_list_remove(&tlist1, &node[5]); + + /* Iterate from the first. And check the pointers */ + iter = ogs_list_first(&tlist1); + ABTS_PTR_EQUAL(tc, &node[0], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[1], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, &node[2], iter); + iter = ogs_list_next(iter); + ABTS_PTR_EQUAL(tc, NULL, iter); +} + +static void list_test5(abts_case *tc, void *data) +{ + int i, j; + + /* List up posssible oders with four nodes */ + int od[24][4] = { + {0,1,2,3}, {0,1,3,2}, {0,2,1,3}, {0,2,3,1}, {0,3,1,2}, {0,3,2,1}, + {1,0,2,3}, {1,0,3,2}, {1,2,0,3}, {1,2,3,0}, {1,3,0,2}, {1,3,2,0}, + {2,1,0,3}, {2,1,3,0}, {2,0,1,3}, {2,0,3,1}, {2,3,1,0}, {2,3,0,1}, + {3,1,2,0}, {3,1,0,2}, {3,2,1,0}, {3,2,0,1}, {3,0,1,2}, {3,0,2,1} + }; + + lt_type1 *iter, node[SIZE_OF_lt_type1]; + + for (i = 0; i < SIZE_OF_lt_type1; i++) + node[i].m1 = i; + + for (i = 0; i < 24; i++) { + /* Initialize head of list */ + ogs_list_init(&tlist1); + + /* Add four nodes using predefined orders */ + for (j = 0; j < 4; j++) + ogs_list_insert_sorted(&tlist1, &node[od[i][j]], <type1_compare); + + /* Iterate from the first. And check the SORTED */ + j = 0; iter = ogs_list_first(&tlist1); + while (iter) { + ABTS_INT_EQUAL(tc, iter->m1, j++); + iter = ogs_list_next(iter); + } + } +} + abts_suite *test_list(abts_suite *suite) { suite = ADD_SUITE(suite) - abts_run_test(suite, test_basic, NULL); + abts_run_test(suite, list_test1, NULL); + abts_run_test(suite, list_test2, NULL); + abts_run_test(suite, list_test3, NULL); + abts_run_test(suite, list_test4, NULL); + abts_run_test(suite, list_test5, NULL); return suite; } diff --git a/tests/cups/abts-main.c b/tests/cups/abts-main.c new file mode 100644 index 000000000..adafb3cc3 --- /dev/null +++ b/tests/cups/abts-main.c @@ -0,0 +1,96 @@ +/* + * 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 "pcscf-fd-path.h" + +abts_suite *test_cups(abts_suite *suite); + +const struct testlist { + abts_suite *(*func)(abts_suite *suite); +} alltests[] = { + {test_cups}, + {NULL}, +}; + +static ogs_thread_t *pcrf_thread = NULL; +static ogs_thread_t *upf_thread = NULL; +static ogs_thread_t *smf_thread = NULL; +static ogs_thread_t *sgw_thread = NULL; +static ogs_thread_t *hss_thread = NULL; +static ogs_thread_t *mme_thread = NULL; + +static void terminate(void) +{ + ogs_msleep(50); + + test_child_terminate(); + + if (mme_thread) ogs_thread_destroy(mme_thread); + if (hss_thread) ogs_thread_destroy(hss_thread); + if (sgw_thread) ogs_thread_destroy(sgw_thread); + if (smf_thread) ogs_thread_destroy(smf_thread); + if (upf_thread) ogs_thread_destroy(upf_thread); + if (pcrf_thread) ogs_thread_destroy(pcrf_thread); + + pcscf_fd_final(); + + ogs_sctp_final(); + + test_app_final(); + ogs_app_terminate(); +} + +static void initialize(const char *const argv[]) +{ + int rv; + + test_no_mme_self = true; + + rv = ogs_app_initialize(NULL, argv); + ogs_assert(rv == OGS_OK); + + pcrf_thread = test_child_create("pcrf", argv); + upf_thread = test_child_create("upf", argv); + smf_thread = test_child_create("smf", argv); + sgw_thread = test_child_create("sgw", argv); + hss_thread = test_child_create("hss", argv); + mme_thread = test_child_create("mme", argv); + + test_app_init(); + ogs_sctp_init(ogs_config()->usrsctp.udp_port); + + rv = pcscf_fd_init(); + ogs_assert(rv == OGS_OK); +} + +int main(int argc, const char *const argv[]) +{ + int i; + abts_suite *suite = NULL; + + atexit(terminate); + test_app_run(argc, argv, "cups.yaml", initialize); + + for (i = 0; alltests[i].func; i++) + suite = alltests[i].func(suite); + + return abts_report(suite); +} diff --git a/tests/cups/cups-test.c b/tests/cups/cups-test.c new file mode 100644 index 000000000..ffbc9ce8e --- /dev/null +++ b/tests/cups/cups-test.c @@ -0,0 +1,1314 @@ +/* + * 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 "pcscf-fd-path.h" + +#define TEST1_PING 1 +#define TEST3_PING 0 + +static void cups_test1(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_s1ap_message_t message; + int i; + int msgindex = 0; + uint8_t *rx_sid = NULL; + + mongoc_collection_t *collection = NULL; + bson_t *doc = NULL; + int64_t count = 0; + bson_error_t error; + const char *json = + "{" + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2b\" }," + "\"imsi\" : \"001010123456819\"," + "\"pdn\" : [" + "{ \"apn\" : \"internet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," + "\"qos\" : {" + "\"qci\" : 9," + "\"arp\" : {" + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }," + "{ \"apn\" : \"internet.ng2.mnet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" }," + "\"pcc_rule\" : [" + "{ \"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," + "\"qos\" : {" + "\"qci\" : 1," + "\"gbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"mbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"arp\" : {" + "\"priority_level\" : 3," + "\"pre_emption_vulnerability\" : 0," + "\"pre_emption_capability\" : 0 } }" + "} ]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"35840\" }," + "\"uplink\" : { \"$numberLong\" : \"15360\" } }," + "\"qos\" : {" + "\"qci\" : 6," + "\"arp\" : {" + "\"priority_level\" : 6," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }" + "]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"1024000\" }," + "\"uplink\" : { \"$numberLong\" : \"1024000\" } }," + "\"subscribed_rau_tau_timer\" : 12," + "\"network_access_mode\" : 2," + "\"subscriber_status\" : 0," + "\"access_restriction_data\" : 32," + "\"security\" : {" + "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\"," + "\"op\" : \"5F1D289C 5D354D0A 140C2548 F5F3E3BA\"," + "\"amf\" : \"8000\"," + "\"sqn\" : { \"$numberLong\" : \"64\" }, " + "\"rand\" : \"20080C38 18183B52 2614162C 07601D0D\" }, " + "\"__v\" : 0" + "}"; + + /* eNB connects to MME */ + s1ap = testenb_s1ap_client("127.0.0.1"); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = testenb_gtpu_server("127.0.0.5"); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send S1-Setup Reqeust */ + rv = tests1ap_build_setup_req( + &sendbuf, S1AP_ENB_ID_PR_macroENB_ID, 0x54f64, 12345, 1, 1, 2); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + rv = ogs_s1ap_decode(&message, recvbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + ogs_s1ap_free(&message); + ogs_pkbuf_free(recvbuf); + + collection = mongoc_client_get_collection( + ogs_mongoc()->client, ogs_mongoc()->name, "subscribers"); + ABTS_PTR_NOTNULL(tc, collection); + + doc = bson_new_from_json((const uint8_t *)json, -1, &error);; + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_insert(collection, + MONGOC_INSERT_NONE, doc, NULL, &error)); + bson_destroy(doc); + + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + do { + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + } while (count == 0); + bson_destroy(doc); + + /*********************************************************************** + * Attach Request : Known IMSI, Integrity Protected, No Security Context + * Send Initial-UE Message + Attach Request + PDN Connectivity */ + rv = tests1ap_build_initial_ue_msg(&sendbuf, msgindex); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Authentication Response */ + rv = tests1ap_build_authentication_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Security mode Complete */ + rv = tests1ap_build_security_mode_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send ESM Information Response */ + rv = tests1ap_build_esm_information_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send UE Capability Info Indication */ + rv = tests1ap_build_ue_capability_info_indication(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + rv = tests1ap_build_initial_context_setup_response(&sendbuf, + 1, 1, 5, 1, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + rv = tests1ap_build_attach_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + +#if TEST1_PING + /* Send GTP-U ICMP Packet */ + rv = testgtpu_build_ping(&sendbuf, 1, "10.45.0.2", "10.45.0.1"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_gtpu_send(gtpu, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testenb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); +#endif + + /* Send PDN Connectivity Request */ + rv = tests1ap_build_pdn_connectivity_request(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Setup Request + + * Activate default EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Setup Response */ + rv = tests1ap_build_e_rab_setup_response(&sendbuf, 1, 1, 6, 2, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Activate default EPS bearer context accept */ + rv = tests1ap_build_activate_default_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + ogs_msleep(50); + +#if TEST1_PING + rv = testgtpu_build_ping(&sendbuf, 3, "10.45.0.3", "10.45.0.1"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_gtpu_send(gtpu, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testenb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); +#endif + + /* Send AA-Request */ + ogs_msleep(300); + pcscf_rx_send_aar(&rx_sid, "10.45.0.3", 1, 1); + + /* Receive E-RAB Setup Request + + * Activate dedicated EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Setup Response */ + rv = tests1ap_build_e_rab_setup_response(&sendbuf, 1, 1, 7, 3, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Activate dedicated EPS bearer context accept */ + rv = tests1ap_build_activate_dedicated_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send AA-Request without Flow */ + ogs_msleep(300); + pcscf_rx_send_aar(&rx_sid, "10.45.0.3", 2, 1); + + /* Receive E-RAB Modify Request + + * Modify EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Modify Response */ + rv = tests1ap_build_e_rab_modify_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Modify EPS bearer context accept */ + rv = tests1ap_build_modify_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(50); + + /* Send Bearer resource allocation request */ + rv = tests1ap_build_bearer_resource_allocation_request(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Bearer resource allocation reject */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send Bearer resource modification request */ + rv = tests1ap_build_bearer_resource_modification_request(&sendbuf, + 1, 1, 3, 0x3f426e62, 7, 7, + OGS_GTP_TFT_CODE_NO_TFT_OPERATION, + 1, 0, 0, 0, 0); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Bearer resource modification reject */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send Bearer resource modification request */ + rv = tests1ap_build_bearer_resource_modification_request(&sendbuf, + 1, 1, 4, 0xdc64fbbc, 8, 7, + OGS_GTP_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT, + 1, 44, 55, 22, 33); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Modify Request + + * Modify EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send Modify EPS bearer context accept */ + rv = tests1ap_build_modify_bearer_accept(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send E-RAB Modify Response */ + rv = tests1ap_build_e_rab_modify_response(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Bearer resource modification request */ + rv = tests1ap_build_bearer_resource_modification_request(&sendbuf, + 1, 1, 5, 0x87a44610, 9, 7, + OGS_GTP_TFT_CODE_REPLACE_PACKET_FILTERS_IN_EXISTING, + 1, 0, 0, 0, 0); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Modify Request + + * Modify EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Modify Response */ + rv = tests1ap_build_e_rab_modify_response(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Modify EPS bearer context accept */ + rv = tests1ap_build_modify_bearer_accept(&sendbuf, msgindex+2); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Session-Termination-Request */ + ogs_msleep(50); + pcscf_rx_send_str(rx_sid); + + /* Receive E-RAB Release Command + + * Dectivate EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Release Response */ + rv = tests1ap_build_e_rab_release_response(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(50); + + /* Send Deactivate EPS bearer context accept */ + rv = tests1ap_build_deactivate_bearer_accept(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(50); + + /* Send Detach Request */ + rv = tests1ap_build_detach_request(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE Context Release Complete */ + rv = tests1ap_build_ue_context_release_complete(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + bson_destroy(doc); + + mongoc_collection_destroy(collection); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disonncect from SGW */ + testenb_gtpu_close(gtpu); +} + +static void cups_test2(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_s1ap_message_t message; + int i; + int msgindex = 0; + uint8_t *rx_sid = NULL; + + mongoc_collection_t *collection = NULL; + bson_t *doc = NULL; + int64_t count = 0; + bson_error_t error; + const char *json = + "{" + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2b\" }," + "\"imsi\" : \"001010123456819\"," + "\"pdn\" : [" + "{ \"apn\" : \"internet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," + "\"qos\" : {" + "\"qci\" : 9," + "\"arp\" : {" + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }," + "{ \"apn\" : \"internet.ng2.mnet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" }," + "\"pcc_rule\" : [" + "{ \"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," + "\"qos\" : {" + "\"qci\" : 1," + "\"gbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"mbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"arp\" : {" + "\"priority_level\" : 3," + "\"pre_emption_vulnerability\" : 0," + "\"pre_emption_capability\" : 0 } }," + "\"flow\" : [" + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/32 23454\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from any 50020 to 10.200.136.98/32 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/32 23455\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from any 50021 to 10.200.136.98/32 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } } ]" + "} ]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"35840\" }," + "\"uplink\" : { \"$numberLong\" : \"15360\" } }," + "\"qos\" : {" + "\"qci\" : 6," + "\"arp\" : {" + "\"priority_level\" : 6," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }" + "]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"1024000\" }," + "\"uplink\" : { \"$numberLong\" : \"1024000\" } }," + "\"subscribed_rau_tau_timer\" : 12," + "\"network_access_mode\" : 2," + "\"subscriber_status\" : 0," + "\"access_restriction_data\" : 32," + "\"security\" : {" + "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\"," + "\"op\" : \"5F1D289C 5D354D0A 140C2548 F5F3E3BA\"," + "\"amf\" : \"8000\"," + "\"sqn\" : { \"$numberLong\" : \"64\" }, " + "\"rand\" : \"20080C38 18183B52 2614162C 07601D0D\" }, " + "\"__v\" : 0" + "}"; + + /* eNB connects to MME */ + s1ap = testenb_s1ap_client("127.0.0.1"); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* Send S1-Setup Reqeust */ + rv = tests1ap_build_setup_req( + &sendbuf, S1AP_ENB_ID_PR_macroENB_ID, 0x54f64, 12345, 1, 1, 2); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + rv = ogs_s1ap_decode(&message, recvbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + ogs_s1ap_free(&message); + ogs_pkbuf_free(recvbuf); + + collection = mongoc_client_get_collection( + ogs_mongoc()->client, ogs_mongoc()->name, "subscribers"); + ABTS_PTR_NOTNULL(tc, collection); + + doc = bson_new_from_json((const uint8_t *)json, -1, &error);; + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_insert(collection, + MONGOC_INSERT_NONE, doc, NULL, &error)); + bson_destroy(doc); + + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + do { + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + } while (count == 0); + bson_destroy(doc); + + /*********************************************************************** + * Attach Request : Known IMSI, Integrity Protected, No Security Context + * Send Initial-UE Message + Attach Request + PDN Connectivity */ + rv = tests1ap_build_initial_ue_msg(&sendbuf, msgindex); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Authentication Response */ + rv = tests1ap_build_authentication_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Security mode Complete */ + rv = tests1ap_build_security_mode_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send ESM Information Response */ + rv = tests1ap_build_esm_information_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send UE Capability Info Indication */ + rv = tests1ap_build_ue_capability_info_indication(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + rv = tests1ap_build_initial_context_setup_response(&sendbuf, + 1, 1, 5, 1, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + rv = tests1ap_build_attach_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send PDN Connectivity Request */ + rv = tests1ap_build_pdn_connectivity_request(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Setup Request + + * Activate default EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Setup Response */ + rv = tests1ap_build_e_rab_setup_response(&sendbuf, 1, 1, 6, 2, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Activate default EPS bearer context accept */ + rv = tests1ap_build_activate_default_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Setup Request + + * Activate dedicated EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send Activate dedicated EPS bearer context accept */ + rv = tests1ap_build_activate_dedicated_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send E-RAB Setup Response */ + rv = tests1ap_build_e_rab_setup_response(&sendbuf, 1, 1, 7, 3, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send AA-Request */ + ogs_msleep(300); + pcscf_rx_send_aar(&rx_sid, "10.45.0.5", 0, 1); + + /* Receive downlink NAS transport + + * Modify EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send Modify EPS bearer context accept */ + rv = tests1ap_build_modify_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDN disconnectivity request */ + rv = tests1ap_build_pdn_disconnectivity_request(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Release Command + + * Deactivate EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Release Response */ + rv = tests1ap_build_e_rab_release_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Deactivate EPS bearer context accept */ + rv = tests1ap_build_deactivate_bearer_accept(&sendbuf, msgindex+2); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + bson_destroy(doc); + + mongoc_collection_destroy(collection); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); +} + +static void cups_test3(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_s1ap_message_t message; + int i; + int msgindex = 0; + + mongoc_collection_t *collection = NULL; + bson_t *doc = NULL; + int64_t count = 0; + bson_error_t error; + const char *json = + "{" + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2b\" }," + "\"imsi\" : \"001010123456819\"," + "\"pdn\" : [" + "{ \"apn\" : \"internet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," + "\"qos\" : {" + "\"qci\" : 9," + "\"arp\" : {" + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }," + "{ \"apn\" : \"internet.ng2.mnet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" }," + "\"pcc_rule\" : [" + "{ \"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," + "\"qos\" : {" + "\"qci\" : 1," + "\"gbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"mbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"arp\" : {" + "\"priority_level\" : 3," + "\"pre_emption_vulnerability\" : 0," + "\"pre_emption_capability\" : 0 } }," + "\"flow\" : [" + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/32 23454\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from any 50020 to 10.200.136.98/32 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/32 23455\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from any 50021 to 10.200.136.98/32 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } } ]" + "} ]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"35840\" }," + "\"uplink\" : { \"$numberLong\" : \"15360\" } }," + "\"qos\" : {" + "\"qci\" : 6," + "\"arp\" : {" + "\"priority_level\" : 6," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }" + "]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"1024000\" }," + "\"uplink\" : { \"$numberLong\" : \"1024000\" } }," + "\"subscribed_rau_tau_timer\" : 12," + "\"network_access_mode\" : 2," + "\"subscriber_status\" : 0," + "\"access_restriction_data\" : 32," + "\"security\" : {" + "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\"," + "\"op\" : \"5F1D289C 5D354D0A 140C2548 F5F3E3BA\"," + "\"amf\" : \"8000\"," + "\"sqn\" : { \"$numberLong\" : \"64\" }, " + "\"rand\" : \"20080C38 18183B52 2614162C 07601D0D\" }, " + "\"__v\" : 0" + "}"; + + /* eNB connects to MME */ + s1ap = testenb_s1ap_client("127.0.0.1"); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = testenb_gtpu_server("127.0.0.5"); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send S1-Setup Reqeust */ + rv = tests1ap_build_setup_req( + &sendbuf, S1AP_ENB_ID_PR_macroENB_ID, 0x54f64, 12345, 1, 1, 2); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + rv = ogs_s1ap_decode(&message, recvbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + ogs_s1ap_free(&message); + ogs_pkbuf_free(recvbuf); + + collection = mongoc_client_get_collection( + ogs_mongoc()->client, ogs_mongoc()->name, "subscribers"); + ABTS_PTR_NOTNULL(tc, collection); + + doc = bson_new_from_json((const uint8_t *)json, -1, &error);; + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_insert(collection, + MONGOC_INSERT_NONE, doc, NULL, &error)); + bson_destroy(doc); + + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + do { + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + } while (count == 0); + bson_destroy(doc); + + /*********************************************************************** + * Attach Request : Known IMSI, Integrity Protected, No Security Context + * Send Initial-UE Message + Attach Request + PDN Connectivity */ + rv = tests1ap_build_initial_ue_msg(&sendbuf, msgindex); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Authentication Response */ + rv = tests1ap_build_authentication_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Security mode Complete */ + rv = tests1ap_build_security_mode_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send ESM Information Response */ + rv = tests1ap_build_esm_information_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send UE Capability Info Indication */ + rv = tests1ap_build_ue_capability_info_indication(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + rv = tests1ap_build_initial_context_setup_response( + &sendbuf, 1, 1, 5, 1, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + rv = tests1ap_build_attach_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + +#if TEST3_PING + /* Send GTP-U ICMP Packet */ + rv = testgtpu_build_ping(&sendbuf, 1, "10.45.0.2", "10.45.0.1"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_gtpu_send(gtpu, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testenb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); +#endif + + /* Send PDN Connectivity Request */ + rv = tests1ap_build_pdn_connectivity_request(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Setup Request + + * Activate default EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Setup Response */ + rv = tests1ap_build_e_rab_setup_response(&sendbuf, 1, 1, 6, 2, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Activate default EPS bearer context accept */ + rv = tests1ap_build_activate_default_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Setup Request + + * Activate dedicated EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send Activate dedicated EPS bearer context accept */ + rv = tests1ap_build_activate_dedicated_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send E-RAB Setup Response */ + rv = tests1ap_build_e_rab_setup_response(&sendbuf, 1, 1, 7, 3, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + ogs_msleep(50); + +#if TEST3_PING + rv = testgtpu_build_ping(&sendbuf, 3, "10.45.0.3", "10.45.0.1"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_gtpu_send(gtpu, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testenb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); +#endif + + /* Send PDN disconnectivity request */ + rv = tests1ap_build_pdn_disconnectivity_request(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive E-RAB Release Command + + * Deactivate EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Release Response */ + rv = tests1ap_build_e_rab_release_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Deactivate EPS bearer context accept */ + rv = tests1ap_build_deactivate_bearer_accept(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send INVALID PDN Connectivity Request */ + rv = tests1ap_build_pdn_connectivity_request(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDN Connectivity Reject */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE Context Release Complete */ + rv = tests1ap_build_ue_context_release_complete(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + bson_destroy(doc); + + mongoc_collection_destroy(collection); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disonncect from SGW */ + testenb_gtpu_close(gtpu); +} + +static void cups_test4(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_s1ap_message_t message; + int i; + int msgindex = 0; + + mongoc_collection_t *collection = NULL; + bson_t *doc = NULL; + int64_t count = 0; + bson_error_t error; + const char *json = + "{" + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2b\" }," + "\"imsi\" : \"001010123456819\"," + "\"pdn\" : [" + "{ \"apn\" : \"internet.ng2.mnet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd32\" }," + "\"qos\" : {" + "\"qci\" : 9," + "\"arp\" : {" + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }," + "{ \"apn\" : \"internet\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2c\" }," + "\"pcc_rule\" : [" + "{ \"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," + "\"qos\" : {" + "\"qci\" : 1," + "\"gbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"mbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" } }," + "\"arp\" : {" + "\"priority_level\" : 3," + "\"pre_emption_vulnerability\" : 0," + "\"pre_emption_capability\" : 0 } }," + "\"flow\" : [" + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/32 23454\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out ip from 10.45.0.1 to any\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from any 1-65535 to 10.200.136.98/24 23455\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out ip from cafe::1 to any\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } } ]" + "} ]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"35840\" }," + "\"uplink\" : { \"$numberLong\" : \"15360\" } }," + "\"qos\" : {" + "\"qci\" : 6," + "\"arp\" : {" + "\"priority_level\" : 6," + "\"pre_emption_vulnerability\" : 1," + "\"pre_emption_capability\" : 1 } }," + "\"type\" : 2 }" + "]," + "\"ambr\" : {" + "\"downlink\" : { \"$numberLong\" : \"1024000\" }," + "\"uplink\" : { \"$numberLong\" : \"1024000\" } }," + "\"subscribed_rau_tau_timer\" : 12," + "\"network_access_mode\" : 2," + "\"subscriber_status\" : 0," + "\"access_restriction_data\" : 32," + "\"security\" : {" + "\"k\" : \"465B5CE8 B199B49F AA5F0A2E E238A6BC\"," + "\"op\" : \"5F1D289C 5D354D0A 140C2548 F5F3E3BA\"," + "\"amf\" : \"8000\"," + "\"sqn\" : { \"$numberLong\" : \"64\" }, " + "\"rand\" : \"20080C38 18183B52 2614162C 07601D0D\" }, " + "\"__v\" : 0" + "}"; + + /* eNB connects to MME */ + s1ap = testenb_s1ap_client("127.0.0.1"); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* Send S1-Setup Reqeust */ + rv = tests1ap_build_setup_req( + &sendbuf, S1AP_ENB_ID_PR_macroENB_ID, 0x54f64, 12345, 1, 1, 2); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + rv = ogs_s1ap_decode(&message, recvbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + ogs_s1ap_free(&message); + ogs_pkbuf_free(recvbuf); + + collection = mongoc_client_get_collection( + ogs_mongoc()->client, ogs_mongoc()->name, "subscribers"); + ABTS_PTR_NOTNULL(tc, collection); + + doc = bson_new_from_json((const uint8_t *)json, -1, &error);; + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_insert(collection, + MONGOC_INSERT_NONE, doc, NULL, &error)); + bson_destroy(doc); + + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + do { + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + } while (count == 0); + bson_destroy(doc); + + /*********************************************************************** + * Attach Request : Known IMSI, Integrity Protected, MAC failed + * Send Initial-UE Message + Attach Request + PDN Connectivity */ + rv = tests1ap_build_initial_ue_msg(&sendbuf, msgindex); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Authentication Response */ + rv = tests1ap_build_authentication_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send Security mode Complete */ + rv = tests1ap_build_security_mode_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send ESM Information Response */ + rv = tests1ap_build_esm_information_response(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Send UE Capability Info Indication */ + rv = tests1ap_build_ue_capability_info_indication(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + rv = tests1ap_build_initial_context_setup_response( + &sendbuf, 16777373, 1, 5, 1, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + rv = tests1ap_build_attach_complete(&sendbuf, msgindex); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + 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); + ogs_pkbuf_free(recvbuf); + + /* Receive E-RAB Setup Request + + * Activate dedicated EPS bearer context request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send E-RAB Setup Response */ + rv = tests1ap_build_e_rab_setup_response( + &sendbuf, 33554492, 1, 6, 2, "127.0.0.5"); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Activate dedicated EPS bearer context accept */ + rv = tests1ap_build_activate_dedicated_bearer_accept(&sendbuf, msgindex+1); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + doc = BCON_NEW("imsi", BCON_UTF8("001010123456819")); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + bson_destroy(doc); + + mongoc_collection_destroy(collection); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); +} + +abts_suite *test_cups(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, cups_test1, NULL); + abts_run_test(suite, cups_test2, NULL); + abts_run_test(suite, cups_test3, NULL); + abts_run_test(suite, cups_test4, NULL); + + return suite; +} diff --git a/tests/cups/meson.build b/tests/cups/meson.build new file mode 100644 index 000000000..03e55fcf0 --- /dev/null +++ b/tests/cups/meson.build @@ -0,0 +1,32 @@ +# 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 . + +testcups_sources = files(''' + pcscf-fd-path.h + pcscf-fd-path.c + + abts-main.c + cups-test.c +'''.split()) + +testcups_exe = executable('cups', + sources : testcups_sources, + c_args : [testcore_cc_flags, + '-DFD_EXT_DIR="@0@"'.format(freediameter_extensions_builddir)], + dependencies : libtestapp_dep) + +test('cups', testcups_exe, is_parallel : false, suite: '5gc') diff --git a/tests/cups/pcscf-fd-path.c b/tests/cups/pcscf-fd-path.c new file mode 100644 index 000000000..24c099cbe --- /dev/null +++ b/tests/cups/pcscf-fd-path.c @@ -0,0 +1,948 @@ +/* + * 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-gtp.h" +#include "ogs-diameter-rx.h" + +#include "pcscf-fd-path.h" + +#define MAX_NUM_SESSION_STATE 32 + +static struct session_handler *pcscf_rx_reg = NULL; +static struct disp_hdl *hdl_rx_fb = NULL; +static struct disp_hdl *hdl_rx_asr = NULL; +static ogs_diam_config_t diam_config; + +struct sess_state { + os0_t sid; /* Rx Session-Id */ + + struct timespec ts; /* Time of sending the message */ +}; + +static void pcscf_rx_aaa_cb(void *data, struct msg **msg); +static void pcscf_rx_sta_cb(void *data, struct msg **msg); + +static __inline__ struct sess_state *new_state(os0_t sid) +{ + struct sess_state *new = NULL; + + new = ogs_calloc(1, sizeof(*new)); + new->sid = (os0_t)ogs_strdup((char *)sid); + ogs_assert(new->sid); + + return new; +} + +static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) +{ + if (sess_data->sid) + ogs_free(sess_data->sid); + + ogs_free(sess_data); +} + +static int pcscf_rx_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 pcscf_rx_send_aar(uint8_t **rx_sid, const char *ip, + int qos_type, int flow_presence) +{ + int rv; + int ret; + + 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; + ogs_ipsubnet_t ipsub; + + ogs_assert(rx_sid); + + ogs_assert(ip); + rv = ogs_ipsubnet(&ipsub, ip, NULL); + ogs_assert(rv == OGS_OK); + + /* 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_RX_APPLICATION_ID; + } + + /* Find Diameter Rx Session */ + if (*rx_sid) { + /* Retrieve session by Session-Id */ + size_t sidlen = strlen((char *)*rx_sid); + ret = fd_sess_fromsid_msg(*rx_sid, sidlen, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + /* Add Session-Id to the message */ + ret = ogs_diam_message_session_id_set(req, *rx_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_RX_APP_SID_OPT "app_rx" + ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_RX_APP_SID_OPT, + CONSTSTRLEN(OGS_DIAM_RX_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(pcscf_rx_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); + + /* Save Session-Id to PGW Session Context */ + *rx_sid = sess_data->sid; + } + + /* 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_RX_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 Subscription-Id */ + ret = fd_msg_avp_new(ogs_diam_rx_subscription_id, 0, &avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_rx_subscription_id_type, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_RX_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); + + #define OGS_DIAM_RX_APP_IMSI_BCD "001010123456789" + ret = fd_msg_avp_new(ogs_diam_rx_subscription_id_data, 0, &avpch1); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)OGS_DIAM_RX_APP_IMSI_BCD; + val.os.len = strlen(OGS_DIAM_RX_APP_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 (ipsub.family == AF_INET) { + /* Set Framed-IP-Address */ + ret = fd_msg_avp_new(ogs_diam_rx_framed_ip_address, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t*)ipsub.sub; + 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); + } else if (ipsub.family == AF_INET6) { + /* Set Framed-IPv6-Prefix */ + ret = fd_msg_avp_new(ogs_diam_rx_framed_ipv6_prefix, 0, &avp); + ogs_assert(ret == 0); + memset(&paa, 0, sizeof(ogs_paa_t)); + + memcpy(paa.addr6, ipsub.sub, OGS_IPV6_LEN); + paa.pdn_type = 0x03; +#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 Media-Component-Description */ + ret = fd_msg_avp_new(ogs_diam_rx_media_component_description, 0, &avp); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_rx_media_component_number, 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_rx_media_type, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_RX_MEDIA_TYPE_AUDIO; + 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 (qos_type == 1) { + ret = fd_msg_avp_new( + ogs_diam_rx_max_requested_bandwidth_dl, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 96000; + 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_rx_max_requested_bandwidth_ul, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 96000; + 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_rx_rr_bandwidth, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 2400; + 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_rx_rs_bandwidth, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 2400; + 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); + } else if (qos_type == 2) { + ret = fd_msg_avp_new( + ogs_diam_rx_max_requested_bandwidth_dl, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 96000; + 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_rx_max_requested_bandwidth_ul, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 96000; + 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_rx_min_requested_bandwidth_dl, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 88000; + 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_rx_min_requested_bandwidth_ul, 0, &avpch1); + ogs_assert(ret == 0); + val.i32 = 88000; + 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 (flow_presence) { + /* Set Media-Sub-Component #1 */ + ret = fd_msg_avp_new(ogs_diam_rx_media_sub_component, 0, &avpch1); + + ret = fd_msg_avp_new(ogs_diam_rx_flow_number, 0, &avpch2); + ogs_assert(ret == 0); + val.i32 = 1; + 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_rx_flow_description, 0, &avpch2); + ogs_assert(ret == 0); + #define TEST_OGS_DIAM_RX_FLOW_DESC1 \ + "permit out 17 from 172.20.166.84 to 172.18.128.20 20001" + val.os.data = (uint8_t *)TEST_OGS_DIAM_RX_FLOW_DESC1; + val.os.len = strlen(TEST_OGS_DIAM_RX_FLOW_DESC1); + 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_rx_flow_description, 0, &avpch2); + ogs_assert(ret == 0); + #define TEST_OGS_DIAM_RX_FLOW_DESC2 \ + "permit in 17 from 172.18.128.20 to 172.20.166.84 20360" + val.os.data = (uint8_t *)TEST_OGS_DIAM_RX_FLOW_DESC2; + val.os.len = strlen(TEST_OGS_DIAM_RX_FLOW_DESC2); + 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); + + /* Set Media-Sub-Component #2 */ + ret = fd_msg_avp_new(ogs_diam_rx_media_sub_component, 0, &avpch1); + + ret = fd_msg_avp_new(ogs_diam_rx_flow_number, 0, &avpch2); + ogs_assert(ret == 0); + val.i32 = 2; + 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_rx_flow_usage, 0, &avpch2); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_RX_FLOW_USAGE_RTCP; + 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_rx_flow_description, 0, &avpch2); + ogs_assert(ret == 0); + #define TEST_OGS_DIAM_RX_FLOW_DESC3 \ + "permit out 17 from 172.20.166.84 to 172.18.128.20 20002" + val.os.data = (uint8_t *)TEST_OGS_DIAM_RX_FLOW_DESC3; + val.os.len = strlen(TEST_OGS_DIAM_RX_FLOW_DESC3); + 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_rx_flow_description, 0, &avpch2); + ogs_assert(ret == 0); + #define TEST_OGS_DIAM_RX_FLOW_DESC4 \ + "permit in 17 from 172.18.128.20 to 172.20.166.84 20361" + val.os.data = (uint8_t *)TEST_OGS_DIAM_RX_FLOW_DESC4; + val.os.len = strlen(TEST_OGS_DIAM_RX_FLOW_DESC4); + 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); + + 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(pcscf_rx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the request */ + ret = fd_msg_send(&req, pcscf_rx_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); +} + +static void pcscf_rx_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; + + 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); + + ret = fd_sess_state_retrieve(pcscf_rx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data); + ogs_assert((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; + ogs_debug("Result Code: %d\n", 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); + result_code = hdr->avp_value->i32; + ogs_debug("Experimental Result Code: %d\n", + 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++; + } + + if (result_code != ER_DIAMETER_SUCCESS) { + ogs_warn("ERROR DIAMETER Result Code(%d)", result_code); + error++; + goto out; + } + +out: + /* 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\n", + (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\n", + (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(pcscf_rx_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 pcscf_rx_asr_cb( struct msg **msg, struct avp *avp, + struct session *sess, void *opaque, enum disp_action *act) +{ + int rv; + int ret; + + struct msg *ans, *qry; + struct avp *avpch1, *avpch2, *avpch3; + struct avp_hdr *hdr; + union avp_value val; + struct sess_state *sess_data = NULL; + os0_t sid; + size_t sidlen; + + ogs_assert(msg); + ogs_assert(sess); + + ret = fd_sess_state_retrieve(pcscf_rx_reg, sess, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data); + + /* 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_RX_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 = 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); + + /* Get Abort-Cause */ + ret = fd_msg_search_avp(qry, ogs_diam_rx_abort_cause, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + } else { + ogs_error("no_Abort-Cause "); + } + + /* 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 */ + sid = sess_data->sid; + ogs_assert(sid); + + ret = fd_sess_state_store(pcscf_rx_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); + + pcscf_rx_send_str(sid); + + return 0; +} + +void pcscf_rx_send_str(uint8_t *rx_sid) +{ + int rv; + int ret; + + 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_assert(rx_sid); + + /* 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_RX_APPLICATION_ID; + } + + /* Retrieve session by Session-Id */ + size_t sidlen = strlen((char*)rx_sid); + ret = fd_sess_fromsid_msg(rx_sid, sidlen, &session, &new); + ogs_assert(ret == 0); + ogs_assert(new == 0); + + /* Add Session-Id to the message */ + ret = ogs_diam_message_session_id_set(req, rx_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(pcscf_rx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data); + + /* 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_RX_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 = OGS_DIAM_RX_TERMINATION_CAUSE_DIAMETER_LOGOUT; + 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(pcscf_rx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == NULL); + + /* Send the request */ + ret = fd_msg_send(&req, pcscf_rx_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); +} + +static void pcscf_rx_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; + + 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); + + ret = fd_sess_state_retrieve(pcscf_rx_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data && (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; + ogs_debug("Result Code: %d\n", 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); + result_code = hdr->avp_value->i32; + ogs_debug("Experimental Result Code: %d\n", + 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++; + } + + if (result_code != ER_DIAMETER_SUCCESS) { + ogs_warn("ERROR DIAMETER Result Code(%d)", result_code); + error++; + goto out; + } + +out: + /* 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\n", + (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\n", + (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), + (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + + state_cleanup(sess_data, NULL, NULL); + + ret = fd_msg_free(*msg); + ogs_assert(ret == 0); + *msg = NULL; + + return; +} + +void pcscf_diam_config(void) +{ + memset(&diam_config, 0, sizeof(ogs_diam_config_t)); + + diam_config.cnf_diamid = "pcscf.open-ims.test"; + diam_config.cnf_diamrlm = "open-ims.test"; + diam_config.cnf_port = DIAMETER_PORT; + diam_config.cnf_port_tls = DIAMETER_SECURE_PORT; + diam_config.cnf_flags.no_sctp = 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 = "pcrf.open-ims.test"; + diam_config.conn[diam_config.num_of_conn].addr = "127.0.0.5"; + diam_config.num_of_conn++; +} + +int pcscf_fd_init(void) +{ + int ret; + struct disp_when data; + + pcscf_diam_config(); + + ret = ogs_diam_init(FD_MODE_CLIENT, NULL, &diam_config); + ogs_assert(ret == 0); + + /* Install objects definitions for this application */ + ret = ogs_diam_rx_init(); + ogs_assert(ret == 0); + + /* Create handler for sessions */ + ret = fd_sess_handler_create(&pcscf_rx_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_rx_application; + + ret = fd_disp_register(pcscf_rx_fb_cb, DISP_HOW_APPID, &data, NULL, + &hdl_rx_fb); + ogs_assert(ret == 0); + + /* Specific handler for Abort-Session-Request */ + data.command = ogs_diam_rx_cmd_asr; + ret = fd_disp_register(pcscf_rx_asr_cb, DISP_HOW_CC, &data, NULL, + &hdl_rx_asr); + ogs_assert(ret == 0); + + /* Advertise the support for the application in the peer */ + ret = fd_disp_app_support(ogs_diam_rx_application, ogs_diam_vendor, 1, 0); + ogs_assert(ret == 0); + + return 0; +} + +void pcscf_fd_final(void) +{ + int ret; + ret = fd_sess_handler_destroy(&pcscf_rx_reg, NULL); + ogs_assert(ret == 0); + + if (hdl_rx_fb) + (void) fd_disp_unregister(&hdl_rx_fb, NULL); + if (hdl_rx_asr) + (void) fd_disp_unregister(&hdl_rx_asr, NULL); + + ogs_diam_final(); +} diff --git a/tests/cups/pcscf-fd-path.h b/tests/cups/pcscf-fd-path.h new file mode 100644 index 000000000..2a42a2fad --- /dev/null +++ b/tests/cups/pcscf-fd-path.h @@ -0,0 +1,39 @@ +/* + * 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 PCSCF_FD_PATH_H +#define PCSCF_FD_PATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +int pcscf_fd_init(void); +void pcscf_fd_final(void); + +void pcscf_rx_send_aar(uint8_t **rx_sid, const char *ip, + int qos_type, int flow_presence); +void pcscf_rx_send_str(uint8_t *rx_sid); + +#ifdef __cplusplus +} +#endif + +#endif /* PCSCF_FD_PATH_H */ + diff --git a/tests/meson.build b/tests/meson.build index 79b0d36ec..0a110665e 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -25,3 +25,4 @@ subdir('simple') subdir('mnc3') subdir('volte') subdir('csfb') +subdir('cups') diff --git a/tests/mnc3/mnc3-test.c b/tests/mnc3/mnc3-test.c index 484a7b0c6..f99b0a861 100644 --- a/tests/mnc3/mnc3-test.c +++ b/tests/mnc3/mnc3-test.c @@ -236,7 +236,7 @@ static void test1_func(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send GTP-U ICMP Packet */ - rv = testgtpu_build_ping(&sendbuf, "10.45.0.2", "10.45.0.1"); + rv = testgtpu_build_ping(&sendbuf, 1, "10.45.0.2", "10.45.0.1"); ABTS_INT_EQUAL(tc, OGS_OK, rv); rv = testenb_gtpu_send(gtpu, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); diff --git a/tests/simple/attach-test.c b/tests/simple/attach-test.c index 953ecf8ca..09e7067c2 100644 --- a/tests/simple/attach-test.c +++ b/tests/simple/attach-test.c @@ -256,7 +256,7 @@ static void attach_test1(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); /* Send GTP-U ICMP Packet */ - rv = testgtpu_build_ping(&sendbuf, "10.45.0.2", "10.45.0.1"); + rv = testgtpu_build_ping(&sendbuf, 1, "10.45.0.2", "10.45.0.1"); ABTS_INT_EQUAL(tc, OGS_OK, rv); rv = testenb_gtpu_send(gtpu, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); @@ -267,7 +267,7 @@ static void attach_test1(abts_case *tc, void *data) ogs_pkbuf_free(recvbuf); #if __linux__ - rv = testgtpu_build_ping(&sendbuf, "cafe::2", "cafe::1"); + rv = testgtpu_build_ping(&sendbuf, 1, "cafe::2", "cafe::1"); ABTS_INT_EQUAL(tc, OGS_OK, rv); rv = testenb_gtpu_send(gtpu, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); diff --git a/tests/simple/volte-test.c b/tests/simple/volte-test.c index d3762ae5f..5449c1062 100644 --- a/tests/simple/volte-test.c +++ b/tests/simple/volte-test.c @@ -534,9 +534,9 @@ static void volte_test2(abts_case *tc, void *data) #if 0 /* TFT Rule Tester */ /* Send GTP-U ICMP Packet */ #if 1 - rv = testgtpu_build_ping(&sendbuf, "10.45.0.2", "10.45.0.1"); + rv = testgtpu_build_ping(&sendbuf, 1, "10.45.0.2", "10.45.0.1"); #else - rv = testgtpu_build_ping(&sendbuf, "cafe::2", "cafe::1"); + rv = testgtpu_build_ping(&sendbuf, 1, "cafe::2", "cafe::1"); #endif rv = testgtpu_enb_send(gtpu, sendbuf); #endif diff --git a/tests/volte/abts-main.c b/tests/volte/abts-main.c index 290db531e..3dd5e4a79 100644 --- a/tests/volte/abts-main.c +++ b/tests/volte/abts-main.c @@ -60,6 +60,8 @@ static void initialize(const char *const argv[]) { int rv; + test_no_mme_self = true; + rv = ogs_app_initialize(NULL, argv); ogs_assert(rv == OGS_OK);