diff options
101 files changed, 2289 insertions, 1558 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..7592debf9 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: osmocom diff --git a/.gitignore b/.gitignore index 3626a5a62..010f151ef 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,8 @@ debian/*.log .deps Makefile Makefile.in -bscconfig.h -bscconfig.h.in +config.h +config.h.in *.*~ *.sw? .libs diff --git a/Makefile.am b/Makefile.am index 023a47050..b70eb4b5d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,7 @@ SUBDIRS = \ BUILT_SOURCES = $(top_srcdir)/.version EXTRA_DIST = \ .version \ + README.md \ contrib/osmo-sgsn.spec.in \ debian \ git-version-gen \ diff --git a/README b/README deleted file mode 100644 index a14ba3803..000000000 --- a/README +++ /dev/null @@ -1,17 +0,0 @@ -About OsmoSGSN -============== - -OsmoSGSN originated from the OpenBSC project, as a separate program within -openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence -OsmoSGSN was given its own separate git repository. - -OsmoSGSN exposes -- GSUP towards OsmoHLR (or a MAP proxy); -- GTP towards a GGSN (e.g. OsmoGGSN); -- Gb towards a BSS (e.g. OsmoPCU); -- IuPS towards an RNC or HNB-GW (e.g. OsmoHNBGW) for 3G data; -- The Osmocom typical telnet VTY and CTRL interfaces. - -Find OsmoSGSN issue tracker and wiki online at -https://osmocom.org/projects/osmosgsn -https://osmocom.org/projects/osmosgsn/wiki diff --git a/README.md b/README.md new file mode 100644 index 000000000..3143d048a --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +osmo-sgsn - Osmocom SGSN Implementation +======================================= + +This repository contains a C-language implementation of a *Serving GPRS +Support Node (SGSN)* for 2.5/2.75G (GPRS/EDGE) and 3G (UMTS). It is part of the +[Osmocom](https://osmocom.org/) Open Source Mobile Communications +project. + +OsmoSGSN exposes + + * *Gb* towards PCUs (e.g. [OsmoPCU](https://osmocom.org/projects/osmopcu/wiki/OsmoPCU)): Various GbIP flavors + Gb/FR/E1 + * *GTP* towards a GGSN (e.g. [OsmoGGSN](https://osmocom.org/projects/openggsn/wiki)) + * IuPS over IP towards RNCs / HNBGW (e.g. [osmo-hnbgw](https://osmocom.org/projects/osmohnbgw/wiki)) + * The Osmocom typical telnet *VTY* and *CTRL* interfaces. + * The Osmocom typical *statsd* exporter. + * GSUP (custom MAP-like protocol) towards [osmo-hlr](https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR) + +OsmoSGSN implements + + * GPRS mobility management + * GPRS session management + + +Homepage +-------- + +You can find the OsmoSGSN homepage online at <https://osmocom.org/projects/osmosgsn/wiki>. + + +GIT Repository +-------------- + +You can clone from the official osmo-sgsn.git repository using + + git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn + +There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn> + + +Documentation +------------- + +User Manuals and VTY reference manuals are [optionally] built in PDF form +as part of the build process. + +Pre-rendered PDF version of the current "master" can be found at +[User Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-usermanual.pdf) +as well as the [VTY Reference Manual](https://ftp.osmocom.org/docs/latest/osmosgsn-vty-reference.pdf) + + +Forum +----- + +We welcome any osmo-sgsn related discussions in the +[Cellular Network Infratructure -> 2G/3G Core Network](https://discourse.osmocom.org/c/cni/2g-3g-cn). +section of the osmocom discourse (web based Forum). + + +Mailing List +------------ + +Discussions related to osmo-sgsn are happening on the +osmocom-net-gprs@lists.osmocom.org mailing list, please see +<https://lists.osmocom.org/postorius/lists/osmocom-net-gprs.lists.osmocom.org/> for subscription +options and the list archive. + +Please observe the [Osmocom Mailing List +Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules) +when posting. + + +Issue Tracker +------------- + +We use the [issue tracker of the osmo-sgsn project on osmocom.org](https://osmocom.org/projects/osmosgsn/issues) for +tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help +us out by resolving existing issues. + + +Contributing +------------ + +Our coding standards are described at +<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards> + +We us a gerrit based patch submission/review process for managing +contributions. Please see +<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for +more details + +The current patch queue for osmo-sgsn can be seen at +<https://gerrit.osmocom.org/#/q/project:osmo-sgsn+status:open> + + +History +------- + +OsmoSGSN originated from the OpenBSC project, as a separate program within +openbsc.git. In 2017, OpenBSC was split in separate repositories, and hence +OsmoSGSN was given its own separate git repository. diff --git a/README.vty-tests b/README.vty-tests index 0669ea8e8..dc34916ee 100644 --- a/README.vty-tests +++ b/README.vty-tests @@ -1,6 +1,6 @@ To run the configuration parsing and output (VTY) test suite, first install - git://git.osmocom.org/python/osmo-python-tests + https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests and pass the following configure options here: diff --git a/TODO-RELEASE b/TODO-RELEASE index 44ee42144..df983c1c4 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -1,3 +1,2 @@ #component what description / commit summary line -libosmogb > 1.5.1 bssgp_encode_rim_pdu symbol was not exported previously -libgtp > 1.7.1 use gtp_ran_info_relay_req(), gtp_set_cb_ran_info_relay_ind() +libosmocore > 1.9.0 gsup.h: Using new fields in struct osmo_gsup_pdp_info (ABI break)
\ No newline at end of file diff --git a/configure.ac b/configure.ac index c29bacb50..ddd91ab2b 100644 --- a/configure.ac +++ b/configure.ac @@ -34,45 +34,32 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then fi PKG_PROG_PKG_CONFIG([0.20]) -dnl check for AX_CHECK_COMPILE_FLAG -m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [ - AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.]) - ]) - dnl use a defined standard across all builds and don't depend on compiler default CFLAGS="$CFLAGS -std=gnu11" dnl checks for libraries -AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""]) -AC_SUBST(LIBRARY_DL) - -AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""]) -AC_SUBST(LIBRARY_DLSYM) - - -PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0) -PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0) -PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0) -PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0) -PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.5.0) -PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0) -PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0) -PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.3.0) +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0) +PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0) +PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0) +PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0) +PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.9.0) +PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0) +PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.4.0) +PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.7.0) +PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.11.0) # Enable/disable 3G aka IuPS + IuCS support? AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS and IuCS interfaces])], [osmo_ac_iu="$enableval"],[osmo_ac_iu="no"]) if test "x$osmo_ac_iu" = "xyes" ; then - PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.4.0) + PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.8.0) PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30) - PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.7.0) + PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 1.5.0) AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support]) fi AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes") AC_SUBST(osmo_ac_iu) - -PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.7.0) PKG_CHECK_MODULES(LIBCARES, libcares) dnl checks for header files @@ -124,13 +111,6 @@ AC_SUBST(SYMBOL_VISIBILITY) CPPFLAGS="$CPPFLAGS -Wall -Wno-trigraphs" CFLAGS="$CFLAGS -Wall -Wno-trigraphs" -AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"]) -AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"]) -AX_CHECK_COMPILE_FLAG([-Werror=memset-transposed-args], [CFLAGS="$CFLAGS -Werror=memset-transposed-args"]) -AX_CHECK_COMPILE_FLAG([-Wnull-dereference], [CFLAGS="$CFLAGS -Wnull-dereference"]) -AX_CHECK_COMPILE_FLAG([-Werror=sizeof-array-argument], [CFLAGS="$CFLAGS -Werror=sizeof-array-argument"]) -AX_CHECK_COMPILE_FLAG([-Werror=sizeof-pointer-memaccess], [CFLAGS="$CFLAGS -Werror=sizeof-pointer-memaccess"]) - # Coverage build taken from WebKit's configure.in AC_MSG_CHECKING([whether to enable code coverage support]) AC_ARG_ENABLE(coverage, @@ -181,7 +161,7 @@ if test "x$enable_ext_tests" = "xyes" ; then fi AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes) if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then - AC_MSG_ERROR([Please install git://osmocom.org/python/osmo-python-tests to run the VTY/CTRL tests.]) + AC_MSG_ERROR([Please install https://gitea.osmocom.org/cellular-infrastructure/osmo-python-tests to run the VTY/CTRL tests.]) fi fi AC_MSG_CHECKING([whether to enable VTY/CTRL tests]) @@ -250,11 +230,12 @@ AC_MSG_RESULT([CFLAGS="$CFLAGS"]) AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"]) dnl Generate the output -AM_CONFIG_HEADER(bscconfig.h) +AM_CONFIG_HEADER(config.h) AC_OUTPUT( include/Makefile include/osmocom/Makefile + include/osmocom/gtphub/Makefile include/osmocom/sgsn/Makefile src/Makefile src/gprs/Makefile diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 2325897a9..321beef1b 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -37,14 +37,11 @@ osmo-build-dep.sh libosmo-netif osmo-build-dep.sh osmo-ggsn osmo-build-dep.sh osmo-hlr -enable_werror="" if [ "x$IU" = "x--enable-iu" ]; then osmo-build-dep.sh libosmo-sccp osmo-build-dep.sh libasn1c #osmo-build-dep.sh asn1c aper-prefix # only needed for make regen in osmo-iuh osmo-build-dep.sh osmo-iuh -else - enable_werror="--enable-werror" fi # Additional configure options and depends @@ -63,12 +60,12 @@ set -x cd "$base" autoreconf --install --force -./configure --enable-sanitize $enable_werror $IU --enable-external-tests $CONFIG +./configure --enable-sanitize --enable-werror $IU --enable-external-tests $CONFIG $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check \ || cat-testlogs.sh LD_LIBRARY_PATH="$inst/lib" \ - DISTCHECK_CONFIGURE_FLAGS="$enable_werror $IU --enable-external-tests $CONFIG" \ + DISTCHECK_CONFIGURE_FLAGS="--enable-werror $IU --enable-external-tests $CONFIG" \ $MAKE $PARALLEL_MAKE distcheck \ || cat-testlogs.sh diff --git a/contrib/osmo-sgsn.spec.in b/contrib/osmo-sgsn.spec.in index f661fa0c8..7ba994f73 100644 --- a/contrib/osmo-sgsn.spec.in +++ b/contrib/osmo-sgsn.spec.in @@ -34,20 +34,20 @@ BuildRequires: systemd-rpm-macros %endif BuildRequires: pkgconfig(libcares) BuildRequires: pkgconfig(libcrypto) >= 0.9.5 -BuildRequires: pkgconfig(libgtp) >= 1.7.0 -BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.3.0 -BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0 -BuildRequires: pkgconfig(libosmoabis) >= 1.1.0 -BuildRequires: pkgconfig(libosmocore) >= 1.5.0 -BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0 -BuildRequires: pkgconfig(libosmogb) >= 1.5.0 -BuildRequires: pkgconfig(libosmogsm) >= 1.5.0 -BuildRequires: pkgconfig(libosmovty) >= 1.5.0 +BuildRequires: pkgconfig(libgtp) >= 1.11.0 +BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.7.0 +BuildRequires: pkgconfig(libosmo-netif) >= 1.4.0 +BuildRequires: pkgconfig(libosmoabis) >= 1.5.0 +BuildRequires: pkgconfig(libosmocore) >= 1.9.0 +BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0 +BuildRequires: pkgconfig(libosmogb) >= 1.9.0 +BuildRequires: pkgconfig(libosmogsm) >= 1.9.0 +BuildRequires: pkgconfig(libosmovty) >= 1.9.0 %{?systemd_requires} %if %{with_iu} BuildRequires: pkgconfig(libasn1c) -BuildRequires: pkgconfig(libosmo-ranap) >= 0.7.0 -BuildRequires: pkgconfig(libosmo-sigtran) >= 1.4.0 +BuildRequires: pkgconfig(libosmo-ranap) >= 1.5.0 +BuildRequires: pkgconfig(libosmo-sigtran) >= 1.8.0 %endif %description @@ -93,7 +93,7 @@ make %{?_smp_mflags} make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +) %files -%doc AUTHORS README +%doc AUTHORS README.md %dir %{_docdir}/%{name}/examples %dir %{_docdir}/%{name}/examples/osmo-sgsn %exclude %{_docdir}/%{name}/examples/osmo-gtphub diff --git a/contrib/systemd/osmo-gtphub.service b/contrib/systemd/osmo-gtphub.service index 488178584..9ade246d4 100644 --- a/contrib/systemd/osmo-gtphub.service +++ b/contrib/systemd/osmo-gtphub.service @@ -1,9 +1,13 @@ [Unit] Description=Osmocom GTP Hub +After=network-online.target +Wants=network-online.target [Service] Type=simple ExecStart=/usr/bin/osmo-gtphub -c /etc/osmocom/osmo-gtphub.cfg +StateDirectory=osmocom +WorkingDirectory=%S/osmocom Restart=always RestartSec=2 RestartPreventExitStatus=1 diff --git a/contrib/systemd/osmo-sgsn.service b/contrib/systemd/osmo-sgsn.service index 0991c70c6..21ecbb752 100644 --- a/contrib/systemd/osmo-sgsn.service +++ b/contrib/systemd/osmo-sgsn.service @@ -3,9 +3,13 @@ Description=Osmocom SGSN (Serving GPRS Support Node) Wants=osmo-hlr.service After=osmo-hlr.service After=osmo-hnbgw.service +After=network-online.target +Wants=network-online.target [Service] Type=simple +StateDirectory=osmocom +WorkingDirectory=%S/osmocom Restart=always ExecStart=/usr/bin/osmo-sgsn -c /etc/osmocom/osmo-sgsn.cfg RestartSec=2 diff --git a/debian/changelog b/debian/changelog index 2edc6e66f..cb629fbdc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,183 @@ +osmo-sgsn (1.11.1) unstable; urgency=medium + + [ Philipp Maier ] + * sgsn_rim: forward message based on RIM ROUTING ADDRESS + + [ Daniel Willmann ] + * sgsn_vty: Fix output in config_write_sgsn + * sgsn_vty: Correctly indent encryption cipher-plugin-path + * vty-tests: Test encryption options + * libgtp: Check for all successful create_pdp_conf causes + + -- Oliver Smith <osmith@sysmocom.de> Tue, 28 Nov 2023 13:32:46 +0100 + +osmo-sgsn (1.11.0) unstable; urgency=medium + + [ Oliver Smith ] + * Run struct_endianness.py + * debian: set compat level to 10 + * systemd: depend on networking-online.target + + [ arehbein ] + * Transition to use of 'telnet_init_default' + + [ Vadim Yanitskiy ] + * tests: use -no-install libtool flag to avoid ./lt-* scripts + * tests: $(BUILT_SOURCES) is not defined, depend on osmo-sgsn + * copyright: fix typo: sysmocom s/s.m.f.c./s.f.m.c./ GmbH + + [ Pau Espin Pedrol ] + * gmm: Ciphering Key Sequence Number IE has half octet tag + * gprs_sm.c: Fix load of misaligned ptr address + * Write explicit role & sctp-role fields in ASP configurations + * gmm: Update DRX params during rx RAU REQ + * gmm: Add missing GSM48_IE_GMM_RX_NPDU_NUM_LIST IE in gsm48_gmm_att_tlvdef + + [ Philipp Maier ] + * sgsn_rim: fix typo + * sgsn_rim: cosmetic: improve comment + * sgsn_rim: get rid of MME check in sgsn_rim_rx_from_gtp: + * sgsn_rim: do not check the origin of a RIM message + + -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 16:57:02 +0200 + +osmo-sgsn (1.10.0) unstable; urgency=medium + + [ Vadim Yanitskiy ] + * configure.ac: do not require unused dlsym/dlopen + * gprs_llc: fix misleading spacing in gprs_llc_rcvmsg() + * gprs_llc.h: use '#pragma once' + * llc: gprs_llc_fcs(): make the input data pointer const + + [ Max ] + * Set working directory in systemd service file + * SNDCP: log more details on failure + * GTP: migrate from deprecated function + * Constify LLC/SNDCP parameters + * GMM: permit E_GMM_COMMON_PROC_SUCCESS in normal state + * ctrl: take both address and port from vty config + + [ Pau Espin Pedrol ] + * vty: Make new libgtp tdefs configurable through VTY + * sndcp: Put decompress handling code into helper function + * Move gprs_gb_parse.[c,h] to tests/sgsn/ + * Create new specific file for BSSGP code + * Move some functions gprs_gb.[c,h] -> gprs_gmm.[c,h] + * Rename gprs_gb.[c,h] -> gprs_ns.[c,h] + * Move gprs_tmr_to_secs() to tests/gprs/gprs_test.c + * cosmetic: gprs_llc_vty.c: Fix trailing whitespace + * vty: Fix wrong value_string used to print llme state + * Standarize lle and llme state enum & value_string + * Remove unused function gprs_parse_mi_tmsi() + * Replace gprs_str_to_apn() with libosmocore API osmo_apn_from_str() + * Move struct sgsn_ggsn_ctx to its own file gtp_ggsn.{c,h} + * gprs_subscriber: Move API declarations to correct header + * Move gprs_sndcp_vty_init() declaration to gprs_sndcp.h + * Introduce new header file sgsn/gtp.h + * Fix -Werror=old-style-definition + * Move related structs to gprs_subscriber.h + * Remove unneeded extern declaration from libosmocotrl + * Keep sgsn subsystems under struct sgsn_instance lifecycle + * Move global ggsn_list into struct sgsn_instance + * Move struct apn_ctx and APN related definitions to its own file + * Move struct sgsn_subscriber_pdp_data to gprs_subscriber.h + * sgsn.h: Drop declaration of non existing function + * Properly split llc->sndcp->gtp unitdata pathi through extra func call + * Move func defintions of funcs implemented in gprs_sndcp.c to gprs_sndcp.h + * sndcp: Standarize unitdata function naming + * Move gtp related functions to gtp.h + * Move global apn_list inside struct sgsn_instance + * gtp_{ggsn,mme}: Allocate contexts under struct sgsn_instance + * Move extern declarations of tall_sgsn_ctx to sgsn.h + * Drop extern declarations of global sgsn_instance in source files + * Move sgsn_pdp_ctx to its own file pdpctx.{c,h} + * Move global pdp_list inside struct sgsn_instance + * Move gtphub header to include/osmocom/gtphub/ + * Move sgsn_ctrl_cmds_install() declaration to sgsn.h + * Move LOGGSUBSCRP to gprs_subscriber.h + * Rename bscconfig.h -> config.h + * gtphub.h: Remove dependency on sgsn/gprs_sgsn.h + * Split gprs_sgsn.{c,h} -> {auth,mmctx,sgsn}.{c,h} + * Move global mmctx list into struct sgsn_instance + * vty: Introduce encryption cipher-plugin-path command + * Fix extra whitespace in pdpctx_ctr_description + + [ Oliver Smith ] + * contrib/jenkins.sh: use enable-werror with IU too + * sgsn_libgtp: cb_data_ind: remove mm_idle assert + * osmo-gtphub.cfg: fix conflict with osmo-ggsn.cfg + + -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 17:34:26 +0100 + +osmo-sgsn (1.9.0) unstable; urgency=medium + + [ Oliver Smith ] + * llme_free: clean up related sndcp + * treewide: remove FSF address + + [ Pau Espin Pedrol ] + * Drop unneeded ax_check_compile_flag.m4 + * Revert "sgsn: Handle different levels of QoS" + + [ Neels Hofmeyr ] + * s/cipher_support_mask/gea_encryption_mask + * Iu: add UEA encryption + + [ Vadim Yanitskiy ] + * tests: use 'check_PROGRAMS' instead of 'noinst_PROGRAMS' + + [ Harald Welte ] + * update git URLs (git -> https; gitea) + * README: Major update + + -- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 29 Jun 2022 11:45:08 +0200 + +osmo-sgsn (1.8.0) unstable; urgency=medium + + [ Harald Welte ] + * Remove bogus DNS log category + + [ Daniel Willmann ] + * manuals: Regenerate counters/VTY through docker + + [ Vadim Yanitskiy ] + * main: resurrect removed 'ns' logging category as deprecated + * doc/manuals: update configuration.adoc to use new command syntax + * tests/Makefile.am: do not try removing non-existing files + + [ Pau Espin Pedrol ] + * ranap: log ranap iu event type name instead of number + * gmm: log GMM msg type name instead of number + * gmm: Expect E_VLR_ANSWERED when in ST_IU_SECURITY_CMD + * gmm_fsm: Expect E_GMM_COMMON_PROC_INIT_REQ when in ST_GMM_COMMON_PROC_INIT + * mm_iu: Send event E_PMM_PS_CONN_ESTABLISH upon rx GMM SERVICE REQUEST + * mm_iu: Expect E_PMM_PS_ATTACH when in ST_PMM_IDLE + * gprs_gmm.c: State proper GMM prefix logging rx/tx of GMM messages + * mm_state_iu_fsm: T3314 expiry must lead to PMM IDLE, not PMM DETACHED + * Iu: Drop timer X3314 + * gprs_ranap.c: Clean up code path releasing IU conn + * mm_state_{gb,iu}_fsm: Add missing license block, improve spec references + * mm_state_{gb,iu}_fsm: Improve naming for detach event + * Drop unused GBRPOXY enum field + * gtp: Delete ctx upon receive UpdateCtxResp with cause Non-existent + * Support forwarding RIM messages over GTPCv1 EUTRAN<->GERAN + * Use new stat item/ctr getter APIs + + [ Keith ] + * vty: Fix optional display of pdp with mm-context + * VTY: Don't display 'PDP Address: invalid' for IPv4v6 + + [ Eric ] + * add support for multiple encryption algorithms and a5/4 + + [ Oliver Smith ] + * gtphub: remove llist_first, llist_last macros + * vty: add "page imsi" + * debian/control: remove dh-systemd build-depend + * Revert "Turn some compiler warnings into errors" + + -- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 16 Nov 2021 17:57:50 +0100 + osmo-sgsn (1.7.0) unstable; urgency=medium [ Daniel Willmann ] diff --git a/debian/compat b/debian/compat index ec635144f..f599e28b8 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 +10 diff --git a/debian/control b/debian/control index bc9c8abc7..aa594553b 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: osmo-sgsn Section: net Priority: extra Maintainer: Osmocom team <openbsc@lists.osmocom.org> -Build-Depends: debhelper (>=9), +Build-Depends: debhelper (>= 10), dh-autoreconf, autotools-dev, autoconf, @@ -11,19 +11,19 @@ Build-Depends: debhelper (>=9), pkg-config, libtalloc-dev, libc-ares-dev, - libgtp-dev (>= 1.7.0), - libosmocore-dev (>= 1.5.0), - libosmo-abis-dev (>= 1.1.0), - libosmo-netif-dev (>= 1.1.0), - libosmo-gsup-client-dev (>= 1.3.0), + libgtp-dev (>= 1.11.0), + libosmocore-dev (>= 1.9.0), + libosmo-abis-dev (>= 1.5.0), + libosmo-netif-dev (>= 1.4.0), + libosmo-gsup-client-dev (>= 1.7.0), libasn1c-dev (>= 0.9.30), - libosmo-ranap-dev (>= 0.7.0), - libosmo-sigtran-dev (>= 1.4.0), - libosmo-sccp-dev (>= 1.4.0), - osmo-gsm-manuals-dev (>= 1.1.0) + libosmo-ranap-dev (>= 1.5.0), + libosmo-sigtran-dev (>= 1.8.0), + libosmo-sccp-dev (>= 1.8.0), + osmo-gsm-manuals-dev (>= 1.5.0) Standards-Version: 3.9.8 -Vcs-Git: git://git.osmocom.org/osmo-sgsn.git -Vcs-Browser: https://git.osmocom.org/osmo-sgsn +Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn +Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn Homepage: https://projects.osmocom.org/projects/osmo-sgsn diff --git a/debian/copyright b/debian/copyright index dd7b6672b..cd8d7e84c 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,6 +1,6 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: osmo-sgsn -Source: git://git.osmocom.org/osmo-sgsn +Source: https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn Files: .gitignore .gitreview @@ -33,7 +33,6 @@ Files: .gitignore include/osmocom/sgsn/crc24.h include/osmocom/sgsn/debug.h include/osmocom/sgsn/gb_proxy.h - include/osmocom/sgsn/gprs_gb_parse.h include/osmocom/sgsn/gprs_gmm.h include/osmocom/sgsn/gprs_llc.h include/osmocom/sgsn/gprs_sgsn.h @@ -53,6 +52,7 @@ Files: .gitignore tests/gprs/gprs_test.ok tests/gtphub/Makefile.am tests/gtphub/gtphub_test.ok + tests/sgsn/gprs_gb_parse.h tests/sgsn/Makefile.am tests/sgsn/sgsn_test.ok tests/slhc/Makefile.am @@ -74,11 +74,10 @@ Files: include/osmocom/sgsn/a_reset.h include/osmocom/sgsn/gprs_sndcp_pcomp.h include/osmocom/sgsn/gprs_sndcp_xid.h include/osmocom/sgsn/gprs_utils.h - include/osmocom/sgsn/gtphub.h + include/osmocom/gtphub/gtphub.h include/osmocom/sgsn/signal.h src/gprs/gprs_llc_parse.c src/gprs/crc24.c - src/gprs/gprs_gb_parse.c src/gprs/gprs_utils.c src/gprs/sgsn_ares.c src/gtphub/gtphub.c @@ -103,6 +102,7 @@ Files: include/osmocom/sgsn/a_reset.h src/sgsn/sgsn_main.c src/sgsn/sgsn_vty.c tests/gtphub/gtphub_test.c + tests/sgsn/gprs_gb_parse.c tests/sgsn/sgsn_test.c tests/slhc/slhc_test.c tests/sndcp_xid/sndcp_xid_test.c diff --git a/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg b/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg index 3913d2c3c..d4dadf901 100644 --- a/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg +++ b/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg @@ -5,6 +5,14 @@ ! For the test, try to use most config commands. ! +log stderr + logging color 1 + logging print category-hex 0 + logging print category 1 + logging timestamp 0 + logging print file basename last + logging print level 1 + line vty no login diff --git a/doc/examples/osmo-gtphub/osmo-gtphub.cfg b/doc/examples/osmo-gtphub/osmo-gtphub.cfg index 0bb63e312..da9bba59a 100644 --- a/doc/examples/osmo-gtphub/osmo-gtphub.cfg +++ b/doc/examples/osmo-gtphub/osmo-gtphub.cfg @@ -2,6 +2,14 @@ ! Osmocom gtphub configuration ! +log stderr + logging color 1 + logging print category-hex 0 + logging print category 1 + logging timestamp 0 + logging print file basename last + logging print level 1 + line vty no login @@ -9,7 +17,7 @@ gtphub ! Local addresses to listen on and send from, each on standard ports ! 2123 and 2152. Setting these addresses is mandatory. bind-to-sgsns 127.0.0.10 - bind-to-ggsns 127.0.0.2 + bind-to-ggsns 127.0.0.20 ! Local nonstandard ports or separate IPs: !bind-to-sgsns ctrl 127.0.0.1 2342 user 127.0.0.1 4223 diff --git a/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg b/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg index 7abe7b38e..69000b439 100644 --- a/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg +++ b/doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg @@ -2,6 +2,14 @@ ! Osmocom SGSN configuration ! ! +log stderr + logging color 1 + logging print category-hex 0 + logging print category 1 + logging timestamp 0 + logging print file basename last + logging print level 1 + line vty no login ! diff --git a/doc/examples/osmo-sgsn/osmo-sgsn.cfg b/doc/examples/osmo-sgsn/osmo-sgsn.cfg index 11413c1b2..0b5ef4b19 100644 --- a/doc/examples/osmo-sgsn/osmo-sgsn.cfg +++ b/doc/examples/osmo-sgsn/osmo-sgsn.cfg @@ -2,6 +2,14 @@ ! Osmocom SGSN configuration ! ! +log stderr + logging color 1 + logging print category-hex 0 + logging print category 1 + logging timestamp 0 + logging print file basename last + logging print level 1 + line vty no login ! diff --git a/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg b/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg index fd5a20560..a7ed9cf1e 100644 --- a/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg +++ b/doc/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg @@ -2,6 +2,14 @@ ! Osmocom SGSN configuration ! ! +log stderr + logging color 1 + logging print category-hex 0 + logging print category 1 + logging timestamp 0 + logging print file basename last + logging print level 1 + line vty no login ! @@ -9,6 +17,8 @@ cs7 instance 0 point-code 0.23.4 asp asp-clnt-OsmoSGSN-A 2905 0 m3ua remote-ip 172.18.8.200 ! where to reach the STP + role asp + sctp-role client as as-clnt-OsmoSGSN-A m3ua asp asp-clnt-OsmoSGSN-A routing-key 3 0.23.4 diff --git a/doc/manuals/chapters/configuration.adoc b/doc/manuals/chapters/configuration.adoc index d51dd77f7..d6ddcd34a 100644 --- a/doc/manuals/chapters/configuration.adoc +++ b/doc/manuals/chapters/configuration.adoc @@ -422,6 +422,7 @@ cs7 instance 0 point-code 0.23.4 asp asp-clnt-OsmoSGSN 2905 0 m3ua remote-ip 127.0.0.1 + role asp sctp-role client as as-clnt-OsmoSGSN m3ua asp asp-clnt-OsmoSGSN diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am index 09db97a95..f5bc76a4f 100644 --- a/include/osmocom/Makefile.am +++ b/include/osmocom/Makefile.am @@ -1,3 +1,4 @@ SUBDIRS = \ + gtphub \ sgsn \ $(NULL) diff --git a/include/osmocom/gtphub/Makefile.am b/include/osmocom/gtphub/Makefile.am new file mode 100644 index 000000000..c61dad9d4 --- /dev/null +++ b/include/osmocom/gtphub/Makefile.am @@ -0,0 +1,3 @@ +noinst_HEADERS = \ + gtphub.h \ + $(NULL) diff --git a/include/osmocom/sgsn/gtphub.h b/include/osmocom/gtphub/gtphub.h index 6a439b576..dbf8469bc 100644 --- a/include/osmocom/sgsn/gtphub.h +++ b/include/osmocom/gtphub/gtphub.h @@ -27,9 +27,7 @@ #include <osmocom/core/select.h> #include <osmocom/core/timer.h> #include <osmocom/core/rate_ctr.h> - -#include <osmocom/sgsn/gprs_sgsn.h> - +#include <osmocom/gsm/apn.h> /* support */ @@ -428,7 +426,7 @@ struct gtphub_resolved_ggsn { /* The APN OI, the Operator Identifier, is the combined address, * including parts of the IMSI and APN NI, and ending with ".gprs". */ - char apn_oi_str[GSM_APN_LENGTH]; + char apn_oi_str[APN_MAXLEN+1]; /* Which address and port we resolved that to. */ struct gtphub_peer_port *peer; diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am index 289f502e8..aa6cd0f0f 100644 --- a/include/osmocom/sgsn/Makefile.am +++ b/include/osmocom/sgsn/Makefile.am @@ -1,18 +1,19 @@ noinst_HEADERS = \ + apn.h \ + auth.h \ common.h \ crc24.h \ debug.h \ - gprs_gb.h \ - gprs_gb_parse.h \ + gprs_bssgp.h \ gprs_gmm.h \ gprs_gmm_fsm.h \ gprs_gmm_attach.h \ gprs_mm_state_gb_fsm.h \ gprs_mm_state_iu_fsm.h \ + gprs_ns.h \ gprs_llc.h \ gprs_llc_xid.h \ gprs_ranap.h \ - gprs_sgsn.h \ gprs_sm.h \ gprs_sndcp_comp.h \ gprs_sndcp_dcomp.h \ @@ -21,8 +22,11 @@ noinst_HEADERS = \ gprs_sndcp_xid.h \ gprs_subscriber.h \ gprs_utils.h \ - gtphub.h \ + gtp.h \ + gtp_ggsn.h \ gtp_mme.h \ + mmctx.h \ + pdpctx.h \ sgsn.h \ sgsn_rim.h \ signal.h \ diff --git a/include/osmocom/sgsn/apn.h b/include/osmocom/sgsn/apn.h new file mode 100644 index 000000000..3dc7a70ca --- /dev/null +++ b/include/osmocom/sgsn/apn.h @@ -0,0 +1,20 @@ +#pragma once + +#include <osmocom/core/linuxlist.h> + +struct sgsn_ggsn_ctx; + +#define GSM_APN_LENGTH 102 + +struct apn_ctx { + struct llist_head list; + struct sgsn_ggsn_ctx *ggsn; + char *name; + char *imsi_prefix; + char *description; +}; + +struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix); +void sgsn_apn_ctx_free(struct apn_ctx *actx); +struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix); +struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix); diff --git a/include/osmocom/sgsn/auth.h b/include/osmocom/sgsn/auth.h new file mode 100644 index 000000000..a46fb16bb --- /dev/null +++ b/include/osmocom/sgsn/auth.h @@ -0,0 +1,39 @@ +/* MS authorization and subscriber data handling */ +#pragma once + +#include <osmocom/core/linuxlist.h> + +struct sgsn_config; +struct sgsn_instance; +struct sgsn_mm_ctx; +struct gsm_auth_tuple; + +/* Authorization/ACL handling */ +enum sgsn_auth_state { + SGSN_AUTH_UNKNOWN, + SGSN_AUTH_AUTHENTICATE, + SGSN_AUTH_UMTS_RESYNC, + SGSN_AUTH_ACCEPTED, + SGSN_AUTH_REJECTED +}; + +extern const struct value_string *sgsn_auth_state_names; + +void sgsn_auth_init(struct sgsn_instance *sgsn); +/* Request authorization */ +enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm); +int sgsn_auth_request(struct sgsn_mm_ctx *mm); +void sgsn_auth_update(struct sgsn_mm_ctx *mm); +struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx, + unsigned key_seq); + +/* + * Authorization/ACL handling + */ +struct imsi_acl_entry { + struct llist_head list; + char imsi[OSMO_IMSI_BUF_SIZE]; +}; +struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg); +int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg); +int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg); diff --git a/include/osmocom/sgsn/crc24.h b/include/osmocom/sgsn/crc24.h index 756638c03..c913eaf76 100644 --- a/include/osmocom/sgsn/crc24.h +++ b/include/osmocom/sgsn/crc24.h @@ -5,6 +5,6 @@ #define INIT_CRC24 0xffffff -uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len); +uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len); #endif diff --git a/include/osmocom/sgsn/gprs_bssgp.h b/include/osmocom/sgsn/gprs_bssgp.h new file mode 100644 index 000000000..0feaa9762 --- /dev/null +++ b/include/osmocom/sgsn/gprs_bssgp.h @@ -0,0 +1,12 @@ +#pragma once + +#include <osmocom/core/msgb.h> + +/* Called by bssgp layer when a prim is received from lower layers. */ +int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph); + +/* called by the bssgp layer to send NS PDUs */ +int sgsn_bssgp_dispatch_ns_unitdata_req_cb(void *ctx, struct msgb *msg); + +/* page a MS in its routing area */ +int sgsn_bssgp_page_ps_ra(struct sgsn_mm_ctx *mmctx); diff --git a/include/osmocom/sgsn/gprs_gb.h b/include/osmocom/sgsn/gprs_gb.h deleted file mode 100644 index 916236761..000000000 --- a/include/osmocom/sgsn/gprs_gb.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include <stdbool.h> - -#include <osmocom/core/msgb.h> -#include <osmocom/sgsn/gprs_llc.h> - -int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, - bool drop_cipherable); -/* Has to be called whenever any PDU (signaling, data, ...) has been received */ -void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg); - -/* page a MS in its routing area */ -int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx); - -/* called by the bssgp layer to send NS PDUs */ -int gprs_gb_send_cb(void *ctx, struct msgb *msg); - -/* called by the ns layer */ -int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx); diff --git a/include/osmocom/sgsn/gprs_gmm.h b/include/osmocom/sgsn/gprs_gmm.h index e2b17d217..71dd1fa7f 100644 --- a/include/osmocom/sgsn/gprs_gmm.h +++ b/include/osmocom/sgsn/gprs_gmm.h @@ -1,10 +1,14 @@ #ifndef _GPRS_GMM_H #define _GPRS_GMM_H +#include <stdbool.h> + #include <osmocom/core/msgb.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/gsm/gsm48.h> +#include <osmocom/crypt/auth.h> -#include <stdbool.h> +struct sgsn_mm_ctx; +struct gprs_llc_llme; int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, const struct osmo_auth_vector *vec, @@ -28,6 +32,11 @@ int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli); int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli, uint8_t suspend_ref); +int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, + bool drop_cipherable); +/* Has to be called whenever any PDU (signaling, data, ...) has been received */ +void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg); + time_t gprs_max_time_to_idle(void); int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type); diff --git a/include/osmocom/sgsn/gprs_gmm_fsm.h b/include/osmocom/sgsn/gprs_gmm_fsm.h index f10851e5c..2f0e81a09 100644 --- a/include/osmocom/sgsn/gprs_gmm_fsm.h +++ b/include/osmocom/sgsn/gprs_gmm_fsm.h @@ -1,8 +1,10 @@ #pragma once #include <osmocom/core/fsm.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> + +struct gprs_llc_llme; /* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */ enum gmm_fsm_states { diff --git a/include/osmocom/sgsn/gprs_llc.h b/include/osmocom/sgsn/gprs_llc.h index ce0e63c51..6f0e4922f 100644 --- a/include/osmocom/sgsn/gprs_llc.h +++ b/include/osmocom/sgsn/gprs_llc.h @@ -1,11 +1,16 @@ -#ifndef _GPRS_LLC_H -#define _GPRS_LLC_H +#pragma once #include <stdint.h> #include <stdbool.h> -#include <osmocom/sgsn/gprs_sgsn.h> + +#include <osmocom/core/timer.h> +#include <osmocom/gsm/tlv.h> +#include <osmocom/crypt/gprs_cipher.h> + #include <osmocom/sgsn/gprs_llc_xid.h> +struct sgsn_mm_ctx; + /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { GPRS_SAPI_GMM = 1, @@ -91,6 +96,7 @@ enum gprs_llc_lle_state { GPRS_LLES_LOCAL_REL = 6, /* Local Release */ GPRS_LLES_TIMER_REC = 7, /* Timer Recovery */ }; +extern const struct value_string gprs_llc_lle_state_names[]; enum gprs_llc_llme_state { GPRS_LLMS_UNASSIGNED = 1, /* No TLLI yet */ @@ -272,18 +278,15 @@ static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur) } /* LLC low level functions */ -void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme); +void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme); /* parse a GPRS LLC header, also check for invalid frames */ int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, uint8_t *llc_hdr, int len); void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle); -int gprs_llc_fcs(uint8_t *data, unsigned int len); +int gprs_llc_fcs(const uint8_t *data, unsigned int len); /* LLME handling routines */ struct llist_head *gprs_llme_list(void); struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi); - - -#endif diff --git a/include/osmocom/sgsn/gprs_ns.h b/include/osmocom/sgsn/gprs_ns.h new file mode 100644 index 000000000..235b118ec --- /dev/null +++ b/include/osmocom/sgsn/gprs_ns.h @@ -0,0 +1,9 @@ +#pragma once + +#include <stdbool.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/sgsn/gprs_llc.h> + +/* called by the ns layer */ +int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx); diff --git a/include/osmocom/sgsn/gprs_ranap.h b/include/osmocom/sgsn/gprs_ranap.h index 62fdf6f2d..68f9115d7 100644 --- a/include/osmocom/sgsn/gprs_ranap.h +++ b/include/osmocom/sgsn/gprs_ranap.h @@ -1,13 +1,15 @@ #pragma once #include <osmocom/core/msgb.h> -#include <osmocom/sgsn/gprs_sgsn.h> #ifdef BUILD_IU #include <osmocom/ranap/ranap_ies_defs.h> #include <osmocom/ranap/ranap_msg_factory.h> #include <osmocom/ranap/iu_client.h> +struct sgsn_mm_ctx; +struct sgsn_pdp_ctx; + void activate_pdp_rabs(struct sgsn_mm_ctx *ctx); int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data); int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp); diff --git a/include/osmocom/sgsn/gprs_sm.h b/include/osmocom/sgsn/gprs_sm.h index 55c95b89d..78bb2d8c3 100644 --- a/include/osmocom/sgsn/gprs_sm.h +++ b/include/osmocom/sgsn/gprs_sm.h @@ -1,7 +1,10 @@ #pragma once #include <osmocom/core/msgb.h> -#include <osmocom/sgsn/gprs_sgsn.h> + +struct sgsn_mm_ctx; +struct sgsn_pdp_ctx; +struct gprs_llc_llme; int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause, bool teardown); int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid, diff --git a/include/osmocom/sgsn/gprs_sndcp.h b/include/osmocom/sgsn/gprs_sndcp.h index d970240e4..30ea05308 100644 --- a/include/osmocom/sgsn/gprs_sndcp.h +++ b/include/osmocom/sgsn/gprs_sndcp.h @@ -3,6 +3,9 @@ #include <stdint.h> #include <osmocom/core/linuxlist.h> +#include <osmocom/gsm/gsm48.h> + +struct gprs_llc_lle; /* A fragment queue header, maintaining list of fragments for one N-PDU */ struct defrag_state { @@ -60,6 +63,8 @@ struct gprs_sndcp_entity { extern struct llist_head gprs_sndcp_entities; +int gprs_sndcp_vty_init(void); + /* Set of SNDCP-XID negotiation (See also: TS 144 065, * Section 6.8 XID parameter negotiation) */ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); @@ -68,7 +73,7 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); * Section 6.8 XID parameter negotiation) */ int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, struct gprs_llc_xid_field *xid_field_response, - struct gprs_llc_lle *lle); + const struct gprs_llc_lle *lle); /* Process SNDCP-XID indication * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ @@ -76,4 +81,21 @@ int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, struct gprs_llc_xid_field *xid_field_request, struct gprs_llc_lle *lle); +/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */ +void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme); + +/* Called by SNDCP when it has received/re-assembled a N-PDU */ +int sndcp_sn_unitdata_ind(struct gprs_sndcp_entity *sne, struct msgb *msg, + uint32_t npdu_len, uint8_t *npdu); +int sndcp_sn_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi, + void *mmcontext); + +/* Entry point for the SNSM-ACTIVATE.indication */ +int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi); +/* Entry point for the SNSM-DEACTIVATE.indication */ +int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi); + +int sndcp_ll_unitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, + uint8_t *hdr, uint16_t len); + #endif /* INT_SNDCP_H */ diff --git a/include/osmocom/sgsn/gprs_subscriber.h b/include/osmocom/sgsn/gprs_subscriber.h index d36db7500..0d4a5947e 100644 --- a/include/osmocom/sgsn/gprs_subscriber.h +++ b/include/osmocom/sgsn/gprs_subscriber.h @@ -4,10 +4,70 @@ #include <stdint.h> #include <osmocom/core/linuxlist.h> +#include <osmocom/core/socket.h> #include <osmocom/gsm/protocol/gsm_23_003.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> + +#include <osmocom/sgsn/apn.h> + +struct sgsn_instance; +struct sgsn_mm_ctx; extern struct llist_head * const gprs_subscribers; +#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001 +#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16) +#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17) +#define GPRS_SUBSCRIBER_CANCELLED (1 << 18) +#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19) + +#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \ + GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \ + GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \ +) + +struct gsm_auth_tuple { + int use_count; + int key_seq; + struct osmo_auth_vector vec; +}; +#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */ + +struct sgsn_subscriber_data { + struct sgsn_mm_ctx *mm; + struct gsm_auth_tuple auth_triplets[5]; + int auth_triplets_updated; + struct llist_head pdp_list; + int error_cause; + + uint8_t msisdn[9]; + size_t msisdn_len; + + uint8_t hlr[9]; + size_t hlr_len; + + uint8_t pdp_charg[2]; + bool has_pdp_charg; +}; + +/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */ +/* see GSM 09.02, B.1, gprsSubscriptionData */ +struct sgsn_subscriber_pdp_data { + struct llist_head list; + + unsigned int context_id; + enum gsm48_pdp_type_org pdp_type_org; + enum gsm48_pdp_type_nr pdp_type_nr; + struct osmo_sockaddr pdp_address[2]; + char apn_str[GSM_APN_LENGTH]; + uint8_t qos_subscribed[20]; + size_t qos_subscribed_len; + uint8_t pdp_charg[2]; + bool has_pdp_charg; +}; + +struct sgsn_subscriber_pdp_data *sgsn_subscriber_pdp_data_alloc(struct sgsn_subscriber_data *sdata); + struct gprs_subscr { struct llist_head entry; int use_count; @@ -29,3 +89,22 @@ struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub, const char *file, int line); #define gprs_subscr_get(gsub) _gprs_subscr_get(gsub, __FILE__, __LINE__) #define gprs_subscr_put(gsub) _gprs_subscr_put(gsub, __FILE__, __LINE__) + +int gprs_subscr_init(struct sgsn_instance *sgi); +int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx); +int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, + const uint8_t *auts, + const uint8_t *auts_rand); +void gprs_subscr_cleanup(struct gprs_subscr *subscr); +struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi); +struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx); +struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi); +void gprs_subscr_cancel(struct gprs_subscr *subscr); +void gprs_subscr_update(struct gprs_subscr *subscr); +void gprs_subscr_update_auth_info(struct gprs_subscr *subscr); +int gprs_subscr_rx_gsup_message(struct msgb *msg); + +#define LOGGSUBSCRP(level, subscr, fmt, args...) \ + LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \ + (subscr) ? (subscr)->imsi : "---", \ + ## args) diff --git a/include/osmocom/sgsn/gprs_utils.h b/include/osmocom/sgsn/gprs_utils.h index eacaec7a2..1e6c8319c 100644 --- a/include/osmocom/sgsn/gprs_utils.h +++ b/include/osmocom/sgsn/gprs_utils.h @@ -29,15 +29,11 @@ struct msgb; struct gprs_ra_id; -int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str); - /* GSM 04.08, 10.5.7.3 GPRS Timer */ -int gprs_tmr_to_secs(uint8_t tmr); uint8_t gprs_secs_to_tmr_floor(int secs); int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len); int gprs_is_mi_imsi(const uint8_t *value, size_t value_len); -int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi); void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi); int gprs_ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2); diff --git a/include/osmocom/sgsn/gtp.h b/include/osmocom/sgsn/gtp.h new file mode 100644 index 000000000..2aec55333 --- /dev/null +++ b/include/osmocom/sgsn/gtp.h @@ -0,0 +1,30 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> + +#include <osmocom/gsm/tlv.h> +#include <osmocom/gprs/gprs_bssgp_rim.h> + +struct gprs_ra_id; +struct sgsn_instance; +struct sgsn_ggsn_ctx; +struct sgsn_pdp_ctx; +struct sgsn_mm_ctx; +struct sgsn_mme_ctx; + +int sgsn_gtp_init(struct sgsn_instance *sgi); + +int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu); + +void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc); +struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, + struct sgsn_mm_ctx *mmctx, + uint16_t nsapi, + struct tlv_parsed *tp); + +int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi, + struct msgb *msg, uint32_t npdu_len, uint8_t *npdu); +int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx); +void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen); +int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx); diff --git a/include/osmocom/sgsn/gtp_ggsn.h b/include/osmocom/sgsn/gtp_ggsn.h new file mode 100644 index 000000000..6afb8664a --- /dev/null +++ b/include/osmocom/sgsn/gtp_ggsn.h @@ -0,0 +1,41 @@ +#pragma once + +#include <stdint.h> +#include <netinet/in.h> +#include <inttypes.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/timer.h> +#include <osmocom/gprs/protocol/gsm_24_301.h> + +struct gsn_t; +struct sgsn_pdp_ctx; +struct sgsn_instance; + +struct sgsn_ggsn_ctx { + struct llist_head list; + uint32_t id; + unsigned int gtp_version; + struct in_addr remote_addr; + int remote_restart_ctr; + struct gsn_t *gsn; + struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */ + struct osmo_timer_list echo_timer; + unsigned int echo_interval; +}; +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(struct sgsn_instance *sgsn, uint32_t id); +void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc); +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(struct sgsn_instance *sgsn, uint32_t id); +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct sgsn_instance *sgsn, struct in_addr *addr); +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(struct sgsn_instance *sgsn, uint32_t id); +void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx); +int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except); +int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn); +void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp); +void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp); +void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc); + +#define LOGGGSN(ggc, level, fmt, args...) { \ + char _buf[INET_ADDRSTRLEN]; \ + LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \ + } while (0) diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/mmctx.h index c176494b1..c19f599c5 100644 --- a/include/osmocom/sgsn/gprs_sgsn.h +++ b/include/osmocom/sgsn/mmctx.h @@ -1,5 +1,4 @@ -#ifndef _GPRS_SGSN_H -#define _GPRS_SGSN_H +#pragma once #include <stdint.h> #include <netinet/in.h> @@ -14,12 +13,17 @@ #include <osmocom/gsm/protocol/gsm_23_003.h> #include <osmocom/crypt/auth.h> +#include <osmocom/sgsn/apn.h> +#include <osmocom/sgsn/auth.h> +#include <osmocom/sgsn/gprs_subscriber.h> + #define GSM_EXTENSION_LENGTH 15 -#define GSM_APN_LENGTH 102 struct gprs_llc_lle; struct ctrl_handle; struct gprs_subscr; +struct sgsn_ggsn_ctx; +struct sgsn_pdp_ctx; enum gsm48_gsm_cause; @@ -37,13 +41,6 @@ enum gprs_mm_ctr { GMM_CTR_RA_UPDATE, }; -enum gprs_pdp_ctx { - PDP_CTR_PKTS_UDATA_IN, - PDP_CTR_PKTS_UDATA_OUT, - PDP_CTR_BYTES_UDATA_IN, - PDP_CTR_BYTES_UDATA_OUT, -}; - enum gprs_t3350_mode { GMM_T3350_MODE_NONE, GMM_T3350_MODE_ATT, @@ -51,17 +48,6 @@ enum gprs_t3350_mode { GMM_T3350_MODE_PTMSI_REALL, }; -/* Authorization/ACL handling */ -enum sgsn_auth_state { - SGSN_AUTH_UNKNOWN, - SGSN_AUTH_AUTHENTICATE, - SGSN_AUTH_UMTS_RESYNC, - SGSN_AUTH_ACCEPTED, - SGSN_AUTH_REJECTED -}; - -#define MS_RADIO_ACCESS_CAPA - enum sgsn_ggsn_lookup_state { SGSN_GGSN_2DIGIT, SGSN_GGSN_3DIGIT, @@ -104,13 +90,6 @@ struct service_info { struct ranap_ue_conn_ctx; -struct gsm_auth_tuple { - int use_count; - int key_seq; - struct osmo_auth_vector vec; -}; -#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */ - /* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */ /* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */ struct sgsn_mm_ctx { @@ -295,64 +274,6 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, enum gsm48_gsm_cause *gsm_cause, char *apn_str); -enum pdp_ctx_state { - PDP_STATE_NONE, - PDP_STATE_CR_REQ, - PDP_STATE_CR_CONF, - - /* 04.08 / Figure 6.2 / 6.1.2.2 */ - PDP_STATE_INACT_PEND, - PDP_STATE_INACTIVE = PDP_STATE_NONE, -}; - -enum pdp_type { - PDP_TYPE_NONE, - PDP_TYPE_ETSI_PPP, - PDP_TYPE_IANA_IPv4, - PDP_TYPE_IANA_IPv6, -}; - -struct sgsn_pdp_ctx { - struct llist_head list; /* list_head for mmctx->pdp_list */ - struct llist_head g_list; /* list_head for global list */ - struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */ - int destroy_ggsn; /* destroy it on destruction */ - struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */ - struct llist_head ggsn_list; /* list_head for ggsn->pdp_list */ - struct rate_ctr_group *ctrg; - - //unsigned int id; - struct pdp_t *lib; /* pointer to libgtp PDP ctx */ - enum pdp_ctx_state state; - enum pdp_type type; - uint32_t address; - char *apn_subscribed; - //char *apn_used; - uint16_t nsapi; /* SNDCP */ - uint16_t sapi; /* LLC */ - uint8_t ti; /* transaction identifier */ - int vplmn_allowed; - uint32_t qos_profile_subscr; - //uint32_t qos_profile_req; - //uint32_t qos_profile_neg; - uint8_t radio_prio; - //uint32_t charging_id; - - struct osmo_timer_list timer; - unsigned int T; /* Txxxx number */ - unsigned int num_T_exp; /* number of consecutive T expirations */ - - struct osmo_timer_list cdr_timer; /* CDR record wird timer */ - struct timespec cdr_start; /* The start of the CDR */ - uint64_t cdr_bytes_in; - uint64_t cdr_bytes_out; - uint32_t cdr_charging_id; -}; - -#define LOGPDPCTXP(level, pdp, fmt, args...) \ - LOGP(DGPRS, level, "PDP(%s/%u) " \ - fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args) - /* look up PDP context by MM context and NSAPI */ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, uint8_t nsapi); @@ -360,168 +281,7 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm, uint8_t tid); -struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, - struct sgsn_ggsn_ctx *ggsn, - uint8_t nsapi); -void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp); -void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp); - - -struct sgsn_ggsn_ctx { - struct llist_head list; - uint32_t id; - unsigned int gtp_version; - struct in_addr remote_addr; - int remote_restart_ctr; - struct gsn_t *gsn; - struct llist_head pdp_list; /* list of associated pdp ctx (struct sgsn_pdp_ctx*) */ - struct osmo_timer_list echo_timer; - unsigned int echo_interval; -}; -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id); -void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc); -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id); -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr); -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id); -void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx); -int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except); -int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn); -void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp); -void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp); -void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc); - -#define LOGGGSN(ggc, level, fmt, args...) { \ - char _buf[INET_ADDRSTRLEN]; \ - LOGP(DGTP, level, "GGSN(%" PRIu32 ":%s): " fmt, (ggc)->id, inet_ntop(AF_INET, &(ggc)->remote_addr, _buf, sizeof(_buf)), ## args); \ - } while (0) - -struct apn_ctx { - struct llist_head list; - struct sgsn_ggsn_ctx *ggsn; - char *name; - char *imsi_prefix; - char *description; -}; - -struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix); -void sgsn_apn_ctx_free(struct apn_ctx *actx); -struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix); -struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix); - -extern struct llist_head sgsn_mm_ctxts; -extern struct llist_head sgsn_ggsn_ctxts; -extern struct llist_head sgsn_apn_ctxts; -extern struct llist_head sgsn_pdp_ctxts; - uint32_t sgsn_alloc_ptmsi(void); -struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx); -void sgsn_inst_init(struct sgsn_instance *sgsn); - -char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len); - -/* - * ctrl interface related work - */ -int sgsn_ctrl_cmds_install(void); - -/* - * Authorization/ACL handling - */ -struct imsi_acl_entry { - struct llist_head list; - char imsi[OSMO_IMSI_BUF_SIZE]; -}; - -/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */ -/* see GSM 09.02, B.1, gprsSubscriptionData */ -struct sgsn_subscriber_pdp_data { - struct llist_head list; - - unsigned int context_id; - uint16_t pdp_type; - char apn_str[GSM_APN_LENGTH]; - uint8_t qos_subscribed[20]; - size_t qos_subscribed_len; - uint8_t pdp_charg[2]; - bool has_pdp_charg; -}; - -struct sgsn_subscriber_data { - struct sgsn_mm_ctx *mm; - struct gsm_auth_tuple auth_triplets[5]; - int auth_triplets_updated; - struct llist_head pdp_list; - int error_cause; - - uint8_t msisdn[9]; - size_t msisdn_len; - - uint8_t hlr[9]; - size_t hlr_len; - - uint8_t pdp_charg[2]; - bool has_pdp_charg; -}; - -#define SGSN_ERROR_CAUSE_NONE (-1) - -#define LOGGSUBSCRP(level, subscr, fmt, args...) \ - LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \ - (subscr) ? (subscr)->imsi : "---", \ - ## args) - -struct sgsn_config; -struct sgsn_instance; -extern const struct value_string *sgsn_auth_state_names; - -void sgsn_auth_init(struct sgsn_instance *sgsn); -struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, const struct sgsn_config *cfg); -int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg); -int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg); -/* Request authorization */ -int sgsn_auth_request(struct sgsn_mm_ctx *mm); -enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm); -void sgsn_auth_update(struct sgsn_mm_ctx *mm); -struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx, - unsigned key_seq); - -/* - * GPRS subscriber data - */ -#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001 -#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16) -#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17) -#define GPRS_SUBSCRIBER_CANCELLED (1 << 18) -#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19) - -#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \ - GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \ - GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \ -) - -int gprs_subscr_init(struct sgsn_instance *sgi); -int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx); -int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, - const uint8_t *auts, - const uint8_t *auts_rand); -int gprs_subscr_auth_sync(struct gprs_subscr *subscr, - const uint8_t *auts, const uint8_t *auts_rand); -void gprs_subscr_cleanup(struct gprs_subscr *subscr); -struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi); -struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx( struct sgsn_mm_ctx *mmctx); -struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi); -void gprs_subscr_cancel(struct gprs_subscr *subscr); -void gprs_subscr_update(struct gprs_subscr *subscr); -void gprs_subscr_update_auth_info(struct gprs_subscr *subscr); -int gprs_subscr_rx_gsup_message(struct msgb *msg); /* Called on subscriber data updates */ void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx); - -int gprs_sndcp_vty_init(void); -struct sgsn_instance; -int sgsn_gtp_init(struct sgsn_instance *sgi); - -void sgsn_rate_ctr_init(); - -#endif /* _GPRS_SGSN_H */ diff --git a/include/osmocom/sgsn/pdpctx.h b/include/osmocom/sgsn/pdpctx.h new file mode 100644 index 000000000..255a77d3f --- /dev/null +++ b/include/osmocom/sgsn/pdpctx.h @@ -0,0 +1,94 @@ +#pragma once + +#include <stdint.h> +#include <netinet/in.h> +#include <inttypes.h> + +#include <osmocom/core/timer.h> +#include <osmocom/core/rate_ctr.h> + +#include <osmocom/gsm/gsm48.h> + +#include <osmocom/crypt/gprs_cipher.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> +#include <osmocom/crypt/auth.h> + +#include <osmocom/sgsn/apn.h> +#include <osmocom/sgsn/gprs_subscriber.h> + +struct sgsn_mm_ctx; +struct sgsn_ggsn_ctx; + +enum gprs_pdp_ctx { + PDP_CTR_PKTS_UDATA_IN, + PDP_CTR_PKTS_UDATA_OUT, + PDP_CTR_BYTES_UDATA_IN, + PDP_CTR_BYTES_UDATA_OUT, +}; + +enum pdp_ctx_state { + PDP_STATE_NONE, + PDP_STATE_CR_REQ, + PDP_STATE_CR_CONF, + + /* 04.08 / Figure 6.2 / 6.1.2.2 */ + PDP_STATE_INACT_PEND, + PDP_STATE_INACTIVE = PDP_STATE_NONE, +}; + +enum pdp_type { + PDP_TYPE_NONE, + PDP_TYPE_ETSI_PPP, + PDP_TYPE_IANA_IPv4, + PDP_TYPE_IANA_IPv6, +}; + +struct sgsn_pdp_ctx { + struct llist_head list; /* list_head for mmctx->pdp_list */ + struct llist_head g_list; /* list_head for global list */ + struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */ + int destroy_ggsn; /* destroy it on destruction */ + struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */ + struct llist_head ggsn_list; /* list_head for ggsn->pdp_list */ + struct rate_ctr_group *ctrg; + + //unsigned int id; + struct pdp_t *lib; /* pointer to libgtp PDP ctx */ + enum pdp_ctx_state state; + enum pdp_type type; + uint32_t address; + char *apn_subscribed; + //char *apn_used; + uint16_t nsapi; /* SNDCP */ + uint16_t sapi; /* LLC */ + uint8_t ti; /* transaction identifier */ + int vplmn_allowed; + uint32_t qos_profile_subscr; + //uint32_t qos_profile_req; + //uint32_t qos_profile_neg; + uint8_t radio_prio; + //uint32_t charging_id; + + struct osmo_timer_list timer; + unsigned int T; /* Txxxx number */ + unsigned int num_T_exp; /* number of consecutive T expirations */ + + struct osmo_timer_list cdr_timer; /* CDR record wird timer */ + struct timespec cdr_start; /* The start of the CDR */ + uint64_t cdr_bytes_in; + uint64_t cdr_bytes_out; + uint32_t cdr_charging_id; +}; + +#define LOGPDPCTXP(level, pdp, fmt, args...) \ + LOGP(DGPRS, level, "PDP(%s/%u) " \ + fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args) + +struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, + struct sgsn_ggsn_ctx *ggsn, + uint8_t nsapi); +void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp); +void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp); + +char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6); + diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h index 5b29873b6..6e93178af 100644 --- a/include/osmocom/sgsn/sgsn.h +++ b/include/osmocom/sgsn/sgsn.h @@ -8,13 +8,13 @@ #include <osmocom/gprs/gprs_ns2.h> #include <osmocom/gprs/gprs_bssgp.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/auth.h> #include <osmocom/sgsn/gtp_mme.h> #include <osmocom/gsm/oap_client.h> #include <osmocom/gsupclient/gsup_client.h> #include <osmocom/sgsn/common.h> -#include "../../bscconfig.h" +#include "../../config.h" #if BUILD_IU #include <osmocom/ranap/iu_client.h> @@ -25,6 +25,8 @@ struct hostent; +#define SGSN_ERROR_CAUSE_NONE (-1) + enum sgsn_auth_policy { SGSN_AUTH_POLICY_OPEN, SGSN_AUTH_POLICY_CLOSED, @@ -75,8 +77,10 @@ struct sgsn_config { /* misc */ struct gprs_ns2_inst *nsi; + char *crypt_cipher_plugin_path; enum sgsn_auth_policy auth_policy; - uint8_t cipher_support_mask; + uint8_t gea_encryption_mask; + uint8_t uea_encryption_mask; struct llist_head imsi_acl; struct sockaddr_in gsup_server_addr; @@ -92,6 +96,7 @@ struct sgsn_config { /* Timer defintions */ struct osmo_tdef *T_defs; + struct osmo_tdef *T_defs_gtp; int dynamic_lookup; @@ -149,10 +154,22 @@ struct sgsn_instance { struct rate_ctr_group *rate_ctrs; + struct llist_head apn_list; /* list of struct sgsn_apn_ctx */ + struct llist_head ggsn_list; /* list of struct sgsn_ggsn_ctx */ struct llist_head mme_list; /* list of struct sgsn_mme_ctx */ + struct llist_head mm_list; /* list of struct sgsn_mm_ctx */ + struct llist_head pdp_list; /* list of struct sgsn_pdp_ctx */ + + struct ctrl_handle *ctrlh; }; extern struct sgsn_instance *sgsn; +extern void *tall_sgsn_ctx; + +/* + * ctrl interface related work (sgsn_ctrl.c) + */ +int sgsn_ctrl_cmds_install(void); /* sgsn_vty.c */ @@ -161,40 +178,13 @@ int sgsn_parse_config(const char *config_file); char *sgsn_gtp_ntoa(struct ul16_t *ul); /* sgsn.c */ - -/* Main input function for Gb proxy */ -int sgsn_rcvmsg(struct msgb *msg, struct gprs_ns2_vc *nsvc, uint16_t ns_bvci); - -/* sgsn_libgtp.c */ -struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, - struct sgsn_mm_ctx *mmctx, - uint16_t nsapi, - struct tlv_parsed *tp); -int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx); -void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen); -void sgsn_ggsn_echo_req(struct sgsn_ggsn_ctx *ggc); -int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx); -int sgsn_mme_ran_info_req(struct sgsn_mme_ctx *mme, const struct bssgp_ran_information_pdu *pdu); - -/* gprs_sndcp.c */ - -/* Entry point for the SNSM-ACTIVATE.indication */ -int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi); -/* Entry point for the SNSM-DEACTIVATE.indication */ -int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi); -/* Called by SNDCP when it has received/re-assembled a N-PDU */ -int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi, - struct msgb *msg, uint32_t npdu_len, uint8_t *npdu); -int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi, - void *mmcontext); -int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, - uint8_t *hdr, uint16_t len); - - +struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx); +int sgsn_inst_init(struct sgsn_instance *sgsn); /* * CDR related functionality */ int sgsn_cdr_init(struct sgsn_instance *sgsn); +void sgsn_cdr_release(struct sgsn_instance *sgsn); /* diff --git a/include/osmocom/sgsn/sgsn_rim.h b/include/osmocom/sgsn/sgsn_rim.h index aa5a72664..fc87b468e 100644 --- a/include/osmocom/sgsn/sgsn_rim.h +++ b/include/osmocom/sgsn/sgsn_rim.h @@ -3,4 +3,4 @@ struct sgsn_mme_ctx; int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg); -int sgsn_rim_rx_from_gtp(struct bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme); +int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address); diff --git a/include/osmocom/sgsn/v42bis.h b/include/osmocom/sgsn/v42bis.h index b64c43e69..d782981b0 100644 --- a/include/osmocom/sgsn/v42bis.h +++ b/include/osmocom/sgsn/v42bis.h @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*! \page v42bis_page V.42bis modem data compression diff --git a/include/osmocom/sgsn/v42bis_private.h b/include/osmocom/sgsn/v42bis_private.h index c6b675a1b..cc7e63448 100644 --- a/include/osmocom/sgsn/v42bis_private.h +++ b/include/osmocom/sgsn/v42bis_private.h @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #if !defined(_SPANDSP_PRIVATE_V42BIS_H_) diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 deleted file mode 100644 index ca3639715..000000000 --- a/m4/ax_check_compile_flag.m4 +++ /dev/null @@ -1,74 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) -# -# DESCRIPTION -# -# Check whether the given FLAG works with the current language's compiler -# or gives an error. (Warnings, however, are ignored) -# -# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on -# success/failure. -# -# If EXTRA-FLAGS is defined, it is added to the current language's default -# flags (e.g. CFLAGS) when the check is done. The check is thus made with -# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to -# force the compiler to issue an error when a bad flag is given. -# -# INPUT gives an alternative input source to AC_COMPILE_IFELSE. -# -# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this -# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. -# -# LICENSE -# -# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de> -# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com> -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU 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 <http://www.gnu.org/licenses/>. -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 4 - -AC_DEFUN([AX_CHECK_COMPILE_FLAG], -[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF -AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl -AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ - ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS - _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" - AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], - [AS_VAR_SET(CACHEVAR,[yes])], - [AS_VAR_SET(CACHEVAR,[no])]) - _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) -AS_VAR_IF(CACHEVAR,yes, - [m4_default([$2], :)], - [m4_default([$3], :)]) -AS_VAR_POPDEF([CACHEVAR])dnl -])dnl AX_CHECK_COMPILE_FLAGS diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am index 170ded8fc..1533dc070 100644 --- a/src/gprs/Makefile.am +++ b/src/gprs/Makefile.am @@ -29,7 +29,6 @@ endif noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = \ - gprs_gb_parse.c \ gprs_llc_parse.c \ crc24.c \ gprs_utils.c \ diff --git a/src/gprs/crc24.c b/src/gprs/crc24.c index da269b375..d47d4ff82 100644 --- a/src/gprs/crc24.c +++ b/src/gprs/crc24.c @@ -59,7 +59,7 @@ static const uint32_t tbl_crc24[256] = { #define INIT_CRC24 0xffffff -uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len) +uint32_t crc24_calc(uint32_t fcs, const uint8_t *cp, unsigned int len) { while (len--) fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff]; diff --git a/src/gprs/gprs_llc_parse.c b/src/gprs/gprs_llc_parse.c index 1d97004e0..d099cdaf3 100644 --- a/src/gprs/gprs_llc_parse.c +++ b/src/gprs/gprs_llc_parse.c @@ -29,7 +29,7 @@ #include <osmocom/gprs/gprs_bssgp.h> #include <osmocom/sgsn/debug.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_llc.h> #include <osmocom/sgsn/crc24.h> @@ -55,7 +55,7 @@ static const struct value_string llc_cmd_strs[] = { #define N202 4 #define CRC24_LENGTH 3 -int gprs_llc_fcs(uint8_t *data, unsigned int len) +int gprs_llc_fcs(const uint8_t *data, unsigned int len) { uint32_t fcs_calc; diff --git a/src/gprs/gprs_utils.c b/src/gprs/gprs_utils.c index 632718aa9..46028c63c 100644 --- a/src/gprs/gprs_utils.c +++ b/src/gprs/gprs_utils.c @@ -30,56 +30,6 @@ #include <string.h> -int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str) -{ - uint8_t *last_len_field; - int len; - - /* Can we even write the length field to the output? */ - if (max_len == 0) - return -1; - - /* Remember where we need to put the length once we know it */ - last_len_field = apn_enc; - len = 1; - apn_enc += 1; - - while (str[0]) { - if (len >= max_len) - return -1; - - if (str[0] == '.') { - *last_len_field = (apn_enc - last_len_field) - 1; - last_len_field = apn_enc; - } else { - *apn_enc = str[0]; - } - apn_enc += 1; - str += 1; - len += 1; - } - - *last_len_field = (apn_enc - last_len_field) - 1; - - return len; -} - -/* GSM 04.08, 10.5.7.3 GPRS Timer */ -int gprs_tmr_to_secs(uint8_t tmr) -{ - switch (tmr & GPRS_TMR_UNIT_MASK) { - case GPRS_TMR_2SECONDS: - return 2 * (tmr & GPRS_TMR_FACT_MASK); - default: - case GPRS_TMR_MINUTE: - return 60 * (tmr & GPRS_TMR_FACT_MASK); - case GPRS_TMR_6MINUTE: - return 360 * (tmr & GPRS_TMR_FACT_MASK); - case GPRS_TMR_DEACTIVATED: - return -1; - } -} - /* This functions returns a tmr value such that * - f is monotonic * - f(s) <= s @@ -132,19 +82,6 @@ int gprs_is_mi_imsi(const uint8_t *value, size_t value_len) return 1; } -int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi) -{ - uint32_t tmsi_be; - - if (!gprs_is_mi_tmsi(value, value_len)) - return 0; - - memcpy(&tmsi_be, value + 1, sizeof(tmsi_be)); - - *tmsi = ntohl(tmsi_be); - return 1; -} - void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi) { uint32_t tmsi_be; diff --git a/src/gprs/sgsn_ares.c b/src/gprs/sgsn_ares.c index 87314f117..81ab83540 100644 --- a/src/gprs/sgsn_ares.c +++ b/src/gprs/sgsn_ares.c @@ -24,8 +24,6 @@ #include <netdb.h> -extern void *tall_sgsn_ctx; - struct cares_event_fd { struct llist_head head; struct osmo_fd fd; diff --git a/src/gtphub/gtphub.c b/src/gtphub/gtphub.c index 09d01fcc2..937e6a4ff 100644 --- a/src/gtphub/gtphub.c +++ b/src/gtphub/gtphub.c @@ -32,7 +32,7 @@ #include <gtp.h> #include <gtpie.h> -#include <osmocom/sgsn/gtphub.h> +#include <osmocom/gtphub/gtphub.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/gprs_utils.h> @@ -475,7 +475,7 @@ static int get_ie_imsi_str(union gtpie_member *ie[], int i, * present but cannot be decoded. */ static int get_ie_apn_str(union gtpie_member *ie[], const char **apn_str) { - static char apn_buf[GSM_APN_LENGTH]; + static char apn_buf[APN_MAXLEN+1]; unsigned int len; if (gtpie_gettlv(ie, GTPIE_APN, 0, &len, apn_buf, sizeof(apn_buf)) != 0) @@ -971,7 +971,7 @@ static inline void set_tei(struct gtp_packet_desc *p, uint32_t tei) static void gtphub_mapping_del_cb(struct expiring_item *expi); -static struct nr_mapping *gtphub_mapping_new() +static struct nr_mapping *gtphub_mapping_new(void) { struct nr_mapping *nrm; nrm = talloc_zero(osmo_gtphub_ctx, struct nr_mapping); @@ -995,7 +995,7 @@ static const char *gtphub_tunnel_side_str(struct gtphub_tunnel *tun, char *pos = buf; int left = sizeof(buf); int l; - + struct gtphub_tunnel_endpoint *c, *u; c = &tun->endpoint[side_idx][GTPH_PLANE_CTRL]; u = &tun->endpoint[side_idx][GTPH_PLANE_USER]; @@ -1104,7 +1104,7 @@ static void gtphub_tunnel_del_cb(struct expiring_item *expi) /* rate counter index for hubs: [7; 10] */ #define CTR_IDX_HUB(s, p) CTR_IDX(s, p, 3, 2) -static struct gtphub_tunnel *gtphub_tunnel_new() +static struct gtphub_tunnel *gtphub_tunnel_new(void) { struct gtphub_tunnel *tun; tun = talloc_zero(osmo_gtphub_ctx, struct gtphub_tunnel); @@ -2283,7 +2283,7 @@ int gtphub_handle_buf(struct gtphub *hub, != 0) return -1; } - + /* Either to_peer was resolved from an existing tunnel, * or a PDP Ctx and thus a tunnel has just been created, * or the tunnel has been deleted due to this message. */ @@ -2690,7 +2690,7 @@ static struct gtphub_peer_addr *gtphub_addr_have(struct gtphub *hub, struct gtphub_peer *peer = gtphub_peer_new(hub, bind); a = gtphub_peer_add_addr(peer, addr); - + LOG(LOGL_DEBUG, "New peer address: %s %s\n", bind->label, gsn_addr_to_str(&a->addr)); diff --git a/src/gtphub/gtphub_ares.c b/src/gtphub/gtphub_ares.c index 87dc860c4..774563db4 100644 --- a/src/gtphub/gtphub_ares.c +++ b/src/gtphub/gtphub_ares.c @@ -28,11 +28,12 @@ #include <string.h> #include <unistd.h> -#include <osmocom/sgsn/gtphub.h> +#include <osmocom/gtphub/gtphub.h> #include <osmocom/sgsn/debug.h> #include <osmocom/core/utils.h> #include <osmocom/gsm/apn.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> /* TODO split GRX ares from sgsn into a separate struct and allow use without * globals. */ @@ -56,8 +57,8 @@ struct ggsn_lookup { struct gtphub *hub; char imsi_str[GSM23003_IMSI_MAX_DIGITS+1]; - char apn_ni_str[GSM_APN_LENGTH]; - char apn_oi_str[GSM_APN_LENGTH]; + char apn_ni_str[APN_MAXLEN+1]; + char apn_oi_str[APN_MAXLEN+1]; int have_3dig_mnc; }; diff --git a/src/gtphub/gtphub_main.c b/src/gtphub/gtphub_main.c index a9a7529cc..9b0532b24 100644 --- a/src/gtphub/gtphub_main.c +++ b/src/gtphub/gtphub_main.c @@ -34,6 +34,7 @@ #include <osmocom/core/logging.h> #include <osmocom/core/utils.h> #include <osmocom/core/rate_ctr.h> +#include <osmocom/core/msgb.h> #include <osmocom/vty/logging.h> #include <osmocom/vty/telnet_interface.h> @@ -41,10 +42,10 @@ #include <osmocom/vty/misc.h> #include <osmocom/sgsn/debug.h> -#include <osmocom/sgsn/gtphub.h> +#include <osmocom/gtphub/gtphub.h> #include <osmocom/sgsn/vty.h> -#include "../../bscconfig.h" +#include "../../config.h" #if BUILD_IU #include <osmocom/sigtran/osmo_ss7.h> @@ -353,8 +354,7 @@ int main(int argc, char **argv) } /* start telnet after reading config for vty_get_bind_addr() */ - rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(), - OSMO_VTY_PORT_GTPHUB); + rc = telnet_init_default(osmo_gtphub_ctx, NULL, OSMO_VTY_PORT_GTPHUB); if (rc < 0) exit(1); diff --git a/src/gtphub/gtphub_sock.c b/src/gtphub/gtphub_sock.c index 183753348..6f299d2d6 100644 --- a/src/gtphub/gtphub_sock.c +++ b/src/gtphub/gtphub_sock.c @@ -25,7 +25,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <osmocom/sgsn/gtphub.h> +#include <errno.h> +#include <string.h> + +#include <osmocom/core/utils.h> + +#include <osmocom/gtphub/gtphub.h> #include <osmocom/sgsn/debug.h> /* Convenience makro, note: only within this C file. */ diff --git a/src/gtphub/gtphub_vty.c b/src/gtphub/gtphub_vty.c index abc08fd69..b5f102ae6 100644 --- a/src/gtphub/gtphub_vty.c +++ b/src/gtphub/gtphub_vty.c @@ -31,7 +31,7 @@ #include <osmocom/vty/misc.h> #include <osmocom/sgsn/vty.h> -#include <osmocom/sgsn/gtphub.h> +#include <osmocom/gtphub/gtphub.h> /* TODO split GRX ares from sgsn into a separate struct and allow use without * globals. */ diff --git a/src/sgsn/Makefile.am b/src/sgsn/Makefile.am index 9e4a34264..93b9fa058 100644 --- a/src/sgsn/Makefile.am +++ b/src/sgsn/Makefile.am @@ -40,12 +40,13 @@ bin_PROGRAMS = \ $(NULL) osmo_sgsn_SOURCES = \ - gprs_gb.c \ + apn.c \ + gprs_bssgp.c \ gprs_gmm_attach.c \ gprs_gmm.c \ gprs_gmm_fsm.c \ gprs_mm_state_gb_fsm.c \ - gprs_sgsn.c \ + gprs_ns.c \ gprs_sm.c \ gprs_sndcp.c \ gprs_sndcp_comp.c \ @@ -53,12 +54,16 @@ osmo_sgsn_SOURCES = \ gprs_sndcp_pcomp.c \ gprs_sndcp_vty.c \ gprs_sndcp_xid.c \ + gtp_ggsn.c \ gtp_mme.c \ + sgsn.c \ sgsn_main.c \ sgsn_vty.c \ sgsn_libgtp.c \ gprs_llc.c \ gprs_llc_vty.c \ + mmctx.c \ + pdpctx.c \ sgsn_ctrl.c \ sgsn_auth.c \ gprs_subscriber.c \ diff --git a/src/sgsn/apn.c b/src/sgsn/apn.c new file mode 100644 index 000000000..a89d15866 --- /dev/null +++ b/src/sgsn/apn.c @@ -0,0 +1,123 @@ +/* APN contexts */ + +/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org> + * (C) 2010 by On-Waves + * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <string.h> +#include <talloc.h> + +#include <osmocom/sgsn/apn.h> +#include <osmocom/sgsn/sgsn.h> + +static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix) +{ + struct apn_ctx *actx; + + actx = talloc_zero(sgsn, struct apn_ctx); + if (!actx) + return NULL; + actx->name = talloc_strdup(actx, ap_name); + actx->imsi_prefix = talloc_strdup(actx, imsi_prefix); + + llist_add_tail(&actx->list, &sgsn->apn_list); + + return actx; +} + +void sgsn_apn_ctx_free(struct apn_ctx *actx) +{ + llist_del(&actx->list); + talloc_free(actx); +} + +struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi) +{ + struct apn_ctx *actx; + struct apn_ctx *found_actx = NULL; + size_t imsi_prio = 0; + size_t name_prio = 0; + size_t name_req_len = strlen(name); + + llist_for_each_entry(actx, &sgsn->apn_list, list) { + size_t name_ref_len, imsi_ref_len; + const char *name_ref_start, *name_match_start; + + imsi_ref_len = strlen(actx->imsi_prefix); + if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0) + continue; + + if (imsi_ref_len < imsi_prio) + continue; + + /* IMSI matches */ + + name_ref_start = &actx->name[0]; + if (name_ref_start[0] == '*') { + /* Suffix match */ + name_ref_start += 1; + name_ref_len = strlen(name_ref_start); + if (name_ref_len > name_req_len) + continue; + } else { + name_ref_len = strlen(name_ref_start); + if (name_ref_len != name_req_len) + continue; + } + + name_match_start = name + (name_req_len - name_ref_len); + if (strcasecmp(name_match_start, name_ref_start) != 0) + continue; + + /* IMSI and name match */ + + if (imsi_ref_len == imsi_prio && name_ref_len < name_prio) + /* Lower priority, skip */ + continue; + + imsi_prio = imsi_ref_len; + name_prio = name_ref_len; + found_actx = actx; + } + return found_actx; +} + +struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix) +{ + struct apn_ctx *actx; + + llist_for_each_entry(actx, &sgsn->apn_list, list) { + if (strcasecmp(name, actx->name) == 0 && + strcasecmp(imsi_prefix, actx->imsi_prefix) == 0) + return actx; + } + return NULL; +} + +struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix) +{ + struct apn_ctx *actx; + + actx = sgsn_apn_ctx_by_name(name, imsi_prefix); + if (!actx) + actx = sgsn_apn_ctx_alloc(name, imsi_prefix); + + return actx; +} diff --git a/src/sgsn/gprs_bssgp.c b/src/sgsn/gprs_bssgp.c new file mode 100644 index 000000000..5db751cce --- /dev/null +++ b/src/sgsn/gprs_bssgp.c @@ -0,0 +1,95 @@ +/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ + +/* (C) 2010 by Harald Welte <laforge@gnumonks.org> + * (C) 2010 by On-Waves + * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#include <osmocom/core/prim.h> +#include <osmocom/core/rate_ctr.h> + +#include <osmocom/gprs/gprs_bssgp.h> +#include <osmocom/gprs/gprs_ns2.h> + +#include <osmocom/sgsn/gprs_llc.h> +#include <osmocom/sgsn/gprs_gmm.h> +#include <osmocom/sgsn/sgsn_rim.h> +#include <osmocom/sgsn/mmctx.h> + +/* call-back function for the BSSGP protocol */ +int sgsn_bssgp_rx_prim(struct osmo_prim_hdr *oph) +{ + struct osmo_bssgp_prim *bp; + bp = container_of(oph, struct osmo_bssgp_prim, oph); + + switch (oph->sap) { + case SAP_BSSGP_LL: + switch (oph->primitive) { + case PRIM_BSSGP_UL_UD: + return gprs_llc_rcvmsg(oph->msg, bp->tp); + } + break; + case SAP_BSSGP_GMM: + switch (oph->primitive) { + case PRIM_BSSGP_GMM_SUSPEND: + return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli); + case PRIM_BSSGP_GMM_RESUME: + return gprs_gmm_rx_resume(bp->ra_id, bp->tlli, + bp->u.resume.suspend_ref); + } + break; + case SAP_BSSGP_NM: + break; + case SAP_BSSGP_RIM: + return sgsn_rim_rx_from_gb(bp, oph->msg); + } + return 0; +} + +int sgsn_bssgp_page_ps_ra(struct sgsn_mm_ctx *mmctx) +{ + struct bssgp_paging_info pinfo; + int rc; + + /* FIXME: page whole routing area, not only the last known cell */ + + /* initiate PS PAGING procedure */ + memset(&pinfo, 0, sizeof(pinfo)); + pinfo.mode = BSSGP_PAGING_PS; + pinfo.scope = BSSGP_PAGING_BVCI; + pinfo.bvci = mmctx->gb.bvci; + pinfo.imsi = mmctx->imsi; + pinfo.ptmsi = &mmctx->p_tmsi; + pinfo.drx_params = mmctx->drx_parms; + pinfo.qos[0] = 0; // FIXME + rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo); + rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PAGING_PS)); + + return rc; +} + +/* called by the bssgp layer to send NS PDUs */ +int sgsn_bssgp_dispatch_ns_unitdata_req_cb(void *ctx, struct msgb *msg) +{ + struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx; + struct osmo_gprs_ns2_prim nsp = {}; + nsp.nsei = msgb_nsei(msg); + nsp.bvci = msgb_bvci(msg); + osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg); + return gprs_ns2_recv_prim(nsi, &nsp.oph); +} diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c index 1f68558ef..c3f5cd3d2 100644 --- a/src/sgsn/gprs_gmm.c +++ b/src/sgsn/gprs_gmm.c @@ -30,7 +30,7 @@ #include <netinet/in.h> #include <arpa/inet.h> -#include "bscconfig.h" +#include "config.h" #include <osmocom/core/msgb.h> #include <osmocom/gsm/tlv.h> @@ -41,13 +41,14 @@ #include <osmocom/core/utils.h> #include <osmocom/core/tdef.h> #include <osmocom/crypt/auth.h> +#include <osmocom/crypt/utran_cipher.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/gprs/gprs_bssgp.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/gprs_llc.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_utils.h> #include <osmocom/sgsn/gprs_subscriber.h> @@ -59,17 +60,17 @@ #include <osmocom/sgsn/signal.h> #include <osmocom/sgsn/gprs_sndcp.h> #include <osmocom/sgsn/gprs_ranap.h> +#include <osmocom/sgsn/gprs_sm.h> +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/pdpctx.h> #include <pdp.h> #define PTMSI_ALLOC -extern struct sgsn_instance *sgsn; -extern void *tall_sgsn_ctx; - static const struct tlv_definition gsm48_gmm_att_tlvdef = { .def = { - [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 1 }, + [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_SINGLE_TV, 1 }, [GSM48_IE_GMM_TIMER_READY] = { TLV_TYPE_TV, 1 }, [GSM48_IE_GMM_ALLOC_PTMSI] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 }, @@ -78,6 +79,7 @@ static const struct tlv_definition gsm48_gmm_att_tlvdef = { [GSM48_IE_GMM_AUTH_RES_EXT] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_AUTH_FAIL_PAR] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_RX_NPDU_NUM_LIST] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_FIXED, 2 }, [GSM48_IE_GMM_MS_NET_CAPA] = { TLV_TYPE_TLV, 0 }, [GSM48_IE_GMM_PDP_CTX_STATUS] = { TLV_TYPE_TLV, 0 }, @@ -916,7 +918,13 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) /* The MS is authorized */ #ifdef BUILD_IU if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) { - rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key); + /* Is any encryption above UEA0 enabled? */ + bool send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0); + LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n", + send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask); + /* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this + * is not possible in the iu_client API. See OS#5487. */ + rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key); ctx->iu.new_key = 0; return rc; } @@ -1319,11 +1327,11 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len); - if (!(ctx->ue_cipher_mask & sgsn->cfg.cipher_support_mask)) { + if (!(ctx->ue_cipher_mask & sgsn->cfg.gea_encryption_mask)) { reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC; LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI " "%s because MS do not support required encryption, mask UE:0x%02x NW:0x%02x \n", - mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.cipher_support_mask); + mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask); goto rejected; } @@ -1335,7 +1343,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, * So let's just assume we will have the auth data required to make it work. */ - ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.cipher_support_mask); + ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.gea_encryption_mask); #ifdef PTMSI_ALLOC /* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */ @@ -1759,6 +1767,10 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, /* Update the MM context with the new (i.e. foreign) TLLI */ mmctx->gb.tlli = msgb_tlli(msg); } + /* Update the MM context with the new DRX params */ + if (TLVP_PRESENT(&tp, GSM48_IE_GMM_DRX_PARAM)) + memcpy(&mmctx->drx_parms, TLVP_VAL(&tp, GSM48_IE_GMM_DRX_PARAM), sizeof(mmctx->drx_parms)); + /* FIXME: Update the MM context with the MS radio acc capabilities */ /* FIXME: Update the MM context with the MS network capabilities */ @@ -2306,3 +2318,51 @@ int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli, osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RESUME, NULL); return 0; } + +/* Has to be called whenever any PDU (signaling, data, ...) has been received */ +void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg) +{ + msgid2mmctx(mmctx, msg); + if (mmctx->gb.llme) + osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL); +} + +/* Main entry point for incoming 04.08 GPRS messages from Gb */ +int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, + bool drop_cipherable) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t pdisc = gsm48_hdr_pdisc(gh); + struct sgsn_mm_ctx *mmctx; + struct gprs_ra_id ra_id; + int rc = -EINVAL; + + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); + if (mmctx) { + rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN)); + mmctx->gb.llme = llme; + gprs_gb_recv_pdu(mmctx, msg); + } + + /* MMCTX can be NULL */ + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable); + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(mmctx, msg, llme); + break; + default: + LOGMMCTXP(LOGL_NOTICE, mmctx, + "Unknown GSM 04.08 discriminator 0x%02x: %s\n", + pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg))); + /* FIXME: return status message */ + break; + } + + /* MMCTX can be invalid */ + + return rc; +} diff --git a/src/sgsn/gprs_gmm_attach.c b/src/sgsn/gprs_gmm_attach.c index 629cc53fe..708ea8f23 100644 --- a/src/sgsn/gprs_gmm_attach.c +++ b/src/sgsn/gprs_gmm_attach.c @@ -1,10 +1,12 @@ #include <osmocom/core/tdef.h> +#include <osmocom/crypt/utran_cipher.h> #include <osmocom/sgsn/gprs_gmm_attach.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/gprs_gmm.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/sgsn.h> #define X(s) (1 << (s)) @@ -257,6 +259,7 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_ { #ifdef BUILD_IU struct sgsn_mm_ctx *ctx = fi->priv; + bool send_ck; /* TODO: shouldn't this set always? not only when the integrity_active? */ if (ctx->iu.ue_ctx->integrity_active) { @@ -264,7 +267,14 @@ static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_ return; } - ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 0, ctx->iu.new_key); + /* Is any encryption above UEA0 enabled? */ + send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0); + LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA encryption mask = 0x%x)\n", + send_ck ? "sending" : "not sending", sgsn->cfg.uea_encryption_mask); + + /* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2(). However, this + * is not possible in the iu_client API. See OS#5487. */ + ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck, ctx->iu.new_key); ctx->iu.new_key = 0; #endif } diff --git a/src/sgsn/gprs_gmm_fsm.c b/src/sgsn/gprs_gmm_fsm.c index 78946b5b1..57e1ec3bb 100644 --- a/src/sgsn/gprs_gmm_fsm.c +++ b/src/sgsn/gprs_gmm_fsm.c @@ -1,6 +1,6 @@ /* GMM mobility management states on the network side, 3GPP TS 24.008 § 4.1.3.3 */ /* - * (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de> + * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> * All Rights Reserved * * SPDX-License-Identifier: AGPL-3.0+ @@ -80,6 +80,11 @@ static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, v case E_GMM_COMMON_PROC_INIT_REQ: gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT); break; + case E_GMM_COMMON_PROC_SUCCESS: + /* If we were moved from ST_GMM_COMMON_PROC_INIT here by + * E_GMM_ATTACH_SUCCESS instead of E_GMM_COMMON_PROC_SUCCESS then we'll receive the latter here: + * we should simply ignore it */ + break; /* case E_GMM_NET_INIT_DETACH_REQ: gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT); break; */ @@ -141,6 +146,7 @@ static struct osmo_fsm_state gmm_fsm_states[] = { [ST_GMM_REGISTERED_NORMAL] = { .in_event_mask = X(E_GMM_COMMON_PROC_INIT_REQ) | + X(E_GMM_COMMON_PROC_SUCCESS) | /* X(E_GMM_NET_INIT_DETACH_REQ) | */ /* X(E_GMM_MS_INIT_DETACH_REQ) | */ X(E_GMM_SUSPEND), diff --git a/src/sgsn/gprs_llc.c b/src/sgsn/gprs_llc.c index eea1cecfa..6f563851f 100644 --- a/src/sgsn/gprs_llc.c +++ b/src/sgsn/gprs_llc.c @@ -33,7 +33,7 @@ #include <osmocom/gsm/gsm_utils.h> #include <osmocom/sgsn/debug.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_llc.h> #include <osmocom/sgsn/crc24.h> @@ -50,10 +50,21 @@ const struct value_string gprs_llc_llme_state_names[] = { { 0, NULL } }; +const struct value_string gprs_llc_lle_state_names[] = { + { GPRS_LLES_UNASSIGNED, "TLLI Unassigned" }, + { GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" }, + { GPRS_LLES_LOCAL_EST, "Local Establishment" }, + { GPRS_LLES_REMOTE_EST, "Remote Establishment" }, + { GPRS_LLES_ABM, "Asynchronous Balanced Mode" }, + { GPRS_LLES_LOCAL_REL, "Local Release" }, + { GPRS_LLES_TIMER_REC, "Timer Recovery" }, + { 0, NULL } +}; + static struct gprs_llc_llme *llme_alloc(uint32_t tlli); -static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, +static int gprs_llc_tx_xid(const struct gprs_llc_lle *lle, struct msgb *msg, int command); -static int gprs_llc_tx_dm(struct gprs_llc_lle *lle); +static int gprs_llc_tx_dm(const struct gprs_llc_lle *lle); static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command, enum gprs_llc_u_cmd u_cmd, int pf_bit); @@ -212,7 +223,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request, int bytes_request_len, uint8_t *bytes_response, int bytes_response_maxlen, - struct gprs_llc_lle *lle) + const struct gprs_llc_lle *lle) { /* Note: This function computes the response that is sent back to the * MS when a mobile originated XID is received. The function is @@ -288,7 +299,7 @@ static int gprs_llc_process_xid_ind(uint8_t *bytes_request, /* Dispatch XID indications and responses comming from the MS */ static void rx_llc_xid(struct gprs_llc_lle *lle, - struct gprs_llc_hdr_parsed *gph) + const struct gprs_llc_hdr_parsed *gph) { uint8_t response[1024]; int response_len; @@ -590,6 +601,7 @@ static struct gprs_llc_llme *llme_alloc(uint32_t tlli) static void llme_free(struct gprs_llc_llme *llme) { + gprs_sndcp_sm_deactivate_ind_by_llme(llme); gprs_sndcp_comp_free(llme->comp.proto); gprs_sndcp_comp_free(llme->comp.data); llist_del(&llme->list); @@ -680,7 +692,7 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command, } /* Send XID response to LLE */ -static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, +static int gprs_llc_tx_xid(const struct gprs_llc_lle *lle, struct msgb *msg, int command) { /* copy identifiers from LLE to ensure lower layers can route */ @@ -691,7 +703,7 @@ static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg, return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1); } -static int gprs_llc_tx_dm(struct gprs_llc_lle *lle) +static int gprs_llc_tx_dm(const struct gprs_llc_lle *lle) { struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_DM"); @@ -704,7 +716,7 @@ static int gprs_llc_tx_dm(struct gprs_llc_lle *lle) } /* encrypt information field + FCS, if needed! */ -static int apply_gea(struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu, +static int apply_gea(const struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu, uint32_t oc, uint8_t sapi, uint8_t *fcs, uint8_t *data) { uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK]; @@ -964,9 +976,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) llhp.data); if (rc < 0) return rc; - llhp.fcs = *(llhp.data + llhp.data_len); - llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8; - llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16; + llhp.fcs = *(llhp.data + llhp.data_len); + llhp.fcs |= *(llhp.data + llhp.data_len + 1) << 8; + llhp.fcs |= *(llhp.data + llhp.data_len + 2) << 16; } else { LOGP(DLLC, LOGL_NOTICE, "encrypted frame for LLC that " "has no KC/Algo! Dropping.\n"); @@ -1018,7 +1030,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) case GPRS_SAPI_SNDCP9: case GPRS_SAPI_SNDCP11: /* send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */ - rc = sndcp_llunitdata_ind(msg, lle, llhp.data, llhp.data_len); + rc = sndcp_ll_unitdata_ind(msg, lle, llhp.data, llhp.data_len); break; case GPRS_SAPI_SMS: /* FIXME */ @@ -1036,7 +1048,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) } /* Propagate crypto parameters MM -> LLME */ -void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme) +void gprs_llme_copy_key(const struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme) { if (!mm) return; diff --git a/src/sgsn/gprs_llc_vty.c b/src/sgsn/gprs_llc_vty.c index 418be8348..4572f957c 100644 --- a/src/sgsn/gprs_llc_vty.c +++ b/src/sgsn/gprs_llc_vty.c @@ -39,22 +39,11 @@ #include <osmocom/vty/vty.h> #include <osmocom/vty/command.h> -struct value_string gprs_llc_state_strs[] = { - { GPRS_LLES_UNASSIGNED, "TLLI Unassigned" }, - { GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" }, - { GPRS_LLES_LOCAL_EST, "Local Establishment" }, - { GPRS_LLES_REMOTE_EST, "Remote Establishment" }, - { GPRS_LLES_ABM, "Asynchronous Balanced Mode" }, - { GPRS_LLES_LOCAL_REL, "Local Release" }, - { GPRS_LLES_TIMER_REC, "Timer Recovery" }, - { 0, NULL } -}; - static void vty_dump_lle(struct vty *vty, struct gprs_llc_lle *lle) { struct gprs_llc_params *par = &lle->params; - vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi, - get_value_string(gprs_llc_state_strs, lle->state), + vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi, + get_value_string(gprs_llc_lle_state_names, lle->state), lle->vu_send, lle->vu_recv); vty_out(vty, " Vsent=%u Vack=%u Vrecv=%u, RetransCtr=%u%s", lle->v_sent, lle->v_ack, lle->v_recv, @@ -79,7 +68,7 @@ static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme) get_value_string(gprs_cipher_names, llme->algo), llme->iov_ui, llme->cksn, llme->age_timestamp == GPRS_LLME_RESET_AGE ? 0 : (int)(now_tp.tv_sec - (time_t)llme->age_timestamp), - get_value_string(gprs_llc_state_strs, llme->state), VTY_NEWLINE); + get_value_string(gprs_llc_llme_state_names, llme->state), VTY_NEWLINE); for (i = 0; i < ARRAY_SIZE(valid_sapis); i++) { struct gprs_llc_lle *lle; diff --git a/src/sgsn/gprs_mm_state_gb_fsm.c b/src/sgsn/gprs_mm_state_gb_fsm.c index 6e812d31d..dde7b770a 100644 --- a/src/sgsn/gprs_mm_state_gb_fsm.c +++ b/src/sgsn/gprs_mm_state_gb_fsm.c @@ -1,6 +1,6 @@ /* TS 23.060 § 6.1.1 Mobility Management States (A/Gb mode) */ /* - * (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de> + * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> * All Rights Reserved * * SPDX-License-Identifier: AGPL-3.0+ @@ -27,6 +27,7 @@ #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/sgsn.h> +#include <osmocom/sgsn/mmctx.h> #define X(s) (1 << (s)) diff --git a/src/sgsn/gprs_mm_state_iu_fsm.c b/src/sgsn/gprs_mm_state_iu_fsm.c index b1604f83b..c2e9c4498 100644 --- a/src/sgsn/gprs_mm_state_iu_fsm.c +++ b/src/sgsn/gprs_mm_state_iu_fsm.c @@ -1,6 +1,6 @@ /* TS 23.060 § 6.1.2 Mobility Management States (Iu mode) */ /* - * (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de> + * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> * All Rights Reserved * * SPDX-License-Identifier: AGPL-3.0+ @@ -29,6 +29,9 @@ #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/sgsn/gprs_ranap.h> +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/pdpctx.h> +#include <osmocom/sgsn/mmctx.h> #define X(s) (1 << (s)) diff --git a/src/sgsn/gprs_gb.c b/src/sgsn/gprs_ns.c index 96157a01e..eb447facd 100644 --- a/src/sgsn/gprs_gb.c +++ b/src/sgsn/gprs_ns.c @@ -29,95 +29,10 @@ #include <osmocom/gprs/gprs_bssgp_bss.h> #include <osmocom/sgsn/gprs_llc.h> -#include "bscconfig.h" +#include "config.h" -#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h> -#include <osmocom/sgsn/gprs_sgsn.h> -#include <osmocom/sgsn/gprs_gmm.h> -#include <osmocom/sgsn/gprs_sm.h> #include <osmocom/sgsn/debug.h> -/* Has to be called whenever any PDU (signaling, data, ...) has been received */ -void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg) { - msgid2mmctx(mmctx, msg); - if (mmctx->gb.llme) - osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL); -} - -/* Main entry point for incoming 04.08 GPRS messages from Gb */ -int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, - bool drop_cipherable) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t pdisc = gsm48_hdr_pdisc(gh); - struct sgsn_mm_ctx *mmctx; - struct gprs_ra_id ra_id; - int rc = -EINVAL; - - bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); - mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); - if (mmctx) { - rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PKTS_SIG_IN)); - mmctx->gb.llme = llme; - gprs_gb_recv_pdu(mmctx, msg); - } - - /* MMCTX can be NULL */ - - switch (pdisc) { - case GSM48_PDISC_MM_GPRS: - rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable); - break; - case GSM48_PDISC_SM_GPRS: - rc = gsm0408_rcv_gsm(mmctx, msg, llme); - break; - default: - LOGMMCTXP(LOGL_NOTICE, mmctx, - "Unknown GSM 04.08 discriminator 0x%02x: %s\n", - pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg))); - /* FIXME: return status message */ - break; - } - - /* MMCTX can be invalid */ - - return rc; -} - - -int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx) -{ - struct bssgp_paging_info pinfo; - int rc; - - /* FIXME: page whole routing area, not only the last known cell */ - - /* initiate PS PAGING procedure */ - memset(&pinfo, 0, sizeof(pinfo)); - pinfo.mode = BSSGP_PAGING_PS; - pinfo.scope = BSSGP_PAGING_BVCI; - pinfo.bvci = mmctx->gb.bvci; - pinfo.imsi = mmctx->imsi; - pinfo.ptmsi = &mmctx->p_tmsi; - pinfo.drx_params = mmctx->drx_parms; - pinfo.qos[0] = 0; // FIXME - rc = bssgp_tx_paging(mmctx->gb.nsei, 0, &pinfo); - rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_PAGING_PS)); - - return rc; -} - -/* called by the bssgp layer to send NS PDUs */ -int gprs_gb_send_cb(void *ctx, struct msgb *msg) -{ - struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx; - struct osmo_gprs_ns2_prim nsp = {}; - nsp.nsei = msgb_nsei(msg); - nsp.bvci = msgb_bvci(msg); - osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg); - return gprs_ns2_recv_prim(nsi, &nsp.oph); -} - void gprs_ns_prim_status_cb(struct osmo_gprs_ns2_prim *nsp) { switch (nsp->u.status.cause) { diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c index ead20f776..5e0d8edc6 100644 --- a/src/sgsn/gprs_ranap.c +++ b/src/sgsn/gprs_ranap.c @@ -21,7 +21,7 @@ * */ -#include "bscconfig.h" +#include "config.h" #include <gtp.h> #include <osmocom/core/rate_ctr.h> @@ -37,6 +37,10 @@ #include <osmocom/sgsn/gprs_ranap.h> #include <osmocom/sgsn/gprs_gmm_attach.h> #include <osmocom/sgsn/gprs_mm_state_iu_fsm.h> +#include <osmocom/sgsn/gtp_ggsn.h> +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/pdpctx.h> +#include <osmocom/sgsn/mmctx.h> /* Send RAB activation requests for all PDP contexts */ void activate_pdp_rabs(struct sgsn_mm_ctx *ctx) @@ -145,6 +149,11 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type rc = 0; break; case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE: + /* FIXME: verify that a permitted UEA level was chosen. Compare how osmo-msc does it in + * msc_a_ran_dec_from_msc_i(), case RAN_MSG_CIPHER_MODE_COMPLETE. + * We should dissolve iu_client.c, it was a design mistake when first implementing Iu support. osmo-msc + * has moved away from it a long time ago. + */ /* Continue authentication here */ mm->iu.ue_ctx->integrity_active = 1; ranap_iu_tx_common_id(mm->iu.ue_ctx, mm->imsi); diff --git a/src/sgsn/gprs_sm.c b/src/sgsn/gprs_sm.c index 6c09c4f97..88d1feb5a 100644 --- a/src/sgsn/gprs_sm.c +++ b/src/sgsn/gprs_sm.c @@ -26,7 +26,7 @@ #include <arpa/inet.h> #include <netdb.h> -#include "bscconfig.h" +#include "config.h" #include <osmocom/core/rate_ctr.h> #include <osmocom/core/tdef.h> @@ -36,13 +36,15 @@ #include <osmocom/sgsn/gprs_sm.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_utils.h> +#include <osmocom/sgsn/gtp_ggsn.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/gprs_llc.h> #include <osmocom/sgsn/gprs_sndcp.h> #include <osmocom/sgsn/gprs_ranap.h> - -extern void *tall_sgsn_ctx; +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/pdpctx.h> +#include <osmocom/sgsn/mmctx.h> /* 3GPP TS 04.08 sec 6.1.3.4.3(.a) "Abnormal cases" */ #define T339X_MAX_RETRANS 4 @@ -376,7 +378,7 @@ static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent * goto reject_due_failure; } - ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX); + ggsn = sgsn_ggsn_ctx_alloc(sgsn, UINT32_MAX); if (!ggsn) { LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n"); goto reject_due_failure; @@ -448,7 +450,7 @@ static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *del DEBUGPC(DMM, "IPv4 "); if (req_pdpa_len >= 6) { struct in_addr ia; - ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2))); + ia.s_addr = osmo_load32be(req_pdpa+2); DEBUGPC(DMM, "%s ", inet_ntop(AF_INET, &ia, buf, sizeof(buf))); } break; diff --git a/src/sgsn/gprs_sndcp.c b/src/sgsn/gprs_sndcp.c index 6692f1ae5..3eae127fc 100644 --- a/src/sgsn/gprs_sndcp.c +++ b/src/sgsn/gprs_sndcp.c @@ -32,7 +32,7 @@ #include <osmocom/gprs/gprs_bssgp.h> #include <osmocom/sgsn/debug.h> -#include <osmocom/sgsn/gprs_gb.h> +#include <osmocom/sgsn/gprs_ns.h> #include <osmocom/sgsn/gprs_llc.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/sgsn/gprs_sndcp.h> @@ -41,6 +41,9 @@ #include <osmocom/sgsn/gprs_sndcp_pcomp.h> #include <osmocom/sgsn/gprs_sndcp_dcomp.h> #include <osmocom/sgsn/gprs_sndcp_comp.h> +#include <osmocom/sgsn/gprs_gmm.h> +#include <osmocom/sgsn/mmctx.h> +#include <osmocom/sgsn/gtp.h> #define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */ @@ -66,7 +69,7 @@ static uint16_t calc_ip_csum(uint8_t *data, int len) } /* Calculate TCP/IP checksum */ -static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) +static uint16_t calc_tcpip_csum(const void *ctx, const uint8_t *packet, int len) { uint8_t *buf; uint16_t csum; @@ -84,7 +87,7 @@ static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len) } /* Show some ip packet details */ -static void debug_ip_packet(uint8_t *data, int len, int dir, char *info) +static void debug_ip_packet(const uint8_t *data, int len, int dir, const char *info) { uint8_t tcp_flags; char flags_debugmsg[256]; @@ -173,7 +176,7 @@ struct sndcp_common_hdr { uint8_t first:1; uint8_t spare:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:1, first:1, type:1, more:1, nsapi:4; #endif } __attribute__((packed)); @@ -185,7 +188,7 @@ struct sndcp_comp_hdr { uint8_t pcomp:4; uint8_t dcomp:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t dcomp:4, pcomp:4; #endif } __attribute__((packed)); @@ -198,7 +201,7 @@ struct sndcp_udata_hdr { /* octet 4 */ uint8_t npdu_low; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t seg_nr:4, npdu_high:4; uint8_t npdu_low; #endif @@ -221,7 +224,8 @@ struct defrag_queue_entry { LLIST_HEAD(gprs_sndcp_entities); /* Check if any compression parameters are set in the sgsn configuration */ -static inline int any_pcomp_or_dcomp_active(struct sgsn_instance *sgsn) { +static inline int any_pcomp_or_dcomp_active(const struct sgsn_instance *sgsn) +{ if (sgsn->cfg.pcomp_rfc1144.active || sgsn->cfg.pcomp_rfc1144.passive || sgsn->cfg.dcomp_v42bis.active || sgsn->cfg.dcomp_v42bis.passive) return true; @@ -260,7 +264,7 @@ static int defrag_enqueue(struct gprs_sndcp_entity *sne, uint8_t seg_nr, } /* return if we have all segments of this N-PDU */ -static int defrag_have_all_segments(struct gprs_sndcp_entity *sne) +static int defrag_have_all_segments(const struct gprs_sndcp_entity *sne) { uint32_t seg_needed = 0; unsigned int i; @@ -275,7 +279,7 @@ static int defrag_have_all_segments(struct gprs_sndcp_entity *sne) return 0; } -static struct defrag_queue_entry *defrag_get_seg(struct gprs_sndcp_entity *sne, +static struct defrag_queue_entry *defrag_get_seg(const struct gprs_sndcp_entity *sne, uint32_t seg_nr) { struct defrag_queue_entry *dqe; @@ -289,13 +293,62 @@ static struct defrag_queue_entry *defrag_get_seg(struct gprs_sndcp_entity *sne, return NULL; } +/* Returns talloced buffer containing decompressed data, NULL on error. */ +static uint8_t *decompress_segment(struct gprs_sndcp_entity *sne, void *ctx, + const uint8_t *compressed_data, unsigned int compressed_data_len, + unsigned int *decompressed_data_len) +{ + int rc; + uint8_t *expnd = NULL; + *decompressed_data_len = 0; + +#if DEBUG_IP_PACKETS == 1 + DEBUGP(DSNDCP, "\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "===================================================\n"); +#endif + + expnd = talloc_zero_size(ctx, compressed_data_len * MAX_DATADECOMPR_FAC + + MAX_HDRDECOMPR_INCR); + memcpy(expnd, compressed_data, compressed_data_len); + + /* Apply data decompression */ + rc = gprs_sndcp_dcomp_expand(expnd, compressed_data_len, sne->defrag.dcomp, + sne->defrag.data); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "Data decompression failed!\n"); + talloc_free(expnd); + return NULL; + } + + /* Apply header decompression */ + rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, sne->defrag.proto); + if (rc < 0) { + LOGP(DSNDCP, LOGL_ERROR, + "TCP/IP Header decompression failed!\n"); + talloc_free(expnd); + return NULL; + } + + *decompressed_data_len = rc; + +#if DEBUG_IP_PACKETS == 1 + debug_ip_packet(expnd, *decompressed_data_len, 1, "defrag_segments()"); + DEBUGP(DSNDCP, "===================================================\n"); + DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); + DEBUGP(DSNDCP, "\n"); +#endif + return expnd; +} + /* Perform actual defragmentation and create an output packet */ static int defrag_segments(struct gprs_sndcp_entity *sne) { struct msgb *msg; unsigned int seg_nr; uint8_t *npdu; - int npdu_len; + unsigned int npdu_len; int rc; uint8_t *expnd = NULL; @@ -336,53 +389,20 @@ static int defrag_segments(struct gprs_sndcp_entity *sne) * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ /* Decompress packet */ -#if DEBUG_IP_PACKETS == 1 - DEBUGP(DSNDCP, " \n"); - DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); - DEBUGP(DSNDCP, "===================================================\n"); -#endif if (any_pcomp_or_dcomp_active(sgsn)) { - - expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC + - MAX_HDRDECOMPR_INCR); - memcpy(expnd, npdu, npdu_len); - - /* Apply data decompression */ - rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp, - sne->defrag.data); - if (rc < 0) { - LOGP(DSNDCP, LOGL_ERROR, - "Data decompression failed!\n"); - talloc_free(expnd); - return -EIO; + expnd = decompress_segment(sne, msg, npdu, npdu_len, &npdu_len); + if (!expnd) { + rc = -EIO; + goto ret_free; } - - /* Apply header decompression */ - rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, - sne->defrag.proto); - if (rc < 0) { - LOGP(DSNDCP, LOGL_ERROR, - "TCP/IP Header decompression failed!\n"); - talloc_free(expnd); - return -EIO; - } - - /* Modify npu length, expnd is handed directly handed - * over to gsn_rx_sndcp_ud_ind(), see below */ - npdu_len = rc; - } else + } else { expnd = npdu; -#if DEBUG_IP_PACKETS == 1 - debug_ip_packet(expnd, npdu_len, 1, "defrag_segments()"); - DEBUGP(DSNDCP, "===================================================\n"); - DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); - DEBUGP(DSNDCP, " \n"); -#endif + } - /* Hand off packet to gtp */ - rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli, - sne->nsapi, msg, npdu_len, expnd); + /* Hand off packet to SGSN (SNDCP SN-UNITDATA.ind), which will forward it to GGSN (GTP): */ + rc = sndcp_sn_unitdata_ind(sne, msg, npdu_len, expnd); +ret_free: /* we must free the memory we allocated above; ownership is not transferred * downwards in the call above */ msgb_free(msg); @@ -522,7 +542,7 @@ int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi) } /* Entry point for the SNSM-DEACTIVATE.indication */ -int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi) +int sndcp_sm_deactivate_ind(const struct gprs_llc_lle *lle, uint8_t nsapi) { struct gprs_sndcp_entity *sne; @@ -544,6 +564,20 @@ int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi) return 0; } +/* Clean up all gprs_sndcp_entities related to llme (OS#4824) */ +void gprs_sndcp_sm_deactivate_ind_by_llme(const struct gprs_llc_llme *llme) +{ + struct gprs_sndcp_entity *sne, *sne2; + + llist_for_each_entry_safe(sne, sne2, &gprs_sndcp_entities, list) { + if (sne->lle->llme == llme) { + LOGP(DSNDCP, LOGL_INFO, "SNSM-DEACTIVATE.ind for SNDCP attached to llme=%p\n", llme); + /* Free and remove from list */ + sndcp_sm_deactivate_ind(sne->lle, sne->nsapi); + } + } +} + /* Fragmenter state */ struct sndcp_frag_state { uint8_t frag_nr; @@ -651,7 +685,7 @@ static int sndcp_send_ud_frag(struct sndcp_frag_state *fs, } /* Request transmission of a SN-PDU over specified LLC Entity + SAPI */ -int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi, +int sndcp_sn_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi, void *mmcontext) { struct gprs_sndcp_entity *sne; @@ -709,13 +743,14 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi sne = gprs_sndcp_entity_by_lle(lle, nsapi); if (!sne) { - LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity\n"); + LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity (lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n", + lle, lle->llme->tlli, lle->sapi, nsapi); msgb_free(msg); return -EIO; } /* Check if we need to fragment this N-PDU into multiple SN-PDUs */ - if (msg->len > lle->params.n201_u - + if (msg->len > lle->params.n201_u - (sizeof(*sch) + sizeof(*suh) + sizeof(*scomph))) { /* initialize the fragmenter state */ fs.msg = msg; @@ -760,7 +795,7 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi } /* Section 5.1.2.17 LL-UNITDATA.ind */ -int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, +int sndcp_ll_unitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t *hdr, uint16_t len) { struct gprs_sndcp_entity *sne; @@ -830,63 +865,40 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, LOGP(DSNDCP, LOGL_ERROR, "Short SNDCP N-PDU: %d\n", npdu_len); return -EIO; } - /* actually send the N-PDU to the SGSN core code, which then - * hands it off to the correct GTP tunnel + GGSN via gtp_data_req() */ + /* actually send the N-PDU to the SGSN core code (SNDCP SN-UNITDATA.ind) */ /* Decompress packet */ -#if DEBUG_IP_PACKETS == 1 - DEBUGP(DSNDCP, " \n"); - DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); - DEBUGP(DSNDCP, "===================================================\n"); -#endif if (any_pcomp_or_dcomp_active(sgsn)) { - - expnd = talloc_zero_size(msg, npdu_len * MAX_DATADECOMPR_FAC + - MAX_HDRDECOMPR_INCR); - memcpy(expnd, npdu, npdu_len); - - /* Apply data decompression */ - rc = gprs_sndcp_dcomp_expand(expnd, npdu_len, sne->defrag.dcomp, - sne->defrag.data); - if (rc < 0) { - LOGP(DSNDCP, LOGL_ERROR, - "Data decompression failed!\n"); - talloc_free(expnd); - return -EIO; - } - - /* Apply header decompression */ - rc = gprs_sndcp_pcomp_expand(expnd, rc, sne->defrag.pcomp, - sne->defrag.proto); - if (rc < 0) { - LOGP(DSNDCP, LOGL_ERROR, - "TCP/IP Header decompression failed!\n"); - talloc_free(expnd); - return -EIO; + expnd = decompress_segment(sne, msg, npdu, npdu_len, (unsigned int *)&npdu_len); + if (!expnd) { + rc = -EIO; + goto ret_free; } - - /* Modify npu length, expnd is handed directly handed - * over to gsn_rx_sndcp_ud_ind(), see below */ - npdu_len = rc; - } else + } else { expnd = npdu; -#if DEBUG_IP_PACKETS == 1 - debug_ip_packet(expnd, npdu_len, 1, "sndcp_llunitdata_ind()"); - DEBUGP(DSNDCP, "===================================================\n"); - DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n"); - DEBUGP(DSNDCP, " \n"); -#endif + } /* Hand off packet to gtp */ - rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, - sne->nsapi, msg, npdu_len, expnd); + rc = sndcp_sn_unitdata_ind(sne, msg, npdu_len, expnd); +ret_free: if (any_pcomp_or_dcomp_active(sgsn)) talloc_free(expnd); return rc; } +/* 5.1.1.4 SN-UNITDATA.indication + * Called by SNDCP when it has received/re-assembled a N-PDU + */ +int sndcp_sn_unitdata_ind(struct gprs_sndcp_entity *sne, + struct msgb *msg, uint32_t npdu_len, uint8_t *npdu) +{ + /* Hand it off N-PDU to the correct GTP tunnel + GGSN: */ + return sgsn_gtp_data_req(&sne->ra_id, sne->lle->llme->tlli, + sne->nsapi, msg, npdu_len, npdu); +} + #if 0 /* Section 5.1.2.1 LL-RESET.ind */ static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se) @@ -1042,7 +1054,7 @@ int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi) /* Handle header compression entites */ static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, - struct gprs_llc_lle *lle) + const struct gprs_llc_lle *lle) { /* Note: This functions also transforms the comp_field into its * echo form (strips comp values, resets propose bit etc...) @@ -1092,7 +1104,7 @@ static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field, /* Hanle data compression entites */ static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, - struct gprs_llc_lle *lle) + const struct gprs_llc_lle *lle) { /* See note in handle_pcomp_entities() */ @@ -1134,7 +1146,7 @@ static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field, * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, struct gprs_llc_xid_field *xid_field_response, - struct gprs_llc_lle *lle) + const struct gprs_llc_lle *lle) { /* Note: This function computes the SNDCP-XID response that is sent * back to the ms when a ms originated XID is received. The diff --git a/src/sgsn/gprs_subscriber.c b/src/sgsn/gprs_subscriber.c index 943fbc3dc..a52abe8f1 100644 --- a/src/sgsn/gprs_subscriber.c +++ b/src/sgsn/gprs_subscriber.c @@ -30,7 +30,7 @@ #include <osmocom/gsupclient/gsup_client.h> #include <osmocom/sgsn/sgsn.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_utils.h> @@ -48,8 +48,6 @@ (gsup)->imsi, \ ## args) -extern void *tall_sgsn_ctx; - LLIST_HEAD(_gprs_subscribers); struct llist_head * const gprs_subscribers = &_gprs_subscribers; @@ -378,7 +376,8 @@ static void gprs_subscr_gsup_insert_data(struct gprs_subscr *subscr, } OSMO_ASSERT(pdp_data != NULL); - pdp_data->pdp_type = pdp_info->pdp_type; + pdp_data->pdp_type_org = pdp_info->pdp_type_org; + pdp_data->pdp_type_nr = pdp_info->pdp_type_nr; osmo_apn_to_str(pdp_data->apn_str, pdp_info->apn_enc, pdp_info->apn_enc_len); diff --git a/src/sgsn/gtp_ggsn.c b/src/sgsn/gtp_ggsn.c new file mode 100644 index 000000000..14cdfea00 --- /dev/null +++ b/src/sgsn/gtp_ggsn.c @@ -0,0 +1,178 @@ +/* GGSN context (peer) */ + +/* (C) 2009 by Harald Welte <laforge@gnumonks.org> + * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdint.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/rate_ctr.h> +#include <osmocom/core/stats.h> + +#include <osmocom/sgsn/gtp_ggsn.h> +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/sgsn.h> +#include <osmocom/sgsn/debug.h> +#include <osmocom/sgsn/gprs_gmm_fsm.h> +#include <osmocom/sgsn/gprs_sm.h> +#include <osmocom/sgsn/pdpctx.h> + +void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc) +{ + bool pending = osmo_timer_pending(&ggc->echo_timer); + + /* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */ + if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) { + if (!pending) + osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0); + } else { + if (pending) + osmo_timer_del(&ggc->echo_timer); + } +} + +/* GGSN contexts */ +static void echo_timer_cb(void *data) +{ + struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data; + sgsn_ggsn_echo_req(ggc); + osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0); +} + +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(struct sgsn_instance *sgsn, uint32_t id) +{ + struct sgsn_ggsn_ctx *ggc; + + ggc = talloc_zero(sgsn, struct sgsn_ggsn_ctx); + if (!ggc) + return NULL; + + ggc->id = id; + ggc->gtp_version = 1; + ggc->remote_restart_ctr = -1; + /* if we are called from config file parse, this gsn doesn't exist yet */ + ggc->gsn = sgsn->gsn; + INIT_LLIST_HEAD(&ggc->pdp_list); + osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc); + llist_add(&ggc->list, &sgsn->ggsn_list); + + return ggc; +} + +void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc) +{ + OSMO_ASSERT(llist_empty(&ggc->pdp_list)); + llist_del(&ggc->list); + talloc_free(ggc); +} + +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(struct sgsn_instance *sgsn, uint32_t id) +{ + struct sgsn_ggsn_ctx *ggc; + + llist_for_each_entry(ggc, &sgsn->ggsn_list, list) { + if (id == ggc->id) + return ggc; + } + return NULL; +} + +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct sgsn_instance *sgsn, struct in_addr *addr) +{ + struct sgsn_ggsn_ctx *ggc; + + llist_for_each_entry(ggc, &sgsn->ggsn_list, list) { + if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr))) + return ggc; + } + return NULL; +} + + +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(struct sgsn_instance *sgsn, uint32_t id) +{ + struct sgsn_ggsn_ctx *ggc; + + ggc = sgsn_ggsn_ctx_by_id(sgsn, id); + if (!ggc) + ggc = sgsn_ggsn_ctx_alloc(sgsn, id); + return ggc; +} + +void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx) +{ + /* the MM context can be deleted while the GGSN is not reachable or + * if has been crashed. */ + if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) { + gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true); + sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx); + } else { + /* FIXME: GPRS paging in case MS is SUSPENDED */ + LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN " + "recovery\n"); + /* FIXME: how to tell this to libgtp? */ + sgsn_pdp_ctx_free(pctx); + } +} + +/* High-level function to be called in case a GGSN has disappeared or + * otherwise lost state (recovery procedure). It will detach all related pdp ctx + * from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can + * be kept alive to allow handling later message which contained the Recovery IE. */ +int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except) +{ + int num = 0; + + struct sgsn_pdp_ctx *pdp, *pdp2; + llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) { + if (pdp == except) + continue; + sgsn_ggsn_ctx_drop_pdp(pdp); + num++; + } + + return num; +} + +int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn) +{ + return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL); +} + +void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp) +{ + llist_add(&pdp->ggsn_list, &ggc->pdp_list); + sgsn_ggsn_ctx_check_echo_timer(ggc); +} + +void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp) +{ + llist_del(&pdp->ggsn_list); + sgsn_ggsn_ctx_check_echo_timer(ggc); + if (pdp->destroy_ggsn) + sgsn_ggsn_ctx_free(pdp->ggsn); + pdp->ggsn = NULL; + /* Drop references to libgtp since the conn is down */ + if (pdp->lib) + pdp_freepdp(pdp->lib); + pdp->lib = NULL; +} diff --git a/src/sgsn/gtp_mme.c b/src/sgsn/gtp_mme.c index 4fe804d94..3d7ec76b6 100644 --- a/src/sgsn/gtp_mme.c +++ b/src/sgsn/gtp_mme.c @@ -1,6 +1,6 @@ /* TS 29.060 § 7.5.14 RAN Information Management Messages */ /* - * (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de> + * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> * All Rights Reserved * * SPDX-License-Identifier: AGPL-3.0+ @@ -26,8 +26,6 @@ #include <osmocom/sgsn/gtp_mme.h> #include <osmocom/sgsn/sgsn.h> -extern void *tall_sgsn_ctx; - static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osmo_eutran_tai *t2) { return t1->mcc == t2->mcc && @@ -39,7 +37,7 @@ static bool _eutran_tai_equal(const struct osmo_eutran_tai *t1, const struct osm struct sgsn_mme_ctx *sgsn_mme_ctx_alloc(struct sgsn_instance *sgsn, const char *name) { struct sgsn_mme_ctx *mme; - mme = talloc_zero(tall_sgsn_ctx, struct sgsn_mme_ctx); + mme = talloc_zero(sgsn, struct sgsn_mme_ctx); if (!mme) return NULL; diff --git a/src/sgsn/gprs_sgsn.c b/src/sgsn/mmctx.c index 304ecc516..0e9309284 100644 --- a/src/sgsn/gprs_sgsn.c +++ b/src/sgsn/mmctx.c @@ -1,4 +1,4 @@ -/* GPRS SGSN functionality */ +/* Mobility Management context */ /* (C) 2009 by Harald Welte <laforge@gnumonks.org> * @@ -27,6 +27,8 @@ #include <osmocom/core/rate_ctr.h> #include <osmocom/core/stats.h> #include <osmocom/core/backtrace.h> +#include <osmocom/ctrl/control_if.h> +#include <osmocom/ctrl/ports.h> #include <osmocom/gprs/gprs_ns2.h> #include <osmocom/gprs/gprs_bssgp.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> @@ -36,7 +38,7 @@ #include <osmocom/sgsn/gprs_subscriber.h> #include <osmocom/sgsn/debug.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_sm.h> @@ -47,22 +49,16 @@ #include <osmocom/sgsn/gprs_mm_state_iu_fsm.h> #include <osmocom/sgsn/gprs_gmm_fsm.h> #include <osmocom/sgsn/gprs_llc.h> +#include <osmocom/sgsn/gprs_sndcp.h> +#include <osmocom/sgsn/gtp_ggsn.h> +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/pdpctx.h> #include <pdp.h> #include <time.h> -#include "../../bscconfig.h" - -#define GPRS_LLME_CHECK_TICK 30 - -extern struct sgsn_instance *sgsn; -extern void *tall_sgsn_ctx; - -LLIST_HEAD(sgsn_mm_ctxts); -LLIST_HEAD(sgsn_ggsn_ctxts); -LLIST_HEAD(sgsn_apn_ctxts); -LLIST_HEAD(sgsn_pdp_ctxts); +#include "../../config.h" const struct value_string sgsn_ran_type_names[] = { { MM_CTX_T_GERAN_Gb, "GPRS/EDGE via Gb" }, @@ -95,66 +91,12 @@ static const struct rate_ctr_group_desc mmctx_ctrg_desc = { .class_id = OSMO_STATS_CLASS_SUBSCRIBER, }; -static const struct rate_ctr_desc pdpctx_ctr_description[] = { - { "udata:packets:in", "User Data Messages ( In)" }, - { "udata:packets:out", "User Data Messages (Out)" }, - { "udata:bytes:in", "User Data Bytes ( In)" }, - { "udata:bytes:out", "User Data Bytes (Out)" }, -}; - -static const struct rate_ctr_group_desc pdpctx_ctrg_desc = { - .group_name_prefix = "sgsn:pdpctx", - .group_description = "SGSN PDP Context Statistics", - .num_ctr = ARRAY_SIZE(pdpctx_ctr_description), - .ctr_desc = pdpctx_ctr_description, - .class_id = OSMO_STATS_CLASS_SUBSCRIBER, -}; - -static const struct rate_ctr_desc sgsn_ctr_description[] = { - { "llc:dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" }, - { "llc:ul_bytes", "Count successful received LLC bytes (encrypt & fcs correct)" }, - { "llc:dl_packets", "Count successful sent LLC packets before giving it to the bssgp layer" }, - { "llc:ul_packets", "Count successful received LLC packets (encrypt & fcs correct)" }, - { "gprs:attach_requested", "Received attach requests" }, - { "gprs:attach_accepted", "Sent attach accepts" }, - { "gprs:attach_rejected", "Sent attach rejects" }, - { "gprs:detach_requested", "Received detach requests" }, - { "gprs:detach_acked", "Sent detach acks" }, - { "gprs:routing_area_requested", "Received routing area requests" }, - { "gprs:routing_area_requested", "Sent routing area acks" }, - { "gprs:routing_area_requested", "Sent routing area rejects" }, - { "pdp:activate_requested", "Received activate requests" }, - { "pdp:activate_rejected", "Sent activate rejects" }, - { "pdp:activate_accepted", "Sent activate accepts" }, - { "pdp:request_activated", "unused" }, - { "pdp:request_activate_rejected", "unused" }, - { "pdp:modify_requested", "unused" }, - { "pdp:modify_accepted", "unused" }, - { "pdp:dl_deactivate_requested", "Sent deactivate requests" }, - { "pdp:dl_deactivate_accepted", "Sent deactivate accepted" }, - { "pdp:ul_deactivate_requested", "Received deactivate requests" }, - { "pdp:ul_deactivate_accepted", "Received deactivate accepts" }, -}; - -static const struct rate_ctr_group_desc sgsn_ctrg_desc = { - "sgsn", - "SGSN Overall Statistics", - OSMO_STATS_CLASS_GLOBAL, - ARRAY_SIZE(sgsn_ctr_description), - sgsn_ctr_description, -}; - -void sgsn_rate_ctr_init() { - sgsn->rate_ctrs = rate_ctr_group_alloc(tall_sgsn_ctx, &sgsn_ctrg_desc, 0); - OSMO_ASSERT(sgsn->rate_ctrs); -} - /* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/ struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx) { struct sgsn_mm_ctx *ctx; - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + llist_for_each_entry(ctx, &sgsn->mm_list, list) { if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && uectx == ctx->iu.ue_ctx) return ctx; @@ -169,7 +111,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, { struct sgsn_mm_ctx *ctx; - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + llist_for_each_entry(ctx, &sgsn->mm_list, list) { if ((tlli == ctx->gb.tlli || tlli == ctx->gb.tlli_new) && gprs_ra_id_equals(raid, &ctx->ra)) return ctx; @@ -193,7 +135,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli, if (tlli_type != TLLI_FOREIGN && tlli_type != TLLI_LOCAL) return NULL; - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + llist_for_each_entry(ctx, &sgsn->mm_list, list) { if ((gprs_tmsi2tlli(ctx->p_tmsi, tlli_type) == tlli || gprs_tmsi2tlli(ctx->p_tmsi_old, tlli_type) == tlli) && gprs_ra_id_equals(raid, &ctx->ra)) @@ -207,7 +149,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi) { struct sgsn_mm_ctx *ctx; - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + llist_for_each_entry(ctx, &sgsn->mm_list, list) { if (p_tmsi == ctx->p_tmsi || (ctx->p_tmsi_old && ctx->p_tmsi_old == p_tmsi)) return ctx; @@ -219,7 +161,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi) { struct sgsn_mm_ctx *ctx; - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + llist_for_each_entry(ctx, &sgsn->mm_list, list) { if (!strcmp(imsi, ctx->imsi)) return ctx; } @@ -261,7 +203,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t rate_ctr_id) INIT_LLIST_HEAD(&ctx->pdp_list); - llist_add(&ctx->list, &sgsn_mm_ctxts); + llist_add(&ctx->list, &sgsn->mm_list); return ctx; @@ -432,288 +374,6 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm, return NULL; } -/* you don't want to use this directly, call sgsn_create_pdp_ctx() */ -struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, - struct sgsn_ggsn_ctx *ggsn, - uint8_t nsapi) -{ - struct sgsn_pdp_ctx *pdp; - - pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi); - if (pdp) - return NULL; - - pdp = talloc_zero(tall_sgsn_ctx, struct sgsn_pdp_ctx); - if (!pdp) - return NULL; - - pdp->mm = mm; - pdp->ggsn = ggsn; - pdp->nsapi = nsapi; - pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi); - if (!pdp->ctrg) { - LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n"); - talloc_free(pdp); - return NULL; - } - llist_add(&pdp->list, &mm->pdp_list); - sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp); - llist_add(&pdp->g_list, &sgsn_pdp_ctxts); - - return pdp; -} - -/* - * This function will not trigger any GSM DEACT PDP ACK messages, so you - * probably want to call sgsn_delete_pdp_ctx() instead if the connection - * isn't detached already. - */ -void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp) -{ - struct sgsn_signal_data sig_data; - - OSMO_ASSERT(pdp->mm != NULL); - - /* There might still be pending callbacks in libgtp. So the parts of - * this object relevant to GTP need to remain intact in this case. */ - - LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n"); - - if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) { - /* Force the deactivation of the SNDCP layer */ - if (pdp->mm->gb.llme) - sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi); - } - - memset(&sig_data, 0, sizeof(sig_data)); - sig_data.pdp = pdp; - osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data); - - /* Detach from MM context */ - pdp_ctx_detach_mm_ctx(pdp); - if (pdp->ggsn) - sgsn_delete_pdp_ctx(pdp); -} - -/* - * Don't call this function directly unless you know what you are doing. - * In normal conditions use sgsn_delete_pdp_ctx and in unspecified or - * implementation dependent abnormal ones sgsn_pdp_ctx_terminate. - */ -void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp) -{ - struct sgsn_signal_data sig_data; - - memset(&sig_data, 0, sizeof(sig_data)); - sig_data.pdp = pdp; - osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data); - - if (osmo_timer_pending(&pdp->timer)) { - LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T); - osmo_timer_del(&pdp->timer); - } - - rate_ctr_group_free(pdp->ctrg); - if (pdp->mm) - llist_del(&pdp->list); - if (pdp->ggsn) - sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp); - llist_del(&pdp->g_list); - - /* _if_ we still have a library handle, at least set it to NULL - * to avoid any dereferences of the now-deleted PDP context from - * sgsn_libgtp:cb_data_ind() */ - if (pdp->lib) { - struct pdp_t *lib = pdp->lib; - LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still " - "has a libgtp handle attached to it, this shouldn't " - "happen!\n"); - osmo_generate_backtrace(); - lib->priv = NULL; - } - - talloc_free(pdp); -} - -void sgsn_ggsn_ctx_check_echo_timer(struct sgsn_ggsn_ctx *ggc) -{ - bool pending = osmo_timer_pending(&ggc->echo_timer); - - /* Only enable if allowed by policy and at least 1 pdp ctx exists against ggsn */ - if (!llist_empty(&ggc->pdp_list) && ggc->echo_interval) { - if (!pending) - osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0); - } else { - if (pending) - osmo_timer_del(&ggc->echo_timer); - } -} - -/* GGSN contexts */ -static void echo_timer_cb(void *data) -{ - struct sgsn_ggsn_ctx *ggc = (struct sgsn_ggsn_ctx *) data; - sgsn_ggsn_echo_req(ggc); - osmo_timer_schedule(&ggc->echo_timer, ggc->echo_interval, 0); -} - -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id) -{ - struct sgsn_ggsn_ctx *ggc; - - ggc = talloc_zero(tall_sgsn_ctx, struct sgsn_ggsn_ctx); - if (!ggc) - return NULL; - - ggc->id = id; - ggc->gtp_version = 1; - ggc->remote_restart_ctr = -1; - /* if we are called from config file parse, this gsn doesn't exist yet */ - ggc->gsn = sgsn->gsn; - INIT_LLIST_HEAD(&ggc->pdp_list); - osmo_timer_setup(&ggc->echo_timer, echo_timer_cb, ggc); - llist_add(&ggc->list, &sgsn_ggsn_ctxts); - - return ggc; -} - -void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc) -{ - OSMO_ASSERT(llist_empty(&ggc->pdp_list)); - llist_del(&ggc->list); - talloc_free(ggc); -} - -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id) -{ - struct sgsn_ggsn_ctx *ggc; - - llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) { - if (id == ggc->id) - return ggc; - } - return NULL; -} - -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr) -{ - struct sgsn_ggsn_ctx *ggc; - - llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) { - if (!memcmp(addr, &ggc->remote_addr, sizeof(*addr))) - return ggc; - } - return NULL; -} - - -struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id) -{ - struct sgsn_ggsn_ctx *ggc; - - ggc = sgsn_ggsn_ctx_by_id(id); - if (!ggc) - ggc = sgsn_ggsn_ctx_alloc(id); - return ggc; -} - -/* APN contexts */ - -static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix) -{ - struct apn_ctx *actx; - - actx = talloc_zero(tall_sgsn_ctx, struct apn_ctx); - if (!actx) - return NULL; - actx->name = talloc_strdup(actx, ap_name); - actx->imsi_prefix = talloc_strdup(actx, imsi_prefix); - - llist_add_tail(&actx->list, &sgsn_apn_ctxts); - - return actx; -} - -void sgsn_apn_ctx_free(struct apn_ctx *actx) -{ - llist_del(&actx->list); - talloc_free(actx); -} - -struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi) -{ - struct apn_ctx *actx; - struct apn_ctx *found_actx = NULL; - size_t imsi_prio = 0; - size_t name_prio = 0; - size_t name_req_len = strlen(name); - - llist_for_each_entry(actx, &sgsn_apn_ctxts, list) { - size_t name_ref_len, imsi_ref_len; - const char *name_ref_start, *name_match_start; - - imsi_ref_len = strlen(actx->imsi_prefix); - if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0) - continue; - - if (imsi_ref_len < imsi_prio) - continue; - - /* IMSI matches */ - - name_ref_start = &actx->name[0]; - if (name_ref_start[0] == '*') { - /* Suffix match */ - name_ref_start += 1; - name_ref_len = strlen(name_ref_start); - if (name_ref_len > name_req_len) - continue; - } else { - name_ref_len = strlen(name_ref_start); - if (name_ref_len != name_req_len) - continue; - } - - name_match_start = name + (name_req_len - name_ref_len); - if (strcasecmp(name_match_start, name_ref_start) != 0) - continue; - - /* IMSI and name match */ - - if (imsi_ref_len == imsi_prio && name_ref_len < name_prio) - /* Lower priority, skip */ - continue; - - imsi_prio = imsi_ref_len; - name_prio = name_ref_len; - found_actx = actx; - } - return found_actx; -} - -struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix) -{ - struct apn_ctx *actx; - - llist_for_each_entry(actx, &sgsn_apn_ctxts, list) { - if (strcasecmp(name, actx->name) == 0 && - strcasecmp(imsi_prefix, actx->imsi_prefix) == 0) - return actx; - } - return NULL; -} - -struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix) -{ - struct apn_ctx *actx; - - actx = sgsn_apn_ctx_by_name(name, imsi_prefix); - if (!actx) - actx = sgsn_apn_ctx_alloc(name, imsi_prefix); - - return actx; -} - uint32_t sgsn_alloc_ptmsi(void) { struct sgsn_mm_ctx *mm; @@ -749,7 +409,7 @@ restart: goto restart; } - llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { + llist_for_each_entry(mm, &sgsn->mm_list, list) { if (mm->p_tmsi == ptmsi) { if (!max_retries--) goto failed; @@ -764,64 +424,6 @@ failed: return GSM_RESERVED_TMSI; } -void sgsn_ggsn_ctx_drop_pdp(struct sgsn_pdp_ctx *pctx) -{ - /* the MM context can be deleted while the GGSN is not reachable or - * if has been crashed. */ - if (pctx->mm && pctx->mm->gmm_fsm->state == ST_GMM_REGISTERED_NORMAL) { - gsm48_tx_gsm_deact_pdp_req(pctx, GSM_CAUSE_NET_FAIL, true); - sgsn_ggsn_ctx_remove_pdp(pctx->ggsn, pctx); - } else { - /* FIXME: GPRS paging in case MS is SUSPENDED */ - LOGPDPCTXP(LOGL_NOTICE, pctx, "Hard-dropping PDP ctx due to GGSN " - "recovery\n"); - /* FIXME: how to tell this to libgtp? */ - sgsn_pdp_ctx_free(pctx); - } -} - -/* High-level function to be called in case a GGSN has disappeared or - * otherwise lost state (recovery procedure). It will detach all related pdp ctx - * from a ggsn and communicate deact to MS. Optionally (!NULL), one pdp ctx can - * be kept alive to allow handling later message which contained the Recovery IE. */ -int sgsn_ggsn_ctx_drop_all_pdp_except(struct sgsn_ggsn_ctx *ggsn, struct sgsn_pdp_ctx *except) -{ - int num = 0; - - struct sgsn_pdp_ctx *pdp, *pdp2; - llist_for_each_entry_safe(pdp, pdp2, &ggsn->pdp_list, ggsn_list) { - if (pdp == except) - continue; - sgsn_ggsn_ctx_drop_pdp(pdp); - num++; - } - - return num; -} - -int sgsn_ggsn_ctx_drop_all_pdp(struct sgsn_ggsn_ctx *ggsn) -{ - return sgsn_ggsn_ctx_drop_all_pdp_except(ggsn, NULL); -} - -void sgsn_ggsn_ctx_add_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp) -{ - llist_add(&pdp->ggsn_list, &ggc->pdp_list); - sgsn_ggsn_ctx_check_echo_timer(ggc); -} -void sgsn_ggsn_ctx_remove_pdp(struct sgsn_ggsn_ctx *ggc, struct sgsn_pdp_ctx *pdp) -{ - llist_del(&pdp->ggsn_list); - sgsn_ggsn_ctx_check_echo_timer(ggc); - if (pdp->destroy_ggsn) - sgsn_ggsn_ctx_free(pdp->ggsn); - pdp->ggsn = NULL; - /* Drop references to libgtp since the conn is down */ - if (pdp->lib) - pdp_freepdp(pdp->lib); - pdp->lib = NULL; -} - void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx) { OSMO_ASSERT(mmctx != NULL); @@ -896,7 +498,7 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, insert_extra(tp, mmctx->subscr->sgsn_data, pdp); continue; } - if (!llist_empty(&sgsn_apn_ctxts)) { + if (!llist_empty(&sgsn->apn_list)) { apn_ctx = sgsn_apn_ctx_match(req_apn_str, mmctx->imsi); /* Not configured */ if (apn_ctx == NULL) @@ -949,13 +551,13 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, if (apn_ctx != NULL) { ggsn = apn_ctx->ggsn; - } else if (llist_empty(&sgsn_apn_ctxts)) { + } else if (llist_empty(&sgsn->apn_list)) { /* No configuration -> use GGSN 0 */ - ggsn = sgsn_ggsn_ctx_by_id(0); + ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0); } else if (allow_any_apn && (selected_apn_str == NULL || strlen(selected_apn_str) == 0)) { /* No APN given and no default configuration -> Use GGSN 0 */ - ggsn = sgsn_ggsn_ctx_by_id(0); + ggsn = sgsn_ggsn_ctx_by_id(sgsn, 0); } else { /* No matching configuration found */ LOGMMCTXP(LOGL_NOTICE, mmctx, @@ -980,72 +582,3 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, return ggsn; } - -static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme) -{ - struct sgsn_mm_ctx *mmctx = NULL; - - llist_for_each_entry(mmctx, &sgsn_mm_ctxts, list) { - if (llme == mmctx->gb.llme) { - gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE); - return; - } - } - - /* No MM context found */ - LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n", - llme->tlli); - gprs_llgmm_unassign(llme); -} - -static void sgsn_llme_check_cb(void *data_) -{ - struct gprs_llc_llme *llme, *llme_tmp; - struct timespec now_tp; - time_t now, age; - time_t max_age = gprs_max_time_to_idle(); - - int rc; - - rc = osmo_clock_gettime(CLOCK_MONOTONIC, &now_tp); - OSMO_ASSERT(rc >= 0); - now = now_tp.tv_sec; - - LOGP(DGPRS, LOGL_DEBUG, - "Checking for inactive LLMEs, time = %u\n", (unsigned)now); - - llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) { - if (llme->age_timestamp == GPRS_LLME_RESET_AGE) - llme->age_timestamp = now; - - age = now - llme->age_timestamp; - - if (age > max_age || age < 0) { - LOGP(DGPRS, LOGL_INFO, - "Inactivity timeout for TLLI 0x%08x, age %d\n", - llme->tlli, (int)age); - sgsn_llme_cleanup_free(llme); - } - } - - osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0); -} - -struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx) -{ - struct sgsn_instance *inst; - inst = talloc_zero(talloc_ctx, struct sgsn_instance); - inst->cfg.gtp_statedir = talloc_strdup(inst, "./"); - inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED; - inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */ - inst->cfg.gsup_server_port = OSMO_GSUP_PORT; - - INIT_LLIST_HEAD(&inst->mme_list); - return inst; -} - -void sgsn_inst_init(struct sgsn_instance *sgsn) -{ - osmo_timer_setup(&sgsn->llme_timer, sgsn_llme_check_cb, NULL); - osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0); -} diff --git a/src/sgsn/pdpctx.c b/src/sgsn/pdpctx.c new file mode 100644 index 000000000..e77942040 --- /dev/null +++ b/src/sgsn/pdpctx.c @@ -0,0 +1,158 @@ +/* PDP context functionality */ + +/* (C) 2009 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdint.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/rate_ctr.h> +#include <osmocom/core/stats.h> + +#include <osmocom/sgsn/pdpctx.h> +#include <osmocom/sgsn/mmctx.h> +#include <osmocom/sgsn/sgsn.h> +#include <osmocom/sgsn/debug.h> +#include <osmocom/sgsn/signal.h> +#include <osmocom/sgsn/gtp_ggsn.h> +#include <osmocom/sgsn/gprs_llc_xid.h> +#include <osmocom/sgsn/gprs_sndcp.h> +#include <osmocom/sgsn/gprs_llc.h> +#include <osmocom/sgsn/gprs_sm.h> +#include <osmocom/sgsn/gtp.h> + +static const struct rate_ctr_desc pdpctx_ctr_description[] = { + { "udata:packets:in", "User Data Messages ( In)" }, + { "udata:packets:out", "User Data Messages (Out)" }, + { "udata:bytes:in", "User Data Bytes ( In)" }, + { "udata:bytes:out", "User Data Bytes (Out)" }, +}; + +static const struct rate_ctr_group_desc pdpctx_ctrg_desc = { + .group_name_prefix = "sgsn:pdpctx", + .group_description = "SGSN PDP Context Statistics", + .num_ctr = ARRAY_SIZE(pdpctx_ctr_description), + .ctr_desc = pdpctx_ctr_description, + .class_id = OSMO_STATS_CLASS_SUBSCRIBER, +}; + +/* you don't want to use this directly, call sgsn_create_pdp_ctx() */ +struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, + struct sgsn_ggsn_ctx *ggsn, + uint8_t nsapi) +{ + struct sgsn_pdp_ctx *pdp; + + pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi); + if (pdp) + return NULL; + + pdp = talloc_zero(sgsn, struct sgsn_pdp_ctx); + if (!pdp) + return NULL; + + pdp->mm = mm; + pdp->ggsn = ggsn; + pdp->nsapi = nsapi; + pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi); + if (!pdp->ctrg) { + LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n"); + talloc_free(pdp); + return NULL; + } + llist_add(&pdp->list, &mm->pdp_list); + sgsn_ggsn_ctx_add_pdp(pdp->ggsn, pdp); + llist_add(&pdp->g_list, &sgsn->pdp_list); + + return pdp; +} + +/* + * This function will not trigger any GSM DEACT PDP ACK messages, so you + * probably want to call sgsn_delete_pdp_ctx() instead if the connection + * isn't detached already. + */ +void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp) +{ + struct sgsn_signal_data sig_data; + + OSMO_ASSERT(pdp->mm != NULL); + + /* There might still be pending callbacks in libgtp. So the parts of + * this object relevant to GTP need to remain intact in this case. */ + + LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n"); + + if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) { + /* Force the deactivation of the SNDCP layer */ + if (pdp->mm->gb.llme) + sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi); + } + + memset(&sig_data, 0, sizeof(sig_data)); + sig_data.pdp = pdp; + osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_TERMINATE, &sig_data); + + /* Detach from MM context */ + pdp_ctx_detach_mm_ctx(pdp); + if (pdp->ggsn) + sgsn_delete_pdp_ctx(pdp); +} + +/* + * Don't call this function directly unless you know what you are doing. + * In normal conditions use sgsn_delete_pdp_ctx and in unspecified or + * implementation dependent abnormal ones sgsn_pdp_ctx_terminate. + */ +void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp) +{ + struct sgsn_signal_data sig_data; + + memset(&sig_data, 0, sizeof(sig_data)); + sig_data.pdp = pdp; + osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data); + + if (osmo_timer_pending(&pdp->timer)) { + LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T); + osmo_timer_del(&pdp->timer); + } + + rate_ctr_group_free(pdp->ctrg); + if (pdp->mm) + llist_del(&pdp->list); + if (pdp->ggsn) + sgsn_ggsn_ctx_remove_pdp(pdp->ggsn, pdp); + llist_del(&pdp->g_list); + + /* _if_ we still have a library handle, at least set it to NULL + * to avoid any dereferences of the now-deleted PDP context from + * sgsn_libgtp:cb_data_ind() */ + if (pdp->lib) { + struct pdp_t *lib = pdp->lib; + LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still " + "has a libgtp handle attached to it, this shouldn't " + "happen!\n"); + osmo_generate_backtrace(); + lib->priv = NULL; + } + + talloc_free(pdp); +} diff --git a/src/sgsn/sgsn.c b/src/sgsn/sgsn.c new file mode 100644 index 000000000..6619bf263 --- /dev/null +++ b/src/sgsn/sgsn.c @@ -0,0 +1,215 @@ +/* SGSN instance */ + +/* (C) 2009 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdint.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/rate_ctr.h> +#include <osmocom/core/stats.h> +#include <osmocom/core/backtrace.h> +#include <osmocom/ctrl/control_if.h> +#include <osmocom/ctrl/ports.h> +#include <osmocom/gprs/gprs_ns2.h> +#include <osmocom/gprs/gprs_bssgp.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> +#include <osmocom/gsm/apn.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/gsup.h> + +#include <osmocom/sgsn/gprs_subscriber.h> +#include <osmocom/sgsn/debug.h> +#include <osmocom/sgsn/sgsn.h> +#include <osmocom/sgsn/gprs_gmm.h> +#include <osmocom/sgsn/gprs_sm.h> +#include <osmocom/sgsn/gprs_utils.h> +#include <osmocom/sgsn/signal.h> +#include <osmocom/sgsn/gprs_gmm_attach.h> +#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h> +#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h> +#include <osmocom/sgsn/gprs_gmm_fsm.h> +#include <osmocom/sgsn/gprs_llc.h> +#include <osmocom/sgsn/gprs_sndcp.h> +#include <osmocom/sgsn/gtp_ggsn.h> +#include <osmocom/sgsn/gtp.h> +#include <osmocom/sgsn/pdpctx.h> + +#include <pdp.h> + +#include <time.h> + +#define GPRS_LLME_CHECK_TICK 30 + +extern struct osmo_tdef sgsn_T_defs[]; + +static const struct rate_ctr_desc sgsn_ctr_description[] = { + { "llc:dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" }, + { "llc:ul_bytes", "Count successful received LLC bytes (encrypt & fcs correct)" }, + { "llc:dl_packets", "Count successful sent LLC packets before giving it to the bssgp layer" }, + { "llc:ul_packets", "Count successful received LLC packets (encrypt & fcs correct)" }, + { "gprs:attach_requested", "Received attach requests" }, + { "gprs:attach_accepted", "Sent attach accepts" }, + { "gprs:attach_rejected", "Sent attach rejects" }, + { "gprs:detach_requested", "Received detach requests" }, + { "gprs:detach_acked", "Sent detach acks" }, + { "gprs:routing_area_requested", "Received routing area requests" }, + { "gprs:routing_area_requested", "Sent routing area acks" }, + { "gprs:routing_area_requested", "Sent routing area rejects" }, + { "pdp:activate_requested", "Received activate requests" }, + { "pdp:activate_rejected", "Sent activate rejects" }, + { "pdp:activate_accepted", "Sent activate accepts" }, + { "pdp:request_activated", "unused" }, + { "pdp:request_activate_rejected", "unused" }, + { "pdp:modify_requested", "unused" }, + { "pdp:modify_accepted", "unused" }, + { "pdp:dl_deactivate_requested", "Sent deactivate requests" }, + { "pdp:dl_deactivate_accepted", "Sent deactivate accepted" }, + { "pdp:ul_deactivate_requested", "Received deactivate requests" }, + { "pdp:ul_deactivate_accepted", "Received deactivate accepts" }, +}; + +static const struct rate_ctr_group_desc sgsn_ctrg_desc = { + "sgsn", + "SGSN Overall Statistics", + OSMO_STATS_CLASS_GLOBAL, + ARRAY_SIZE(sgsn_ctr_description), + sgsn_ctr_description, +}; + +static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme) +{ + struct sgsn_mm_ctx *mmctx = NULL; + + llist_for_each_entry(mmctx, &sgsn->mm_list, list) { + if (llme == mmctx->gb.llme) { + gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE); + return; + } + } + + /* No MM context found */ + LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n", + llme->tlli); + gprs_llgmm_unassign(llme); +} + +static void sgsn_llme_check_cb(void *data_) +{ + struct gprs_llc_llme *llme, *llme_tmp; + struct timespec now_tp; + time_t now, age; + time_t max_age = gprs_max_time_to_idle(); + + int rc; + + rc = osmo_clock_gettime(CLOCK_MONOTONIC, &now_tp); + OSMO_ASSERT(rc >= 0); + now = now_tp.tv_sec; + + LOGP(DGPRS, LOGL_DEBUG, + "Checking for inactive LLMEs, time = %u\n", (unsigned)now); + + llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) { + if (llme->age_timestamp == GPRS_LLME_RESET_AGE) + llme->age_timestamp = now; + + age = now - llme->age_timestamp; + + if (age > max_age || age < 0) { + LOGP(DGPRS, LOGL_INFO, + "Inactivity timeout for TLLI 0x%08x, age %d\n", + llme->tlli, (int)age); + sgsn_llme_cleanup_free(llme); + } + } + + osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0); +} + +static int sgsn_instance_talloc_destructor(struct sgsn_instance *sgi) +{ + sgsn_cdr_release(sgi); + osmo_timer_del(&sgi->llme_timer); + rate_ctr_group_free(sgi->rate_ctrs); + return 0; +} + +struct sgsn_instance *sgsn_instance_alloc(void *talloc_ctx) +{ + struct sgsn_instance *inst; + inst = talloc_zero(talloc_ctx, struct sgsn_instance); + + talloc_set_destructor(inst, sgsn_instance_talloc_destructor); + + inst->cfg.gtp_statedir = talloc_strdup(inst, "./"); + inst->cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED; + inst->cfg.require_authentication = true; /* only applies if auth_policy is REMOTE */ + inst->cfg.gsup_server_port = OSMO_GSUP_PORT; + + inst->cfg.T_defs = sgsn_T_defs; + osmo_tdefs_reset(inst->cfg.T_defs); + inst->cfg.T_defs_gtp = gtp_T_defs; + osmo_tdefs_reset(inst->cfg.T_defs_gtp); + + inst->rate_ctrs = rate_ctr_group_alloc(inst, &sgsn_ctrg_desc, 0); + OSMO_ASSERT(inst->rate_ctrs); + + INIT_LLIST_HEAD(&inst->apn_list); + INIT_LLIST_HEAD(&inst->ggsn_list); + INIT_LLIST_HEAD(&inst->mme_list); + INIT_LLIST_HEAD(&inst->mm_list); + INIT_LLIST_HEAD(&inst->pdp_list); + + osmo_timer_setup(&inst->llme_timer, sgsn_llme_check_cb, NULL); + osmo_timer_schedule(&inst->llme_timer, GPRS_LLME_CHECK_TICK, 0); + /* These are mostly setting up stuff not related to VTY cfg, so they can be set up here: */ + sgsn_auth_init(inst); + sgsn_cdr_init(inst); + return inst; +} + +/* To be called after VTY config parsing: */ +int sgsn_inst_init(struct sgsn_instance *sgsn) +{ + int rc; + + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + sgsn->ctrlh = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_SGSN, NULL); + if (!sgsn->ctrlh) { + LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n"); + return -EIO; + } + + rc = sgsn_ctrl_cmds_install(); + if (rc != 0) { + LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n"); + return -EFAULT; + } + + rc = gprs_subscr_init(sgsn); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n"); + return rc; + } + return 0; +} diff --git a/src/sgsn/sgsn_auth.c b/src/sgsn/sgsn_auth.c index b8d803590..cbff6f8ba 100644 --- a/src/sgsn/sgsn_auth.c +++ b/src/sgsn/sgsn_auth.c @@ -22,7 +22,7 @@ #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/core/utils.h> #include <osmocom/sgsn/sgsn.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_subscriber.h> #include <osmocom/sgsn/debug.h> diff --git a/src/sgsn/sgsn_cdr.c b/src/sgsn/sgsn_cdr.c index a50b4dfdd..1536c135a 100644 --- a/src/sgsn/sgsn_cdr.c +++ b/src/sgsn/sgsn_cdr.c @@ -27,6 +27,9 @@ #include <osmocom/gsm/apn.h> #include <osmocom/sgsn/vty.h> +#include <osmocom/sgsn/gtp_ggsn.h> +#include <osmocom/sgsn/pdpctx.h> +#include <osmocom/sgsn/mmctx.h> #include <gtp.h> #include <pdp.h> @@ -38,10 +41,6 @@ #include <stdio.h> #include <inttypes.h> -/* TODO...avoid going through a global */ -extern struct sgsn_instance *sgsn; -extern struct ctrl_handle *g_ctrlh; - /** * The CDR module will generate an entry like: * @@ -64,7 +63,7 @@ extern struct ctrl_handle *g_ctrlh; static void send_cdr_trap(char *value) { - if (ctrl_cmd_send_trap(g_ctrlh, "cdr-v1", value) < 0) + if (ctrl_cmd_send_trap(sgsn->ctrlh, "cdr-v1", value) < 0) LOGP(DGPRS, LOGL_ERROR, "Failed to create and send TRAP cdr-v1\n"); } @@ -299,3 +298,8 @@ int sgsn_cdr_init(struct sgsn_instance *sgsn) return 0; } + +void sgsn_cdr_release(struct sgsn_instance *sgsn) +{ + osmo_signal_unregister_handler(SS_SGSN, handle_sgsn_sig, sgsn); +} diff --git a/src/sgsn/sgsn_ctrl.c b/src/sgsn/sgsn_ctrl.c index ad91d25a5..069304abd 100644 --- a/src/sgsn/sgsn_ctrl.c +++ b/src/sgsn/sgsn_ctrl.c @@ -21,20 +21,19 @@ #include <osmocom/ctrl/control_if.h> #include <osmocom/ctrl/control_cmd.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> +#include <osmocom/sgsn/pdpctx.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/sgsn/debug.h> #include <pdp.h> -extern vector ctrl_node_vec; - static int get_subscriber_list(struct ctrl_cmd *cmd, void *d) { struct sgsn_mm_ctx *mm; cmd->reply = talloc_strdup(cmd, ""); - llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { + llist_for_each_entry(mm, &sgsn->mm_list, list) { char *addr = NULL; struct sgsn_pdp_ctx *pdp; @@ -43,7 +42,7 @@ static int get_subscriber_list(struct ctrl_cmd *cmd, void *d) llist_for_each_entry(pdp, &mm->pdp_list, list) addr = gprs_pdpaddr2str(pdp->lib->eua.v, - pdp->lib->eua.l); + pdp->lib->eua.l, false); cmd->reply = talloc_asprintf_append( cmd->reply, diff --git a/src/sgsn/sgsn_libgtp.c b/src/sgsn/sgsn_libgtp.c index 1ac3b44cd..9edd0c60e 100644 --- a/src/sgsn/sgsn_libgtp.c +++ b/src/sgsn/sgsn_libgtp.c @@ -34,7 +34,7 @@ #include <netinet/in.h> #include <arpa/inet.h> -#include "bscconfig.h" +#include "config.h" #include <osmocom/core/talloc.h> #include <osmocom/core/select.h> @@ -45,9 +45,9 @@ #include <osmocom/sgsn/signal.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/sgsn.h> -#include <osmocom/sgsn/gprs_gb.h> +#include <osmocom/sgsn/gprs_ns.h> #include <osmocom/sgsn/gprs_llc.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/mmctx.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_sm.h> #include <osmocom/sgsn/gprs_subscriber.h> @@ -55,8 +55,11 @@ #include <osmocom/sgsn/gprs_ranap.h> #include <osmocom/sgsn/gprs_gmm_fsm.h> #include <osmocom/sgsn/gprs_mm_state_gb_fsm.h> +#include <osmocom/sgsn/gtp_ggsn.h> #include <osmocom/sgsn/gtp_mme.h> #include <osmocom/sgsn/sgsn_rim.h> +#include <osmocom/sgsn/gprs_bssgp.h> +#include <osmocom/sgsn/pdpctx.h> #include <gtp.h> #include <pdp.h> @@ -228,18 +231,11 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, qos = TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS); } - if (qos_len <= 3) { - pdp->qos_req.l = qos_len + 1; - if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) - pdp->qos_req.l = sizeof(pdp->qos_req.v); - pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */ - memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1); - } else { - pdp->qos_req.l = qos_len; - if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) - pdp->qos_req.l = sizeof(pdp->qos_req.v); - memcpy(pdp->qos_req.v, qos, pdp->qos_req.l); - } + pdp->qos_req.l = qos_len + 1; + if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) + pdp->qos_req.l = sizeof(pdp->qos_req.v); + pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */ + memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1); /* charging characteristics if present */ if (TLVP_LEN(tp, OSMO_IE_GSM_CHARG_CHAR) >= sizeof(pdp->cch_pdp)) @@ -421,7 +417,7 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) } /* Check for cause value if it was really successful */ - if (cause != GTPCAUSE_ACC_REQ) { + if (!gtp_cause_successful(cause)) { reject_cause = cause_map(gtp2sm_cause_map, cause, GSM_CAUSE_ACT_REJ_GGSN); goto reject; @@ -600,12 +596,12 @@ static int echo_conf(void *cbp, bool timeout) } /* Any message received by GGSN contains a recovery IE */ -static int cb_recovery2(struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery) +static int cb_recovery3(struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery) { struct sgsn_ggsn_ctx *ggsn; struct sgsn_pdp_ctx *pctx = NULL; - ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr); + ggsn = sgsn_ggsn_ctx_by_addr(sgsn, &peer->sin_addr); if (!ggsn) { LOGP(DGPRS, LOGL_NOTICE, "Received Recovery IE for unknown GGSN\n"); return -EINVAL; @@ -699,9 +695,46 @@ static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_membe LOGMME(mme, DGTP, LOGL_INFO, "Rx GTP RAN Information Relay\n"); + int rc; unsigned int len = 0; - struct msgb *msg = msgb_alloc(4096, "gtpcv1_ran_info"); - struct bssgp_ran_information_pdu pdu; + struct msgb *msg = bssgp_msgb_alloc(); + + uint8_t rim_ra_encoded[256]; + unsigned int rim_ra_encoded_len = 0; + struct bssgp_rim_routing_info rim_ra; + + unsigned int rim_ra_discr_encoded_len = 0; + uint8_t rim_ra_discr; + + /* Read RIM Routing Address Discriminator (optional) */ + rc = gtpie_gettlv(ie, GTPIE_RIM_RA_DISCR, 0, &rim_ra_discr_encoded_len, &rim_ra_discr, + sizeof(rim_ra_discr)); + if (rc || rim_ra_discr_encoded_len <= 0) { + LOGMME(mme, DGTP, LOGL_NOTICE, "Rx GTP RAN Information Relay: No RIM Routing Address Discriminator IE found!\n"); + + /* It is not an error when the RIM ROUTING ADDRESS DISCRIMINATOR IE is missing. The RIM ROUTING ADDRESS + * DISCRIMINATOR IE is an optional IE. When it is missing, the RIM Routing Address shall be processed + * as an RNC address ("0001") See also: 3GPP TS 29.060 */ + rim_ra_discr = BSSGP_RIM_ROUTING_INFO_UTRAN; + } + + /* Read RIM Routing Address (optional) */ + rc = gtpie_gettlv(ie, GTPIE_RIM_ROUT_ADDR, 0, &rim_ra_encoded_len, rim_ra_encoded, sizeof(rim_ra_encoded)); + if (rc || rim_ra_encoded_len <= 0) { + LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No RIM Routing Address IE found!\n"); + + /* TODO: The (usually included) RIM ROUTING ADDRESS field is an optional field. However, we cannot + * proceed without a destination address. A possible way to fix this would be a default route that + * can be configured via the VTY. */ + goto ret_error; + } else { + rc = bssgp_parse_rim_ra(&rim_ra, rim_ra_encoded, rim_ra_encoded_len, rim_ra_discr); + if (rc < 0) { + LOGMME(mme, DGTP, LOGL_ERROR, + "Rx GTP RAN Information Relay: Failed parsing RIM Routing Address/RIM Routing Address Discriminator IE!\n"); + goto ret_error; + } + } if (gtpie_gettlv(ie, GTPIE_RAN_T_CONTAIN, 0, &len, msgb_data(msg), 4096) || len <= 0) { LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: No Transparent Container IE found!\n"); @@ -710,13 +743,8 @@ static int cb_gtp_ran_info_relay_ind(struct sockaddr_in *peer, union gtpie_membe msgb_put(msg, len); msgb_bssgph(msg) = msg->data; msgb_nsei(msg) = 0; - if (bssgp_parse_rim_pdu(&pdu, msg) < 0) { - LOGMME(mme, DGTP, LOGL_ERROR, "Rx GTP RAN Information Relay: Failed parsing Transparent Container IE!\n"); - goto ret_error; - } - msgb_free(msg); - return sgsn_rim_rx_from_gtp(&pdu, mme); + return sgsn_rim_rx_from_gtp(msg, &rim_ra); ret_error: msgb_free(msg); @@ -775,15 +803,24 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len) msgb_free(msg); return -1; case ST_GMM_REGISTERED_NORMAL: - OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE); - if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY) { + switch (mm->gb.mm_state_fsm->state) { + case ST_MM_IDLE: + LOGP(DGPRS, LOGL_ERROR, "Dropping DL packet for MS in MM state %s\n", + osmo_fsm_inst_state_name(mm->gb.mm_state_fsm)); + msgb_free(msg); + return -1; + case ST_MM_READY: + /* Go ahead */ + break; + case ST_MM_STANDBY: LOGMMCTXP(LOGL_INFO, mm, "Paging MS in GMM state %s, MM state %s\n", osmo_fsm_inst_state_name(mm->gmm_fsm), osmo_fsm_inst_state_name(mm->gb.mm_state_fsm)); - gprs_gb_page_ps_ra(mm); - } + sgsn_bssgp_page_ps_ra(mm); - /* FIXME: queue the packet we received from GTP */ + /* FIXME: queue the packet we received from GTP */ + break; + } break; default: LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state " @@ -800,12 +837,12 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len) /* It is easier to have a global count */ pdp->cdr_bytes_out += len; - return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi], + return sndcp_sn_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi], pdp->nsapi, mm); } /* Called by SNDCP when it has received/re-assembled a N-PDU */ -int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi, +int sgsn_gtp_data_req(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi, struct msgb *msg, uint32_t npdu_len, uint8_t *npdu) { struct sgsn_mm_ctx *mmctx; @@ -908,7 +945,7 @@ int sgsn_gtp_init(struct sgsn_instance *sgi) /* Register callbackcs with libgtp */ gtp_set_cb_delete_context(gsn, cb_delete_context); gtp_set_cb_conf(gsn, cb_conf); - gtp_set_cb_recovery2(gsn, cb_recovery2); + gtp_set_cb_recovery3(gsn, cb_recovery3); gtp_set_cb_data_ind(gsn, cb_data_ind); gtp_set_cb_unsup_ind(gsn, cb_unsup_ind); gtp_set_cb_extheader_ind(gsn, cb_extheader_ind); diff --git a/src/sgsn/sgsn_main.c b/src/sgsn/sgsn_main.c index af9757a89..d6afdef52 100644 --- a/src/sgsn/sgsn_main.c +++ b/src/sgsn/sgsn_main.c @@ -59,17 +59,18 @@ #include <osmocom/sgsn/vty.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/sgsn/gprs_llc.h> +#include <osmocom/sgsn/gprs_sndcp.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/gprs_ranap.h> -#include <osmocom/sgsn/gprs_gb.h> - -#include <osmocom/ctrl/control_if.h> -#include <osmocom/ctrl/ports.h> +#include <osmocom/sgsn/gprs_ns.h> +#include <osmocom/sgsn/gprs_bssgp.h> +#include <osmocom/sgsn/gprs_subscriber.h> +#include <osmocom/sgsn/gtp.h> #include <gtp.h> #include <osmocom/sgsn/sgsn_rim.h> -#include "../../bscconfig.h" +#include "../../config.h" #if BUILD_IU #include <osmocom/sigtran/osmo_ss7.h> @@ -81,7 +82,6 @@ #include <getopt.h> void *tall_sgsn_ctx; -struct ctrl_handle *g_ctrlh; struct gprs_ns2_inst *sgsn_nsi; static int daemonize = 0; @@ -97,34 +97,11 @@ const char *openbsc_copyright = struct sgsn_instance *sgsn; -/* call-back function for the BSSGP protocol */ +/* call-back function for the BSSGP protocol. + * Must be left here so that we can add a new one in tests/sgsn_test */ int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) { - struct osmo_bssgp_prim *bp; - bp = container_of(oph, struct osmo_bssgp_prim, oph); - - switch (oph->sap) { - case SAP_BSSGP_LL: - switch (oph->primitive) { - case PRIM_BSSGP_UL_UD: - return gprs_llc_rcvmsg(oph->msg, bp->tp); - } - break; - case SAP_BSSGP_GMM: - switch (oph->primitive) { - case PRIM_BSSGP_GMM_SUSPEND: - return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli); - case PRIM_BSSGP_GMM_RESUME: - return gprs_gmm_rx_resume(bp->ra_id, bp->tlli, - bp->u.resume.suspend_ref); - } - break; - case SAP_BSSGP_NM: - break; - case SAP_BSSGP_RIM: - return sgsn_rim_rx_from_gb(bp, oph->msg); - } - return 0; + return sgsn_bssgp_rx_prim(oph); } static void signal_handler(int signum) @@ -434,19 +411,12 @@ int main(int argc, char **argv) exit(1); } sgsn->cfg.nsi = sgsn_nsi; - bssgp_set_bssgp_callback(gprs_gb_send_cb, sgsn_nsi); - - gprs_llc_init("/usr/local/lib/osmocom/crypt/"); - sgsn_rate_ctr_init(); - sgsn_inst_init(sgsn); - + bssgp_set_bssgp_callback(sgsn_bssgp_dispatch_ns_unitdata_req_cb, sgsn_nsi); gprs_ns2_vty_init(sgsn_nsi); bssgp_vty_init(); gprs_llc_vty_init(); gprs_sndcp_vty_init(); - sgsn_auth_init(sgsn); - sgsn_cdr_init(sgsn); handle_options(argc, argv); @@ -472,25 +442,11 @@ int main(int argc, char **argv) } /* start telnet after reading config for vty_get_bind_addr() */ - rc = telnet_init_dynif(tall_sgsn_ctx, NULL, - vty_get_bind_addr(), OSMO_VTY_PORT_SGSN); + rc = telnet_init_default(tall_sgsn_ctx, NULL, OSMO_VTY_PORT_SGSN); if (rc < 0) exit(1); - /* start control interface after reading config for - * ctrl_vty_get_bind_addr() */ - g_ctrlh = ctrl_interface_setup_dynip(NULL, ctrl_vty_get_bind_addr(), - OSMO_CTRL_PORT_SGSN, NULL); - if (!g_ctrlh) { - LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n"); - exit(1); - } - - if (sgsn_ctrl_cmds_install() != 0) { - LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n"); - exit(1); - } - + gprs_llc_init(sgsn->cfg.crypt_cipher_plugin_path); rc = sgsn_gtp_init(sgsn); if (rc) { @@ -499,9 +455,9 @@ int main(int argc, char **argv) } else LOGP(DGPRS, LOGL_NOTICE, "libGTP v%s initialized\n", gtp_version()); - rc = gprs_subscr_init(sgsn); + rc = sgsn_inst_init(sgsn); if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot set up subscriber management\n"); + LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n"); exit(2); } diff --git a/src/sgsn/sgsn_rim.c b/src/sgsn/sgsn_rim.c index f28ba60bf..40e1f9033 100644 --- a/src/sgsn/sgsn_rim.c +++ b/src/sgsn/sgsn_rim.c @@ -12,6 +12,7 @@ #include <osmocom/gprs/gprs_bssgp_rim.h> #include <osmocom/sgsn/sgsn_rim.h> #include <osmocom/sgsn/gtp_mme.h> +#include <osmocom/sgsn/gtp.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/sgsn.h> @@ -20,6 +21,7 @@ static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *p struct bssgp_bvc_ctx *bvc_ctx; OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_GERAN); + /* Resolve RIM ROUTING ADDRESS to a BVC context */ bvc_ctx = btsctx_by_raid_cid(&pdu->routing_info_dest.geran.raid, pdu->routing_info_dest.geran.cid); if (!bvc_ctx) { LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n", @@ -27,10 +29,27 @@ static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *p return -EINVAL; } - /* Forward PDU as it is to the correct interface */ + /* Forward PDU to the NSEI of the resolved BVC context */ return bssgp_tx_rim(pdu, bvc_ctx->nsei); } +static int sgsn_bssgp_fwd_rim_to_geran_encoded(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address) +{ + struct bssgp_bvc_ctx *bvc_ctx; + OSMO_ASSERT(rim_routing_address->discr == BSSGP_RIM_ROUTING_INFO_GERAN); + + /* Resolve RIM ROUTING ADDRESS to a BVC context */ + bvc_ctx = btsctx_by_raid_cid(&rim_routing_address->geran.raid, rim_routing_address->geran.cid); + if (!bvc_ctx) { + LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n", + bssgp_rim_ri_name(rim_routing_address)); + return -EINVAL; + } + + /* Forward PDU to the NSEI of the resolved BVC context */ + return bssgp_tx_rim_encoded(msg, bvc_ctx->nsei); +} + static int sgsn_bssgp_fwd_rim_to_eutran(const struct bssgp_ran_information_pdu *pdu) { struct sgsn_mme_ctx *mme; @@ -88,36 +107,21 @@ err: return -1; } -/* Receive a RIM PDU from GTPvC1 (EUTRAN) */ -int sgsn_rim_rx_from_gtp(struct bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme) +/* Receive a RIM PDU from GTPv1C (EUTRAN) */ +int sgsn_rim_rx_from_gtp(struct msgb *msg, struct bssgp_rim_routing_info *rim_routing_address) { - struct sgsn_mme_ctx *mme_tmp; - if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_EUTRAN) { - LOGMME(mme, DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected src %s, got %s\n", - bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_EUTRAN), - bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr)); - return -EINVAL; - } - - if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) { - LOGMME(mme, DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected dst %s, got %s\n", - bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN), - bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr)); - return -EINVAL; - } - - mme_tmp = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_src.eutran.tai); - if (!mme_tmp)/* See if we have a default route configured */ - mme_tmp = sgsn_mme_ctx_by_default_route(sgsn); - if (mme != mme_tmp) { - LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: " - "Source MME doesn't have RIM routing configured for TAI: %s\n", - bssgp_rim_ri_name(&pdu->routing_info_src)); + /* TODO: In this code path, we currently only support RIM message forwarding to GERAN (BSSGP). However, it + * technically also be possible to route a message back to GTP (BSSGP_RIM_ROUTING_INFO_EUTRAN) or to + * IuPS (BSSGP_RIM_ROUTING_INFO_UTRAN) */ + if (rim_routing_address->discr != BSSGP_RIM_ROUTING_INFO_GERAN) { + LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected dst %s, got %s\n", + bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN), + bssgp_rim_routing_info_discr_str(rim_routing_address->discr)); return -EINVAL; } - LOGMME(mme, DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n", - bssgp_rim_ri_name(&pdu->routing_info_dest)); + LOGP(DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n", + bssgp_rim_ri_name(rim_routing_address)); - return sgsn_bssgp_fwd_rim_to_geran(pdu); + return sgsn_bssgp_fwd_rim_to_geran_encoded(msg, rim_routing_address); } diff --git a/src/sgsn/sgsn_vty.c b/src/sgsn/sgsn_vty.c index e0e26775e..29f9cd604 100644 --- a/src/sgsn/sgsn_vty.c +++ b/src/sgsn/sgsn_vty.c @@ -35,11 +35,14 @@ #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/gprs/gprs_ns2.h> -#include <osmocom/sgsn/gprs_gb.h> +#include <osmocom/sgsn/gprs_ns.h> #include <osmocom/sgsn/gprs_gmm.h> -#include <osmocom/sgsn/gprs_sgsn.h> +#include <osmocom/sgsn/gprs_bssgp.h> +#include <osmocom/sgsn/mmctx.h> +#include <osmocom/sgsn/gtp_ggsn.h> #include <osmocom/sgsn/gtp_mme.h> #include <osmocom/sgsn/vty.h> +#include <osmocom/sgsn/pdpctx.h> #include <osmocom/gsupclient/gsup_client.h> #include <osmocom/vty/tdef_vty.h> @@ -47,6 +50,7 @@ #include <osmocom/vty/vty.h> #include <osmocom/vty/misc.h> #include <osmocom/crypt/gprs_cipher.h> +#include <osmocom/crypt/utran_cipher.h> #include <osmocom/abis/ipa.h> #include <osmocom/gprs/gprs_bssgp.h> @@ -54,14 +58,12 @@ #include <pdp.h> #include <gtp.h> -#include "../../bscconfig.h" +#include "../../config.h" #ifdef BUILD_IU #include <osmocom/ranap/iu_client.h> #endif -extern void *tall_sgsn_ctx; - static struct sgsn_config *g_cfg = NULL; const struct value_string sgsn_auth_pol_strs[] = { @@ -96,7 +98,7 @@ const struct value_string sgsn_auth_pol_strs[] = { #define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */ -static struct osmo_tdef sgsn_T_defs[] = { +struct osmo_tdef sgsn_T_defs[] = { { .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" }, { .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" }, { .T=3314, .default_val=GSM0408_T3314_SECS, .desc="READY timer. Force to STANDBY on expiry timer (s)" }, @@ -135,7 +137,27 @@ DEFUN(cfg_sgsn_timer, cfg_sgsn_timer_cmd, return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs, argv); } -char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len) +DEFUN(show_timer_gtp, show_timer_gtp_cmd, + "show timer gtp " OSMO_TDEF_VTY_ARG_T_OPTIONAL, + SHOW_STR "Show timers\n" "GTP (libgtp) timers\n" + OSMO_TDEF_VTY_DOC_T) +{ + const char *T_arg = argc > 0 ? argv[0] : NULL; + return osmo_tdef_vty_show_cmd(vty, g_cfg->T_defs_gtp, T_arg, NULL); +} + +DEFUN(cfg_sgsn_timer_gtp, cfg_sgsn_timer_gtp_cmd, + "timer gtp " OSMO_TDEF_VTY_ARG_SET_OPTIONAL, + "Configure or show timers\n" "GTP (libgtp) timers\n" + OSMO_TDEF_VTY_DOC_SET) +{ + /* If any arguments are missing, redirect to 'show' */ + if (argc < 2) + return show_timer(self, vty, argc, argv); + return osmo_tdef_vty_set_cmd(vty, g_cfg->T_defs_gtp, argv); +} + +char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len, bool return_ipv6) { static char str[INET6_ADDRSTRLEN + 10]; @@ -148,15 +170,28 @@ char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len) case PDP_TYPE_N_IETF_IPv4: if (len < 2 + 4) break; - strcpy(str, "IPv4 "); + osmo_strlcpy(str, "IPv4 ", sizeof(str)); inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5); return str; case PDP_TYPE_N_IETF_IPv6: if (len < 2 + 8) break; - strcpy(str, "IPv6 "); + osmo_strlcpy(str, "IPv6 ", sizeof(str)); inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5); return str; + case PDP_TYPE_N_IETF_IPv4v6: + if (len < 2 + 20) + break; + if (return_ipv6) { + /* The IPv6 token, (rightmost four fields) is a duplicate of + * the site prefix + subnetID (leftmost fields) in pdpa here */ + osmo_strlcpy(str, "IPv6 ", sizeof(str)); + inet_ntop(AF_INET6, pdpa+6, str+5, sizeof(str)-5); + return str; + } + osmo_strlcpy(str, "IPv4 ", sizeof(str)); + inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5); + return str; default: break; } @@ -216,7 +251,7 @@ static int config_write_sgsn(struct vty *vty) vty_out(vty, " gtp local-ip %s%s", inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE); - llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) { + llist_for_each_entry(gctx, &sgsn->ggsn_list, list) { if (gctx->id == UINT32_MAX) continue; @@ -238,15 +273,26 @@ static int config_write_sgsn(struct vty *vty) for (server = sgsn->ares_servers; server; server = server->next) vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE); - if (g_cfg->cipher_support_mask != 0) { + if (g_cfg->gea_encryption_mask != 0) { vty_out(vty, " encryption gea"); for (i = 0; i < _GPRS_ALGO_NUM; i++) - if (g_cfg->cipher_support_mask >> i & 1) + if (g_cfg->gea_encryption_mask >> i & 1) + vty_out(vty, " %u", i); + + vty_out(vty, "%s", VTY_NEWLINE); + } + if (g_cfg->uea_encryption_mask != 0) { + vty_out(vty, " encryption uea"); + + for (i = 0; i < _OSMO_UTRAN_UEA_NUM; i++) + if (g_cfg->uea_encryption_mask >> i & 1) vty_out(vty, " %u", i); vty_out(vty, "%s", VTY_NEWLINE); } + if (g_cfg->crypt_cipher_plugin_path) + vty_out(vty, " encryption cipher-plugin-path %s%s", g_cfg->crypt_cipher_plugin_path, VTY_NEWLINE); if (g_cfg->sgsn_ipa_name) vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE); if (g_cfg->gsup_server_addr.sin_addr.s_addr) @@ -275,9 +321,9 @@ static int config_write_sgsn(struct vty *vty) llist_for_each_entry(acl, &g_cfg->imsi_acl, list) vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE); - if (llist_empty(&sgsn_apn_ctxts)) + if (llist_empty(&sgsn->apn_list)) vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE); - llist_for_each_entry(actx, &sgsn_apn_ctxts, list) { + llist_for_each_entry(actx, &sgsn->apn_list, list) { if (strlen(actx->imsi_prefix) > 0) vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s", actx->name, actx->imsi_prefix, actx->ggsn->id, @@ -298,6 +344,7 @@ static int config_write_sgsn(struct vty *vty) vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE); osmo_tdef_vty_write(vty, g_cfg->T_defs, " timer "); + osmo_tdef_vty_write(vty, g_cfg->T_defs_gtp, " timer gtp "); if (g_cfg->pcomp_rfc1144.active) { vty_out(vty, " compression rfc1144 active slots %d%s", @@ -385,7 +432,7 @@ DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd, "IPv4 Address\n") { uint32_t id = atoi(argv[0]); - struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); + struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id); inet_aton(argv[1], &ggc->remote_addr); @@ -410,7 +457,7 @@ DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd, "Version 0\n" "Version 1\n") { uint32_t id = atoi(argv[0]); - struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); + struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id); if (atoi(argv[1])) ggc->gtp_version = 1; @@ -428,7 +475,7 @@ DEFUN(cfg_ggsn_echo_interval, cfg_ggsn_echo_interval_cmd, "Interval between echo requests in seconds.\n") { uint32_t id = atoi(argv[0]); - struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); + struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id); ggc->echo_interval = atoi(argv[1]); @@ -447,7 +494,7 @@ DEFUN(cfg_ggsn_no_echo_interval, cfg_ggsn_no_echo_interval_cmd, NO_STR "Send an echo request to this static GGSN every interval.\n") { uint32_t id = atoi(argv[0]); - struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); + struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(sgsn, id); ggc->echo_interval = 0; sgsn_ggsn_ctx_check_echo_timer(ggc); @@ -488,7 +535,7 @@ static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str, struct apn_ctx *actx; struct sgsn_ggsn_ctx *ggsn; - ggsn = sgsn_ggsn_ctx_by_id(ggsn_id); + ggsn = sgsn_ggsn_ctx_by_id(sgsn, ggsn_id); if (ggsn == NULL) { vty_out(vty, "%% a GGSN with id %d has not been defined%s", ggsn_id, VTY_NEWLINE); @@ -552,8 +599,13 @@ static void vty_dump_pdp(struct vty *vty, const char *pfx, osmo_apn_to_str(apnbuf, pdp->lib->apn_use.v, pdp->lib->apn_use.l), VTY_NEWLINE); vty_out(vty, "%s PDP Address: %s%s", pfx, - gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l), + gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, false), VTY_NEWLINE); + if (pdp->lib->eua.v[1] == PDP_TYPE_N_IETF_IPv4v6) { + vty_out(vty, "%s PDP Address: %s%s", pfx, + gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l, true), + VTY_NEWLINE); + } vty_out(vty, "%s GTPv%d Local Control(%s / TEIC: 0x%08x) ", pfx, pdp->lib->version, sgsn_gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own); vty_out(vty, "Data(%s / TEID: 0x%08x)%s", @@ -670,7 +722,7 @@ DEFUN(swow_mmctx_all, show_mmctx_all_cmd, SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR) { struct sgsn_mm_ctx *mm; - llist_for_each_entry(mm, &sgsn_mm_ctxts, list) + llist_for_each_entry(mm, &sgsn->mm_list, list) vty_dump_mmctx(vty, "", mm, (argc > 0) ? 1 : 0); return CMD_SUCCESS; @@ -682,7 +734,7 @@ DEFUN(show_pdpctx_all, show_pdpctx_all_cmd, { struct sgsn_pdp_ctx *pdp; - llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list) + llist_for_each_entry(pdp, &sgsn->pdp_list, g_list) vty_dump_pdp(vty, "", pdp); return CMD_SUCCESS; @@ -752,14 +804,16 @@ DEFUN_DEPRECATED(cfg_encrypt, cfg_encrypt_cmd, } } - g_cfg->cipher_support_mask |= (1 << c); + g_cfg->gea_encryption_mask |= (1 << c); return CMD_SUCCESS; } +#define ENCRYPTION_STR "Set encryption algorithms for SGSN\n" + DEFUN(cfg_encrypt2, cfg_encrypt2_cmd, "encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>]", - "Set encryption algorithms for SGSN\n" + ENCRYPTION_STR "GPRS Encryption Algorithm\n" "GEAn Algorithm Number\n" "GEAn Algorithm Number\n" @@ -769,12 +823,12 @@ DEFUN(cfg_encrypt2, cfg_encrypt2_cmd, { int i = 0; - g_cfg->cipher_support_mask = 0; + g_cfg->gea_encryption_mask = 0; for (i = 0; i < argc; i++) - g_cfg->cipher_support_mask |= (1 << atoi(argv[i])); + g_cfg->gea_encryption_mask |= (1 << atoi(argv[i])); for (i = 0; i < _GPRS_ALGO_NUM; i++) { - if (g_cfg->cipher_support_mask >> i & 1) { + if (g_cfg->gea_encryption_mask >> i & 1) { if (i == GPRS_ALGO_GEA0) continue; @@ -796,6 +850,27 @@ DEFUN(cfg_encrypt2, cfg_encrypt2_cmd, return CMD_SUCCESS; } +DEFUN(cfg_encrypt_cipher_plugin_path, cfg_encrypt_cipher_plugin_path_cmd, + "encryption cipher-plugin-path PATH", + ENCRYPTION_STR + "Path to gprs encryption cipher plugin directory\n" + "Plugin path\n") +{ + osmo_talloc_replace_string(sgsn, &sgsn->cfg.crypt_cipher_plugin_path, argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_encrypt_cipher_plugin_path, cfg_no_encrypt_cipher_plugin_path_cmd, + "no encryption cipher-plugin-path PATH", + NO_STR ENCRYPTION_STR + "Path to gprs encryption cipher plugin directory\n" + "Plugin path\n") +{ + TALLOC_FREE(sgsn->cfg.crypt_cipher_plugin_path); + return CMD_SUCCESS; +} + DEFUN(cfg_authentication, cfg_authentication_cmd, "authentication (optional|required)", "Whether to enforce MS authentication in GERAN (only with auth-policy remote)\n" @@ -817,6 +892,23 @@ DEFUN(cfg_authentication, cfg_authentication_cmd, return CMD_SUCCESS; } +DEFUN(cfg_encryption_uea, cfg_encryption_uea_cmd, + "encryption uea <0-2> [<0-2>] [<0-2>]", + ENCRYPTION_STR + "UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n" + "UEAn Algorithm Number\n" + "UEAn Algorithm Number\n" + "UEAn Algorithm Number\n") +{ + unsigned int i; + + g_cfg->uea_encryption_mask = 0; + for (i = 0; i < argc; i++) + g_cfg->uea_encryption_mask |= (1 << atoi(argv[i])); + + return CMD_SUCCESS; +} + DEFUN(cfg_auth_policy, cfg_auth_policy_cmd, "auth-policy (accept-all|closed|acl-only|remote)", "Configure the Authorization policy of the SGSN. This setting determines which subscribers are" @@ -898,8 +990,17 @@ static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int } llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) { - vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'", - pdp->context_id, pdp->pdp_type, pdp->apn_str); + char ip_str[INET6_ADDRSTRLEN] = { 0 }; + + vty_out(vty, " PDP info: Id: %d, Addr(Org: 0x%02x Type: 0x%02x", + pdp->context_id, pdp->pdp_type_org, pdp->pdp_type_nr); + + if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC) + vty_out(vty, " Addr[0]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[0].u.sa, ip_str)); + if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC) + vty_out(vty, " Addr[1]: %s", osmo_sockaddr_ntop(&pdp->pdp_address[1].u.sa, ip_str)); + + vty_out(vty, ") APN: '%s'", pdp->apn_str); if (pdp->qos_subscribed_len) vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len)); @@ -946,7 +1047,7 @@ DEFUN_HIDDEN(reset_sgsn_state, struct gprs_subscr *subscr, *tmp_subscr; struct sgsn_mm_ctx *mm, *tmp_mm; - llist_for_each_entry_safe(mm, tmp_mm, &sgsn_mm_ctxts, list) + llist_for_each_entry_safe(mm, tmp_mm, &sgsn->mm_list, list) { gsm0408_gprs_access_cancelled(mm, SGSN_ERROR_CAUSE_NONE); } @@ -1225,7 +1326,7 @@ DEFUN(page_subscr, page_subscr_info_cmd, return CMD_WARNING; } - gprs_gb_page_ps_ra(mm); + sgsn_bssgp_page_ps_ra(mm); return CMD_SUCCESS; } @@ -1678,9 +1779,6 @@ int sgsn_vty_init(struct sgsn_config *cfg) { g_cfg = cfg; - g_cfg->T_defs = sgsn_T_defs; - osmo_tdefs_reset(g_cfg->T_defs); - install_element_ve(&show_sgsn_cmd); //install_element_ve(&show_mmctx_tlli_cmd); install_element_ve(&show_mmctx_imsi_cmd); @@ -1688,6 +1786,7 @@ int sgsn_vty_init(struct sgsn_config *cfg) install_element_ve(&show_pdpctx_all_cmd); install_element_ve(&show_subscr_cache_cmd); install_element_ve(&show_timer_cmd); + install_element_ve(&show_timer_gtp_cmd); install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd); install_element(ENABLE_NODE, &update_subscr_create_cmd); @@ -1714,6 +1813,9 @@ int sgsn_vty_init(struct sgsn_config *cfg) /* order matters here: ensure we attempt to parse our new command first! */ install_element(SGSN_NODE, &cfg_encrypt2_cmd); install_element(SGSN_NODE, &cfg_encrypt_cmd); + install_element(SGSN_NODE, &cfg_encryption_uea_cmd); + install_element(SGSN_NODE, &cfg_encrypt_cipher_plugin_path_cmd); + install_element(SGSN_NODE, &cfg_no_encrypt_cipher_plugin_path_cmd); install_element(SGSN_NODE, &cfg_gsup_ipa_name_cmd); install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd); @@ -1734,6 +1836,7 @@ int sgsn_vty_init(struct sgsn_config *cfg) install_element(SGSN_NODE, &cfg_grx_ggsn_cmd); install_element(SGSN_NODE, &cfg_sgsn_timer_cmd); + install_element(SGSN_NODE, &cfg_sgsn_timer_gtp_cmd); install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); @@ -1765,7 +1868,8 @@ int sgsn_parse_config(const char *config_file) /* make sure sgsn_vty_init() was called before this */ OSMO_ASSERT(g_cfg); - g_cfg->cipher_support_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */ + g_cfg->gea_encryption_mask = 0x1; /* support GEA0 by default unless specific encryption config exists */ + g_cfg->uea_encryption_mask = (1 << OSMO_UTRAN_UEA0); /* support UEA0 by default unless specific encryption config exists */ rc = vty_read_config_file(config_file, NULL); if (rc < 0) { diff --git a/src/sgsn/v42bis.c b/src/sgsn/v42bis.c index 0759cdf1c..ddca5f8c9 100644 --- a/src/sgsn/v42bis.c +++ b/src/sgsn/v42bis.c @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. diff --git a/tests/Makefile.am b/tests/Makefile.am index cb6d343b5..2c07ac96e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -42,38 +42,38 @@ DISTCLEANFILES = \ $(NULL) if ENABLE_EXT_TESTS -python-tests: $(BUILT_SOURCES) +python-tests: $(MAKE) vty-test $(MAKE) ctrl-python-test else -python-tests: $(BUILT_SOURCES) +python-tests: echo "Not running python-based tests (determined at configure-time)" endif -vty-python-test: $(BUILT_SOURCES) +vty-python-test: $(top_builddir)/src/sgsn/osmo-sgsn osmotestvty.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v osmotestconfig.py -p $(abs_top_srcdir) -w $(abs_top_builddir) -v $(srcdir)/vty_test_runner.py -w $(abs_top_builddir) -v - rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count + rm -f $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count # To update the VTY script from current application behavior, # pass -u to vty_script_runner.py by doing: # make vty-transcript-test U=-u -vty-transcript-test: +vty-transcript-test: $(top_builddir)/src/sgsn/osmo-sgsn osmo_verify_transcript_vty.py -v \ -n OsmoSGSN -p 4245 \ -r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \ $(U) $${T:-$(srcdir)/osmo-sgsn*.vty} - rm -f $(builddir)/sms.db $(builddir)/gsn_restart + rm -f $(builddir)/gsn_restart # don't run multiple tests concurrently so that the ports don't conflict vty-test: $(MAKE) vty-python-test $(MAKE) vty-transcript-test -ctrl-python-test: $(BUILT_SOURCES) +ctrl-python-test: $(top_builddir)/src/sgsn/osmo-sgsn $(srcdir)/ctrl_test_runner.py -w $(abs_top_builddir) -v - rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count + rm -f $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count check-local: atconfig $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) diff --git a/tests/gprs/Makefile.am b/tests/gprs/Makefile.am index 902313f2a..ddfd2aec0 100644 --- a/tests/gprs/Makefile.am +++ b/tests/gprs/Makefile.am @@ -1,9 +1,10 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) +AM_LDFLAGS = -no-install EXTRA_DIST = gprs_test.ok -noinst_PROGRAMS = gprs_test +check_PROGRAMS = gprs_test gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c diff --git a/tests/gprs/gprs_test.c b/tests/gprs/gprs_test.c index 99e3ea519..f239b7032 100644 --- a/tests/gprs/gprs_test.c +++ b/tests/gprs/gprs_test.c @@ -24,7 +24,7 @@ static int nu_is_retransmission(uint16_t nu, uint16_t vur) return ret; } -static void test_8_4_2() +static void test_8_4_2(void) { printf("Testing gprs_llc_is_retransmit.\n"); @@ -48,6 +48,22 @@ static void test_8_4_2() ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped } +/* GSM 04.08, 10.5.7.3 GPRS Timer */ +static int gprs_tmr_to_secs(uint8_t tmr) +{ + switch (tmr & GPRS_TMR_UNIT_MASK) { + case GPRS_TMR_2SECONDS: + return 2 * (tmr & GPRS_TMR_FACT_MASK); + default: + case GPRS_TMR_MINUTE: + return 60 * (tmr & GPRS_TMR_FACT_MASK); + case GPRS_TMR_6MINUTE: + return 360 * (tmr & GPRS_TMR_FACT_MASK); + case GPRS_TMR_DEACTIVATED: + return -1; + } +} + static void test_gprs_timer_enc_dec(void) { int i, u, secs, tmr; diff --git a/tests/gtphub/Makefile.am b/tests/gtphub/Makefile.am index fea01e0d1..22b2a522c 100644 --- a/tests/gtphub/Makefile.am +++ b/tests/gtphub/Makefile.am @@ -12,11 +12,13 @@ AM_CFLAGS = \ $(LIBGTP_CFLAGS) \ $(NULL) +AM_LDFLAGS = -no-install + EXTRA_DIST = \ gtphub_test.ok \ $(NULL) -noinst_PROGRAMS = \ +check_PROGRAMS = \ gtphub_test \ $(NULL) @@ -28,6 +30,7 @@ gtphub_test_LDFLAGS = \ -Wl,--wrap=gtphub_resolve_ggsn_addr \ -Wl,--wrap=gtphub_ares_init \ -Wl,--wrap=gtphub_write \ + $(AM_LDFLAGS) \ $(NULL) gtphub_test_LDADD = \ diff --git a/tests/gtphub/gtphub_test.c b/tests/gtphub/gtphub_test.c index dab39775b..5fa730a05 100644 --- a/tests/gtphub/gtphub_test.c +++ b/tests/gtphub/gtphub_test.c @@ -27,10 +27,11 @@ #include <osmocom/core/utils.h> #include <osmocom/core/application.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> #include <osmocom/sgsn/debug.h> -#include <osmocom/sgsn/gtphub.h> +#include <osmocom/gtphub/gtphub.h> #include <gtp.h> #include <gtpie.h> @@ -376,7 +377,7 @@ static void test_expiry(void) } char resolve_ggsn_got_imsi[GSM23003_IMSI_MAX_DIGITS+1]; -char resolve_ggsn_got_ni[GSM_APN_LENGTH]; +char resolve_ggsn_got_ni[APN_MAXLEN+1]; struct sgsn_sockaddr resolved_ggsn_addr; static int resolve_to_ggsn(const char *addr, uint16_t port) @@ -577,7 +578,7 @@ time_t now; static struct gtphub _hub; static struct gtphub *hub = &_hub; -static int setup_test_hub() +static int setup_test_hub(void) { /* Not really needed, but to make 100% sure... */ ZERO_STRUCT(hub); @@ -613,7 +614,7 @@ static int setup_test_hub() return 1; } -static int clear_test_hub() +static int clear_test_hub(void) { /* expire all */ gtphub_gc(hub, now + (60 * GTPH_EXPIRE_SLOWLY_MINUTES) + 1); @@ -817,7 +818,7 @@ static void test_echo(void) "87" /* 135: Quality of Service (QoS) Profile */ \ "0004" /* length */ \ "00" /* priority */ \ - "0b921f" /* QoS profile data */ + "0b921f" /* QoS profile data */ #define MSG_PDP_CTX_RSP(len, tei_h, seq, restart, tei_u, tei_c, gsn_c, gsn_u) \ "32" \ @@ -898,7 +899,7 @@ static int msg_from_ggsn(int plane_idx, return 1; } -static int create_pdp_ctx() +static int create_pdp_ctx(void) { const char *gtp_req_from_sgsn = MSG_PDP_CTX_REQ("0068", diff --git a/tests/osmo-sgsn_test-nodes.vty b/tests/osmo-sgsn_test-nodes.vty index f2ed2dce7..32ff8e71d 100644 --- a/tests/osmo-sgsn_test-nodes.vty +++ b/tests/osmo-sgsn_test-nodes.vty @@ -36,6 +36,9 @@ OsmoSGSN(config-sgsn)# list auth-policy (accept-all|closed|acl-only|remote) authentication (optional|required) encryption gea <0-4> [<0-4>] [<0-4>] [<0-4>] [<0-4>] + encryption uea <0-2> [<0-2>] [<0-2>] + encryption cipher-plugin-path PATH + no encryption cipher-plugin-path PATH gsup ipa-name NAME gsup remote-ip A.B.C.D gsup remote-port <0-65535> @@ -54,6 +57,7 @@ OsmoSGSN(config-sgsn)# list ggsn dynamic grx-dns-add A.B.C.D timer [TNNNN] [(<0-2147483647>|default)] + timer gtp [TNNNN] [(<0-2147483647>|default)] no compression rfc1144 compression rfc1144 active slots <1-256> compression rfc1144 passive @@ -116,3 +120,14 @@ sgsn gtp remote-ip 5.6.7.8 ... OsmoSGSN(config-sgsn)# no mme test1 +OsmoSGSN(config-sgsn)# encryption gea 0 3 +OsmoSGSN(config-sgsn)# encryption uea 1 2 +OsmoSGSN(config-sgsn)# encryption cipher-plugin-path /foo/bar +OsmoSGSN(config-sgsn)# show running-config +... +sgsn +... + encryption gea 0 3 + encryption uea 1 2 + encryption cipher-plugin-path /foo/bar +... diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am index bdf941dad..c6c1f4a68 100644 --- a/tests/sgsn/Makefile.am +++ b/tests/sgsn/Makefile.am @@ -7,6 +7,7 @@ AM_CFLAGS = \ -Wall \ -ggdb3 \ $(LIBOSMOCORE_CFLAGS) \ + $(LIBOSMOCTRL_CFLAGS) \ $(LIBOSMOABIS_CFLAGS) \ $(LIBOSMOGSM_CFLAGS) \ $(LIBOSMOGSUPCLIENT_CFLAGS) \ @@ -21,16 +22,23 @@ AM_CFLAGS += \ $(NULL) endif +AM_LDFLAGS = -no-install + EXTRA_DIST = \ sgsn_test.ok \ $(NULL) -noinst_PROGRAMS = \ +check_PROGRAMS = \ sgsn_test \ $(NULL) +noinst_HEADERS = \ + gprs_gb_parse.h \ + $(NULL) + sgsn_test_SOURCES = \ sgsn_test.c \ + gprs_gb_parse.c \ $(NULL) sgsn_test_LDFLAGS = \ @@ -39,18 +47,26 @@ sgsn_test_LDFLAGS = \ -Wl,--wrap=gprs_subscr_request_update_location \ -Wl,--wrap=gprs_subscr_request_auth_info \ -Wl,--wrap=osmo_gsup_client_send \ + $(AM_LDFLAGS) \ $(NULL) sgsn_test_LDADD = \ + $(top_builddir)/src/sgsn/apn.o \ + $(top_builddir)/src/sgsn/gprs_bssgp.o \ $(top_builddir)/src/sgsn/gprs_llc.o \ - $(top_builddir)/src/sgsn/gprs_gb.o \ + $(top_builddir)/src/sgsn/gprs_ns.o \ $(top_builddir)/src/sgsn/gprs_sndcp.o \ $(top_builddir)/src/sgsn/gprs_gmm_attach.o \ $(top_builddir)/src/sgsn/gprs_gmm.o \ $(top_builddir)/src/sgsn/gprs_gmm_fsm.o \ $(top_builddir)/src/sgsn/gprs_mm_state_gb_fsm.o \ - $(top_builddir)/src/sgsn/gprs_sgsn.o \ + $(top_builddir)/src/sgsn/gtp_ggsn.o \ $(top_builddir)/src/sgsn/gtp_mme.o \ + $(top_builddir)/src/sgsn/mmctx.o \ + $(top_builddir)/src/sgsn/pdpctx.o \ + $(top_builddir)/src/sgsn/sgsn.o \ + $(top_builddir)/src/sgsn/sgsn_cdr.o \ + $(top_builddir)/src/sgsn/sgsn_ctrl.o \ $(top_builddir)/src/sgsn/sgsn_vty.o \ $(top_builddir)/src/sgsn/sgsn_libgtp.o \ $(top_builddir)/src/sgsn/sgsn_auth.o \ @@ -66,11 +82,11 @@ sgsn_test_LDADD = \ $(top_builddir)/src/sgsn/sgsn_rim.o \ $(top_builddir)/src/gprs/gprs_utils.o \ $(top_builddir)/src/gprs/gprs_llc_parse.o \ - $(top_builddir)/src/gprs/gprs_gb_parse.o \ $(top_builddir)/src/gprs/crc24.o \ $(top_builddir)/src/gprs/sgsn_ares.o \ $(LIBOSMOABIS_LIBS) \ $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOCTRL_LIBS) \ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOGSUPCLIENT_LIBS) \ diff --git a/src/gprs/gprs_gb_parse.c b/tests/sgsn/gprs_gb_parse.c index e6a82acb2..670839f73 100644 --- a/src/gprs/gprs_gb_parse.c +++ b/tests/sgsn/gprs_gb_parse.c @@ -18,10 +18,12 @@ * */ +#include <arpa/inet.h> + #include <osmocom/gsm/gsm48.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> -#include <osmocom/sgsn/gprs_gb_parse.h> +#include "gprs_gb_parse.h" #include <osmocom/sgsn/gprs_utils.h> diff --git a/include/osmocom/sgsn/gprs_gb_parse.h b/tests/sgsn/gprs_gb_parse.h index 58de17f81..58de17f81 100644 --- a/include/osmocom/sgsn/gprs_gb_parse.h +++ b/tests/sgsn/gprs_gb_parse.h diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c index 562ae845d..a149b8e2c 100644 --- a/tests/sgsn/sgsn_test.c +++ b/tests/sgsn/sgsn_test.c @@ -19,44 +19,38 @@ * */ +#include <osmocom/core/application.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/rate_ctr.h> +#include <osmocom/core/utils.h> +#include <osmocom/gsm/apn.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/gsup.h> +#include <osmocom/gprs/gprs_bssgp.h> +#include <osmocom/vty/vty.h> + +#include <osmocom/gsupclient/gsup_client.h> + #include <osmocom/sgsn/gprs_llc.h> #include <osmocom/sgsn/sgsn.h> #include <osmocom/sgsn/gprs_gmm.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/gprs_subscriber.h> -#include <osmocom/gsm/gsup.h> -#include <osmocom/gsupclient/gsup_client.h> #include <osmocom/sgsn/gprs_utils.h> -#include <osmocom/sgsn/gprs_gb_parse.h> #include <osmocom/sgsn/gprs_gmm_fsm.h> - -#include <osmocom/gprs/gprs_bssgp.h> - -#include <osmocom/gsm/gsm_utils.h> - -#include <osmocom/core/application.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/rate_ctr.h> -#include <osmocom/core/utils.h> -#include <osmocom/vty/vty.h> +#include <osmocom/sgsn/gtp_ggsn.h> #include <stdio.h> +#include "gprs_gb_parse.h" + void *tall_sgsn_ctx; -static struct sgsn_instance sgsn_inst = { - .config_file = "osmo_sgsn.cfg", - .cfg = { - .gtp_statedir = "./", - .auth_policy = SGSN_AUTH_POLICY_CLOSED, - .cipher_support_mask = 0x1, - }, -}; -struct sgsn_instance *sgsn = &sgsn_inst; +struct sgsn_instance *sgsn; unsigned sgsn_tx_counter = 0; struct msgb *last_msg = NULL; struct gprs_gb_parse_context last_dl_parse_ctx; -static void reset_last_msg() +static void reset_last_msg(void) { if (last_msg) msgb_free(last_msg); @@ -65,9 +59,10 @@ static void reset_last_msg() memset(&last_dl_parse_ctx, 0, sizeof(last_dl_parse_ctx)); } -static void cleanup_test() +static void cleanup_test(void) { reset_last_msg(); + TALLOC_FREE(sgsn); } static uint32_t get_new_ptmsi(const struct gprs_gb_parse_context *parse_ctx) @@ -282,7 +277,7 @@ static void show_subscrs(FILE *out) } } -static void assert_no_subscrs() +static void assert_no_subscrs(void) { show_subscrs(stdout); fflush(stdout); @@ -384,6 +379,7 @@ static void test_auth_triplets(void) uint32_t local_tlli = 0xffeeddcc; printf("Testing authentication triplet handling\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* Check for emptiness */ OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); @@ -572,6 +568,7 @@ static void test_subscriber_gsup(void) printf("Testing subscriber GSUP handling\n"); update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data; + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* Check for emptiness */ OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); @@ -748,6 +745,7 @@ static void test_gmm_detach(void) uint32_t local_tlli; printf("Testing GMM detach\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* DTAP - Detach Request (MO) */ /* normal detach, power_off = 0 */ @@ -789,6 +787,7 @@ static void test_gmm_detach_power_off(void) uint32_t local_tlli; printf("Testing GMM detach (power off)\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* DTAP - Detach Request (MO) */ /* normal detach, power_off = 1 */ @@ -829,6 +828,7 @@ static void test_gmm_detach_no_mmctx(void) uint32_t local_tlli; printf("Testing GMM detach (no MMCTX)\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* DTAP - Detach Request (MO) */ /* normal detach, power_off = 0 */ @@ -865,6 +865,7 @@ static void test_gmm_detach_accept_unexpected(void) uint32_t local_tlli; printf("Testing GMM detach accept (unexpected)\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* DTAP - Detach Accept (MT) */ /* normal detach */ @@ -901,6 +902,7 @@ static void test_gmm_status_no_mmctx(void) uint32_t local_tlli; printf("Testing GMM Status (no MMCTX)\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* DTAP - GMM Status, protocol error */ static const unsigned char gmm_status[] = { @@ -1195,6 +1197,7 @@ static void test_gmm_reject(void) }; printf("Testing GMM reject\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* reset the PRNG used by sgsn_alloc_ptmsi */ srand(1); @@ -1241,6 +1244,9 @@ static void test_gmm_cancel(void) uint32_t foreign_tlli; uint32_t local_tlli = 0; struct gprs_llc_lle *lle; + + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); + sgsn->cfg.gea_encryption_mask = 0x1; const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; /* DTAP - Attach Request */ @@ -1271,8 +1277,7 @@ static void test_gmm_cancel(void) }; printf("Testing cancellation\n"); - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_OPEN; + sgsn->cfg.auth_policy = SGSN_AUTH_POLICY_OPEN; foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); @@ -1344,6 +1349,7 @@ static void test_apn_matching(void) struct apn_ctx *actx, *actxs[9]; printf("Testing APN matching\n"); + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); actxs[0] = sgsn_apn_ctx_find_alloc("*.test", ""); actxs[1] = sgsn_apn_ctx_find_alloc("*.def.test", ""); @@ -1433,9 +1439,6 @@ static void test_apn_matching(void) cleanup_test(); } -struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc( - struct sgsn_subscriber_data *sdata); - static void test_ggsn_selection(void) { struct apn_ctx *actxs[4]; @@ -1454,6 +1457,7 @@ static void test_ggsn_selection(void) printf("Testing GGSN selection\n"); osmo_gsup_client_send_cb = my_gsup_client_send_dummy; + sgsn = sgsn_instance_alloc(tall_sgsn_ctx); /* Check for emptiness */ OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); @@ -1472,9 +1476,9 @@ static void test_ggsn_selection(void) /* TODO: Add PDP info entries to s1 */ - ggcs[0] = sgsn_ggsn_ctx_find_alloc(0); - ggcs[1] = sgsn_ggsn_ctx_find_alloc(1); - ggcs[2] = sgsn_ggsn_ctx_find_alloc(2); + ggcs[0] = sgsn_ggsn_ctx_find_alloc(sgsn, 0); + ggcs[1] = sgsn_ggsn_ctx_find_alloc(sgsn, 1); + ggcs[2] = sgsn_ggsn_ctx_find_alloc(sgsn, 2); actxs[0] = sgsn_apn_ctx_find_alloc("test.apn", "123456"); actxs[0]->ggsn = ggcs[0]; @@ -1485,13 +1489,14 @@ static void test_ggsn_selection(void) pdp_data = sgsn_subscriber_pdp_data_alloc(s1->sgsn_data); pdp_data->context_id = 1; - pdp_data->pdp_type = 0x0121; + pdp_data->pdp_type_org = PDP_TYPE_ORG_IETF; + pdp_data->pdp_type_nr = PDP_TYPE_N_IETF_IPv4; osmo_strlcpy(pdp_data->apn_str, "*", sizeof(pdp_data->apn_str)); /* Resolve GGSNs */ tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn"); + osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Test.Apn"); ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); OSMO_ASSERT(ggc != NULL); @@ -1499,7 +1504,7 @@ static void test_ggsn_selection(void) OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0); tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn"); + osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Other.Apn"); ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); OSMO_ASSERT(ggc != NULL); @@ -1525,7 +1530,7 @@ static void test_ggsn_selection(void) tp.lv[GSM48_IE_GSM_APN].val = apn_enc; tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Foo.Bar"); + osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Foo.Bar"); ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); OSMO_ASSERT(ggc == NULL); @@ -1542,7 +1547,7 @@ static void test_ggsn_selection(void) osmo_strlcpy(pdp_data->apn_str, "Test.Apn", sizeof(pdp_data->apn_str)); tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn"); + osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Test.Apn"); ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); OSMO_ASSERT(ggc != NULL); @@ -1550,7 +1555,7 @@ static void test_ggsn_selection(void) OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0); tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn"); + osmo_apn_from_str(apn_enc, sizeof(apn_enc), "Other.Apn"); ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); OSMO_ASSERT(ggc == NULL); @@ -1652,11 +1657,7 @@ int main(int argc, char **argv) tall_sgsn_ctx = talloc_named_const(osmo_sgsn_ctx, 0, "sgsn"); msgb_ctx = msgb_talloc_ctx_init(osmo_sgsn_ctx, 0); - sgsn_rate_ctr_init(); - sgsn_auth_init(sgsn); - gprs_subscr_init(sgsn); vty_init(&vty_info); - sgsn_vty_init(&sgsn->cfg); test_llme(); test_subscriber(); @@ -1676,7 +1677,7 @@ int main(int argc, char **argv) talloc_report_full(osmo_sgsn_ctx, stderr); OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1); - OSMO_ASSERT(talloc_total_blocks(tall_sgsn_ctx) == 2); + OSMO_ASSERT(talloc_total_blocks(tall_sgsn_ctx) == 1); return 0; } diff --git a/tests/slhc/Makefile.am b/tests/slhc/Makefile.am index b6738c25d..33cb7faac 100644 --- a/tests/slhc/Makefile.am +++ b/tests/slhc/Makefile.am @@ -1,9 +1,10 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) +AM_LDFLAGS = -no-install EXTRA_DIST = slhc_test.ok -noinst_PROGRAMS = slhc_test +check_PROGRAMS = slhc_test slhc_test_SOURCES = slhc_test.c diff --git a/tests/sndcp_xid/Makefile.am b/tests/sndcp_xid/Makefile.am index 24626b32e..c4702b893 100644 --- a/tests/sndcp_xid/Makefile.am +++ b/tests/sndcp_xid/Makefile.am @@ -1,9 +1,10 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) +AM_LDFLAGS = -no-install EXTRA_DIST = sndcp_xid_test.ok -noinst_PROGRAMS = sndcp_xid_test +check_PROGRAMS = sndcp_xid_test sndcp_xid_test_SOURCES = sndcp_xid_test.c diff --git a/tests/v42bis/Makefile.am b/tests/v42bis/Makefile.am index 744239279..0e544a684 100644 --- a/tests/v42bis/Makefile.am +++ b/tests/v42bis/Makefile.am @@ -1,9 +1,10 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) +AM_LDFLAGS = -no-install EXTRA_DIST = v42bis_test.ok -noinst_PROGRAMS = v42bis_test +check_PROGRAMS = v42bis_test v42bis_test_SOURCES = v42bis_test.c diff --git a/tests/xid/Makefile.am b/tests/xid/Makefile.am index 6f058f5a6..d3a260bca 100644 --- a/tests/xid/Makefile.am +++ b/tests/xid/Makefile.am @@ -11,11 +11,13 @@ AM_CFLAGS = \ $(LIBCARES_CFLAGS) \ $(NULL) +AM_LDFLAGS = -no-install + EXTRA_DIST = \ xid_test.ok \ $(NULL) -noinst_PROGRAMS = \ +check_PROGRAMS = \ xid_test \ $(NULL) |