diff --git a/configs/310014.yaml.in b/configs/310014.yaml.in index 2465326af..9dc0af7e3 100644 --- a/configs/310014.yaml.in +++ b/configs/310014.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/configs/csfb.yaml.in b/configs/csfb.yaml.in index 60dd81f8f..3542dabed 100644 --- a/configs/csfb.yaml.in +++ b/configs/csfb.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/configs/non3gpp.yaml.in b/configs/non3gpp.yaml.in index bbbb5992a..a9842fe86 100644 --- a/configs/non3gpp.yaml.in +++ b/configs/non3gpp.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/configs/open5gs/amf.yaml.in b/configs/open5gs/amf.yaml.in index c37fd459d..be70fd239 100644 --- a/configs/open5gs/amf.yaml.in +++ b/configs/open5gs/amf.yaml.in @@ -178,6 +178,13 @@ logger: # sinit_max_attempts : 4 # sinit_max_init_timeo : 8000 # +# +# +# o Metrics Server(http://:9090) +# metrics: +# addr: 0.0.0.0 +# port: 9090 +# # # # o Multiple GUAMI @@ -263,6 +270,9 @@ amf: port: 7777 ngap: - addr: 127.0.0.5 + metrics: + addr: 127.0.0.5 + port: 9090 guami: - plmn_id: mcc: 999 @@ -391,17 +401,3 @@ usrsctp: # handover: # duration: 500 time: - -# -# metrics: -# -# -# -# o Metrics Server(http://:9090) -# metrics: -# addr: 0.0.0.0 -# port: 9090 -# -metrics: - addr: 127.0.0.5 - port: 9090 diff --git a/configs/open5gs/hss.yaml.in b/configs/open5gs/hss.yaml.in index 81f69a44f..b6c13b9de 100644 --- a/configs/open5gs/hss.yaml.in +++ b/configs/open5gs/hss.yaml.in @@ -41,6 +41,7 @@ hss: # prefer_ipv4: true # parameter: +# use_mongodb_change_stream: true # # max: diff --git a/configs/open5gs/mme.yaml.in b/configs/open5gs/mme.yaml.in index bcaf15951..384d8f885 100644 --- a/configs/open5gs/mme.yaml.in +++ b/configs/open5gs/mme.yaml.in @@ -175,6 +175,12 @@ logger: # mnc: 02 # lac: 43693 # +# +# +# o Metrics Server(http://:9090) +# metrics: +# addr: 0.0.0.0 +# port: 9090 # # # @@ -248,6 +254,9 @@ mme: - addr: 127.0.0.2 gtpc: - addr: 127.0.0.2 + metrics: + addr: 127.0.0.2 + port: 9090 gummei: plmn_id: mcc: 999 @@ -421,17 +430,3 @@ usrsctp: # handover: # duration: 500 time: - -# -# metrics: -# -# -# -# o Metrics Server(http://:9090) -# metrics: -# addr: 0.0.0.0 -# port: 9090 -# -metrics: - addr: 127.0.0.2 - port: 9090 diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in index 561fc5600..d919b8839 100644 --- a/configs/open5gs/smf.yaml.in +++ b/configs/open5gs/smf.yaml.in @@ -16,7 +16,7 @@ # # o Set OGS_LOG_TRACE to all domain level # level: trace -# domain: core,pfcp,fd,pfcp,gtp,smf,event,tlv,mem,sock +# domain: core,fd,pfcp,gtp,smf,event,tlv,mem,sock # logger: file: @localstatedir@/log/open5gs/smf.log @@ -179,6 +179,13 @@ logger: # option: # so_bindtodevice: vrf-blue # +# +# +# o Metrics Server(http://:9090) +# metrics: +# addr: 0.0.0.0 +# port: 9090 +# # # # o IPv4 Pool @@ -423,6 +430,9 @@ smf: gtpu: - addr: 127.0.0.4 - addr: ::1 + metrics: + addr: 127.0.0.4 + port: 9090 subnet: - addr: 10.45.0.1/16 - addr: 2001:db8:cafe::1/48 @@ -599,17 +609,3 @@ max: # handover: # duration: 500 time: - -# -# metrics: -# -# -# -# o Metrics Server(http://:9090) -# metrics: -# addr: 0.0.0.0 -# port: 9090 -# -metrics: - addr: 127.0.0.4 - port: 9090 diff --git a/configs/sample.yaml.in b/configs/sample.yaml.in index 20df424f2..a64e14d9f 100644 --- a/configs/sample.yaml.in +++ b/configs/sample.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/configs/slice.yaml.in b/configs/slice.yaml.in index 1d21c1fd1..91177cab1 100644 --- a/configs/slice.yaml.in +++ b/configs/slice.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/configs/srslte.yaml.in b/configs/srslte.yaml.in index b6811c5c5..20055efd0 100644 --- a/configs/srslte.yaml.in +++ b/configs/srslte.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/configs/volte.yaml.in b/configs/volte.yaml.in index 90b9805c5..f9a8a6ce7 100644 --- a/configs/volte.yaml.in +++ b/configs/volte.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/configs/vonr.yaml.in b/configs/vonr.yaml.in index 93a4910f3..122660717 100644 --- a/configs/vonr.yaml.in +++ b/configs/vonr.yaml.in @@ -19,6 +19,7 @@ parameter: # no_sgwu: true # no_pcrf: true # no_hss: true +# use_mongodb_change_stream: true mme: freeDiameter: diff --git a/docs/_docs/guide/01-quickstart.md b/docs/_docs/guide/01-quickstart.md index 4dfda5bcc..2546e2216 100644 --- a/docs/_docs/guide/01-quickstart.md +++ b/docs/_docs/guide/01-quickstart.md @@ -430,6 +430,21 @@ $ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE $ sudo ip6tables -t nat -A POSTROUTING -s 2001:db8:cafe::/48 ! -o ogstun -j MASQUERADE ``` +Optionally, you may consider the settings below for security purposes. + +```bash +### Prevent UE's from connecting to the host on which UPF is running +$ sudo iptables -I INPUT -s 10.45.0.0/16 -j DROP +$ sudo ip6tables -I INPUT -s 2001:db8:cafe::/48 -j DROP + +### If your core network runs over multiple hosts, you probably want to block +### UE originating traffic from accessing other network functions. +### Replace x.x.x.x/y with the VNFs IP/subnet +$ sudo iptables -I FORWARD -s 10.45.0.0/16 -d x.x.x.x/y -j DROP +``` + +**Note:** The above assumes you do not have any existing rules in the filter and nat tables. If a program such as docker has already set up rules, you may need to add the Open5GS related rules differently. +{: .notice--danger} ## 5. Turn on your eNB/gNB and UE --- diff --git a/docs/_docs/guide/02-building-open5gs-from-sources.md b/docs/_docs/guide/02-building-open5gs-from-sources.md index 360b2e963..897e387b7 100644 --- a/docs/_docs/guide/02-building-open5gs-from-sources.md +++ b/docs/_docs/guide/02-building-open5gs-from-sources.md @@ -468,6 +468,19 @@ $ sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE $ sudo ip6tables -t nat -A POSTROUTING -s 2001:db8:cafe::/48 ! -o ogstun -j MASQUERADE ``` +Optionally, you may consider the settings below for security purposes. + +```bash +### Prevent UE's from connecting to the host on which UPF is running +$ sudo iptables -I INPUT -s 10.45.0.0/16 -j DROP +$ sudo ip6tables -I INPUT -s 2001:db8:cafe::/48 -j DROP + +### If your core network runs over multiple hosts, you probably want to block +### UE originating traffic from accessing other network functions. +### Replace x.x.x.x/y with the VNFs IP/subnet +$ sudo iptables -I FORWARD -s 10.45.0.0/16 -d x.x.x.x/y -j DROP +``` + **Note:** The above assumes you do not have any existing rules in the filter and nat tables. If a program such as docker has already set up rules, you may need to add the Open5GS related rules differently. {: .notice--danger} diff --git a/docs/_docs/platform/05-macosx-apple-silicon.md b/docs/_docs/platform/05-macosx-apple-silicon.md index cc90825ef..504a6e436 100644 --- a/docs/_docs/platform/05-macosx-apple-silicon.md +++ b/docs/_docs/platform/05-macosx-apple-silicon.md @@ -69,6 +69,7 @@ $ sudo ifconfig lo0 alias 127.0.0.17 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.18 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.19 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.20 netmask 255.255.255.255 +$ sudo ifconfig lo0 alias 127.0.1.10 netmask 255.255.255.255 ``` Enable IP forwarding & Masquerading diff --git a/docs/_docs/platform/06-macosx-intel.md b/docs/_docs/platform/06-macosx-intel.md index 60689c3f4..6a7d0dafb 100644 --- a/docs/_docs/platform/06-macosx-intel.md +++ b/docs/_docs/platform/06-macosx-intel.md @@ -69,6 +69,7 @@ $ sudo ifconfig lo0 alias 127.0.0.17 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.18 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.19 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.20 netmask 255.255.255.255 +$ sudo ifconfig lo0 alias 127.0.1.10 netmask 255.255.255.255 ``` Enable IP forwarding & Masquerading diff --git a/docs/_docs/platform/07-freebsd.md b/docs/_docs/platform/07-freebsd.md index 479c75b58..ce73e2dc5 100644 --- a/docs/_docs/platform/07-freebsd.md +++ b/docs/_docs/platform/07-freebsd.md @@ -89,6 +89,7 @@ $ sudo ifconfig lo0 alias 127.0.0.17 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.18 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.19 netmask 255.255.255.255 $ sudo ifconfig lo0 alias 127.0.0.20 netmask 255.255.255.255 +$ sudo ifconfig lo0 alias 127.0.1.10 netmask 255.255.255.255 ``` Enable IP forwarding diff --git a/lib/app/ogs-context.c b/lib/app/ogs-context.c index 08c2024b3..24b4d900a 100644 --- a/lib/app/ogs-context.c +++ b/lib/app/ogs-context.c @@ -350,6 +350,10 @@ int ogs_app_context_parse_config(void) } else if (!strcmp(parameter_key, "no_pfcp_rr_select")) { self.parameter.no_pfcp_rr_select = ogs_yaml_iter_bool(¶meter_iter); + } else if (!strcmp(parameter_key, + "use_mongodb_change_stream")) { + self.use_mongodb_change_stream = + ogs_yaml_iter_bool(¶meter_iter); } else ogs_warn("unknown key `%s`", parameter_key); } diff --git a/lib/app/ogs-context.h b/lib/app/ogs-context.h index 2850c88ff..a27b821d1 100644 --- a/lib/app/ogs-context.h +++ b/lib/app/ogs-context.h @@ -35,6 +35,8 @@ typedef struct ogs_app_context_s { void *document; const char *db_uri; + int use_mongodb_change_stream; + struct { const char *file; const char *level; diff --git a/lib/core/ogs-time.c b/lib/core/ogs-time.c index 65cbd3b66..5edaccc5e 100644 --- a/lib/core/ogs-time.c +++ b/lib/core/ogs-time.c @@ -125,7 +125,7 @@ ogs_time_t ogs_time_now(void) rc = ogs_gettimeofday(&tv); ogs_assert(rc == 0); - return tv.tv_sec * OGS_USEC_PER_SEC + tv.tv_usec; + return ogs_time_from_sec(tv.tv_sec) + tv.tv_usec; } /* The following code is stolen from APR library */ @@ -188,13 +188,13 @@ uint32_t ogs_time_ntp32_now(void) rc = ogs_gettimeofday(&tv); ogs_assert(rc == 0); - return ogs_time_to_ntp32(tv.tv_sec * OGS_USEC_PER_SEC + tv.tv_usec); + return ogs_time_to_ntp32(ogs_time_from_sec(tv.tv_sec) + tv.tv_usec); } ogs_time_t ogs_time_from_ntp32(uint32_t ntp_timestamp) { if (ntp_timestamp < OGS_1970_1900_SEC_DIFF) return 0; - return (ntp_timestamp - OGS_1970_1900_SEC_DIFF) * OGS_USEC_PER_SEC; + return ogs_time_from_sec(ntp_timestamp - OGS_1970_1900_SEC_DIFF); } uint32_t ogs_time_to_ntp32(ogs_time_t time) { @@ -242,7 +242,7 @@ ogs_time_t ogs_get_monotonic_time(void) #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return ((ts.tv_sec * 1000000UL) + (ts.tv_nsec / 1000UL)); + return ogs_time_from_sec(ts.tv_sec) + ts.tv_nsec / 1000UL; #elif defined(__APPLE__) static mach_timebase_info_data_t info = {0}; static double ratio = 0.0; @@ -268,7 +268,7 @@ ogs_time_t ogs_get_monotonic_time(void) struct timeval tv; ogs_gettimeofday(&tv); - return (tv.tv_sec * 1000000UL) + tv.tv_usec; + return ogs_time_from_sec(tv.tv_sec) + tv.tv_usec; #endif } diff --git a/lib/core/ogs-tlv.c b/lib/core/ogs-tlv.c index 94c0c60f0..0299145b3 100644 --- a/lib/core/ogs-tlv.c +++ b/lib/core/ogs-tlv.c @@ -461,7 +461,11 @@ ogs_tlv_t *ogs_tlv_parse_block(uint32_t length, void *data, uint8_t mode) ogs_assert(pos); } - ogs_assert(length == (pos - blk)); + if (length != (pos - blk)) { + ogs_fatal("ogs_tlv_parse_block() failed[LEN:%d,MODE:%d]", length, mode); + ogs_log_hexdump(OGS_LOG_FATAL, data, length); + ogs_assert_if_reached(); + } return root; } diff --git a/lib/core/ogs-uuid.c b/lib/core/ogs-uuid.c index 3ade274a6..07cd862ee 100644 --- a/lib/core/ogs-uuid.c +++ b/lib/core/ogs-uuid.c @@ -80,7 +80,7 @@ static void get_system_time(uint64_t *uuid_time) /* ### fix this call to be more portable? */ ogs_gettimeofday(&tv); - *uuid_time = tv.tv_sec * OGS_USEC_PER_SEC + tv.tv_usec; + *uuid_time = ogs_time_from_sec(tv.tv_sec) + tv.tv_usec; /* Offset between UUID formatted times and Unix formatted times. UUID UTC base time is October 15, 1582. diff --git a/lib/dbi/meson.build b/lib/dbi/meson.build index a48f47785..ac3c9d3f3 100644 --- a/lib/dbi/meson.build +++ b/lib/dbi/meson.build @@ -19,11 +19,14 @@ libdbi_sources = files(''' ogs-dbi.h ogs-mongoc.h + timer.h ogs-mongoc.c subscription.c session.c ims.c + path.c + timer.c '''.split()) libmongoc_dep = dependency('libmongoc-1.0') @@ -35,10 +38,10 @@ libdbi = library('ogsdbi', version : libogslib_version, c_args : '-DOGS_DBI_COMPILATION', include_directories : [libdbi_inc, libinc], - dependencies : [libcrypt_dep, libmongoc_dep], + dependencies : [libcrypt_dep, libapp_dep, libmongoc_dep], install : true) libdbi_dep = declare_dependency( link_with : libdbi, include_directories : [libdbi_inc, libinc], - dependencies : [libcrypt_dep, libmongoc_dep]) + dependencies : [libcrypt_dep, libapp_dep, libmongoc_dep]) diff --git a/lib/dbi/ogs-dbi.h b/lib/dbi/ogs-dbi.h index 66e1b6c3c..7d575db29 100644 --- a/lib/dbi/ogs-dbi.h +++ b/lib/dbi/ogs-dbi.h @@ -21,6 +21,7 @@ #define OGS_DBI_H #include "crypt/ogs-crypt.h" +#include "app/ogs-app.h" #define OGS_DBI_INSIDE @@ -28,6 +29,8 @@ #include "dbi/subscription.h" #include "dbi/session.h" #include "dbi/ims.h" +#include "dbi/path.h" +#include "dbi/timer.h" #undef OGS_DBI_INSIDE diff --git a/lib/dbi/ogs-mongoc.c b/lib/dbi/ogs-mongoc.c index 19026aca7..b533ed182 100644 --- a/lib/dbi/ogs-mongoc.c +++ b/lib/dbi/ogs-mongoc.c @@ -182,5 +182,62 @@ void ogs_dbi_final() mongoc_collection_destroy(self.collection.subscriber); } + if (self.stream) { + mongoc_change_stream_destroy(self.stream); + } + ogs_mongoc_final(); } + +int ogs_dbi_collection_watch_init(void) +{ + bson_t empty = BSON_INITIALIZER; + const bson_t *err_doc; + bson_error_t error; + bson_t *options = BCON_NEW("fullDocument", "updateLookup"); + + ogs_mongoc()->stream = mongoc_collection_watch(self.collection.subscriber, + &empty, options); + + if (mongoc_change_stream_error_document(ogs_mongoc()->stream, &error, + &err_doc)) { + if (!bson_empty (err_doc)) { + ogs_error("Change Stream Error. Enable replica sets to " + "enable database updates to be sent to MME."); + } else { + ogs_error("Client Error: %s\n", error.message); + } + return OGS_ERROR; + } else { + ogs_info("Change Streams are Enabled."); + } + + return OGS_OK; +} + +int ogs_dbi_poll_change_stream(void) +{ + int rv; + + const bson_t *document; + const bson_t *err_document; + bson_error_t error; + + while (mongoc_change_stream_next(ogs_mongoc()->stream, &document)) { + rv = ogs_dbi_process_change_stream(document); + if (rv != OGS_OK) return rv; + } + + if (mongoc_change_stream_error_document(ogs_mongoc()->stream, &error, + &err_document)) { + if (!bson_empty (err_document)) { + ogs_debug("Server Error: %s\n", + bson_as_relaxed_extended_json(err_document, NULL)); + } else { + ogs_debug("Client Error: %s\n", error.message); + } + return OGS_ERROR; + } + + return OGS_OK; +} diff --git a/lib/dbi/ogs-mongoc.h b/lib/dbi/ogs-mongoc.h index 9e3b4515b..a0037dfbe 100644 --- a/lib/dbi/ogs-mongoc.h +++ b/lib/dbi/ogs-mongoc.h @@ -37,6 +37,8 @@ typedef struct ogs_mongoc_s { void *client; void *database; + mongoc_change_stream_t *stream; + char *masked_db_uri; struct { @@ -51,6 +53,9 @@ ogs_mongoc_t *ogs_mongoc(void); int ogs_dbi_init(const char *db_uri); void ogs_dbi_final(void); +int ogs_dbi_collection_watch_init(void); +int ogs_dbi_poll_change_stream(void); + #ifdef __cplusplus } #endif diff --git a/lib/dbi/path.c b/lib/dbi/path.c new file mode 100644 index 000000000..c15c0f0e7 --- /dev/null +++ b/lib/dbi/path.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ogs-dbi.h" + +int ogs_dbi_process_change_stream(const bson_t *document) +{ + int rv; + + ogs_event_t *e = NULL; + + e = ogs_event_new(OGS_EVENT_DBI_MESSAGE); + ogs_assert(e); + e->dbi.document = bson_copy(document); + rv = ogs_queue_push(ogs_app()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + bson_destroy((bson_t*)e->dbi.document); + ogs_event_free(e); + } else { + ogs_pollset_notify(ogs_app()->pollset); + } + + return OGS_OK; +} diff --git a/lib/dbi/path.h b/lib/dbi/path.h new file mode 100644 index 000000000..e6486d5e7 --- /dev/null +++ b/lib/dbi/path.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OGS_DBI_PATH_H +#define OGS_DBI_PATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +int ogs_dbi_process_change_stream(const bson_t *document); + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_DBI_PATH_H */ diff --git a/lib/dbi/timer.c b/lib/dbi/timer.c new file mode 100644 index 000000000..743bb6a08 --- /dev/null +++ b/lib/dbi/timer.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ogs-dbi.h" + +static void timer_send_event(int timer_id, void *data) +{ + int rv; + ogs_event_t *e = NULL; + + e = ogs_event_new(OGS_EVENT_DBI_POLL_TIMER); + ogs_assert(e); + e->timer_id = timer_id; + + rv = ogs_queue_push(ogs_app()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + ogs_event_free(e); + } +} + +void ogs_timer_dbi_poll_change_stream(void *data) +{ + timer_send_event(OGS_TIMER_DBI_POLL_CHANGE_STREAM, data); +} diff --git a/lib/dbi/timer.h b/lib/dbi/timer.h new file mode 100644 index 000000000..8928ab349 --- /dev/null +++ b/lib/dbi/timer.h @@ -0,0 +1,33 @@ +/* + * 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_DBI_TIMER_H +#define OGS_DBI_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +void ogs_timer_dbi_poll_change_stream(void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* OGS_DBI_TIMER_H */ diff --git a/lib/metrics/context.h b/lib/metrics/context.h index ce8b1819b..072104a06 100644 --- a/lib/metrics/context.h +++ b/lib/metrics/context.h @@ -39,7 +39,7 @@ void ogs_metrics_context_open(ogs_metrics_context_t *ctx); void ogs_metrics_context_close(ogs_metrics_context_t *ctx); void ogs_metrics_context_final(void); ogs_metrics_context_t *ogs_metrics_self(void); -int ogs_metrics_context_parse_config(void); +int ogs_metrics_context_parse_config(const char *local); typedef struct ogs_metrics_spec_s ogs_metrics_spec_t; ogs_metrics_spec_t *ogs_metrics_spec_new( diff --git a/lib/metrics/prometheus/context.c b/lib/metrics/prometheus/context.c index a2284afd6..d72640f01 100644 --- a/lib/metrics/prometheus/context.c +++ b/lib/metrics/prometheus/context.c @@ -104,7 +104,7 @@ ogs_metrics_context_t *ogs_metrics_self(void) return &self; } -int ogs_metrics_context_parse_config(void) +int ogs_metrics_context_parse_config(const char *local) { int family = AF_UNSPEC; const char *hostname = NULL; @@ -121,17 +121,26 @@ int ogs_metrics_context_parse_config(void) 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, "metrics")) { + if (local && !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); - if (!strcmp(local_key, "addr")) { - if ((v = ogs_yaml_iter_value(&local_iter))) - hostname = v; - } else if (!strcmp(local_key, "port")) { - if ((v = ogs_yaml_iter_value(&local_iter))) - port = atoi(v); + ogs_assert(local_key); + if (!strcmp(local_key, "metrics")) { + ogs_yaml_iter_t metrics_iter; + ogs_yaml_iter_recurse(&local_iter, &metrics_iter); + while (ogs_yaml_iter_next(&metrics_iter)) { + const char *metrics_key = ogs_yaml_iter_key(&metrics_iter); + ogs_assert(metrics_key); + if (!strcmp(metrics_key, "addr")) { + if ((v = ogs_yaml_iter_value(&metrics_iter))) + hostname = v; + } else if (!strcmp(metrics_key, "port")) { + if ((v = ogs_yaml_iter_value(&metrics_iter))) + port = atoi(v); + } + } } } } diff --git a/lib/metrics/void/context.c b/lib/metrics/void/context.c index ac7e41dd0..465d4322e 100644 --- a/lib/metrics/void/context.c +++ b/lib/metrics/void/context.c @@ -50,7 +50,7 @@ ogs_metrics_context_t *ogs_metrics_self(void) return &self; } -int ogs_metrics_context_parse_config(void) +int ogs_metrics_context_parse_config(const char *local) { return OGS_OK; } diff --git a/lib/proto/event.c b/lib/proto/event.c index 61694a942..ba8ad5074 100644 --- a/lib/proto/event.c +++ b/lib/proto/event.c @@ -65,6 +65,11 @@ const char *ogs_event_get_name(ogs_event_t *e) case OGS_EVENT_SBI_TIMER: return OGS_EVENT_NAME_SBI_TIMER; + case OGS_EVENT_DBI_POLL_TIMER: + return "OGS_EVENT_DBI_POLL_TIMER"; + case OGS_EVENT_DBI_MESSAGE: + return "OGS_EVENT_DBI_MESSAGE"; + default: break; } diff --git a/lib/proto/event.h b/lib/proto/event.h index 21445281f..51ed9ef4c 100644 --- a/lib/proto/event.h +++ b/lib/proto/event.h @@ -39,6 +39,9 @@ typedef enum { OGS_EVENT_SBI_CLIENT, OGS_EVENT_SBI_TIMER, + OGS_EVENT_DBI_POLL_TIMER, + OGS_EVENT_DBI_MESSAGE, + OGS_MAX_NUM_OF_PROTO_EVENT, } ogs_event_e; @@ -47,6 +50,8 @@ typedef struct ogs_sbi_request_s ogs_sbi_request_t; typedef struct ogs_sbi_response_s ogs_sbi_response_t; typedef struct ogs_sbi_message_s ogs_sbi_message_t; +typedef struct _bson_t bson_t; + typedef struct ogs_event_s { int id; int timer_id; @@ -59,6 +64,10 @@ typedef struct ogs_event_s { ogs_sbi_message_t *message; } sbi; + + struct { + const bson_t *document; + } dbi; } ogs_event_t; void *ogs_event_size(int id, size_t size); diff --git a/lib/proto/timer.c b/lib/proto/timer.c index 11cfcd1f4..70e74831d 100644 --- a/lib/proto/timer.c +++ b/lib/proto/timer.c @@ -47,6 +47,8 @@ const char *ogs_timer_get_name(int timer_id) return OGS_TIMER_NAME_SUBSCRIPTION_VALIDITY; case OGS_TIMER_SBI_CLIENT_WAIT: return OGS_TIMER_NAME_SBI_CLIENT_WAIT; + case OGS_TIMER_DBI_POLL_CHANGE_STREAM: + return "OGS_TIMER_DBI_POLL_CHANGE_STREAM"; default: break; } diff --git a/lib/proto/timer.h b/lib/proto/timer.h index b52092207..b027fecd3 100644 --- a/lib/proto/timer.h +++ b/lib/proto/timer.h @@ -46,6 +46,8 @@ typedef enum { OGS_TIMER_SUBSCRIPTION_VALIDITY, OGS_TIMER_SBI_CLIENT_WAIT, + OGS_TIMER_DBI_POLL_CHANGE_STREAM, + OGS_MAX_NUM_OF_PROTO_TIMER, } ogs_timer_e; diff --git a/lib/proto/types.h b/lib/proto/types.h index 225b504c2..b057591c0 100644 --- a/lib/proto/types.h +++ b/lib/proto/types.h @@ -81,6 +81,7 @@ extern "C" { #define OGS_MAX_PCO_LEN 251 #define OGS_MAX_FQDN_LEN 256 +#define OGS_MAX_NUM_OF_SERVED_GUAMI 8 #define OGS_MAX_NUM_OF_SERVED_TAI 16 #define OGS_MAX_NUM_OF_ALGORITHM 8 diff --git a/lib/sbi/client.c b/lib/sbi/client.c index 8f30ac999..e4a5290ca 100644 --- a/lib/sbi/client.c +++ b/lib/sbi/client.c @@ -44,6 +44,7 @@ typedef struct connection_s { char *memory; size_t size; + bool memory_overflow; char *location; @@ -533,6 +534,8 @@ static void check_multi_info(ogs_sbi_client_t *client) res = resource->data.result; if (res == CURLE_OK) { + ogs_log_level_e level = OGS_LOG_DEBUG; + response = ogs_sbi_response_new(); ogs_assert(response); @@ -546,7 +549,17 @@ static void check_multi_info(ogs_sbi_client_t *client) response->h.uri = ogs_strdup(url); ogs_assert(response->h.uri); - ogs_debug("[%d:%s] %s", + if (content_type) + ogs_sbi_header_set(response->http.headers, + OGS_SBI_CONTENT_TYPE, content_type); + if (conn->location) + ogs_sbi_header_set(response->http.headers, + OGS_SBI_LOCATION, conn->location); + + if (conn->memory_overflow == true) + level = OGS_LOG_ERROR; + + ogs_log_message(level, 0, "[%d:%s] %s", response->status, response->h.method, response->h.uri); if (conn->memory) { @@ -557,16 +570,17 @@ static void check_multi_info(ogs_sbi_client_t *client) ogs_assert(response->http.content_length); } - ogs_debug("RECEIVED[%d]", (int)response->http.content_length); + ogs_log_message(level, 0, "RECEIVED[%d]", + (int)response->http.content_length); if (response->http.content_length && response->http.content) - ogs_debug("%s", response->http.content); + ogs_log_message(level, 0, "%s", response->http.content); + + if (conn->memory_overflow == true) { + ogs_sbi_response_free(response); + connection_remove(conn); + break; + } - if (content_type) - ogs_sbi_header_set(response->http.headers, - OGS_SBI_CONTENT_TYPE, content_type); - if (conn->location) - ogs_sbi_header_set(response->http.headers, - OGS_SBI_LOCATION, conn->location); } else ogs_warn("[%d] %s", res, conn->error); @@ -727,8 +741,12 @@ static size_t write_cb(void *contents, size_t size, size_t nmemb, void *data) realsize = size * nmemb; ptr = ogs_realloc(conn->memory, conn->size + realsize + 1); if(!ptr) { - ogs_fatal("not enough memory (realloc returned NULL)"); - ogs_assert_if_reached(); + conn->memory_overflow = true; + + ogs_error("Overflow : conn->size[%d], realsize[%d]", + (int)conn->size, (int)realsize); + ogs_log_hexdump(OGS_LOG_ERROR, contents, realsize); + return 0; } diff --git a/lib/sbi/context.c b/lib/sbi/context.c index aa6b58dda..7346a99a6 100644 --- a/lib/sbi/context.c +++ b/lib/sbi/context.c @@ -1189,6 +1189,11 @@ ogs_sbi_nf_info_t *ogs_sbi_nf_info_add( return nf_info; } +static void amf_info_free(ogs_sbi_amf_info_t *amf_info) +{ + /* Nothing */ +} + static void smf_info_free(ogs_sbi_smf_info_t *smf_info) { int i, j; @@ -1214,6 +1219,9 @@ void ogs_sbi_nf_info_remove(ogs_list_t *list, ogs_sbi_nf_info_t *nf_info) ogs_list_remove(list, nf_info); switch(nf_info->nf_type) { + case OpenAPI_nf_type_AMF: + amf_info_free(&nf_info->amf); + break; case OpenAPI_nf_type_SMF: smf_info_free(&nf_info->smf); break; diff --git a/lib/sbi/context.h b/lib/sbi/context.h index d56a0672b..ae41a7e6e 100644 --- a/lib/sbi/context.h +++ b/lib/sbi/context.h @@ -255,12 +255,37 @@ typedef struct ogs_sbi_smf_info_s { } nr_tai_range[OGS_MAX_NUM_OF_TAI]; } ogs_sbi_smf_info_t; +typedef struct ogs_sbi_amf_info_s { + int amf_set_id; + int amf_region_id; + + int num_of_guami; + ogs_guami_t guami[OGS_MAX_NUM_OF_SERVED_GUAMI]; + + int num_of_nr_tai; + ogs_5gs_tai_t nr_tai[OGS_MAX_NUM_OF_TAI]; + + int num_of_nr_tai_range; + struct { + ogs_plmn_id_t plmn_id; + /* + * TS29.510 6.1.6.2.28 Type: TacRange + * + * Either the start and end attributes, or + * the pattern attribute, shall be present. + */ + int num_of_tac_range; + ogs_uint24_t start[OGS_MAX_NUM_OF_TAI], end[OGS_MAX_NUM_OF_TAI]; + } nr_tai_range[OGS_MAX_NUM_OF_TAI]; +} ogs_sbi_amf_info_t; + typedef struct ogs_sbi_nf_info_s { ogs_lnode_t lnode; OpenAPI_nf_type_e nf_type; union { ogs_sbi_smf_info_t smf; + ogs_sbi_amf_info_t amf; }; } ogs_sbi_nf_info_t; diff --git a/lib/sbi/nghttp2-server.c b/lib/sbi/nghttp2-server.c index 7272ac44e..9c6fc4248 100644 --- a/lib/sbi/nghttp2-server.c +++ b/lib/sbi/nghttp2-server.c @@ -82,6 +82,7 @@ typedef struct ogs_sbi_stream_s { int32_t stream_id; ogs_sbi_request_t *request; + bool memory_overflow; ogs_sbi_session_t *session; } ogs_sbi_stream_t; @@ -791,12 +792,23 @@ static int on_frame_recv(nghttp2_session *session, case NGHTTP2_DATA: /* HEADERS or DATA frame with +END_STREAM flag */ if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + ogs_log_level_e level = OGS_LOG_DEBUG; - ogs_debug("[%s] %s", request->h.method, request->h.uri); + if (stream->memory_overflow == true) + level = OGS_LOG_ERROR; + + ogs_log_message(level, 0, + "[%s] %s", request->h.method, request->h.uri); if (request->http.content_length && request->http.content) { - ogs_debug("RECEIVED: %d", (int)request->http.content_length); - ogs_debug("%s", request->http.content); + ogs_log_message(level, 0, + "RECEIVED: %d", (int)request->http.content_length); + ogs_log_message(level, 0, "%s", request->http.content); + } + + if (stream->memory_overflow == true) { + ogs_error("[DROP] Overflow"); + break; } if (server->cb(request, stream) != OGS_OK) { @@ -967,23 +979,30 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, ogs_assert(len); if (request->http.content == NULL) { - request->http.content_length = len; - request->http.content = - (char*)ogs_malloc(request->http.content_length + 1); - ogs_assert(request->http.content); + ogs_assert(request->http.content_length == 0); + ogs_assert(offset == 0); + + request->http.content = (char*)ogs_malloc(len + 1); } else { - offset = request->http.content_length; - if ((request->http.content_length + len) > OGS_HUGE_LEN) { - ogs_error("Overflow : Content-Length[%d], len[%d]", - (int)request->http.content_length, (int)len); - ogs_assert_if_reached(); - } - request->http.content_length += len; - request->http.content = (char *)ogs_realloc( - request->http.content, request->http.content_length + 1); - ogs_assert(request->http.content); + ogs_assert(request->http.content_length != 0); + + request->http.content = (char*)ogs_realloc( + request->http.content, request->http.content_length + len + 1); } + if (!request->http.content) { + stream->memory_overflow = true; + + ogs_error("Overflow : Content-Length[%d], len[%d]", + (int)request->http.content_length, (int)len); + ogs_log_hexdump(OGS_LOG_ERROR, data, len); + + return 0; + } + + offset = request->http.content_length; + request->http.content_length += len; + memcpy(request->http.content + offset, data, len); request->http.content[request->http.content_length] = '\0'; diff --git a/lib/sbi/nnrf-build.c b/lib/sbi/nnrf-build.c index 5a69eb66e..2e2808b2d 100644 --- a/lib/sbi/nnrf-build.c +++ b/lib/sbi/nnrf-build.c @@ -23,7 +23,9 @@ static OpenAPI_nf_service_t *build_nf_service( ogs_sbi_nf_service_t *nf_service); static void free_nf_service(OpenAPI_nf_service_t *NFService); static OpenAPI_smf_info_t *build_smf_info(ogs_sbi_nf_info_t *nf_info); +static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info); static void free_smf_info(OpenAPI_smf_info_t *SmfInfo); +static void free_amf_info(OpenAPI_amf_info_t *AmfInfo); ogs_sbi_request_t *ogs_nnrf_nfm_build_register(void) { @@ -79,13 +81,15 @@ OpenAPI_nf_profile_t *ogs_nnrf_nfm_build_nf_profile( OpenAPI_list_t *AllowedNfTypeList = NULL; OpenAPI_list_t *NFServiceList = NULL; OpenAPI_map_t *NFServiceMap = NULL; - OpenAPI_list_t *SmfInfoList = NULL; - OpenAPI_map_t *SmfInfoMap = NULL; + OpenAPI_list_t *InfoList = NULL; + OpenAPI_map_t *InfoMap = NULL; OpenAPI_smf_info_t *SmfInfo = NULL; - int SmfInfoMapKey; + int InfoMapKey; OpenAPI_lnode_t *node = NULL; + OpenAPI_amf_info_t *AmfInfo = NULL; + int i = 0; char *ipstr = NULL; @@ -222,10 +226,10 @@ OpenAPI_nf_profile_t *ogs_nnrf_nfm_build_nf_profile( } else OpenAPI_list_free(NFServiceList); - SmfInfoList = OpenAPI_list_create(); - ogs_assert(SmfInfoList); + InfoList = OpenAPI_list_create(); + ogs_assert(InfoList); - SmfInfoMapKey = 0; + InfoMapKey = 0; ogs_list_for_each(&nf_instance->nf_info_list, nf_info) { if (nf_info->nf_type == OpenAPI_nf_type_SMF) { @@ -238,11 +242,21 @@ OpenAPI_nf_profile_t *ogs_nnrf_nfm_build_nf_profile( SmfInfo = build_smf_info(nf_info); ogs_expect_or_return_val(SmfInfo, NULL); - SmfInfoMap = OpenAPI_map_create( - ogs_msprintf("%d", ++SmfInfoMapKey), SmfInfo); - ogs_assert(SmfInfoMap); + InfoMap = OpenAPI_map_create( + ogs_msprintf("%d", ++InfoMapKey), SmfInfo); + ogs_assert(InfoMap); - OpenAPI_list_add(SmfInfoList, SmfInfoMap); + OpenAPI_list_add(InfoList, InfoMap); + + } else if (nf_info->nf_type == OpenAPI_nf_type_AMF) { + AmfInfo = build_amf_info(nf_info); + ogs_expect_or_return_val(AmfInfo, NULL); + + InfoMap = OpenAPI_map_create( + ogs_msprintf("%d", ++InfoMapKey), AmfInfo); + ogs_assert(InfoMap); + + OpenAPI_list_add(InfoList, InfoMap); } else { ogs_fatal("Not implemented NF-type[%s]", @@ -250,23 +264,37 @@ OpenAPI_nf_profile_t *ogs_nnrf_nfm_build_nf_profile( ogs_assert_if_reached(); } } - - if (SmfInfoList->count == 1) { - NFProfile->smf_info = SmfInfo; - - OpenAPI_list_for_each(SmfInfoList, node) { - SmfInfoMap = node->data; - if (SmfInfoMap) { - if (SmfInfoMap->key) - ogs_free(SmfInfoMap->key); - ogs_free(SmfInfoMap); + if (InfoList->count == 1) { + if (nf_instance->nf_type == OpenAPI_nf_type_SMF) { + NFProfile->smf_info = SmfInfo; + } else if (nf_instance->nf_type == OpenAPI_nf_type_AMF) { + NFProfile->amf_info = AmfInfo; + } else { + ogs_fatal("Not implemented NF-type[%s]", + OpenAPI_nf_type_ToString(nf_instance->nf_type)); + ogs_assert_if_reached(); + } + OpenAPI_list_for_each(InfoList, node) { + InfoMap = node->data; + if (InfoMap) { + if (InfoMap->key) + ogs_free(InfoMap->key); + ogs_free(InfoMap); } } - OpenAPI_list_free(SmfInfoList); - } else if (SmfInfoList->count > 1) { - NFProfile->smf_info_list = SmfInfoList; + OpenAPI_list_free(InfoList); + } else if (InfoList->count > 1) { + if (nf_instance->nf_type == OpenAPI_nf_type_SMF) { + NFProfile->smf_info_list = InfoList; + } else if (nf_instance->nf_type == OpenAPI_nf_type_AMF) { + NFProfile->amf_info_list = InfoList; + } else { + ogs_fatal("Not implemented NF-type[%s]", + OpenAPI_nf_type_ToString(nf_instance->nf_type)); + ogs_assert_if_reached(); + } } else - OpenAPI_list_free(SmfInfoList); + OpenAPI_list_free(InfoList); return NFProfile; } @@ -277,6 +305,8 @@ void ogs_nnrf_nfm_free_nf_profile(OpenAPI_nf_profile_t *NFProfile) OpenAPI_nf_service_t *NFService = NULL; OpenAPI_map_t *SmfInfoMap = NULL; OpenAPI_smf_info_t *SmfInfo = NULL; + OpenAPI_map_t *AmfInfoMap = NULL; + OpenAPI_amf_info_t *AmfInfo = NULL; OpenAPI_lnode_t *node = NULL; ogs_assert(NFProfile); @@ -327,6 +357,22 @@ void ogs_nnrf_nfm_free_nf_profile(OpenAPI_nf_profile_t *NFProfile) if (NFProfile->smf_info) free_smf_info(NFProfile->smf_info); + OpenAPI_list_for_each(NFProfile->amf_info_list, node) { + AmfInfoMap = node->data; + if (AmfInfoMap) { + AmfInfo = AmfInfoMap->value; + if (AmfInfo) + free_amf_info(AmfInfo); + if (AmfInfoMap->key) + ogs_free(AmfInfoMap->key); + ogs_free(AmfInfoMap); + } + } + OpenAPI_list_free(NFProfile->amf_info_list); + + if (NFProfile->amf_info) + free_amf_info(NFProfile->amf_info); + ogs_free(NFProfile); } @@ -622,6 +668,124 @@ static OpenAPI_smf_info_t *build_smf_info(ogs_sbi_nf_info_t *nf_info) return SmfInfo; } +static OpenAPI_amf_info_t *build_amf_info(ogs_sbi_nf_info_t *nf_info) +{ + int i, j; + OpenAPI_amf_info_t *AmfInfo = NULL; + + OpenAPI_list_t *guamiAmfInfoList = NULL; + OpenAPI_guami_t *guamiAmfInfoItem = NULL; + + OpenAPI_list_t *TaiList = NULL; + OpenAPI_tai_t *TaiItem = NULL; + OpenAPI_list_t *TaiRangeList = NULL; + OpenAPI_tai_range_t *TaiRangeItem = NULL; + OpenAPI_list_t *TacRangeList = NULL; + OpenAPI_tac_range_t *TacRangeItem = NULL; + + ogs_assert(nf_info); + + AmfInfo = ogs_calloc(1, sizeof(*AmfInfo)); + ogs_expect_or_return_val(AmfInfo, NULL); + + AmfInfo->amf_set_id = ogs_msprintf("%03x", nf_info->amf.amf_set_id); + AmfInfo->amf_region_id = ogs_msprintf("%02x", nf_info->amf.amf_region_id); + + guamiAmfInfoList = OpenAPI_list_create(); + ogs_assert(guamiAmfInfoList); + + for (i = 0; i < nf_info->amf.num_of_guami; i++) { + + guamiAmfInfoItem = ogs_calloc(1, sizeof(*guamiAmfInfoItem)); + ogs_expect_or_return_val(guamiAmfInfoItem, NULL); + + guamiAmfInfoItem->plmn_id = + ogs_sbi_build_plmn_id_nid(&nf_info->amf.guami[i].plmn_id); + ogs_expect_or_return_val(guamiAmfInfoItem->plmn_id, NULL); + guamiAmfInfoItem->amf_id = + ogs_amf_id_to_string(&nf_info->amf.guami[i].amf_id); + ogs_expect_or_return_val(guamiAmfInfoItem->amf_id, NULL); + + OpenAPI_list_add(guamiAmfInfoList, guamiAmfInfoItem); + } + + if (guamiAmfInfoList->count) + AmfInfo->guami_list = guamiAmfInfoList; + else + OpenAPI_list_free(guamiAmfInfoList); + + TaiList = OpenAPI_list_create(); + ogs_assert(TaiList); + + for (i = 0; i < nf_info->amf.num_of_nr_tai; i++) { + TaiItem = ogs_calloc(1, sizeof(*TaiItem)); + ogs_expect_or_return_val(TaiItem, NULL); + TaiItem->plmn_id = ogs_sbi_build_plmn_id( + &nf_info->amf.nr_tai[i].plmn_id); + ogs_expect_or_return_val(TaiItem->plmn_id, NULL); + TaiItem->tac = + ogs_uint24_to_0string(nf_info->amf.nr_tai[i].tac); + ogs_expect_or_return_val(TaiItem->tac, NULL); + + OpenAPI_list_add(TaiList, TaiItem); + } + + if (TaiList->count) + AmfInfo->tai_list = TaiList; + else + OpenAPI_list_free(TaiList); + + TaiRangeList = OpenAPI_list_create(); + ogs_assert(TaiRangeList); + + for (i = 0; i < nf_info->amf.num_of_nr_tai_range; i++) { + TacRangeList = OpenAPI_list_create(); + ogs_assert(TacRangeList); + + for (j = 0; + j < nf_info->amf.nr_tai_range[i].num_of_tac_range; + j++) { + TacRangeItem = ogs_calloc(1, sizeof(*TacRangeItem)); + ogs_expect_or_return_val(TacRangeItem, NULL); + + TacRangeItem->start = ogs_uint24_to_0string( + nf_info->amf.nr_tai_range[i].start[j]); + ogs_expect_or_return_val(TacRangeItem->start, NULL); + TacRangeItem->end = + ogs_uint24_to_0string( + nf_info->amf.nr_tai_range[i].end[j]); + ogs_expect_or_return_val(TacRangeItem->end, NULL); + + OpenAPI_list_add(TacRangeList, TacRangeItem); + } + + if (!TacRangeList->count) { + OpenAPI_list_free(TacRangeList); + + ogs_error("CHECK CONFIGURATION: No Start/End in TacRange"); + ogs_expect_or_return_val(0, NULL); + } + + TaiRangeItem = ogs_calloc(1, sizeof(*TaiRangeItem)); + ogs_expect_or_return_val(TaiRangeItem, NULL); + + TaiRangeItem->plmn_id = ogs_sbi_build_plmn_id( + &nf_info->amf.nr_tai_range[i].plmn_id); + ogs_expect_or_return_val(TaiRangeItem->plmn_id, NULL); + + TaiRangeItem->tac_range_list = TacRangeList; + + OpenAPI_list_add(TaiRangeList, TaiRangeItem); + } + + if (TaiRangeList->count) + AmfInfo->tai_range_list = TaiRangeList; + else + OpenAPI_list_free(TaiRangeList); + + return AmfInfo; +} + static void free_smf_info(OpenAPI_smf_info_t *SmfInfo) { OpenAPI_list_t *sNssaiSmfInfoList = NULL; @@ -705,6 +869,84 @@ static void free_smf_info(OpenAPI_smf_info_t *SmfInfo) ogs_free(SmfInfo); } +static void free_amf_info(OpenAPI_amf_info_t *AmfInfo) +{ + OpenAPI_list_t *guamiAmfInfoList = NULL; + OpenAPI_guami_t *guamiAmfInfoItem = NULL; + + OpenAPI_list_t *TaiList = NULL; + OpenAPI_tai_t *TaiItem = NULL; + OpenAPI_list_t *TaiRangeList = NULL; + OpenAPI_tai_range_t *TaiRangeItem = NULL; + OpenAPI_list_t *TacRangeList = NULL; + OpenAPI_tac_range_t *TacRangeItem = NULL; + + OpenAPI_lnode_t *node = NULL, *node2 = NULL; + + ogs_assert(AmfInfo); + + ogs_free(AmfInfo->amf_set_id); + ogs_free(AmfInfo->amf_region_id); + + guamiAmfInfoList = AmfInfo->guami_list; + OpenAPI_list_for_each(guamiAmfInfoList, node) { + guamiAmfInfoItem = node->data; + if (guamiAmfInfoItem) { + if (guamiAmfInfoItem->plmn_id) { + if (guamiAmfInfoItem->plmn_id->mcc) + ogs_free(guamiAmfInfoItem->plmn_id->mcc); + if (guamiAmfInfoItem->plmn_id->mnc) + ogs_free(guamiAmfInfoItem->plmn_id->mnc); + ogs_free(guamiAmfInfoItem->plmn_id); + } + if (guamiAmfInfoItem->amf_id) + ogs_free(guamiAmfInfoItem->amf_id); + } + ogs_free(guamiAmfInfoItem); + } + + OpenAPI_list_free(guamiAmfInfoList); + + TaiList = AmfInfo->tai_list; + OpenAPI_list_for_each(TaiList, node) { + TaiItem = node->data; + ogs_assert(TaiItem); + if (TaiItem->plmn_id) + ogs_sbi_free_plmn_id(TaiItem->plmn_id); + if (TaiItem->tac) + ogs_free(TaiItem->tac); + ogs_free(TaiItem); + } + OpenAPI_list_free(TaiList); + + TaiRangeList = AmfInfo->tai_range_list; + OpenAPI_list_for_each(TaiRangeList, node) { + TaiRangeItem = node->data; + ogs_assert(TaiRangeItem); + + if (TaiRangeItem->plmn_id) + ogs_sbi_free_plmn_id(TaiRangeItem->plmn_id); + + TacRangeList = TaiRangeItem->tac_range_list; + OpenAPI_list_for_each(TacRangeList, node2) { + TacRangeItem = node2->data; + ogs_assert(TacRangeItem); + if (TacRangeItem->start) + ogs_free(TacRangeItem->start); + if (TacRangeItem->end) + ogs_free(TacRangeItem->end); + + ogs_free(TacRangeItem); + } + OpenAPI_list_free(TacRangeList); + + ogs_free(TaiRangeItem); + } + OpenAPI_list_free(TaiRangeList); + + ogs_free(AmfInfo); +} + ogs_sbi_request_t *ogs_nnrf_nfm_build_update(void) { ogs_sbi_nf_instance_t *nf_instance = NULL; diff --git a/src/amf/context.c b/src/amf/context.c index e0ccf7b6c..719d4fb6c 100644 --- a/src/amf/context.c +++ b/src/amf/context.c @@ -330,7 +330,7 @@ int amf_context_parse_config(void) const char *region = NULL, *set = NULL; const char *pointer = NULL; ogs_assert(self.num_of_served_guami < - MAX_NUM_OF_SERVED_GUAMI); + OGS_MAX_NUM_OF_SERVED_GUAMI); if (ogs_yaml_iter_type(&guami_array) == YAML_MAPPING_NODE) { @@ -825,6 +825,8 @@ int amf_context_parse_config(void) /* handle config in sbi library */ } else if (!strcmp(amf_key, "discovery")) { /* handle config in sbi library */ + } else if (!strcmp(amf_key, "metrics")) { + /* handle config in metrics library */ } else ogs_warn("unknown key `%s`", amf_key); } @@ -837,6 +839,97 @@ int amf_context_parse_config(void) return OGS_OK; } +int amf_context_nf_info(void) +{ + ogs_sbi_nf_instance_t *nf_instance = NULL; + ogs_sbi_nf_info_t *nf_info = NULL; + + int served_i, next_new_i, info_i; + bool next_found; + served_i = 0; + next_new_i = 0; + next_found = false; + do { + nf_instance = ogs_sbi_self()->nf_instance; + ogs_assert(nf_instance); + + nf_info = ogs_sbi_nf_info_add( + &nf_instance->nf_info_list, OpenAPI_nf_type_AMF); + ogs_assert(nf_info); + nf_info->amf.amf_set_id = self.served_guami[next_new_i].amf_id.set2; + nf_info->amf.amf_region_id = self.served_guami[next_new_i].amf_id.region; + next_found = false; + info_i = 0; + for (served_i = next_new_i; served_i < + self.num_of_served_guami; served_i++) { + if (self.served_guami[served_i].amf_id.set2 == + nf_info->amf.amf_set_id && + self.served_guami[served_i].amf_id.region == + nf_info->amf.amf_region_id) { + nf_info->amf.guami[info_i] = self.served_guami[served_i]; + nf_info->amf.num_of_guami++; + info_i++; + } else { + if (!next_found) { + int handled_i; + for (handled_i = 0; handled_i < served_i; handled_i++) { + if (self.served_guami[handled_i].amf_id.set2 == + self.served_guami[served_i].amf_id.set2 && + self.served_guami[handled_i].amf_id.region == + self.served_guami[served_i].amf_id.region) { + break; + } + next_found = true; + next_new_i = served_i; + } + } + } + } + + nf_info->amf.num_of_nr_tai = 0; + int i = 0, j = 0, info_tai_i = 0; + for (i = 0; i < self.num_of_served_tai; i++) { + if (self.served_tai[i].list2.num) { + for (j = 0; j < self.served_tai[i].list2.num; j++) { + for (served_i = 0; served_i < info_i; served_i++) { + if (ogs_plmn_id_hexdump + (&self.served_tai[i].list2.tai[j].plmn_id) == + ogs_plmn_id_hexdump + (&nf_info->amf.guami[served_i].plmn_id)) { + nf_info->amf.nr_tai[info_tai_i].plmn_id = + self.served_tai[i].list2.tai[j].plmn_id; + nf_info->amf.nr_tai[info_tai_i].tac = + self.served_tai[i].list2.tai[j].tac; + nf_info->amf.num_of_nr_tai++; + info_tai_i++; + } + } + } + } + for (j = 0; self.served_tai[i].list0.tai[j].num; j++) { + int k = 0; + for (k = 0; k < self.served_tai[i].list0.tai[j].num; k++) { + for (served_i = 0; served_i < info_i; served_i++) { + if (ogs_plmn_id_hexdump + (&self.served_tai[i].list0.tai[j].plmn_id) == + ogs_plmn_id_hexdump + (&nf_info->amf.guami[served_i].plmn_id)) { + nf_info->amf.nr_tai[info_tai_i].plmn_id = + self.served_tai[i].list0.tai[j].plmn_id; + nf_info->amf.nr_tai[info_tai_i].tac = + self.served_tai[i].list0.tai[j].tac[k]; + nf_info->amf.num_of_nr_tai++; + info_tai_i++; + } + } + } + } + } + } while (next_found); + + return OGS_OK; +} + amf_gnb_t *amf_gnb_add(ogs_sock_t *sock, ogs_sockaddr_t *addr) { amf_gnb_t *gnb = NULL; diff --git a/src/amf/context.h b/src/amf/context.h index 63e12980c..4a209b4c9 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -34,8 +34,6 @@ extern "C" { #endif -#define MAX_NUM_OF_SERVED_GUAMI 8 - extern int __amf_log_domain; extern int __gmm_log_domain; @@ -50,7 +48,7 @@ typedef uint32_t amf_m_tmsi_t; typedef struct amf_context_s { /* Served GUAMI */ uint8_t num_of_served_guami; - ogs_guami_t served_guami[MAX_NUM_OF_SERVED_GUAMI]; + ogs_guami_t served_guami[OGS_MAX_NUM_OF_SERVED_GUAMI]; /* Served TAI */ uint8_t num_of_served_tai; @@ -613,6 +611,7 @@ void amf_context_final(void); amf_context_t *amf_self(void); int amf_context_parse_config(void); +int amf_context_nf_info(void); amf_gnb_t *amf_gnb_add(ogs_sock_t *sock, ogs_sockaddr_t *addr); void amf_gnb_remove(amf_gnb_t *gnb); diff --git a/src/amf/init.c b/src/amf/init.c index a51c64b41..8519e9fd5 100644 --- a/src/amf/init.c +++ b/src/amf/init.c @@ -37,12 +37,15 @@ int amf_initialize() rv = ogs_sbi_context_parse_config("amf", "nrf", "scp"); if (rv != OGS_OK) return rv; - rv = ogs_metrics_context_parse_config(); + rv = ogs_metrics_context_parse_config("amf"); if (rv != OGS_OK) return rv; rv = amf_context_parse_config(); if (rv != OGS_OK) return rv; + rv = amf_context_nf_info(); + if (rv != OGS_OK) return rv; + rv = amf_m_tmsi_pool_generate(); if (rv != OGS_OK) return rv; diff --git a/src/ausf/context.h b/src/ausf/context.h index 5470b9b6b..cb38789c7 100644 --- a/src/ausf/context.h +++ b/src/ausf/context.h @@ -30,8 +30,6 @@ extern "C" { #endif -#define MAX_NUM_OF_SERVED_GUAMI 8 - extern int __ausf_log_domain; #undef OGS_LOG_DOMAIN diff --git a/src/hss/hss-context.c b/src/hss/hss-context.c index 9eb372f70..f11430112 100644 --- a/src/hss/hss-context.c +++ b/src/hss/hss-context.c @@ -19,6 +19,9 @@ #include "ogs-dbi.h" #include "hss-context.h" +#include "hss-event.h" +#include "hss-s6a-path.h" + typedef struct hss_impi_s hss_impi_t; @@ -680,7 +683,7 @@ void hss_cx_associate_identity(char *user_name, char *public_identity) { hss_impi_t *impi = NULL; hss_impu_t *impu = NULL; - + ogs_assert(user_name); ogs_assert(public_identity); @@ -1171,3 +1174,134 @@ char *hss_cx_download_user_data( return user_data; } + +int hss_db_poll_change_stream(void) +{ + int rv; + + ogs_thread_mutex_lock(&self.db_lock); + + rv = ogs_dbi_poll_change_stream(); + + ogs_thread_mutex_unlock(&self.db_lock); + + return rv; +} + +int hss_handle_change_event(const bson_t *document) +{ + bson_iter_t iter, child1_iter, child2_iter, child3_iter; + + char *utf8 = NULL; + uint32_t length = 0; + + bool send_clr_flag = false; + bool send_idr_flag = false; + uint32_t subdatamask = 0; + + char *imsi_bcd; + + char *as_json = bson_as_relaxed_extended_json(document, NULL); + ogs_debug("Got document: %s\n", as_json); + if (!bson_iter_init_find(&iter, document, "fullDocument")) { + ogs_error("No 'imsi' field in this document."); + return OGS_ERROR; + } else { + bson_iter_recurse(&iter, &child1_iter); + while (bson_iter_next(&child1_iter)) { + const char *key = bson_iter_key(&child1_iter); + if (!strcmp(key, "imsi") && + BSON_ITER_HOLDS_UTF8(&child1_iter)) { + utf8 = (char *)bson_iter_utf8(&child1_iter, &length); + imsi_bcd = ogs_strndup(utf8, + ogs_min(length, OGS_MAX_IMSI_BCD_LEN) + 1); + ogs_assert(imsi_bcd); + } + } + } + + if (!imsi_bcd) { + ogs_error("No 'imsi' field in this document."); + return OGS_ERROR; + } + + if (bson_iter_init_find(&iter, document, "updateDescription")) { + bson_iter_recurse(&iter, &child1_iter); + while (bson_iter_next(&child1_iter)) { + const char *key = bson_iter_key(&child1_iter); + if (!strcmp(key, "updatedFields") && + BSON_ITER_HOLDS_DOCUMENT(&child1_iter)) { + bson_iter_recurse(&child1_iter, &child2_iter); + while (bson_iter_next(&child2_iter)) { + const char *child2_key = bson_iter_key(&child2_iter); + if (!strcmp(child2_key, + "request_cancel_location") && + BSON_ITER_HOLDS_BOOL(&child2_iter)) { + send_clr_flag = (char *)bson_iter_bool(&child2_iter); + } else if (!strncmp(child2_key, "msisdn", + strlen("msisdn"))) { + int msisdn_count = 0; + bson_iter_recurse(&child2_iter, &child3_iter); + while (bson_iter_next(&child3_iter)) { + if (BSON_ITER_HOLDS_UTF8(&child3_iter)) { + msisdn_count++; + } + } + if (msisdn_count) { + send_idr_flag = true; + subdatamask = (subdatamask | + OGS_HSS_SUBDATA_MSISDN); + } else { + send_clr_flag = true; + } + } else if (!strncmp(child2_key, + "access_restriction_data", + strlen("access_restriction_data"))) { + send_idr_flag = true; + subdatamask = (subdatamask | OGS_HSS_SUBDATA_ARD); + } else if (!strncmp(child2_key, + "subscriber_status", + strlen("subscriber_status"))) { + send_idr_flag = true; + subdatamask = (subdatamask | + OGS_HSS_SUBDATA_SUB_STATUS); + } else if (!strncmp(child2_key, + "network_access_mode", + strlen("network_access_mode"))) { + send_idr_flag = true; + subdatamask = (subdatamask | OGS_HSS_SUBDATA_NAM); + } else if (!strncmp(child2_key, "ambr", strlen("ambr"))) { + send_idr_flag = true; + subdatamask = (subdatamask | OGS_HSS_SUBDATA_UEAMBR); + } else if (!strncmp(child2_key, + "subscribed_rau_tau_timer", + strlen("subscribed_rau_tau_timer"))) { + send_idr_flag = true; + subdatamask = (subdatamask | + OGS_HSS_SUBDATA_RAU_TAU_TIMER); + } else if (!strncmp(child2_key, "slice", strlen("slice"))) { + send_idr_flag = true; + subdatamask = (subdatamask | OGS_HSS_SUBDATA_SLICE); + } + } + } + } + } else { + ogs_debug("No 'updateDescription' field in this document"); + } + + bson_free (as_json); + + if (send_clr_flag) { + ogs_info("[%s] Cancel Location Requested", imsi_bcd); + hss_s6a_send_clr(imsi_bcd, NULL, NULL, + OGS_DIAM_S6A_CT_SUBSCRIPTION_WITHDRAWL); + } else if (send_idr_flag) { + ogs_info("[%s] Subscription-Data Changed", imsi_bcd); + hss_s6a_send_idr(imsi_bcd, 0, subdatamask); + } + + ogs_free(imsi_bcd); + + return OGS_OK; +} diff --git a/src/hss/hss-context.h b/src/hss/hss-context.h index 8e1318c5c..decb94b6d 100644 --- a/src/hss/hss-context.h +++ b/src/hss/hss-context.h @@ -92,6 +92,9 @@ char *hss_cx_download_user_data( char *user_name, char *visited_network_identifier, ogs_ims_data_t *ims_data); +int hss_db_poll_change_stream(void); +int hss_handle_change_event(const bson_t *document); + #ifdef __cplusplus } diff --git a/src/hss/hss-event.c b/src/hss/hss-event.c new file mode 100644 index 000000000..a3c783cf0 --- /dev/null +++ b/src/hss/hss-event.c @@ -0,0 +1,27 @@ +/* + * 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 "hss-event.h" +#include "ogs-app.h" + +void hss_event_term(void) +{ + ogs_queue_term(ogs_app()->queue); + ogs_pollset_notify(ogs_app()->pollset); +} diff --git a/src/hss/hss-event.h b/src/hss/hss-event.h new file mode 100644 index 000000000..91e4fe417 --- /dev/null +++ b/src/hss/hss-event.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 HSS_EVENT_H +#define HSS_EVENT_H + +#include "ogs-core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void hss_event_term(void); + +#ifdef __cplusplus +} +#endif + +#endif /* HSS_EVENT_H */ diff --git a/src/hss/hss-fd-path.h b/src/hss/hss-fd-path.h index b8bf8c2bd..3f88c35e7 100644 --- a/src/hss/hss-fd-path.h +++ b/src/hss/hss-fd-path.h @@ -39,4 +39,3 @@ void hss_swx_final(void); #endif #endif /* HSS_FD_PATH_H */ - diff --git a/src/hss/hss-init.c b/src/hss/hss-init.c index cf77babb9..2a29b0f19 100644 --- a/src/hss/hss-init.c +++ b/src/hss/hss-init.c @@ -19,6 +19,11 @@ #include "hss-context.h" #include "hss-fd-path.h" +#include "hss-sm.h" + + +static ogs_thread_t *thread; +static void hss_main(void *data); static int initialized = 0; @@ -41,6 +46,9 @@ int hss_initialize(void) rv = hss_fd_init(); if (rv != OGS_OK) return OGS_ERROR; + thread = ogs_thread_create(hss_main, NULL); + if (!thread) return OGS_ERROR; + initialized = 1; return OGS_OK; @@ -50,6 +58,9 @@ void hss_terminate(void) { if (!initialized) return; + hss_event_term(); + ogs_thread_destroy(thread); + hss_fd_final(); ogs_dbi_final(); @@ -57,3 +68,49 @@ void hss_terminate(void) return; } + +static void hss_main(void *data) +{ + ogs_fsm_t hss_sm; + int rv; + + ogs_fsm_init(&hss_sm, hss_state_initial, hss_state_final, 0); + + for ( ;; ) { + ogs_pollset_poll(ogs_app()->pollset, + ogs_timer_mgr_next(ogs_app()->timer_mgr)); + + /* + * After ogs_pollset_poll(), ogs_timer_mgr_expire() must be called. + * + * The reason is why ogs_timer_mgr_next() can get the corrent value + * when ogs_timer_stop() is called internally in ogs_timer_mgr_expire(). + * + * You should not use event-queue before ogs_timer_mgr_expire(). + * In this case, ogs_timer_mgr_expire() does not work + * because 'if rv == OGS_DONE' statement is exiting and + * not calling ogs_timer_mgr_expire(). + */ + ogs_timer_mgr_expire(ogs_app()->timer_mgr); + + for ( ;; ) { + ogs_event_t *e = NULL; + + rv = ogs_queue_trypop(ogs_app()->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(&hss_sm, e); + ogs_event_free(e); + } + } +done: + + ogs_fsm_fini(&hss_sm, 0); +} diff --git a/src/hss/hss-s6a-path.c b/src/hss/hss-s6a-path.c index 1d3f49c7d..ff9abd6f3 100644 --- a/src/hss/hss-s6a-path.c +++ b/src/hss/hss-s6a-path.c @@ -719,7 +719,7 @@ static int hss_s6a_avp_add_subscription_data( ret = fd_msg_avp_add(apn_configuration_profile, MSG_BRW_LAST_CHILD, apn_configuration); ogs_assert(ret == 0); - + } ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, apn_configuration_profile); @@ -825,7 +825,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp, ogs_assert(mme_host); ogs_assert(mme_realm); - /* If UE is not purged at MME, determine if the MME sending the ULR + /* If UE is not purged at MME, determine if the MME sending the ULR * is different from the one that was last used. if so, send CLR. */ if (subscription_data.mme_host != NULL && @@ -1269,6 +1269,7 @@ void hss_s6a_send_clr(char *imsi_bcd, char *mme_host, char *mme_realm, 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); + } /* HSS received Cancel Location Answer from MME */ @@ -1286,7 +1287,7 @@ static void hss_s6a_cla_cb(void *data, struct msg **msg) ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); ogs_expect_or_return(ret == 0); ogs_expect_or_return(new == 0); - + ret = fd_sess_state_retrieve(hss_s6a_reg, session, &sess_data); ogs_expect_or_return(ret == 0); ogs_expect_or_return(sess_data); @@ -1326,8 +1327,8 @@ int hss_s6a_send_idr(char *imsi_bcd, uint32_t idr_flags, uint32_t subdatamask) if (subscription_data.purge_flag) { ogs_error(" [%s] UE Purged at MME. Cannot send IDR.", imsi_bcd); - return OGS_ERROR; - } + return OGS_ERROR; + } /* Create the random value to store with the session */ sess_data = ogs_calloc(1, sizeof(*sess_data)); @@ -1405,7 +1406,7 @@ int hss_s6a_send_idr(char *imsi_bcd, uint32_t idr_flags, uint32_t subdatamask) ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); ogs_assert(ret == 0); } - + /* Set the Subscription Data */ ret = fd_msg_avp_new(ogs_diam_s6a_subscription_data, 0, &avp); ogs_assert(ret == 0); @@ -1415,11 +1416,11 @@ int hss_s6a_send_idr(char *imsi_bcd, uint32_t idr_flags, uint32_t subdatamask) if (ret != OGS_OK) { ogs_error(" [%s] Could not build Subscription-Data.", imsi_bcd); - return OGS_ERROR; + return OGS_ERROR; } } ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); - ogs_assert(ret == 0); + ogs_assert(ret == 0); /* Set Vendor-Specific-Application-Id AVP */ ret = ogs_diam_message_vendor_specific_appid_set( @@ -1464,7 +1465,7 @@ static void hss_s6a_ida_cb(void *data, struct msg **msg) ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); ogs_expect_or_return(ret == 0); ogs_expect_or_return(new == 0); - + ret = fd_sess_state_retrieve(hss_s6a_reg, session, &sess_data); ogs_expect_or_return(ret == 0); ogs_expect_or_return(sess_data); @@ -1527,7 +1528,7 @@ int hss_s6a_init(void) void hss_s6a_final(void) { int ret; - + ret = fd_sess_handler_destroy(&hss_s6a_reg, NULL); ogs_assert(ret == OGS_OK); diff --git a/src/hss/hss-sm.c b/src/hss/hss-sm.c new file mode 100644 index 000000000..60ce6d4ea --- /dev/null +++ b/src/hss/hss-sm.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2019-2022 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 "hss-sm.h" +#include "hss-context.h" +#include "hss-event.h" + +#define DB_POLLING_TIME ogs_time_from_msec(100) + +static ogs_timer_t *t_db_polling = NULL; + +void hss_state_initial(ogs_fsm_t *s, ogs_event_t *e) +{ + hss_sm_debug(e); + + ogs_assert(s); + + if (ogs_app()->use_mongodb_change_stream) { + ogs_dbi_collection_watch_init(); + + t_db_polling = ogs_timer_add(ogs_app()->timer_mgr, + ogs_timer_dbi_poll_change_stream, 0); + ogs_assert(t_db_polling); + ogs_timer_start(t_db_polling, DB_POLLING_TIME); + + OGS_FSM_TRAN(s, &hss_state_operational); + } +} + +void hss_state_final(ogs_fsm_t *s, ogs_event_t *e) +{ + hss_sm_debug(e); + + if (t_db_polling) + ogs_timer_delete(t_db_polling); + + ogs_assert(s); +} + +void hss_state_operational(ogs_fsm_t *s, ogs_event_t *e) +{ + hss_sm_debug(e); + + ogs_assert(s); + + switch (e->id) { + case OGS_FSM_ENTRY_SIG: + break; + + case OGS_FSM_EXIT_SIG: + if (t_db_polling) { + ogs_timer_stop(t_db_polling); + } + break; + + case OGS_EVENT_DBI_POLL_TIMER: + ogs_assert(e); + + switch(e->timer_id) { + case OGS_TIMER_DBI_POLL_CHANGE_STREAM: + hss_db_poll_change_stream(); + ogs_timer_start(t_db_polling, DB_POLLING_TIME); + break; + + default: + ogs_error("Unknown timer[%s:%d]", + ogs_timer_get_name(e->timer_id), e->timer_id); + } + break; + + case OGS_EVENT_DBI_MESSAGE: + ogs_assert(e); + + ogs_assert(e->dbi.document); + hss_handle_change_event(e->dbi.document); + + bson_destroy((bson_t*)e->dbi.document); + break; + + default: + ogs_error("No handler for event %s", ogs_event_get_name(e)); + break; + } +} diff --git a/src/hss/hss-sm.h b/src/hss/hss-sm.h new file mode 100644 index 000000000..ce18d30fa --- /dev/null +++ b/src/hss/hss-sm.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019-2022 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 HSS_SM_H +#define HSS_SM_H + +#include "hss-event.h" +#include "ogs-proto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void hss_state_initial(ogs_fsm_t *s, ogs_event_t *e); +void hss_state_final(ogs_fsm_t *s, ogs_event_t *e); +void hss_state_operational(ogs_fsm_t *s, ogs_event_t *e); +void hss_state_exception(ogs_fsm_t *s, ogs_event_t *e); + +#define hss_sm_debug(__pe) \ + ogs_debug("%s(): %s", __func__, ogs_event_get_name(__pe)) + +#ifdef __cplusplus +} +#endif + +#endif /* HSS_SM_H */ diff --git a/src/hss/meson.build b/src/hss/meson.build index cd52f987c..f2b6ce57c 100644 --- a/src/hss/meson.build +++ b/src/hss/meson.build @@ -19,9 +19,13 @@ libhss_sources = files(''' hss-context.h hss-fd-path.h hss-s6a-path.h + hss-event.h + hss-sm.h hss-init.c hss-context.c + hss-event.c + hss-sm.c hss-s6a-path.c hss-cx-path.c diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index c1cc9abcb..5368f1f2e 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -1277,6 +1277,8 @@ int mme_context_parse_config() YAML_SEQUENCE_NODE); } else if (!strcmp(mme_key, "mme_name")) { self.mme_name = ogs_yaml_iter_value(&mme_iter); + } else if (!strcmp(mme_key, "metrics")) { + /* handle config in metrics library */ } else ogs_warn("unknown key `%s`", mme_key); } diff --git a/src/mme/mme-init.c b/src/mme/mme-init.c index 44e4f3ec9..82173d38e 100644 --- a/src/mme/mme-init.c +++ b/src/mme/mme-init.c @@ -49,7 +49,7 @@ int mme_initialize() rv = ogs_gtp_context_parse_config("mme", "sgwc"); if (rv != OGS_OK) return rv; - rv = ogs_metrics_context_parse_config(); + rv = ogs_metrics_context_parse_config("mme"); if (rv != OGS_OK) return rv; rv = mme_context_parse_config(); diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index e3a06a569..c6febf92b 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -220,7 +220,7 @@ void mme_s11_handle_create_session_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); + ogs_error("GTP Bearer Cause [VALUE:%d]", cause_value); if (create_action == OGS_GTP_CREATE_IN_ATTACH_REQUEST) { ogs_error("[%s] Attach reject", mme_ue->imsi_bcd); ogs_assert(OGS_OK == nas_eps_send_attach_reject(mme_ue, @@ -240,7 +240,7 @@ void mme_s11_handle_create_session_response( OGS_GTP2_CAUSE_NEW_PDN_TYPE_DUE_TO_NETWORK_PREFERENCE && cause_value != OGS_GTP2_CAUSE_NEW_PDN_TYPE_DUE_TO_SINGLE_ADDRESS_BEARER_ONLY) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); if (create_action == OGS_GTP_CREATE_IN_ATTACH_REQUEST) { ogs_error("[%s] Attach reject", mme_ue->imsi_bcd); ogs_assert(OGS_OK == nas_eps_send_attach_reject(mme_ue, @@ -467,7 +467,7 @@ void mme_s11_handle_modify_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); mme_send_delete_session_or_mme_ue_context_release(mme_ue); return; } @@ -548,7 +548,7 @@ void mme_s11_handle_delete_session_response( cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) - ogs_error("GTP Failed [CAUSE:%d] - Ignored", cause_value); + ogs_error("GTP Cause [Value:%d] - Ignored", cause_value); } /******************** @@ -1143,7 +1143,7 @@ void mme_s11_handle_release_access_bearers_response( cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) - ogs_error("GTP Failed [CAUSE:%d, ACTION:%d]", cause_value, action); + ogs_error("GTP Cause [Value:%d, ACTION:%d]", cause_value, action); } /******************** @@ -1455,7 +1455,7 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); mme_send_delete_session_or_mme_ue_context_release(mme_ue); return; } @@ -1571,7 +1571,7 @@ void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); mme_send_delete_session_or_mme_ue_context_release(mme_ue); return; } @@ -1639,7 +1639,7 @@ void mme_s11_handle_bearer_resource_failure_indication( ogs_assert(cause); cause_value = cause->value; - ogs_warn("GTP Failed [CAUSE:%d] - Ignored", cause_value); + ogs_warn("GTP Cause [Value:%d] - Ignored", cause_value); } else { ogs_error("No Cause"); } diff --git a/src/mme/mme-s6a-handler.c b/src/mme/mme-s6a-handler.c index 6c54b9bf7..b4199f945 100644 --- a/src/mme/mme-s6a-handler.c +++ b/src/mme/mme-s6a-handler.c @@ -102,13 +102,27 @@ uint8_t mme_s6a_handle_ula( break; } - mme_ue->session[i].name = ogs_strdup(slice_data->session[i].name); - ogs_assert(mme_ue->session[i].name); + if (slice_data->session[i].name) { + mme_ue->session[i].name = ogs_strdup(slice_data->session[i].name); + ogs_assert(mme_ue->session[i].name); + } mme_ue->session[i].context_identifier = slice_data->session[i].context_identifier; - mme_ue->session[i].session_type = slice_data->session[i].session_type; + if (slice_data->session[i].session_type == OGS_PDU_SESSION_TYPE_IPV4 || + slice_data->session[i].session_type == OGS_PDU_SESSION_TYPE_IPV6 || + slice_data->session[i].session_type == + OGS_PDU_SESSION_TYPE_IPV4V6) { + mme_ue->session[i].session_type = + slice_data->session[i].session_type; + } else { + ogs_error("Invalid PDN_TYPE[%d]", + slice_data->session[i].session_type); + if (mme_ue->session[i].name) + ogs_free(mme_ue->session[i].name); + break; + } memcpy(&mme_ue->session[i].paa, &slice_data->session[i].paa, sizeof(mme_ue->session[i].paa)); @@ -127,6 +141,11 @@ uint8_t mme_s6a_handle_ula( slice_data->session[i].charging_characteristics_presence; } + if (i == 0) { + ogs_error("No Session"); + return OGS_NAS_EMM_CAUSE_SEVERE_NETWORK_FAILURE; + } + mme_ue->num_of_session = i; mme_ue->context_identifier = slice_data->context_identifier; diff --git a/src/nssf/context.h b/src/nssf/context.h index 192a12223..d29bedc4c 100644 --- a/src/nssf/context.h +++ b/src/nssf/context.h @@ -29,8 +29,6 @@ extern "C" { #endif -#define MAX_NUM_OF_SERVED_GUAMI 8 - extern int __nssf_log_domain; #undef OGS_LOG_DOMAIN diff --git a/src/pcf/context.h b/src/pcf/context.h index bb347d177..50704eece 100644 --- a/src/pcf/context.h +++ b/src/pcf/context.h @@ -31,8 +31,6 @@ extern "C" { #endif -#define MAX_NUM_OF_SERVED_GUAMI 8 - extern int __pcf_log_domain; #undef OGS_LOG_DOMAIN diff --git a/src/sgwc/pfcp-sm.c b/src/sgwc/pfcp-sm.c index c12465d7c..66cbf94d8 100644 --- a/src/sgwc/pfcp-sm.c +++ b/src/sgwc/pfcp-sm.c @@ -169,12 +169,16 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: - ogs_info("PFCP associated"); + ogs_info("PFCP associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_start(node->t_no_heartbeat, ogs_app()->time.message.pfcp.no_heartbeat_duration); break; case OGS_FSM_EXIT_SIG: - ogs_info("PFCP de-associated"); + ogs_info("PFCP de-associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_stop(node->t_no_heartbeat); break; case SGWC_EVT_SXA_MESSAGE: @@ -206,12 +210,16 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e) &message->pfcp_heartbeat_response)); break; case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: - ogs_warn("PFCP[REQ] has already been associated"); + ogs_warn("PFCP[REQ] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_cp_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"); + ogs_warn("PFCP[RSP] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_cp_handle_association_setup_response(node, xact, &message->pfcp_association_setup_response); break; diff --git a/src/sgwc/s11-handler.c b/src/sgwc/s11-handler.c index 5fea1f8e5..3629700ba 100644 --- a/src/sgwc/s11-handler.c +++ b/src/sgwc/s11-handler.c @@ -766,7 +766,7 @@ void sgwc_s11_handle_create_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); ogs_assert(OGS_OK == sgwc_pfcp_send_bearer_modification_request( bearer, NULL, NULL, @@ -919,7 +919,7 @@ void sgwc_s11_handle_update_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); + ogs_error("GTP Bearer Cause [VALUE:%d]", cause_value); ogs_gtp_send_error_message(s5c_xact, sess ? sess->pgw_s5c_teid : 0, OGS_GTP2_UPDATE_BEARER_RESPONSE_TYPE, cause_value); return; @@ -929,7 +929,7 @@ void sgwc_s11_handle_update_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); ogs_gtp_send_error_message(s5c_xact, sess ? sess->pgw_s5c_teid : 0, OGS_GTP2_UPDATE_BEARER_RESPONSE_TYPE, cause_value); return; @@ -1022,7 +1022,7 @@ void sgwc_s11_handle_delete_bearer_response( cause_value = cause->value; if (cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { } else { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); } } else { ogs_error("No Cause"); @@ -1062,13 +1062,13 @@ void sgwc_s11_handle_delete_bearer_response( if (cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { } else { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); } } else { ogs_error("No Cause"); } } else { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); } } else { ogs_error("No Cause"); @@ -1172,7 +1172,7 @@ void sgwc_s11_handle_downlink_data_notification_ack( cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) - ogs_warn("GTP Failed [CAUSE:%d] - PFCP_CAUSE[%d]", + ogs_warn("GTP Cause [Value:%d] - PFCP_CAUSE[%d]", cause_value, pfcp_cause_from_gtp(cause_value)); } else { ogs_error("No Cause"); diff --git a/src/sgwc/s5c-handler.c b/src/sgwc/s5c-handler.c index 63f88e128..1971e33ab 100644 --- a/src/sgwc/s5c-handler.c +++ b/src/sgwc/s5c-handler.c @@ -79,9 +79,6 @@ void sgwc_s5c_handle_create_session_response( ogs_gtp_xact_t *s11_xact = NULL; ogs_gtp_node_t *pgw = NULL; - ogs_assert(sess); - sgwc_ue = sess->sgwc_ue; - ogs_assert(sgwc_ue); ogs_assert(gtpbuf); ogs_assert(message); rsp = &message->create_session_response; @@ -99,10 +96,32 @@ void sgwc_s5c_handle_create_session_response( rv = ogs_gtp_xact_commit(s5c_xact); ogs_expect(rv == OGS_OK); + /************************ + * Check Session Context + * + * - Session could be deleted before a message is received from SMF. + ************************/ + cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_error("No Context in TEID"); + cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; + } else { + sgwc_ue = sess->sgwc_ue; + ogs_assert(sgwc_ue); + } + + if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); + return; + } + /***************************************** * Check Mandatory/Conditional IE Missing *****************************************/ - cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + ogs_assert(cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED); if (rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.presence == 0) { ogs_error("No GTP TEID"); @@ -150,7 +169,7 @@ void sgwc_s5c_handle_create_session_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); + ogs_error("GTP Bearer Cause [VALUE:%d]", cause_value); ogs_gtp_send_error_message( s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); @@ -167,7 +186,7 @@ void sgwc_s5c_handle_create_session_response( OGS_GTP2_CAUSE_NEW_PDN_TYPE_DUE_TO_NETWORK_PREFERENCE && cause_value != OGS_GTP2_CAUSE_NEW_PDN_TYPE_DUE_TO_SINGLE_ADDRESS_BEARER_ONLY) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); ogs_gtp_send_error_message( s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); @@ -280,9 +299,6 @@ void sgwc_s5c_handle_modify_bearer_response( ogs_gtp_xact_t *s11_xact = NULL; ogs_gtp2_modify_bearer_response_t *rsp = NULL; - ogs_assert(sess); - sgwc_ue = sess->sgwc_ue; - ogs_assert(sgwc_ue); ogs_assert(message); rsp = &message->modify_bearer_response; ogs_assert(rsp); @@ -300,10 +316,37 @@ void sgwc_s5c_handle_modify_bearer_response( rv = ogs_gtp_xact_commit(s5c_xact); ogs_expect(rv == OGS_OK); + /************************ + * Check Session Context + * + * - Session could be deleted before a message is received from SMF. + ************************/ + cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_error("No Context in TEID"); + cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; + } else { + sgwc_ue = sess->sgwc_ue; + ogs_assert(sgwc_ue); + } + + if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { + if (modify_action == OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST) + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); + else + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE, cause_value); + return; + } + /***************************************** * Check Mandatory/Conditional IE Missing *****************************************/ - cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + ogs_assert(cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED); if (rsp->cause.presence == 0) { ogs_error("No Cause"); @@ -331,7 +374,7 @@ void sgwc_s5c_handle_modify_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); if (modify_action == OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST) ogs_gtp_send_error_message( s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, @@ -385,9 +428,6 @@ void sgwc_s5c_handle_delete_session_response( ogs_gtp_xact_t *s11_xact = NULL; ogs_gtp2_delete_session_response_t *rsp = NULL; - ogs_assert(sess); - sgwc_ue = sess->sgwc_ue; - ogs_assert(sgwc_ue); ogs_assert(message); rsp = &message->delete_session_response; ogs_assert(rsp); @@ -404,10 +444,32 @@ void sgwc_s5c_handle_delete_session_response( rv = ogs_gtp_xact_commit(s5c_xact); ogs_expect(rv == OGS_OK); + /************************ + * Check Session Context + * + * - Session could be deleted before a message is received from SMF. + ************************/ + cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_error("No Context in TEID"); + cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; + } else { + sgwc_ue = sess->sgwc_ue; + ogs_assert(sgwc_ue); + } + + if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE, cause_value); + return; + } + /***************************************** * Check Mandatory/Conditional IE Missing *****************************************/ - cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + ogs_assert(cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED); if (rsp->cause.presence == 0) { ogs_error("No Cause"); @@ -430,7 +492,7 @@ void sgwc_s5c_handle_delete_session_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); ogs_gtp_send_error_message( s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE, cause_value); @@ -835,9 +897,6 @@ void sgwc_s5c_handle_bearer_resource_failure_indication( sgwc_ue_t *sgwc_ue = NULL; - ogs_assert(sess); - sgwc_ue = sess->sgwc_ue; - ogs_assert(sgwc_ue); ogs_assert(message); ind = &message->bearer_resource_failure_indication; ogs_assert(ind); @@ -851,6 +910,19 @@ void sgwc_s5c_handle_bearer_resource_failure_indication( s11_xact = s5c_xact->assoc_xact; ogs_assert(s11_xact); + /************************ + * Check Session Context + * + * - Session could be deleted before a message is received from SMF. + ************************/ + if (!sess) { + ogs_error("No Context in TEID"); + cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; + } else { + sgwc_ue = sess->sgwc_ue; + ogs_assert(sgwc_ue); + } + /******************** * Check Cause Value ********************/ diff --git a/src/sgwc/sxa-handler.c b/src/sgwc/sxa-handler.c index 59c61c7dd..c86c95962 100644 --- a/src/sgwc/sxa-handler.c +++ b/src/sgwc/sxa-handler.c @@ -1325,12 +1325,21 @@ void sgwc_sxa_handle_session_report_request( ogs_debug("Session Report Request"); - ogs_assert(sess); ogs_assert(pfcp_xact); ogs_assert(pfcp_req); cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + /************************ + * Check Session Context + * + * - Session could be deleted before a message is received from SMF. + ************************/ + if (!sess) { + ogs_error("No Context"); + cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + } + if (pfcp_req->report_type.presence == 0) { ogs_error("No Report Type"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; diff --git a/src/sgwu/pfcp-sm.c b/src/sgwu/pfcp-sm.c index 7d8d7cb06..814981d53 100644 --- a/src/sgwu/pfcp-sm.c +++ b/src/sgwu/pfcp-sm.c @@ -165,12 +165,16 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: - ogs_info("PFCP associated"); + ogs_info("PFCP associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_start(node->t_no_heartbeat, ogs_app()->time.message.pfcp.no_heartbeat_duration); break; case OGS_FSM_EXIT_SIG: - ogs_info("PFCP de-associated"); + ogs_info("PFCP de-associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_stop(node->t_no_heartbeat); break; case SGWU_EVT_SXA_MESSAGE: @@ -194,12 +198,16 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e) &message->pfcp_heartbeat_response)); break; case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: - ogs_warn("PFCP[REQ] has already been associated"); + ogs_warn("PFCP[REQ] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_up_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"); + ogs_warn("PFCP[RSP] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_up_handle_association_setup_response(node, xact, &message->pfcp_association_setup_response); break; diff --git a/src/smf/context.c b/src/smf/context.c index 7ceb962b1..cf09db526 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -835,6 +835,8 @@ int smf_context_parse_config(void) /* handle config in sbi library */ } else if (!strcmp(smf_key, "discovery")) { /* handle config in sbi library */ + } else if (!strcmp(smf_key, "metrics")) { + /* handle config in metrics library */ } else ogs_warn("unknown key `%s`", smf_key); } diff --git a/src/smf/init.c b/src/smf/init.c index 669bc0637..f7024609c 100644 --- a/src/smf/init.c +++ b/src/smf/init.c @@ -55,7 +55,7 @@ int smf_initialize() rv = ogs_sbi_context_parse_config("smf", "nrf", "scp"); if (rv != OGS_OK) return rv; - rv = ogs_metrics_context_parse_config(); + rv = ogs_metrics_context_parse_config("smf"); if (rv != OGS_OK) return rv; rv = smf_context_parse_config(); diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index 96d9fd468..8104156b4 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -1063,7 +1063,7 @@ uint8_t smf_epc_n4_handle_session_deletion_response( return OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; } if (rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { - ogs_warn("PFCP Cause[%d] : Not Accepted", rsp->cause.u8); + ogs_warn("PFCP Cause [%d] : Not Accepted", rsp->cause.u8); return rsp->cause.u8; } diff --git a/src/smf/pfcp-sm.c b/src/smf/pfcp-sm.c index de2fdd4a1..ebd0b6fd7 100644 --- a/src/smf/pfcp-sm.c +++ b/src/smf/pfcp-sm.c @@ -171,12 +171,16 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) switch (e->h.id) { case OGS_FSM_ENTRY_SIG: - ogs_info("PFCP associated"); + ogs_info("PFCP associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_start(node->t_no_heartbeat, ogs_app()->time.message.pfcp.no_heartbeat_duration); break; case OGS_FSM_EXIT_SIG: - ogs_info("PFCP de-associated"); + ogs_info("PFCP de-associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_stop(node->t_no_heartbeat); break; case SMF_EVT_N4_MESSAGE: @@ -210,12 +214,16 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) &message->pfcp_heartbeat_response)); break; case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: - ogs_warn("PFCP[REQ] has already been associated"); + ogs_warn("PFCP[REQ] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_cp_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"); + ogs_warn("PFCP[RSP] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_cp_handle_association_setup_response(node, xact, &message->pfcp_association_setup_response); break; diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c index 90a1d6d45..c7c7acb75 100644 --- a/src/smf/s5c-handler.c +++ b/src/smf/s5c-handler.c @@ -708,7 +708,7 @@ void smf_s5c_handle_create_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); + ogs_error("GTP Bearer Cause [VALUE:%d]", cause_value); ogs_assert(OGS_OK == smf_epc_pfcp_send_one_bearer_modification_request( bearer, NULL, OGS_PFCP_MODIFY_REMOVE, @@ -721,7 +721,7 @@ void smf_s5c_handle_create_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); ogs_assert(OGS_OK == smf_epc_pfcp_send_one_bearer_modification_request( bearer, NULL, OGS_PFCP_MODIFY_REMOVE, @@ -837,7 +837,7 @@ void smf_s5c_handle_update_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); + ogs_error("GTP Bearer Cause [VALUE:%d]", cause_value); return; } @@ -845,7 +845,7 @@ void smf_s5c_handle_update_bearer_response( ogs_assert(cause); cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); return; } @@ -925,7 +925,7 @@ bool smf_s5c_handle_delete_bearer_response( cause_value = cause->value; if (cause->value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { } else { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); } } else { ogs_error("No Cause"); @@ -965,13 +965,13 @@ bool smf_s5c_handle_delete_bearer_response( if (cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { } else { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); } } else { ogs_error("No Cause"); } } else { - ogs_error("GTP Failed [CAUSE:%d]", cause_value); + ogs_error("GTP Cause [Value:%d]", cause_value); } } else { ogs_error("No Cause"); diff --git a/src/udm/context.h b/src/udm/context.h index 0c675a36c..95b27cf50 100644 --- a/src/udm/context.h +++ b/src/udm/context.h @@ -30,8 +30,6 @@ extern "C" { #endif -#define MAX_NUM_OF_SERVED_GUAMI 8 - extern int __udm_log_domain; #undef OGS_LOG_DOMAIN diff --git a/src/udr/context.h b/src/udr/context.h index effddb1c4..b2bb51d66 100644 --- a/src/udr/context.h +++ b/src/udr/context.h @@ -30,8 +30,6 @@ extern "C" { #endif -#define MAX_NUM_OF_SERVED_GUAMI 8 - extern int __udr_log_domain; #undef OGS_LOG_DOMAIN diff --git a/src/upf/context.c b/src/upf/context.c index 94d38fa99..819b37fc4 100644 --- a/src/upf/context.c +++ b/src/upf/context.c @@ -547,7 +547,8 @@ static void upf_sess_urr_acc_validity_time_setup(upf_sess_t *sess, ogs_pfcp_urr_ if (!urr_acc->t_validity_time) urr_acc->t_validity_time = ogs_timer_add(ogs_app()->timer_mgr, upf_sess_urr_acc_timers_cb, urr); - ogs_timer_start(urr_acc->t_validity_time, urr->quota_validity_time * OGS_USEC_PER_SEC); + ogs_timer_start(urr_acc->t_validity_time, + ogs_time_from_sec(urr->quota_validity_time)); } static void upf_sess_urr_acc_time_quota_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) { @@ -558,7 +559,7 @@ static void upf_sess_urr_acc_time_quota_setup(upf_sess_t *sess, ogs_pfcp_urr_t * if (!urr_acc->t_time_quota) urr_acc->t_time_quota = ogs_timer_add(ogs_app()->timer_mgr, upf_sess_urr_acc_timers_cb, urr); - ogs_timer_start(urr_acc->t_time_quota, urr->time_quota * OGS_USEC_PER_SEC); + ogs_timer_start(urr_acc->t_time_quota, ogs_time_from_sec(urr->time_quota)); } static void upf_sess_urr_acc_time_threshold_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) { @@ -569,7 +570,8 @@ static void upf_sess_urr_acc_time_threshold_setup(upf_sess_t *sess, ogs_pfcp_urr if (!urr_acc->t_time_threshold) urr_acc->t_time_threshold = ogs_timer_add(ogs_app()->timer_mgr, upf_sess_urr_acc_timers_cb, urr); - ogs_timer_start(urr_acc->t_time_threshold, urr->time_threshold * OGS_USEC_PER_SEC); + ogs_timer_start(urr_acc->t_time_threshold, + ogs_time_from_sec(urr->time_threshold)); } void upf_sess_urr_acc_timers_setup(upf_sess_t *sess, ogs_pfcp_urr_t *urr) diff --git a/src/upf/pfcp-sm.c b/src/upf/pfcp-sm.c index c4c3e10fe..a98dd1557 100644 --- a/src/upf/pfcp-sm.c +++ b/src/upf/pfcp-sm.c @@ -170,12 +170,16 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: - ogs_info("PFCP associated"); + ogs_info("PFCP associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_start(node->t_no_heartbeat, ogs_app()->time.message.pfcp.no_heartbeat_duration); break; case OGS_FSM_EXIT_SIG: - ogs_info("PFCP de-associated"); + ogs_info("PFCP de-associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_timer_stop(node->t_no_heartbeat); break; case UPF_EVT_N4_MESSAGE: @@ -199,12 +203,16 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e) &message->pfcp_heartbeat_response)); break; case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: - ogs_warn("PFCP[REQ] has already been associated"); + ogs_warn("PFCP[REQ] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_up_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"); + ogs_warn("PFCP[RSP] has already been associated [%s]:%d", + OGS_ADDR(&node->addr, buf), + OGS_PORT(&node->addr)); ogs_pfcp_up_handle_association_setup_response(node, xact, &message->pfcp_association_setup_response); break; diff --git a/tests/common/context.h b/tests/common/context.h index 5481defd1..7c8a2077a 100644 --- a/tests/common/context.h +++ b/tests/common/context.h @@ -36,8 +36,6 @@ extern "C" { #define TEST_PING_IPV4 "10.45.0.1" #define TEST_PING_IPV6 "2001:db8:cafe::1" -#define MAX_NUM_OF_SERVED_GUAMI 8 - #define TEST_MSISDN "491725670014" #define TEST_ADDITIONAL_MSISDN "491725670015"