summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-10-25 22:31:59 +0200
committerHarald Welte <laforge@gnumonks.org>2017-10-26 00:06:40 +0200
commited03661871ac8ee1715c04390d25631537b084ac (patch)
tree39aeda51387ba5af9ebd44a552163fa0d0345e52
parent888e35aa7fbb2ba40526456abab739b7c15013e0 (diff)
remove sgsn, gbproxy and gtphub from openbsc.git
The GPRS related programs osmo-sgsn, osmo-gtphub and osmo-gbproxy have been split off into the separate osmo-sgsn repository, which can be found at git://git.osmocom.org/osmo-sgsn.git http://git.osmocom.org/osmo-sgsn/ This is technically unrelated but conceptually part of the larger NITB-split activities. I did a brief log of all changes in src/gprs and couldn't find any commits that we might have applied here but which are missing from osmo-sgsn.git. Change-Id: If60e28b23f5cfb2c4eb354951363a2bb63f3e0de
-rw-r--r--debian/control57
-rw-r--r--debian/osmo-gtphub.default2
-rw-r--r--debian/osmo-gtphub.examples1
-rwxr-xr-xdebian/osmo-gtphub.init150
-rw-r--r--debian/osmo-gtphub.install1
-rwxr-xr-xdebian/osmocom-gbproxy.init151
-rw-r--r--debian/osmocom-gbproxy.install1
-rw-r--r--debian/osmocom-sgsn.default2
-rw-r--r--debian/osmocom-sgsn.examples1
-rwxr-xr-xdebian/osmocom-sgsn.init150
-rw-r--r--debian/osmocom-sgsn.install1
-rwxr-xr-xdebian/rules3
-rw-r--r--openbsc/.gitignore15
-rw-r--r--openbsc/configure.ac26
-rwxr-xr-xopenbsc/contrib/gprs/gb-proxy-unblock-bug.py58
-rw-r--r--openbsc/contrib/gprs/gprs-bssgp-histogram.lua78
-rw-r--r--openbsc/contrib/gprs/gprs-buffer-count.lua80
-rw-r--r--openbsc/contrib/gprs/gprs-split-trace-by-tlli.lua46
-rw-r--r--openbsc/contrib/gprs/gprs-verify-nu.lua59
-rw-r--r--openbsc/contrib/systemd/osmo-gbproxy.service12
-rw-r--r--openbsc/contrib/systemd/osmo-sgsn.service11
-rw-r--r--openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg44
-rw-r--r--openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg25
-rw-r--r--openbsc/doc/examples/osmo-gtphub/gtphub-example.txt90
-rw-r--r--openbsc/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg25
-rw-r--r--openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg25
-rw-r--r--openbsc/doc/examples/osmo-sgsn/osmo-sgsn.cfg26
-rw-r--r--openbsc/include/openbsc/Makefile.am19
-rw-r--r--openbsc/include/openbsc/crc24.h10
-rw-r--r--openbsc/include/openbsc/gb_proxy.h288
-rw-r--r--openbsc/include/openbsc/gprs_gb_parse.h59
-rw-r--r--openbsc/include/openbsc/gprs_gmm.h35
-rw-r--r--openbsc/include/openbsc/gprs_llc.h284
-rw-r--r--openbsc/include/openbsc/gprs_llc_xid.h57
-rw-r--r--openbsc/include/openbsc/gprs_sgsn.h478
-rw-r--r--openbsc/include/openbsc/gprs_sndcp.h79
-rw-r--r--openbsc/include/openbsc/gprs_sndcp_comp.h82
-rw-r--r--openbsc/include/openbsc/gprs_sndcp_dcomp.h53
-rw-r--r--openbsc/include/openbsc/gprs_sndcp_pcomp.h46
-rw-r--r--openbsc/include/openbsc/gprs_sndcp_xid.h218
-rw-r--r--openbsc/include/openbsc/gprs_subscriber.h31
-rw-r--r--openbsc/include/openbsc/gprs_utils.h44
-rw-r--r--openbsc/include/openbsc/gsm_subscriber.h5
-rw-r--r--openbsc/include/openbsc/gtphub.h523
-rw-r--r--openbsc/include/openbsc/sgsn.h186
-rw-r--r--openbsc/include/openbsc/signal.h21
-rw-r--r--openbsc/include/openbsc/slhc.h187
-rw-r--r--openbsc/include/openbsc/v42bis.h147
-rw-r--r--openbsc/include/openbsc/v42bis_private.h126
-rw-r--r--openbsc/osmoappdesc.py9
-rw-r--r--openbsc/src/Makefile.am1
-rw-r--r--openbsc/src/gprs/.gitignore2
-rw-r--r--openbsc/src/gprs/Makefile.am132
-rw-r--r--openbsc/src/gprs/crc24.c67
-rw-r--r--openbsc/src/gprs/gb_proxy.c1438
-rw-r--r--openbsc/src/gprs/gb_proxy_main.c317
-rw-r--r--openbsc/src/gprs/gb_proxy_patch.c459
-rw-r--r--openbsc/src/gprs/gb_proxy_peer.c222
-rw-r--r--openbsc/src/gprs/gb_proxy_tlli.c723
-rw-r--r--openbsc/src/gprs/gb_proxy_vty.c853
-rw-r--r--openbsc/src/gprs/gprs_gb_parse.c636
-rw-r--r--openbsc/src/gprs/gprs_gmm.c2939
-rw-r--r--openbsc/src/gprs/gprs_llc.c1132
-rw-r--r--openbsc/src/gprs/gprs_llc_parse.c251
-rw-r--r--openbsc/src/gprs/gprs_llc_vty.c116
-rw-r--r--openbsc/src/gprs/gprs_llc_xid.c281
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c923
-rw-r--r--openbsc/src/gprs/gprs_sndcp.c1258
-rw-r--r--openbsc/src/gprs/gprs_sndcp_comp.c323
-rw-r--r--openbsc/src/gprs/gprs_sndcp_dcomp.c358
-rw-r--r--openbsc/src/gprs/gprs_sndcp_pcomp.c282
-rw-r--r--openbsc/src/gprs/gprs_sndcp_vty.c71
-rw-r--r--openbsc/src/gprs/gprs_sndcp_xid.c1822
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c936
-rw-r--r--openbsc/src/gprs/gprs_utils.c246
-rw-r--r--openbsc/src/gprs/gtphub.c2937
-rw-r--r--openbsc/src/gprs/gtphub_ares.c220
-rw-r--r--openbsc/src/gprs/gtphub_main.c359
-rw-r--r--openbsc/src/gprs/gtphub_sock.c60
-rw-r--r--openbsc/src/gprs/gtphub_vty.c613
-rw-r--r--openbsc/src/gprs/osmo_sgsn.cfg23
-rw-r--r--openbsc/src/gprs/sgsn_ares.c173
-rw-r--r--openbsc/src/gprs/sgsn_auth.c312
-rw-r--r--openbsc/src/gprs/sgsn_cdr.c259
-rw-r--r--openbsc/src/gprs/sgsn_ctrl.c69
-rw-r--r--openbsc/src/gprs/sgsn_libgtp.c874
-rw-r--r--openbsc/src/gprs/sgsn_main.c464
-rw-r--r--openbsc/src/gprs/sgsn_vty.c1312
-rw-r--r--openbsc/src/gprs/slhc.c813
-rw-r--r--openbsc/src/gprs/v42bis.c767
-rw-r--r--openbsc/tests/Makefile.am18
-rw-r--r--openbsc/tests/atlocal.in3
-rw-r--r--openbsc/tests/ctrl_test_runner.py23
-rw-r--r--openbsc/tests/gbproxy/Makefile.am54
-rw-r--r--openbsc/tests/gbproxy/gbproxy_test.c4971
-rw-r--r--openbsc/tests/gbproxy/gbproxy_test.ok7244
-rw-r--r--openbsc/tests/gprs/Makefile.am10
-rw-r--r--openbsc/tests/gprs/gprs_test.c140
-rw-r--r--openbsc/tests/gprs/gprs_test.ok17
-rw-r--r--openbsc/tests/gtphub/Makefile.am44
-rw-r--r--openbsc/tests/gtphub/gtphub_test.c1786
-rw-r--r--openbsc/tests/gtphub/gtphub_test.ok42
-rw-r--r--openbsc/tests/nanobts_omlattr/nanobts_omlattr_test.c1
-rw-r--r--openbsc/tests/oap/Makefile.am36
-rw-r--r--openbsc/tests/oap/oap_client_test.c270
-rw-r--r--openbsc/tests/oap/oap_client_test.err35
-rw-r--r--openbsc/tests/oap/oap_client_test.ok2
-rw-r--r--openbsc/tests/sgsn/Makefile.am82
-rw-r--r--openbsc/tests/sgsn/sgsn_test.c2487
-rw-r--r--openbsc/tests/sgsn/sgsn_test.ok45
-rw-r--r--openbsc/tests/slhc/Makefile.am15
-rw-r--r--openbsc/tests/slhc/slhc_test.c272
-rw-r--r--openbsc/tests/slhc/slhc_test.ok154
-rw-r--r--openbsc/tests/sndcp_xid/Makefile.am21
-rw-r--r--openbsc/tests/sndcp_xid/sndcp_xid_test.c284
-rw-r--r--openbsc/tests/sndcp_xid/sndcp_xid_test.ok11
-rw-r--r--openbsc/tests/testsuite.at62
-rw-r--r--openbsc/tests/v42bis/Makefile.am15
-rw-r--r--openbsc/tests/v42bis/v42bis_test.c435
-rw-r--r--openbsc/tests/v42bis/v42bis_test.ok648
-rw-r--r--openbsc/tests/vty_test_runner.py216
-rw-r--r--openbsc/tests/xid/Makefile.am39
-rw-r--r--openbsc/tests/xid/xid_test.c164
-rw-r--r--openbsc/tests/xid/xid_test.ok12
124 files changed, 2 insertions, 48826 deletions
diff --git a/debian/control b/debian/control
index 87b6f07c3..58e89668d 100644
--- a/debian/control
+++ b/debian/control
@@ -6,7 +6,6 @@ Build-Depends: debhelper (>= 9),
autotools-dev,
autoconf-archive,
pkg-config,
- libgtp-dev,
libosmocore-dev,
libosmo-sccp-dev,
libdbi0-dev,
@@ -16,7 +15,6 @@ Build-Depends: debhelper (>= 9),
libdbd-sqlite3,
libpcap-dev,
libssl-dev,
- libc-ares-dev,
libsmpp34-dev
Standards-Version: 3.9.8
Vcs-Git: git://bs11-abis.gnumonks.org/openbsc.git
@@ -62,31 +60,6 @@ Description: Command line utilities for Siemens BS-11 BTS
Additionally, it contains one tool for making use of an ISDN-card and the
public telephone network as frequency standard for the E1 line.
-Package: osmocom-sgsn
-Architecture: any
-Depends: ${shlibs:Depends},
- ${misc:Depends}
-Suggests: osmocom-bsc
-Description: Osmocom Serving GPRS Support Node
- This is an implementation of the GPRS Serving GPRS Support Node (SGSN). As
- such it implements the GPRS Mobility Management (GMM) and SM (Session
- Management).
- .
- The SGSN connects via the Gb-interface to the BSS (like the osmo-pcu or an
- ip.access nanoBTS), and it connects via the GTP protocol to a Gateway GPRS
- Support Node (GGSN) like openggsn.
-
-Package: osmocom-gbproxy
-Architecture: any
-Depends: ${shlibs:Depends},
- ${misc:Depends}
-Recommends: osmocom-sgsn
-Description: Osmocom GPRS Gb Interface Proxy
- The purpose of the Gb proxy is to aggregate the Gb links of multiple
- BSS's and present them in one Gb link to the SGSN.
- .
- This package is part of OpenBSC and closely related to osmocom-sgsn.
-
Package: osmocom-bsc-nat
Architecture: any
Depends: ${shlibs:Depends},
@@ -110,12 +83,6 @@ Description: Header file needed by tools tightly integrated
The directory structure is copied after the structure in the repository
and the header and .c file are installed into /usr/src/osmocom/openbsc/.
-Package: osmo-gtphub
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
-Description: Osmocom GTP Hub
- Proxy for comms between multiple SGSNs and GGSNs.
-
Package: osmocom-bsc-dbg
Architecture: any
Section: debug
@@ -148,22 +115,6 @@ Depends: osmocom-bs11-utils (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the OpenBSC BS11 utils
Make debugging possible
-Package: osmocom-sgsn-dbg
-Architecture: any
-Section: debug
-Priority: extra
-Depends: osmocom-sgsn (= ${binary:Version}), ${misc:Depends}
-Description: Debug symbols for the OpenBSC Serving GPRS Support Node
- Make debugging possible
-
-Package: osmocom-gbproxy-dbg
-Architecture: any
-Section: debug
-Priority: extra
-Depends: osmocom-gbproxy (= ${binary:Version}), ${misc:Depends}
-Description: Debug symbols for the OpenBSC GPRS GBProxy
- Make debugging possible
-
Package: osmocom-bsc-nat-dbg
Architecture: any
Section: debug
@@ -171,11 +122,3 @@ Priority: extra
Depends: osmocom-bsc-nat (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the OpenBSC Network Address Translation
Make debugging possible
-
-Package: osmo-gtphub-dbg
-Architecture: any
-Section: debug
-Priority: extra
-Depends: osmo-gtphub (= ${binary:Version}), ${misc:Depends}
-Description: Debug symbols for Osmocom GTP Hub
- Make debugging possible
diff --git a/debian/osmo-gtphub.default b/debian/osmo-gtphub.default
deleted file mode 100644
index 6af82da39..000000000
--- a/debian/osmo-gtphub.default
+++ /dev/null
@@ -1,2 +0,0 @@
-CONFIG_FILE="/etc/osmocom/osmo-gtphub.cfg"
-
diff --git a/debian/osmo-gtphub.examples b/debian/osmo-gtphub.examples
deleted file mode 100644
index 48c2dc028..000000000
--- a/debian/osmo-gtphub.examples
+++ /dev/null
@@ -1 +0,0 @@
-openbsc/doc/examples/osmo-gtphub
diff --git a/debian/osmo-gtphub.init b/debian/osmo-gtphub.init
deleted file mode 100755
index 160d55b70..000000000
--- a/debian/osmo-gtphub.init
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/bin/sh
-### BEGIN INIT INFO
-# Provides: osmo-gtphub
-# Required-Start: $network $local_fs
-# Required-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Osmocom GTP hub
-# Description: Osmocom GTP hub
-### END INIT INFO
-
-# Author: Neels Hofmeyr <nhofmeyr@sysmocom.de>
-
-# PATH should only include /usr/* if it runs after the mountnfs.sh script
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-NAME=osmo-gtphub # Introduce the short server's name here
-DESC="Osmocom GTP hub" # Introduce a short description here
-DAEMON=/usr/bin/osmo-gtphub # Introduce the server's location here
-SCRIPTNAME=/etc/init.d/osmo-gtphub
-
-# Exit if the package is not installed
-[ -x $DAEMON ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/osmo-gtphub ] && . /etc/default/osmo-gtphub
-
-# Load the VERBOSE setting and other rcS variables
-. /lib/init/vars.sh
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
-. /lib/lsb/init-functions
-
-DAEMON_ARGS="$DAEMON_ARGS -D -c $CONFIG_FILE"
-
-#
-# Function that starts the daemon/service
-#
-do_start()
-{
- # Return
- # 0 if daemon has been started
- # 1 if daemon was already running
- # 2 if daemon could not be started
- start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
- || return 1
- start-stop-daemon --start --quiet --exec $DAEMON -- \
- $DAEMON_ARGS \
- || return 2
- # Add code here, if necessary, that waits for the process to be ready
- # to handle requests from services started subsequently which depend
- # on this one. As a last resort, sleep for some time.
-}
-
-#
-# Function that stops the daemon/service
-#
-do_stop()
-{
- # Return
- # 0 if daemon has been stopped
- # 1 if daemon was already stopped
- # 2 if daemon could not be stopped
- # other if a failure occurred
- start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
- RETVAL="$?"
- [ "$RETVAL" = 2 ] && return 2
- # Wait for children to finish too if this is a daemon that forks
- # and if the daemon is only ever run from this initscript.
- # If the above conditions are not satisfied then add some other code
- # that waits for the process to drop all resources that could be
- # needed by services started subsequently. A last resort is to
- # sleep for some time.
- start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
- [ "$?" = 2 ] && return 2
- return "$RETVAL"
-}
-
-#
-# Function that sends a SIGHUP to the daemon/service
-#
-do_reload() {
- #
- # If the daemon can reload its configuration without
- # restarting (for example, when it is sent a SIGHUP),
- # then implement that here.
- #
- start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
- return 0
-}
-
-case "$1" in
- start)
- [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
- do_start
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- stop)
- [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- status)
- status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
- ;;
- #reload|force-reload)
- #
- # If do_reload() is not implemented then leave this commented out
- # and leave 'force-reload' as an alias for 'restart'.
- #
- #log_daemon_msg "Reloading $DESC" "$NAME"
- #do_reload
- #log_end_msg $?
- #;;
- restart|force-reload)
- #
- # If the "reload" option is implemented then remove the
- # 'force-reload' alias
- #
- log_daemon_msg "Restarting $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1)
- do_start
- case "$?" in
- 0) log_end_msg 0 ;;
- 1) log_end_msg 1 ;; # Old process is still running
- *) log_end_msg 1 ;; # Failed to start
- esac
- ;;
- *)
- # Failed to stop
- log_end_msg 1
- ;;
- esac
- ;;
- *)
- #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
- echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
- exit 3
- ;;
-esac
-
-:
diff --git a/debian/osmo-gtphub.install b/debian/osmo-gtphub.install
deleted file mode 100644
index 908c1a5eb..000000000
--- a/debian/osmo-gtphub.install
+++ /dev/null
@@ -1 +0,0 @@
-/usr/bin/osmo-gtphub
diff --git a/debian/osmocom-gbproxy.init b/debian/osmocom-gbproxy.init
deleted file mode 100755
index 924f32d10..000000000
--- a/debian/osmocom-gbproxy.init
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/bin/sh
-### BEGIN INIT INFO
-# Provides: osmo-gbproxy
-# Required-Start: $network $local_fs
-# Required-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Osmocom GBproxy
-# Description: A tool to proxy the GPRS Gb interface.
-### END INIT INFO
-
-# Author: Harald Welte <laforge@gnumonks.org>
-
-# PATH should only include /usr/* if it runs after the mountnfs.sh script
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-NAME=osmo-gbproxy # Introduce the short server's name here
-DESC="Osmocom GBProxy" # Introduce a short description here
-DAEMON=/usr/bin/osmo-gbproxy # Introduce the server's location here
-SCRIPTNAME=/etc/init.d/osmocom-gbproxy
-CONFIG_FILE=/etc/osmocom/osmocom-gbproxy.cfg
-
-# Exit if the package is not installed
-[ -x $DAEMON ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/osmocom-gbproxy ] && . /etc/default/osmocom-gbproxy
-
-# Load the VERBOSE setting and other rcS variables
-. /lib/init/vars.sh
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
-. /lib/lsb/init-functions
-
-DAEMON_ARGS="-D -c $CONFIG_FILE"
-
-#
-# Function that starts the daemon/service
-#
-do_start()
-{
- # Return
- # 0 if daemon has been started
- # 1 if daemon was already running
- # 2 if daemon could not be started
- start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
- || return 1
- start-stop-daemon --start --quiet --exec $DAEMON -- \
- $DAEMON_ARGS \
- || return 2
- # Add code here, if necessary, that waits for the process to be ready
- # to handle requests from services started subsequently which depend
- # on this one. As a last resort, sleep for some time.
-}
-
-#
-# Function that stops the daemon/service
-#
-do_stop()
-{
- # Return
- # 0 if daemon has been stopped
- # 1 if daemon was already stopped
- # 2 if daemon could not be stopped
- # other if a failure occurred
- start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
- RETVAL="$?"
- [ "$RETVAL" = 2 ] && return 2
- # Wait for children to finish too if this is a daemon that forks
- # and if the daemon is only ever run from this initscript.
- # If the above conditions are not satisfied then add some other code
- # that waits for the process to drop all resources that could be
- # needed by services started subsequently. A last resort is to
- # sleep for some time.
- start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
- [ "$?" = 2 ] && return 2
- return "$RETVAL"
-}
-
-#
-# Function that sends a SIGHUP to the daemon/service
-#
-do_reload() {
- #
- # If the daemon can reload its configuration without
- # restarting (for example, when it is sent a SIGHUP),
- # then implement that here.
- #
- start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
- return 0
-}
-
-case "$1" in
- start)
- [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
- do_start
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- stop)
- [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- status)
- status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
- ;;
- #reload|force-reload)
- #
- # If do_reload() is not implemented then leave this commented out
- # and leave 'force-reload' as an alias for 'restart'.
- #
- #log_daemon_msg "Reloading $DESC" "$NAME"
- #do_reload
- #log_end_msg $?
- #;;
- restart|force-reload)
- #
- # If the "reload" option is implemented then remove the
- # 'force-reload' alias
- #
- log_daemon_msg "Restarting $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1)
- do_start
- case "$?" in
- 0) log_end_msg 0 ;;
- 1) log_end_msg 1 ;; # Old process is still running
- *) log_end_msg 1 ;; # Failed to start
- esac
- ;;
- *)
- # Failed to stop
- log_end_msg 1
- ;;
- esac
- ;;
- *)
- #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
- echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
- exit 3
- ;;
-esac
-
-:
diff --git a/debian/osmocom-gbproxy.install b/debian/osmocom-gbproxy.install
deleted file mode 100644
index ba3f6eedb..000000000
--- a/debian/osmocom-gbproxy.install
+++ /dev/null
@@ -1 +0,0 @@
-/usr/bin/osmo-gbproxy
diff --git a/debian/osmocom-sgsn.default b/debian/osmocom-sgsn.default
deleted file mode 100644
index 77c9679a9..000000000
--- a/debian/osmocom-sgsn.default
+++ /dev/null
@@ -1,2 +0,0 @@
-CONFIG_FILE="/etc/osmocom/osmo-sgsn.cfg"
-
diff --git a/debian/osmocom-sgsn.examples b/debian/osmocom-sgsn.examples
deleted file mode 100644
index 15de78d59..000000000
--- a/debian/osmocom-sgsn.examples
+++ /dev/null
@@ -1 +0,0 @@
-openbsc/doc/examples/osmo-sgsn
diff --git a/debian/osmocom-sgsn.init b/debian/osmocom-sgsn.init
deleted file mode 100755
index 0794dc1d0..000000000
--- a/debian/osmocom-sgsn.init
+++ /dev/null
@@ -1,150 +0,0 @@
-#!/bin/sh
-### BEGIN INIT INFO
-# Provides: osmo-sgsn
-# Required-Start: $network $local_fs
-# Required-Stop:
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: Osmocom Serving GPRS Support Node
-# Description: Osmocom Serving GPRS Support Node
-### END INIT INFO
-
-# Author: Harald Welte <laforge@gnumonks.org>
-
-# PATH should only include /usr/* if it runs after the mountnfs.sh script
-PATH=/sbin:/usr/sbin:/bin:/usr/bin
-NAME=osmo-sgsn # Introduce the short server's name here
-DESC="Osmocom Serving GPRS Support Node" # Introduce a short description here
-DAEMON=/usr/bin/osmo-sgsn # Introduce the server's location here
-SCRIPTNAME=/etc/init.d/osmocom-sgsn
-
-# Exit if the package is not installed
-[ -x $DAEMON ] || exit 0
-
-# Read configuration variable file if it is present
-[ -r /etc/default/osmocom-sgsn ] && . /etc/default/osmocom-sgsn
-
-# Load the VERBOSE setting and other rcS variables
-. /lib/init/vars.sh
-
-# Define LSB log_* functions.
-# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
-. /lib/lsb/init-functions
-
-DAEMON_ARGS="$DAEMON_ARGS -D -c $CONFIG_FILE"
-
-#
-# Function that starts the daemon/service
-#
-do_start()
-{
- # Return
- # 0 if daemon has been started
- # 1 if daemon was already running
- # 2 if daemon could not be started
- start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
- || return 1
- start-stop-daemon --start --quiet --exec $DAEMON -- \
- $DAEMON_ARGS \
- || return 2
- # Add code here, if necessary, that waits for the process to be ready
- # to handle requests from services started subsequently which depend
- # on this one. As a last resort, sleep for some time.
-}
-
-#
-# Function that stops the daemon/service
-#
-do_stop()
-{
- # Return
- # 0 if daemon has been stopped
- # 1 if daemon was already stopped
- # 2 if daemon could not be stopped
- # other if a failure occurred
- start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
- RETVAL="$?"
- [ "$RETVAL" = 2 ] && return 2
- # Wait for children to finish too if this is a daemon that forks
- # and if the daemon is only ever run from this initscript.
- # If the above conditions are not satisfied then add some other code
- # that waits for the process to drop all resources that could be
- # needed by services started subsequently. A last resort is to
- # sleep for some time.
- start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
- [ "$?" = 2 ] && return 2
- return "$RETVAL"
-}
-
-#
-# Function that sends a SIGHUP to the daemon/service
-#
-do_reload() {
- #
- # If the daemon can reload its configuration without
- # restarting (for example, when it is sent a SIGHUP),
- # then implement that here.
- #
- start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
- return 0
-}
-
-case "$1" in
- start)
- [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
- do_start
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- stop)
- [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
- 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
- esac
- ;;
- status)
- status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
- ;;
- #reload|force-reload)
- #
- # If do_reload() is not implemented then leave this commented out
- # and leave 'force-reload' as an alias for 'restart'.
- #
- #log_daemon_msg "Reloading $DESC" "$NAME"
- #do_reload
- #log_end_msg $?
- #;;
- restart|force-reload)
- #
- # If the "reload" option is implemented then remove the
- # 'force-reload' alias
- #
- log_daemon_msg "Restarting $DESC" "$NAME"
- do_stop
- case "$?" in
- 0|1)
- do_start
- case "$?" in
- 0) log_end_msg 0 ;;
- 1) log_end_msg 1 ;; # Old process is still running
- *) log_end_msg 1 ;; # Failed to start
- esac
- ;;
- *)
- # Failed to stop
- log_end_msg 1
- ;;
- esac
- ;;
- *)
- #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
- echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
- exit 3
- ;;
-esac
-
-:
diff --git a/debian/osmocom-sgsn.install b/debian/osmocom-sgsn.install
deleted file mode 100644
index d89c45672..000000000
--- a/debian/osmocom-sgsn.install
+++ /dev/null
@@ -1 +0,0 @@
-/usr/bin/osmo-sgsn
diff --git a/debian/rules b/debian/rules
index 4e187a6cf..d1d74a547 100755
--- a/debian/rules
+++ b/debian/rules
@@ -21,10 +21,7 @@ override_dh_strip:
dh_strip -posmocom-nitb --dbg-package=osmocom-nitb-dbg
dh_strip -posmocom-ipaccess-utils --dbg-package=osmocom-ipaccess-utils-dbg
dh_strip -posmocom-bs11-utils --dbg-package=osmocom-bs11-utils-dbg
- dh_strip -posmocom-sgsn --dbg-package=osmocom-sgsn-dbg
- dh_strip -posmocom-gbproxy --dbg-package=osmocom-gbproxy-dbg
dh_strip -posmocom-bsc-nat --dbg-package=osmocom-bsc-nat-dbg
- dh_strip -posmo-gtphub --dbg-package=osmo-gtphub-dbg
override_dh_auto_configure:
echo $(VERSION) > openbsc/.tarball-version
diff --git a/openbsc/.gitignore b/openbsc/.gitignore
index 3dabea929..f54aa5925 100644
--- a/openbsc/.gitignore
+++ b/openbsc/.gitignore
@@ -52,9 +52,6 @@ src/ipaccess/ipaccess-firmware
src/ipaccess/ipaccess-proxy
src/utils/isdnsync
src/nat/bsc_nat
-src/gprs/osmo-sgsn
-src/gprs/osmo-gbproxy
-src/gprs/osmo-gtphub
src/osmo-bsc_nat/osmo-bsc_nat
src/libcommon/gsup_test_client
@@ -70,26 +67,16 @@ tests/mgcp/mgcp_test
tests/sccp/sccp_test
tests/sms/sms_test
tests/timer/timer_test
-tests/gprs/gprs_test
-tests/gbproxy/gbproxy_test
tests/abis/abis_test
tests/si/si_test
tests/smpp/smpp_test
tests/bsc/bsc_test
tests/trau/trau_test
tests/mgcp/mgcp_transcoding_test
-tests/sgsn/sgsn_test
tests/subscr/subscr_test
tests/subscr/bsc_subscr_test
-tests/oap/oap_test
-tests/gtphub/gtphub_test
tests/mm_auth/mm_auth_test
-tests/xid/xid_test
-tests/sndcp_xid/sndcp_xid_test
-tests/slhc/slhc_test
-tests/v42bis/v42bis_test
tests/nanobts_omlattr/nanobts_omlattr_test
-tests/oap/oap_client_test
tests/atconfig
tests/atlocal
@@ -97,7 +84,5 @@ tests/package.m4
tests/testsuite
tests/testsuite.log
-gsn_restart
src/openbsc.cfg*
writtenconfig/
-gtphub_restart_count
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index 48c5c822b..a0df05f62 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -105,22 +105,6 @@ AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
AC_SUBST(osmo_ac_iu)
-found_libgtp=yes
-PKG_CHECK_MODULES(LIBGTP, libgtp >= 0.92, , found_libgtp=no)
-AM_CONDITIONAL(HAVE_LIBGTP, test "$found_libgtp" = yes)
-AC_SUBST(found_libgtp)
-
-found_libcares=yes
-PKG_CHECK_MODULES([LIBCARES], [libcares], [], [found_libcares=no])
-AM_CONDITIONAL(HAVE_LIBCARES, test "$found_libcares" = yes)
-AC_SUBST(found_libcares)
-
-found_libgtp_and_libcares=no
-if test "$found_libgtp" = "yes" -a "$found_libcares" = "yes"; then
- found_libgtp_and_libcares=yes
-fi
-AC_SUBST(found_libgtp_and_libcares)
-
dnl checks for header files
AC_HEADER_STDC
AC_CHECK_HEADERS(dbi/dbd.h,,AC_MSG_ERROR(DBI library is not installed))
@@ -240,7 +224,6 @@ AC_OUTPUT(
src/osmo-bsc_mgcp/Makefile
src/ipaccess/Makefile
src/utils/Makefile
- src/gprs/Makefile
tests/Makefile
tests/atlocal
tests/gsm0408/Makefile
@@ -250,20 +233,11 @@ AC_OUTPUT(
tests/bsc-nat/Makefile
tests/bsc-nat-trie/Makefile
tests/mgcp/Makefile
- tests/gprs/Makefile
- tests/gbproxy/Makefile
tests/abis/Makefile
tests/smpp/Makefile
tests/trau/Makefile
- tests/sgsn/Makefile
tests/subscr/Makefile
- tests/oap/Makefile
- tests/gtphub/Makefile
tests/mm_auth/Makefile
- tests/xid/Makefile
- tests/sndcp_xid/Makefile
- tests/slhc/Makefile
- tests/v42bis/Makefile
tests/nanobts_omlattr/Makefile
doc/Makefile
doc/examples/Makefile
diff --git a/openbsc/contrib/gprs/gb-proxy-unblock-bug.py b/openbsc/contrib/gprs/gb-proxy-unblock-bug.py
deleted file mode 100755
index 0cd4b871f..000000000
--- a/openbsc/contrib/gprs/gb-proxy-unblock-bug.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-
-"""
-demonstrate a unblock bug on the GB Proxy..
-"""
-
-bts_ns_reset = "\x02\x00\x81\x01\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
-ns_reset_ack = "\x03\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
-
-bts_ns_unblock = "\x06"
-ns_unblock_ack = "\x07"
-
-bts_bvc_reset_0 = "\x00\x00\x00\x00\x22\x04\x82\x00\x00\x07\x81\x03\x3b\x81\x02"
-ns_bvc_reset_0_ack = "\x00\x00\x00\x00\x23\x04\x82\x00\x00"
-
-bts_bvc_reset_8167 = "\x00\x00\x00\x00\x22\x04\x82\x1f\xe7\x07\x81\x08\x08\x88\x72\xf4\x80\x10\x1c\x00\x9c\x40"
-
-
-import socket
-socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-socket.bind(("0.0.0.0", 0))
-socket.setblocking(1)
-
-
-import sys
-port = int(sys.argv[1])
-print "Sending data to port: %d" % port
-
-def send_and_receive(packet):
- socket.sendto(packet, ("127.0.0.1", port))
-
- try:
- data, addr = socket.recvfrom(4096)
- except socket.error, e:
- print "ERROR", e
- import sys
- sys.exit(0)
- return data
-
-#send stuff once
-
-to_send = [
- (bts_ns_reset, ns_reset_ack, "reset ack"),
- (bts_ns_unblock, ns_unblock_ack, "unblock ack"),
- (bts_bvc_reset_0, ns_bvc_reset_0_ack, "BVCI=0 reset ack"),
-]
-
-
-for (out, inp, type) in to_send:
- res = send_and_receive(out)
- if res != inp:
- print "Failed to get the %s" % type
- sys.exit(-1)
-
-import time
-time.sleep(3)
-res = send_and_receive(bts_bvc_reset_8167)
-print "Sent all messages... check wireshark for the last response"
diff --git a/openbsc/contrib/gprs/gprs-bssgp-histogram.lua b/openbsc/contrib/gprs/gprs-bssgp-histogram.lua
deleted file mode 100644
index b1ab5df7f..000000000
--- a/openbsc/contrib/gprs/gprs-bssgp-histogram.lua
+++ /dev/null
@@ -1,78 +0,0 @@
--- Simple LUA script to print the size of BSSGP messages over their type...
-
-do
- local ip_bucket = {}
-
- local pdu_types = {}
- pdu_types[ 6] = "PAGING"
- pdu_types[11] = "SUSPEND"
- pdu_types[12] = "SUSPEND-ACK"
- pdu_types[32] = "BVC-BLOCK"
- pdu_types[33] = "BVC-BLOCK-ACK"
- pdu_types[34] = "BVC-RESET"
- pdu_types[35] = "BVC-RESET-ACK"
- pdu_types[36] = "UNBLOCK"
- pdu_types[37] = "UNBLOCK-ACK"
- pdu_types[38] = "FLOW-CONTROL-BVC"
- pdu_types[39] = "FLOW-CONTROL-BVC-ACK"
- pdu_types[40] = "FLOW-CONTROL-MS"
- pdu_types[41] = "FLOW-CONTROL-MS-ACK"
- pdu_types[44] = "LLC-DISCARDED"
-
- local function init_listener()
- -- handle the port as NS over IP
- local udp_port_table = DissectorTable.get("udp.port")
- local gprs_ns_dis = Dissector.get("gprs_ns")
- udp_port_table:add(23000,gprs_ns_dis)
-
- -- bssgp filters
- local bssgp_pdu_get = Field.new("bssgp.pdu_type")
- local udp_length_get = Field.new("udp.length")
-
- local tap = Listener.new("ip", "udp.port == 23000")
- function tap.packet(pinfo,tvb,ip)
- local pdu = bssgp_pdu_get()
- local len = udp_length_get()
-
- -- only handle bssgp, but we also want the IP frame
- if not pdu then
- return
- end
-
- pdu = tostring(pdu)
- if tonumber(pdu) == 0 or tonumber(pdu) == 1 then
- return
- end
-
- local ip_src = tostring(ip.ip_src)
- local bssgp_histo = ip_bucket[ip_src]
- if not bssgp_histo then
- bssgp_histo = {}
- ip_bucket[ip_src] = bssgp_histo
- end
-
- local key = pdu
- local bucket = bssgp_histo[key]
- if not bucket then
- bucket = {}
- bssgp_histo[key] = bucket
- end
-
- table.insert(bucket, tostring(len))
- print("IP: " .. ip_src .. " PDU: " .. pdu_types[tonumber(pdu)] .. " Length: " .. tostring(len))
- end
-
- function tap.draw()
- -- well... this will not be called...
--- for ip,bssgp_histo in pairs(dumpers) do
--- print("IP " .. ip)
--- end
- end
-
- function tap.reset()
- -- well... this will not be called...
- end
- end
-
- init_listener()
-end
diff --git a/openbsc/contrib/gprs/gprs-buffer-count.lua b/openbsc/contrib/gprs/gprs-buffer-count.lua
deleted file mode 100644
index ca8864ad1..000000000
--- a/openbsc/contrib/gprs/gprs-buffer-count.lua
+++ /dev/null
@@ -1,80 +0,0 @@
--- I count the buffer space needed for LLC PDUs in the worse case and print it
-
-do
- local function init_listener()
- -- handle the port as NS over IP
- local udp_port_table = DissectorTable.get("udp.port")
- local gprs_ns_dis = Dissector.get("gprs_ns")
- udp_port_table:add(23000,gprs_ns_dis)
-
- -- bssgp filters
- local bssgp_pdu_get = Field.new("bssgp.pdu_type")
- local bssgp_delay_get = Field.new("bssgp.delay_val")
- local llcgprs_get = Field.new("llcgprs")
- local pdus = nil
-
- print("START...")
-
- local tap = Listener.new("ip", "udp.port == 23000 && bssgp.pdu_type == 0")
- function tap.packet(pinfo,tvb,ip)
- local pdu = bssgp_pdu_get()
- local len = llcgprs_get().len
- local delay = bssgp_delay_get()
-
- -- only handle bssgp, but we also want the IP frame
- if not pdu then
- return
- end
-
- if tonumber(tostring(delay)) == 65535 then
- pdus = { next = pdus,
- len = len,
- expires = -1 }
- else
- local off = tonumber(tostring(delay)) / 100.0
- pdus = { next = pdus,
- len = len,
- expires = pinfo.rel_ts + off }
- end
- local now_time = tonumber(tostring(pinfo.rel_ts))
- local now_size = 0
- local l = pdus
- local prev = nil
- local count = 0
- while l do
- if now_time < l.expires or l.expires == -1 then
- now_size = now_size + l.len
- prev = l
- l = l.next
- count = count + 1
- else
- -- delete things
- if prev == nil then
- pdus = nil
- l = nil
- else
- prev.next = l.next
- l = l.next
- end
- end
- end
--- print("TOTAL: " .. now_time .. " PDU_SIZE: " .. now_size)
- print(now_time .. " " .. now_size / 1024.0 .. " " .. count)
--- print("NOW: " .. tostring(pinfo.rel_ts) .. " Delay: " .. tostring(delay) .. " Length: " .. tostring(len))
- end
-
- function tap.draw()
- -- well... this will not be called...
--- for ip,bssgp_histo in pairs(dumpers) do
--- print("IP " .. ip)
--- end
- print("END")
- end
-
- function tap.reset()
- -- well... this will not be called...
- end
- end
-
- init_listener()
-end
diff --git a/openbsc/contrib/gprs/gprs-split-trace-by-tlli.lua b/openbsc/contrib/gprs/gprs-split-trace-by-tlli.lua
deleted file mode 100644
index 018c377c5..000000000
--- a/openbsc/contrib/gprs/gprs-split-trace-by-tlli.lua
+++ /dev/null
@@ -1,46 +0,0 @@
--- Create a file named by_ip/''ip_addess''.cap with all ip traffic of each ip host. (works for tshark only)
--- Dump files are created for both source and destination hosts
-do
- local dir = "by_tlli"
- local dumpers = {}
- local function init_listener()
- local udp_port_table = DissectorTable.get("udp.port")
- local gprs_ns_dis = Dissector.get("gprs_ns")
- udp_port_table:add(23000,gprs_ns_dis)
-
- local field_tlli = Field.new("bssgp.tlli")
- local tap = Listener.new("ip", "udp.port == 23000")
-
- -- we will be called once for every IP Header.
- -- If there's more than one IP header in a given packet we'll dump the packet once per every header
- function tap.packet(pinfo,tvb,ip)
- local tlli = field_tlli()
- if not tlli then
- return
- end
-
- local tlli_str = tostring(tlli)
- tlli_dmp = dumpers[tlli_str]
- if not tlli_dmp then
- local tlli_hex = string.format("0x%x", tonumber(tlli_str))
- print("Creating dump for TLLI " .. tlli_hex)
- tlli_dmp = Dumper.new_for_current(dir .. "/" .. tlli_hex .. ".pcap")
- dumpers[tlli_str] = tlli_dmp
- end
- tlli_dmp:dump_current()
- tlli_dmp:flush()
- end
- function tap.draw()
- for tlli,dumper in pairs(dumpers) do
- dumper:flush()
- end
- end
- function tap.reset()
- for tlli,dumper in pairs(dumpers) do
- dumper:close()
- end
- dumpers = {}
- end
- end
- init_listener()
-end
diff --git a/openbsc/contrib/gprs/gprs-verify-nu.lua b/openbsc/contrib/gprs/gprs-verify-nu.lua
deleted file mode 100644
index e44fdd16f..000000000
--- a/openbsc/contrib/gprs/gprs-verify-nu.lua
+++ /dev/null
@@ -1,59 +0,0 @@
--- This script verifies that the N(U) is increasing...
---
-do
- local nu_state_src = {}
-
- local function init_listener()
- -- handle the port as NS over IP
- local udp_port_table = DissectorTable.get("udp.port")
- local gprs_ns_dis = Dissector.get("gprs_ns")
- udp_port_table:add(23000,gprs_ns_dis)
-
- -- we want to look here...
- local llc_sapi_get = Field.new("llcgprs.sapib")
- local llc_nu_get = Field.new("llcgprs.nu")
- local bssgp_tlli_get = Field.new("bssgp.tlli")
-
- local tap = Listener.new("ip", "udp.port == 23000")
- function tap.packet(pinfo,tvb,ip)
- local llc_sapi = llc_sapi_get()
- local llc_nu = llc_nu_get()
- local bssgp_tlli = bssgp_tlli_get()
-
- if not llc_sapi or not llc_nu or not bssgp_tlli then
- return
- end
-
- local ip_src = tostring(ip.ip_src)
- local bssgp_tlli = tostring(bssgp_tlli)
- local llc_nu = tostring(llc_nu)
- local llc_sapi = tostring(llc_sapi)
-
- local src_key = ip_src .. "-" .. bssgp_tlli .. "-" .. llc_sapi
- local last_nu = nu_state_src[src_key]
- if not last_nu then
- -- print("Establishing mapping for " .. src_key)
- nu_state_src[src_key] = llc_nu
- return
- end
-
- local function tohex(number)
- return string.format("0x%x", tonumber(number))
- end
-
- nu_state_src[src_key] = llc_nu
- if tonumber(last_nu) + 1 ~= tonumber(llc_nu) then
- print("JUMP in N(U) on TLLI " .. tohex(bssgp_tlli) .. " and SAPI: " .. llc_sapi .. " src: " .. ip_src)
- print("\t last: " .. last_nu .. " now: " .. llc_nu)
- end
- end
-
- function tap.draw()
- end
-
- function tap.reset()
- end
- end
- init_listener()
-end
-
diff --git a/openbsc/contrib/systemd/osmo-gbproxy.service b/openbsc/contrib/systemd/osmo-gbproxy.service
deleted file mode 100644
index a0b7829db..000000000
--- a/openbsc/contrib/systemd/osmo-gbproxy.service
+++ /dev/null
@@ -1,12 +0,0 @@
-[Unit]
-Description=Osmocom Gb proxy
-
-[Service]
-Type=simple
-ExecStart=/usr/bin/osmo-gbproxy -c /etc/osmocom/osmo-gbproxy.cfg
-Restart=always
-RestartSec=2
-RestartPreventExitStatus=1
-
-[Install]
-WantedBy=multi-user.target
diff --git a/openbsc/contrib/systemd/osmo-sgsn.service b/openbsc/contrib/systemd/osmo-sgsn.service
deleted file mode 100644
index 674d78656..000000000
--- a/openbsc/contrib/systemd/osmo-sgsn.service
+++ /dev/null
@@ -1,11 +0,0 @@
-[Unit]
-Description=OpenBSC SGSN
-
-[Service]
-Type=simple
-Restart=always
-ExecStart=/usr/bin/osmo-sgsn -c /etc/osmocom/osmo-sgsn.cfg
-RestartSec=2
-
-[Install]
-WantedBy=multi-user.target
diff --git a/openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg b/openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg
deleted file mode 100644
index 15fd74a2b..000000000
--- a/openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg
+++ /dev/null
@@ -1,44 +0,0 @@
-!
-! OsmoGbProxy (UNKNOWN) configuration saved from vty
-!!
-!
-log stderr
- logging filter all 1
- logging color 1
- logging timestamp 0
- logging level all debug
- logging level gprs debug
- logging level ns info
- logging level bssgp debug
- logging level lglobal notice
- logging level llapd notice
- logging level linp notice
- logging level lmux notice
- logging level lmi notice
- logging level lmib notice
- logging level lsms notice
-!
-line vty
- no login
-!
-ns
- nse 666 nsvci 666
- nse 666 remote-role sgsn
-! nse 666 encapsulation framerelay-gre
-! nse 666 remote-ip 172.16.1.70
-! nse 666 fr-dlci 666
- timer tns-block 3
- timer tns-block-retries 3
- timer tns-reset 3
- timer tns-reset-retries 3
- timer tns-test 30
- timer tns-alive 3
- timer tns-alive-retries 10
- encapsulation udp local-port 23000
-! encapsulation framerelay-gre enabled 1
-gbproxy
- sgsn nsei 666
- core-mobile-country-code 666
- core-mobile-network-code 6
- core-access-point-name none match-imsi ^666066|^66607
- tlli-list max-length 200
diff --git a/openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg b/openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg
deleted file mode 100644
index 0c3917a3e..000000000
--- a/openbsc/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-!
-! Osmocom Gb Proxy (0.9.0.404-6463) configuration saved from vty
-!!
-!
-line vty
- no login
-!
-gbproxy
- sgsn nsei 101
-ns
- nse 101 nsvci 101
- nse 101 remote-role sgsn
- nse 101 encapsulation udp
- nse 101 remote-ip 192.168.100.239
- nse 101 remote-port 7777
- timer tns-block 3
- timer tns-block-retries 3
- timer tns-reset 3
- timer tns-reset-retries 3
- timer tns-test 30
- timer tns-alive 3
- timer tns-alive-retries 10
- encapsulation framerelay-gre enabled 0
- encapsulation framerelay-gre local-ip 0.0.0.0
- encapsulation udp local-port 23000
diff --git a/openbsc/doc/examples/osmo-gtphub/gtphub-example.txt b/openbsc/doc/examples/osmo-gtphub/gtphub-example.txt
deleted file mode 100644
index 9c65f925f..000000000
--- a/openbsc/doc/examples/osmo-gtphub/gtphub-example.txt
+++ /dev/null
@@ -1,90 +0,0 @@
-Here is a simple setup to test GTPHub operations. The IP addresses picked will
-work well only on a system that creates local addresses (127.0.0.123) on the
-fly (like linux) -- you may pick of course different IP addresses.
-
-Overview of the example setup:
-
- sgsnemu gtphub ggsn
- 127.0.0.1 <--> 127.0.0.3 127.0.0.4 <--> 127.0.0.2
-
-Prerequisites: openggsn.
-
-Have a local directory where you store config files and from which you launch
-the GSNs and the hub (they will store restart counter files in that dir).
-In it, have these config files:
-
-ggsn.conf:
-
- # GGSN local address
- listen 127.0.0.2
-
- # End User Addresses are picked from this range
- net 10.23.42.0/24
-
- pcodns1 8.8.8.8
-
- logfile /tmp/foo
-
-gtphub.conf:
-
- gtphub
- bind-to-sgsns 127.0.0.3
- bind-to-ggsns 127.0.0.4
- ggsn-proxy 127.0.0.2
- end
-
-
-(
-You may omit the ggsn-proxy if GRX ares is working, or if you add the GRX
-address and GGSN IP address to /etc/hosts something like:
-
- 127.0.0.2 internet.mnc070.mcc901.gprs
-
-)
-
-
-Once the config files are in place, start the programs, in separate terminals.
-GGSN and SGSN need to be started with root priviliges to be able to create tun
-interfaces. GTPHub may run as unprivileged user.
-
-The LD_LIBRARY_PATH below may be needed if OpenGGSN installed to /usr/local.
-
-
-1. GGSN:
-
- sudo -s
- cd <your-test-dir>
- LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/ggsn -f -c ./ggsn.conf
-
-2. GTPHub:
-
- cd <your-test-dir>
- path/to/openbsc/openbsc/src/gprs/osmo-gtphub -c gtphub.conf #-e 1 #for DEBUG level
-
-3. SGSN tests:
-
- sudo -s
- cd <your-test-dir>
- /usr/local/bin/sgsnemu --createif -l 127.0.0.1 -r 127.0.0.3 --imsi 420001214365100 --contexts=3
-
-Add more SGSNs using different IMSIs and local ports (if the same IMSI is used,
-the GGSN will reuse TEIs and tunnels will be discarded automatically):
-
- /usr/local/bin/sgsnemu --createif -l 127.0.0.11 -r 127.0.0.3 --imsi 420001214365300 --contexts=3
-
-This shows the basic setup of GTPHub. Testing internet traffic via sgsnemu
-still needs some effort to announce a mobile subscriber or the like (I have
-used a real BTS, osmo-sgsn and a testing SIM in a web phone, instead).
-
-The core capability of GTPHub is to manage more than two GSNs, e.g. an SGSN
-contacting various GGSNs over the single GTPHub link. You would configure the
-SGSN to use one fixed GGSN (sending to gtphub) and gtphub will resolve the
-GGSNs once it has received the messages. So the SGSN may be behind NAT (add
-"sgsn-use-sender" to gtphub.conf) and communicate to various GGSNs over a
-single link to gtphub.
-
-I hope this helps to get you going.
-Any suggestions/patches are welcome!
-
-~Neels
-
diff --git a/openbsc/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg b/openbsc/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
deleted file mode 100644
index 3913d2c3c..000000000
--- a/openbsc/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-!
-! Osmocom gtphub configuration
-!
-! This file is used for VTY tests, referenced by openbsc/osmoappdesc.py
-! For the test, try to use most config commands.
-!
-
-line vty
- no login
-
-gtphub
- ! Local addresses to listen on and send from, both on one interface.
- ! The side towards SGSN uses nonstandard ports.
- bind-to-sgsns ctrl 127.0.0.1 12123 user 127.0.0.1 12153
- ! The GGSN side with standard ports.
- bind-to-ggsns 127.0.0.1
-
- ! Proxy: unconditionally direct all traffic to...
- sgsn-proxy 127.0.0.4
-
- ! Proxy with nonstandard ports or separate IPs:
- ggsn-proxy ctrl 127.0.0.3 2123 user 127.0.0.5 2152
-
- ! Add a name server for GGSN resolution
- grx-dns-add 192.168.0.1
diff --git a/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg b/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg
deleted file mode 100644
index 0dc415047..000000000
--- a/openbsc/doc/examples/osmo-gtphub/osmo-gtphub.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-!
-! Osmocom gtphub configuration
-!
-
-line vty
- no login
-
-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.1
- bind-to-ggsns 127.0.0.2
-
- ! Local nonstandard ports or separate IPs:
- !bind-to-sgsns ctrl 127.0.0.1 2342 user 127.0.0.1 4223
-
- ! Proxy: unconditionally direct all traffic to...
- !ggsn-proxy 127.0.0.3
- !sgsn-proxy 127.0.0.4
-
- ! Proxy with nonstandard ports or separate IPs:
- !ggsn-proxy ctrl 127.0.0.3 2123 user 127.0.0.5 2152
-
- ! Add a name server for GGSN resolution
- !grx-dns-add 192.168.0.1
diff --git a/openbsc/doc/examples/osmo-sgsn/osmo-sgsn.cfg b/openbsc/doc/examples/osmo-sgsn/osmo-sgsn.cfg
deleted file mode 100644
index 49559830a..000000000
--- a/openbsc/doc/examples/osmo-sgsn/osmo-sgsn.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-!
-! Osmocom SGSN configuration
-!
-!
-line vty
- no login
-!
-sgsn
- gtp local-ip 127.0.0.1
- ggsn 0 remote-ip 127.0.0.1
- ggsn 0 gtp-version 1
-!
-ns
- timer tns-block 3
- timer tns-block-retries 3
- timer tns-reset 3
- timer tns-reset-retries 3
- timer tns-test 30
- timer tns-alive 3
- timer tns-alive-retries 10
- encapsulation udp local-ip 127.0.0.1
- encapsulation udp local-port 23000
- encapsulation framerelay-gre enabled 0
-!
-bssgp
-!
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index db03caac2..126b115ed 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -16,24 +16,10 @@ noinst_HEADERS = \
chan_alloc.h \
common_bsc.h \
common_cs.h \
- crc24.h \
ctrl.h \
db.h \
debug.h \
e1_config.h \
- gb_proxy.h \
- gprs_gb_parse.h \
- gprs_gmm.h \
- gprs_llc.h \
- gprs_llc_xid.h \
- gprs_sgsn.h \
- gprs_sndcp.h \
- gprs_sndcp_comp.h \
- gprs_sndcp_dcomp.h \
- gprs_sndcp_pcomp.h \
- gprs_sndcp_xid.h \
- gprs_subscriber.h \
- gprs_utils.h \
gsm_04_08.h \
gsm_04_11.h \
gsm_04_14.h \
@@ -42,7 +28,6 @@ noinst_HEADERS = \
gsm_data_shared.h \
gsm_subscriber.h \
gsup_client.h \
- gtphub.h \
handover.h \
handover_decision.h \
ipaccess.h \
@@ -72,10 +57,8 @@ noinst_HEADERS = \
rrlp.h \
rs232.h \
rtp_proxy.h \
- sgsn.h \
signal.h \
silent_call.h \
- slhc.h \
smpp.h \
sms_queue.h \
socket.h \
@@ -86,8 +69,6 @@ noinst_HEADERS = \
trau_upqueue.h \
ussd.h \
vty.h \
- v42bis.h \
- v42bis_private.h \
$(NULL)
openbsc_HEADERS = \
diff --git a/openbsc/include/openbsc/crc24.h b/openbsc/include/openbsc/crc24.h
deleted file mode 100644
index 756638c03..000000000
--- a/openbsc/include/openbsc/crc24.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _CRC24_H
-#define _CRC24_H
-
-#include <stdint.h>
-
-#define INIT_CRC24 0xffffff
-
-uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len);
-
-#endif
diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h
deleted file mode 100644
index e10894fc3..000000000
--- a/openbsc/include/openbsc/gb_proxy.h
+++ /dev/null
@@ -1,288 +0,0 @@
-#ifndef _GB_PROXY_H
-#define _GB_PROXY_H
-
-
-#include <osmocom/core/msgb.h>
-
-#include <osmocom/gprs/gprs_ns.h>
-#include <osmocom/vty/command.h>
-
-#include <sys/types.h>
-#include <regex.h>
-
-#define GBPROXY_INIT_VU_GEN_TX 256
-
-struct rate_ctr_group;
-struct gprs_gb_parse_context;
-struct tlv_parsed;
-
-enum gbproxy_global_ctr {
- GBPROX_GLOB_CTR_INV_BVCI,
- GBPROX_GLOB_CTR_INV_LAI,
- GBPROX_GLOB_CTR_INV_RAI,
- GBPROX_GLOB_CTR_INV_NSEI,
- GBPROX_GLOB_CTR_PROTO_ERR_BSS,
- GBPROX_GLOB_CTR_PROTO_ERR_SGSN,
- GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS,
- GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN,
- GBPROX_GLOB_CTR_RESTART_RESET_SGSN,
- GBPROX_GLOB_CTR_TX_ERR_SGSN,
- GBPROX_GLOB_CTR_OTHER_ERR,
- GBPROX_GLOB_CTR_PATCH_PEER_ERR,
-};
-
-enum gbproxy_peer_ctr {
- GBPROX_PEER_CTR_BLOCKED,
- GBPROX_PEER_CTR_UNBLOCKED,
- GBPROX_PEER_CTR_DROPPED,
- GBPROX_PEER_CTR_INV_NSEI,
- GBPROX_PEER_CTR_TX_ERR,
- GBPROX_PEER_CTR_RAID_PATCHED_BSS,
- GBPROX_PEER_CTR_RAID_PATCHED_SGSN,
- GBPROX_PEER_CTR_APN_PATCHED,
- GBPROX_PEER_CTR_TLLI_PATCHED_BSS,
- GBPROX_PEER_CTR_TLLI_PATCHED_SGSN,
- GBPROX_PEER_CTR_PTMSI_PATCHED_BSS,
- GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN,
- GBPROX_PEER_CTR_PATCH_CRYPT_ERR,
- GBPROX_PEER_CTR_PATCH_ERR,
- GBPROX_PEER_CTR_ATTACH_REQS,
- GBPROX_PEER_CTR_ATTACH_REJS,
- GBPROX_PEER_CTR_ATTACH_ACKS,
- GBPROX_PEER_CTR_ATTACH_COMPLS,
- GBPROX_PEER_CTR_RA_UPD_REQS,
- GBPROX_PEER_CTR_RA_UPD_REJS,
- GBPROX_PEER_CTR_RA_UPD_ACKS,
- GBPROX_PEER_CTR_RA_UPD_COMPLS,
- GBPROX_PEER_CTR_GMM_STATUS_BSS,
- GBPROX_PEER_CTR_GMM_STATUS_SGSN,
- GBPROX_PEER_CTR_DETACH_REQS,
- GBPROX_PEER_CTR_DETACH_ACKS,
- GBPROX_PEER_CTR_PDP_ACT_REQS,
- GBPROX_PEER_CTR_PDP_ACT_REJS,
- GBPROX_PEER_CTR_PDP_ACT_ACKS,
- GBPROX_PEER_CTR_PDP_DEACT_REQS,
- GBPROX_PEER_CTR_PDP_DEACT_ACKS,
- GBPROX_PEER_CTR_TLLI_UNKNOWN,
- GBPROX_PEER_CTR_TLLI_CACHE_SIZE,
- GBPROX_PEER_CTR_LAST,
-};
-
-enum gbproxy_keep_mode {
- GBPROX_KEEP_NEVER,
- GBPROX_KEEP_REATTACH,
- GBPROX_KEEP_IDENTIFIED,
- GBPROX_KEEP_ALWAYS,
-};
-
-enum gbproxy_match_id {
- GBPROX_MATCH_PATCHING,
- GBPROX_MATCH_ROUTING,
- GBPROX_MATCH_LAST
-};
-
-struct gbproxy_match {
- int enable;
- char *re_str;
- regex_t re_comp;
-};
-
-struct gbproxy_config {
- /* parsed from config file */
- uint16_t nsip_sgsn_nsei;
-
- /* misc */
- struct gprs_ns_inst *nsi;
-
- /* Linked list of all Gb peers (except SGSN) */
- struct llist_head bts_peers;
-
- /* Counter */
- struct rate_ctr_group *ctrg;
-
- /* force mcc/mnc */
- int core_mnc;
- int core_mcc;
- uint8_t* core_apn;
- size_t core_apn_size;
- int tlli_max_age;
- int tlli_max_len;
-
- /* Experimental config */
- int patch_ptmsi;
- int acquire_imsi;
- int route_to_sgsn2;
- uint16_t nsip_sgsn2_nsei;
- enum gbproxy_keep_mode keep_link_infos;
-
- /* IMSI checking/matching */
- struct gbproxy_match matches[GBPROX_MATCH_LAST];
-};
-
-struct gbproxy_patch_state {
- int local_mnc;
- int local_mcc;
-
- /* List of TLLIs for which patching is enabled */
- struct llist_head logical_links;
- int logical_link_count;
-};
-
-struct gbproxy_peer {
- struct llist_head list;
-
- /* point back to the config */
- struct gbproxy_config *cfg;
-
- /* NSEI of the peer entity */
- uint16_t nsei;
-
- /* BVCI used for Point-to-Point to this peer */
- uint16_t bvci;
- int blocked;
-
- /* Routeing Area that this peer is part of (raw 04.08 encoding) */
- uint8_t ra[6];
-
- /* Counter */
- struct rate_ctr_group *ctrg;
-
- struct gbproxy_patch_state patch_state;
-};
-
-struct gbproxy_tlli_state {
- uint32_t current;
- uint32_t assigned;
- int bss_validated;
- int net_validated;
-
- uint32_t ptmsi;
-};
-
-struct gbproxy_link_info {
- struct llist_head list;
-
- struct gbproxy_tlli_state tlli;
- struct gbproxy_tlli_state sgsn_tlli;
- uint32_t sgsn_nsei;
-
- time_t timestamp;
- uint8_t *imsi;
- size_t imsi_len;
-
- int imsi_acq_pending;
- struct llist_head stored_msgs;
- unsigned vu_gen_tx_bss;
-
- int is_deregistered;
-
- int is_matching[GBPROX_MATCH_LAST];
-};
-
-
-/* gb_proxy_vty .c */
-
-int gbproxy_vty_init(void);
-int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg);
-
-
-/* gb_proxy.c */
-int gbproxy_init_config(struct gbproxy_config *cfg);
-
-/* Main input function for Gb proxy */
-int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t nsvci);
-
-int gbprox_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data);
-
-/* Reset all persistent NS-VC's */
-int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi);
-
-void gbprox_reset(struct gbproxy_config *cfg);
-
-/* TLLI info handling */
-void gbproxy_delete_link_infos(struct gbproxy_peer *peer);
-struct gbproxy_link_info *gbproxy_update_link_state_ul(
- struct gbproxy_peer *peer, time_t now,
- struct gprs_gb_parse_context *parse_ctx);
-struct gbproxy_link_info *gbproxy_update_link_state_dl(
- struct gbproxy_peer *peer, time_t now,
- struct gprs_gb_parse_context *parse_ctx);
-int gbproxy_update_link_state_after(
- struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
- time_t now, struct gprs_gb_parse_context *parse_ctx);
-int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now);
-void gbproxy_delete_link_info(struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info);
-void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info);
-
-void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
- struct gbproxy_link_info *link_info);
-void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
- const uint8_t *imsi, size_t imsi_len);
-void gbproxy_detach_link_info(struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info);
-struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer);
-
-struct gbproxy_link_info *gbproxy_link_info_by_tlli(
- struct gbproxy_peer *peer, uint32_t tlli);
-struct gbproxy_link_info *gbproxy_link_info_by_imsi(
- struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len);
-struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
- struct gbproxy_peer *peer, uint32_t tlli);
-struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
- struct gbproxy_peer *peer,
- uint32_t tlli, uint32_t sgsn_nsei);
-struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
- struct gbproxy_peer *peer,
- uint32_t ptmsi);
-
-int gbproxy_imsi_matches(
- struct gbproxy_config *cfg,
- enum gbproxy_match_id match_id,
- struct gbproxy_link_info *link_info);
-uint32_t gbproxy_map_tlli(
- uint32_t other_tlli, struct gbproxy_link_info *link_info, int to_bss);
-
-/* needed by gb_proxy_tlli.h */
-uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi);
-uint32_t gbproxy_make_sgsn_tlli(
- struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
- uint32_t bss_tlli);
-void gbproxy_reset_link(struct gbproxy_link_info *link_info);
-int gbproxy_check_imsi(
- struct gbproxy_match *match, const uint8_t *imsi, size_t imsi_len);
-
-/* Message patching */
-void gbproxy_patch_bssgp(
- struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
- struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
- int *len_change, struct gprs_gb_parse_context *parse_ctx);
-
-int gbproxy_patch_llc(
- struct msgb *msg, uint8_t *llc, size_t llc_len,
- struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
- int *len_change, struct gprs_gb_parse_context *parse_ctx);
-
-int gbproxy_set_patch_filter(
- struct gbproxy_match *match, const char *filter, const char **err_msg);
-void gbproxy_clear_patch_filter(struct gbproxy_match *match);
-
-/* Peer handling */
-struct gbproxy_peer *gbproxy_peer_by_bvci(
- struct gbproxy_config *cfg, uint16_t bvci);
-struct gbproxy_peer *gbproxy_peer_by_nsei(
- struct gbproxy_config *cfg, uint16_t nsei);
-struct gbproxy_peer *gbproxy_peer_by_rai(
- struct gbproxy_config *cfg, const uint8_t *ra);
-struct gbproxy_peer *gbproxy_peer_by_lai(
- struct gbproxy_config *cfg, const uint8_t *la);
-struct gbproxy_peer *gbproxy_peer_by_lac(
- struct gbproxy_config *cfg, const uint8_t *la);
-struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(
- struct gbproxy_config *cfg, struct tlv_parsed *tp);
-struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci);
-void gbproxy_peer_free(struct gbproxy_peer *peer);
-int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci);
-
-#endif
diff --git a/openbsc/include/openbsc/gprs_gb_parse.h b/openbsc/include/openbsc/gprs_gb_parse.h
deleted file mode 100644
index 246839286..000000000
--- a/openbsc/include/openbsc/gprs_gb_parse.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-#include <openbsc/gprs_llc.h>
-
-#include <sys/types.h>
-
-struct gprs_gb_parse_context {
- /* Pointer to protocol specific parts */
- struct gsm48_hdr *g48_hdr;
- struct bssgp_normal_hdr *bgp_hdr;
- struct bssgp_ud_hdr *bud_hdr;
- uint8_t *bssgp_data;
- size_t bssgp_data_len;
- uint8_t *llc;
- size_t llc_len;
-
- /* Extracted information */
- struct gprs_llc_hdr_parsed llc_hdr_parsed;
- struct tlv_parsed bssgp_tp;
- int to_bss;
- uint8_t *tlli_enc;
- uint8_t *old_tlli_enc;
- uint8_t *imsi;
- size_t imsi_len;
- uint8_t *apn_ie;
- size_t apn_ie_len;
- uint8_t *ptmsi_enc;
- uint8_t *new_ptmsi_enc;
- uint8_t *raid_enc;
- uint8_t *old_raid_enc;
- uint8_t *bssgp_raid_enc;
- uint8_t *bssgp_ptmsi_enc;
-
- /* General info */
- const char *llc_msg_name;
- int invalidate_tlli;
- int await_reattach;
- int need_decryption;
- uint32_t tlli;
- int pdu_type;
- int old_raid_is_foreign;
- int peer_nsei;
-};
-
-int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx);
-
-int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
- struct gprs_gb_parse_context *parse_ctx);
-
-int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
- struct gprs_gb_parse_context *parse_ctx);
-
-const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
- const char *default_msg_name);
-
-void gprs_gb_log_parse_context(int log_level,
- struct gprs_gb_parse_context *parse_ctx,
- const char *default_msg_name);
diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h
deleted file mode 100644
index d210a3547..000000000
--- a/openbsc/include/openbsc/gprs_gmm.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _GPRS_GMM_H
-#define _GPRS_GMM_H
-
-#include <osmocom/core/msgb.h>
-#include <openbsc/gprs_sgsn.h>
-
-#include <stdbool.h>
-
-int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause);
-int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
- uint8_t cause, uint8_t pco_len, uint8_t *pco_v);
-int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);
-int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
-
-int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
- bool drop_cipherable);
-int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
- uint16_t *sai);
-int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
-int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
- struct gprs_llc_llme *llme);
-void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx);
-void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *mmctx, int gmm_cause);
-void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *mmctx, int gmm_cause);
-void gsm0408_gprs_authenticate(struct sgsn_mm_ctx *mmctx);
-
-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);
-
-time_t gprs_max_time_to_idle(void);
-
-int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap);
-
-#endif /* _GPRS_GMM_H */
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
deleted file mode 100644
index 8bc226781..000000000
--- a/openbsc/include/openbsc/gprs_llc.h
+++ /dev/null
@@ -1,284 +0,0 @@
-#ifndef _GPRS_LLC_H
-#define _GPRS_LLC_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <openbsc/gprs_sgsn.h>
-#include <openbsc/gprs_llc_xid.h>
-
-/* Section 4.7 LLC Layer Structure */
-enum gprs_llc_sapi {
- GPRS_SAPI_GMM = 1,
- GPRS_SAPI_TOM2 = 2,
- GPRS_SAPI_SNDCP3 = 3,
- GPRS_SAPI_SNDCP5 = 5,
- GPRS_SAPI_SMS = 7,
- GPRS_SAPI_TOM8 = 8,
- GPRS_SAPI_SNDCP9 = 9,
- GPRS_SAPI_SNDCP11 = 11,
-};
-
-/* Section 6.4 Commands and Responses */
-enum gprs_llc_u_cmd {
- GPRS_LLC_U_DM_RESP = 0x01,
- GPRS_LLC_U_DISC_CMD = 0x04,
- GPRS_LLC_U_UA_RESP = 0x06,
- GPRS_LLC_U_SABM_CMD = 0x07,
- GPRS_LLC_U_FRMR_RESP = 0x08,
- GPRS_LLC_U_XID = 0x0b,
- GPRS_LLC_U_NULL_CMD = 0x00,
-};
-
-/* Section 6.4.1.6 / Table 6 */
-enum gprs_llc_xid_type {
- GPRS_LLC_XID_T_VERSION = 0,
- GPRS_LLC_XID_T_IOV_UI = 1,
- GPRS_LLC_XID_T_IOV_I = 2,
- GPRS_LLC_XID_T_T200 = 3,
- GPRS_LLC_XID_T_N200 = 4,
- GPRS_LLC_XID_T_N201_U = 5,
- GPRS_LLC_XID_T_N201_I = 6,
- GPRS_LLC_XID_T_mD = 7,
- GPRS_LLC_XID_T_mU = 8,
- GPRS_LLC_XID_T_kD = 9,
- GPRS_LLC_XID_T_kU = 10,
- GPRS_LLC_XID_T_L3_PAR = 11,
- GPRS_LLC_XID_T_RESET = 12,
-};
-
-extern const struct value_string gprs_llc_xid_type_names[];
-
-/* TS 04.64 Section 7.1.2 Table 7: LLC layer primitives (GMM/SNDCP/SMS/TOM) */
-/* TS 04.65 Section 5.1.2 Table 2: Service primitives used by SNDCP */
-enum gprs_llc_primitive {
- /* GMM <-> LLME */
- LLGMM_ASSIGN_REQ, /* GMM tells us new TLLI: TLLI old, TLLI new, Kc, CiphAlg */
- LLGMM_RESET_REQ, /* GMM tells us to perform XID negotiation: TLLI */
- LLGMM_RESET_CNF, /* LLC informs GMM that XID has completed: TLLI */
- LLGMM_SUSPEND_REQ, /* GMM tells us MS has suspended: TLLI, Page */
- LLGMM_RESUME_REQ, /* GMM tells us MS has resumed: TLLI */
- LLGMM_PAGE_IND, /* LLC asks GMM to page MS: TLLI */
- LLGMM_IOV_REQ, /* GMM tells us to perform XID: TLLI */
- LLGMM_STATUS_IND, /* LLC informs GMM about error: TLLI, Cause */
- /* LLE <-> (GMM/SNDCP/SMS/TOM) */
- LL_RESET_IND, /* TLLI */
- LL_ESTABLISH_REQ, /* TLLI, XID Req */
- LL_ESTABLISH_IND, /* TLLI, XID Req, N201-I, N201-U */
- LL_ESTABLISH_RESP, /* TLLI, XID Negotiated */
- LL_ESTABLISH_CONF, /* TLLI, XID Neg, N201-i, N201-U */
- LL_RELEASE_REQ, /* TLLI, Local */
- LL_RELEASE_IND, /* TLLI, Cause */
- LL_RELEASE_CONF, /* TLLI */
- LL_XID_REQ, /* TLLI, XID Requested */
- LL_XID_IND, /* TLLI, XID Req, N201-I, N201-U */
- LL_XID_RESP, /* TLLI, XID Negotiated */
- LL_XID_CONF, /* TLLI, XID Neg, N201-I, N201-U */
- LL_DATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
- LL_DATA_IND, /* TLLI, SN-PDU */
- LL_DATA_CONF, /* TLLI, Ref */
- LL_UNITDATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
- LL_UNITDATA_IND, /* TLLI, SN-PDU */
- LL_STATUS_IND, /* TLLI, Cause */
-};
-
-/* Section 4.5.2 Logical Link States + Annex C.2 */
-enum gprs_llc_lle_state {
- GPRS_LLES_UNASSIGNED = 1, /* No TLLI yet */
- GPRS_LLES_ASSIGNED_ADM = 2, /* TLLI assigned */
- GPRS_LLES_LOCAL_EST = 3, /* Local Establishment */
- GPRS_LLES_REMOTE_EST = 4, /* Remote Establishment */
- GPRS_LLES_ABM = 5,
- GPRS_LLES_LOCAL_REL = 6, /* Local Release */
- GPRS_LLES_TIMER_REC = 7, /* Timer Recovery */
-};
-
-enum gprs_llc_llme_state {
- GPRS_LLMS_UNASSIGNED = 1, /* No TLLI yet */
- GPRS_LLMS_ASSIGNED = 2, /* TLLI assigned */
-};
-
-/* Section 8.9.9 LLC layer parameter default values */
-struct gprs_llc_params {
- uint16_t iov_i_exp;
- uint16_t t200_201;
- uint16_t n200;
- uint16_t n201_u;
- uint16_t n201_i;
- uint16_t mD;
- uint16_t mU;
- uint16_t kD;
- uint16_t kU;
-};
-
-/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */
-struct gprs_llc_lle {
- struct llist_head list;
-
- uint32_t sapi;
-
- struct gprs_llc_llme *llme;
-
- enum gprs_llc_lle_state state;
-
- struct osmo_timer_list t200;
- struct osmo_timer_list t201; /* wait for acknowledgement */
-
- uint16_t v_sent;
- uint16_t v_ack;
- uint16_t v_recv;
-
- uint16_t vu_send;
- uint16_t vu_recv;
-
- /* non-standard LLC state */
- uint16_t vu_recv_last;
- uint16_t vu_recv_duplicates;
-
- /* Overflow Counter for ABM */
- uint32_t oc_i_send;
- uint32_t oc_i_recv;
-
- /* Overflow Counter for unconfirmed transfer */
- uint32_t oc_ui_send;
- uint32_t oc_ui_recv;
-
- unsigned int retrans_ctr;
-
- struct gprs_llc_params params;
-};
-
-#define NUM_SAPIS 16
-
-struct gprs_llc_llme {
- struct llist_head list;
-
- enum gprs_llc_llme_state state;
-
- uint32_t tlli;
- uint32_t old_tlli;
-
- /* Crypto parameters */
- enum gprs_ciph_algo algo;
- uint8_t kc[16];
- uint8_t cksn;
- /* 3GPP TS 44.064 § 8.9.2: */
- uint32_t iov_ui;
-
- /* over which BSSGP BTS ctx do we need to transmit */
- uint16_t bvci;
- uint16_t nsei;
- struct gprs_llc_lle lle[NUM_SAPIS];
-
- /* Copy of the XID fields we have sent with the last
- * network originated XID-Request. Since the phone
- * may strip the optional fields in the confirmation
- * we need to remeber those fields in order to be
- * able to create the compression entity. */
- struct llist_head *xid;
-
- /* Compression entities */
- struct {
- /* In these two list_heads we will store the
- * data and protocol compression entities,
- * together with their compression states */
- struct llist_head *proto;
- struct llist_head *data;
- } comp;
-
- /* Internal management */
- uint32_t age_timestamp;
-};
-
-#define GPRS_LLME_RESET_AGE (0)
-
-extern struct llist_head gprs_llc_llmes;
-
-/* LLC low level types */
-
-enum gprs_llc_cmd {
- GPRS_LLC_NULL,
- GPRS_LLC_RR,
- GPRS_LLC_ACK,
- GPRS_LLC_RNR,
- GPRS_LLC_SACK,
- GPRS_LLC_DM,
- GPRS_LLC_DISC,
- GPRS_LLC_UA,
- GPRS_LLC_SABM,
- GPRS_LLC_FRMR,
- GPRS_LLC_XID,
- GPRS_LLC_UI,
-};
-
-struct gprs_llc_hdr_parsed {
- uint8_t sapi;
- uint8_t is_cmd:1,
- ack_req:1,
- is_encrypted:1;
- uint32_t seq_rx;
- uint32_t seq_tx;
- uint32_t fcs;
- uint32_t fcs_calc;
- uint8_t *data;
- uint16_t data_len;
- uint16_t crc_length;
- enum gprs_llc_cmd cmd;
-};
-
-
-/* BSSGP-UL-UNITDATA.ind */
-int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
-
-/* LL-UNITDATA.req */
-int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
- struct sgsn_mm_ctx *mmctx, bool encryptable);
-
-/* Chapter 7.2.1.2 LLGMM-RESET.req */
-int gprs_llgmm_reset(struct gprs_llc_llme *llme);
-int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
- struct gprs_llc_llme *llme);
-
-/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */
-int gprs_ll_xid_req(struct gprs_llc_lle *lle,
- struct gprs_llc_xid_field *l3_xid_field);
-
-/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
-int gprs_llgmm_assign(struct gprs_llc_llme *llme,
- uint32_t old_tlli, uint32_t new_tlli);
-int gprs_llgmm_unassign(struct gprs_llc_llme *llme);
-
-int gprs_llc_init(const char *cipher_plugin_path);
-int gprs_llc_vty_init(void);
-
-/**
- * \short Check if N(U) should be considered a retransmit
- *
- * Implements the range check as of GSM 04.64 8.4.2
- * Receipt of unacknowledged information.
- *
- * @returns Returns 1 if (V(UR)-32) <= N(U) < V(UR)
- * @param nu N(U) unconfirmed sequence number of the UI frame
- * @param vur V(UR) unconfirmend received state variable
- */
-static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
-{
- int delta = (vur - nu) & 0x1ff;
- return 0 < delta && delta < 32;
-}
-
-/* LLC low level functions */
-void gprs_llme_copy_key(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);
-
-
-/* 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/openbsc/include/openbsc/gprs_llc_xid.h b/openbsc/include/openbsc/gprs_llc_xid.h
deleted file mode 100644
index d340d40b7..000000000
--- a/openbsc/include/openbsc/gprs_llc_xid.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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/>.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <osmocom/core/linuxlist.h>
-
-/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID)
- command/response parameter field */
-struct gprs_llc_xid_field {
- struct llist_head list;
- uint8_t type; /* See also Table 6: LLC layer parameter
- negotiation */
- uint8_t *data; /* Payload data (memory is owned by the
- * creator of the struct) */
- unsigned int data_len; /* Payload length */
-};
-
-/* Transform a list with XID fields into a XID message (dst) */
-int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen,
- const struct llist_head *xid_fields);
-
-/* Transform a XID message (dst) into a list of XID fields */
-struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src,
- int src_len);
-
-/* Create a duplicate of an XID-Field */
-struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx,
- const struct gprs_llc_xid_field *xid_field);
-
-/* Copy an llist with xid fields */
-struct llist_head *gprs_llc_copy_xid(const void *ctx,
- const struct llist_head *xid_fields);
-
-/* Dump a list with XID fields (Debug) */
-void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields,
- unsigned int logl);
-
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
deleted file mode 100644
index 4e49c0889..000000000
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ /dev/null
@@ -1,478 +0,0 @@
-#ifndef _GPRS_SGSN_H
-#define _GPRS_SGSN_H
-
-#include <stdint.h>
-#include <netinet/in.h>
-
-#include <osmocom/core/timer.h>
-
-#include <osmocom/gsm/gsm48.h>
-
-#include <osmocom/crypt/gprs_cipher.h>
-#include <osmocom/gsm/protocol/gsm_23_003.h>
-
-#include <openbsc/gsm_data.h>
-
-#define GSM_EXTENSION_LENGTH 15
-#define GSM_APN_LENGTH 102
-
-struct gprs_llc_lle;
-struct ctrl_handle;
-struct gprs_subscr;
-
-enum gsm48_gsm_cause;
-
-/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */
-enum gprs_gmm_state {
- GMM_DEREGISTERED, /* 4.1.3.3.1.1 */
- GMM_COMMON_PROC_INIT, /* 4.1.3.3.1.2 */
- GMM_REGISTERED_NORMAL, /* 4.1.3.3.2.1 */
- GMM_REGISTERED_SUSPENDED, /* 4.1.3.3.2.2 */
- GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */
-};
-
-/* TS 23.060 6.1.1 and 6.1.2 Mobility management states A/Gb and Iu mode */
-enum gprs_pmm_state {
- PMM_DETACHED,
- PMM_CONNECTED,
- PMM_IDLE,
- MM_IDLE,
- MM_READY,
- MM_STANDBY,
-};
-
-enum gprs_mm_ctr {
- GMM_CTR_PKTS_SIG_IN,
- GMM_CTR_PKTS_SIG_OUT,
- GMM_CTR_PKTS_UDATA_IN,
- GMM_CTR_PKTS_UDATA_OUT,
- GMM_CTR_BYTES_UDATA_IN,
- GMM_CTR_BYTES_UDATA_OUT,
- GMM_CTR_PDP_CTX_ACT,
- GMM_CTR_SUSPEND,
- GMM_CTR_PAGING_PS,
- GMM_CTR_PAGING_CS,
- 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,
- GMM_T3350_MODE_RAU,
- 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,
-};
-
-struct sgsn_ggsn_lookup {
- int state;
-
- struct sgsn_mm_ctx *mmctx;
-
- /* APN string */
- char apn_str[GSM_APN_LENGTH];
-
- /* the original data */
- struct msgb *orig_msg;
- struct tlv_parsed tp;
-
- /* for dealing with re-transmissions */
- uint8_t nsapi;
- uint8_t sapi;
- uint8_t ti;
-};
-
-enum sgsn_ran_type {
- /* GPRS/EDGE via Gb */
- MM_CTX_T_GERAN_Gb,
- /* UMTS via Iu */
- MM_CTX_T_UTRAN_Iu,
- /* GPRS/EDGE via Iu */
- MM_CTX_T_GERAN_Iu,
-};
-
-struct service_info {
- uint8_t type;
- uint16_t pdp_status;
-};
-
-struct ue_conn_ctx;
-
-/* 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 {
- struct llist_head list;
-
- enum sgsn_ran_type ran_type;
-
- char imsi[GSM23003_IMSI_MAX_DIGITS+1];
- enum gprs_gmm_state gmm_state;
- enum gprs_pmm_state pmm_state; /* Iu: page when in PMM-IDLE mode */
- uint32_t p_tmsi;
- uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */
- uint32_t p_tmsi_sig;
- char imei[GSM23003_IMEISV_NUM_DIGITS+1];
- /* Opt: Software Version Numbber / TS 23.195 */
- char msisdn[GSM_EXTENSION_LENGTH];
- struct gprs_ra_id ra;
- struct {
- uint16_t cell_id; /* Gb only */
- uint32_t cell_id_age; /* Gb only */
- uint8_t radio_prio_sms;
-
- /* Additional bits not present in the GSM TS */
- uint16_t nsei;
- uint16_t bvci;
- struct gprs_llc_llme *llme;
- uint32_t tlli;
- uint32_t tlli_new;
- } gb;
- struct {
- int new_key;
- uint16_t sac; /* Iu: Service Area Code */
- uint32_t sac_age; /* Iu: Service Area Code age */
- /* CSG ID */
- /* CSG Membership */
- /* Access Mode */
- /* Seelected CN Operator ID (TS 23.251) */
- /* CSG Subscription Data */
- /* LIPA Allowed */
- /* Voice Support Match Indicator */
- struct ue_conn_ctx *ue_ctx;
- struct service_info service;
- } iu;
- /* VLR number */
- uint32_t new_sgsn_addr;
- /* Authentication Triplet */
- struct gsm_auth_tuple auth_triplet;
- /* Kc */
- /* Iu: CK, IK, KSI */
- /* CKSN */
- enum gprs_ciph_algo ciph_algo;
- /* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */
- uint8_t ac_ref_nr_used;
-
- struct {
- uint8_t len;
- uint8_t buf[50]; /* GSM 04.08 10.5.5.12a, extended in TS 24.008 */
- } ms_radio_access_capa;
- /* Supported Codecs (SRVCC) */
- struct {
- uint8_t len;
- uint8_t buf[8]; /* GSM 04.08 10.5.5.12, extended in TS 24.008 */
- } ms_network_capa;
- /* UE Netowrk Capability (E-UTRAN) */
- uint16_t drx_parms;
- /* Active Time value for PSM */
- int mnrg; /* MS reported to HLR? */
- int ngaf; /* MS reported to MSC/VLR? */
- int ppf; /* paging for GPRS + non-GPRS? */
- /* Subscribed Charging Characteristics */
- /* Trace Reference */
- /* Trace Type */
- /* Trigger ID */
- /* OMC Identity */
- /* SMS Parameters */
- int recovery;
- /* Access Restriction */
- /* GPRS CSI (CAMEL) */
- /* MG-CSI (CAMEL) */
- /* Subscribed UE-AMBR */
- /* UE-AMBR */
- /* APN Subscribed */
-
- struct llist_head pdp_list;
-
- struct rate_ctr_group *ctrg;
- struct osmo_timer_list timer;
- unsigned int T; /* Txxxx number */
- unsigned int num_T_exp; /* number of consecutive T expirations */
-
- enum gprs_t3350_mode t3350_mode;
- uint8_t t3370_id_type;
- uint8_t pending_req; /* the request's message type */
- /* TODO: There isn't much semantic difference between t3350_mode
- * (refers to the timer) and pending_req (refers to the procedure),
- * where mm->T == 3350 => mm->t3350_mode == f(mm->pending_req). Check
- * whether one of them can be dropped. */
-
- enum sgsn_auth_state auth_state;
- int is_authenticated;
-
- /* the string representation of the current hlr */
- char hlr[GSM_EXTENSION_LENGTH];
-
- /* the current GGSN look-up operation */
- struct sgsn_ggsn_lookup *ggsn_lookup;
-
- struct gprs_subscr *subscr;
-};
-
-#define LOGMMCTXP(level, mm, fmt, args...) \
- LOGP(DMM, level, "MM(%s/%08x) " fmt, (mm) ? (mm)->imsi : "---", \
- (mm) ? (mm)->p_tmsi : GSM_RESERVED_TMSI, ## args)
-
-/* look-up a SGSN MM context based on TLLI + RAI */
-struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
- const struct gprs_ra_id *raid);
-struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi);
-struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi);
-struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx);
-
-/* look-up by matching TLLI and P-TMSI (think twice before using this) */
-struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
- const struct gprs_ra_id *raid);
-
-/* Allocate a new SGSN MM context */
-struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
- const struct gprs_ra_id *raid);
-struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx);
-
-void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx);
-
-struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
- struct tlv_parsed *tp,
- 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 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);
-/* look up PDP context by MM context and transaction ID */
-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,
- 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 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);
-
-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);
-void sgsn_inst_init(void);
-
-/* High-level function to be called in case a GGSN has disappeared or
- * ottherwise lost state (recovery procedure) */
-int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn);
-
-char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
-
-/*
- * ctrl interface related work
- */
-struct gsm_network;
-struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *,
- const char *bind_addr, uint16_t port);
-int sgsn_ctrl_cmds_install(void);
-
-/*
- * Authorization/ACL handling
- */
-struct imsi_acl_entry {
- struct llist_head list;
- char imsi[16+1];
-};
-
-/* 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(void);
-struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, 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/openbsc/include/openbsc/gprs_sndcp.h b/openbsc/include/openbsc/gprs_sndcp.h
deleted file mode 100644
index d970240e4..000000000
--- a/openbsc/include/openbsc/gprs_sndcp.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef _INT_SNDCP_H
-#define _INT_SNDCP_H
-
-#include <stdint.h>
-#include <osmocom/core/linuxlist.h>
-
-/* A fragment queue header, maintaining list of fragments for one N-PDU */
-struct defrag_state {
- /* PDU number for which the defragmentation state applies */
- uint16_t npdu;
- /* highest segment number we have received so far */
- uint8_t highest_seg;
- /* bitmask of the segments we already have */
- uint32_t seg_have;
- /* do we still expect more segments? */
- unsigned int no_more;
- /* total length of all segments together */
- unsigned int tot_len;
-
- /* linked list of defrag_queue_entry: one for each fragment */
- struct llist_head frag_list;
-
- struct osmo_timer_list timer;
-
- /* Holds state to know which compression mode is used
- * when the packet is re-assembled */
- uint8_t pcomp;
- uint8_t dcomp;
-
- /* Holds the pointers to the compression entity list
- * that is used when the re-assembled packet is decompressed */
- struct llist_head *proto;
- struct llist_head *data;
-};
-
-/* See 6.7.1.2 Reassembly */
-enum sndcp_rx_state {
- SNDCP_RX_S_FIRST,
- SNDCP_RX_S_SUBSEQ,
- SNDCP_RX_S_DISCARD,
-};
-
-struct gprs_sndcp_entity {
- struct llist_head list;
-
- /* FIXME: move this RA_ID up to the LLME or even higher */
- struct gprs_ra_id ra_id;
- /* reference to the LLC Entity below this SNDCP entity */
- struct gprs_llc_lle *lle;
- /* The NSAPI we shall use on top of LLC */
- uint8_t nsapi;
-
- /* NPDU number for the GTP->SNDCP side */
- uint16_t tx_npdu_nr;
- /* SNDCP eeceiver state */
- enum sndcp_rx_state rx_state;
- /* The defragmentation queue */
- struct defrag_state defrag;
-};
-
-extern struct llist_head gprs_sndcp_entities;
-
-/* 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);
-
-/* Process SNDCP-XID indication (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);
-
-/* Process SNDCP-XID indication
- * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
-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);
-
-#endif /* INT_SNDCP_H */
diff --git a/openbsc/include/openbsc/gprs_sndcp_comp.h b/openbsc/include/openbsc/gprs_sndcp_comp.h
deleted file mode 100644
index 87ab6382a..000000000
--- a/openbsc/include/openbsc/gprs_sndcp_comp.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* GPRS SNDCP header compression entity management tools */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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/>.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <osmocom/core/linuxlist.h>
-#include <openbsc/gprs_sndcp_xid.h>
-
-/* Header / Data compression entity */
-struct gprs_sndcp_comp {
- struct llist_head list;
-
- /* Serves as an ID in case we want to delete this entity later */
- unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */
-
- /* Specifies to which NSAPIs the compression entity is assigned */
- uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */
- uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
-
- /* Assigned pcomp values */
- uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */
- uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */
-
- /* Algorithm parameters */
- int algo; /* Algorithm type (see gprs_sndcp_xid.h) */
- int compclass; /* See gprs_sndcp_xid.h/c */
- void *state; /* Algorithm status and parameters */
-};
-
-#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */
-#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */
-
-/* Allocate a compression enitiy list */
-struct llist_head *gprs_sndcp_comp_alloc(const void *ctx);
-
-/* Free a compression entitiy list */
-void gprs_sndcp_comp_free(struct llist_head *comp_entities);
-
-/* Delete a compression entity */
-void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity);
-
-/* Create and Add a new compression entity
- * (returns a pointer to the compression entity that has just been created) */
-struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx,
- struct llist_head *comp_entities,
- const struct gprs_sndcp_comp_field
- *comp_field);
-
-/* Find which compression entity handles the specified pcomp/dcomp */
-struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head
- *comp_entities, uint8_t comp);
-
-/* Find which compression entity handles the specified nsapi */
-struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head
- *comp_entities, uint8_t nsapi);
-
-/* Find a comp_index for a given pcomp/dcomp value */
-uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity,
- uint8_t comp);
-
-/* Find a pcomp/dcomp value for a given comp_index */
-uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity,
- uint8_t comp_index);
diff --git a/openbsc/include/openbsc/gprs_sndcp_dcomp.h b/openbsc/include/openbsc/gprs_sndcp_dcomp.h
deleted file mode 100644
index a76b4a4b3..000000000
--- a/openbsc/include/openbsc/gprs_sndcp_dcomp.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* GPRS SNDCP data compression handler */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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/>.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <osmocom/core/linuxlist.h>
-#include <openbsc/gprs_sndcp_comp.h>
-
-/* Note: The decompressed packet may have a maximum size of:
- * Return value * MAX_DATADECOMPR_FAC */
-#define MAX_DATADECOMPR_FAC 10
-
-/* Note: In unacknowledged mode (SN_UNITDATA), the comression state is reset
- * for every NPDU. The compressor needs a reasonably large payload to operate
- * effectively (yield positive compression gain). For packets shorter than 100
- * byte, no positive compression gain can be expected so we will skip the
- * compression for short packets. */
-#define MIN_COMPR_PAYLOAD 100
-
-/* Initalize data compression */
-int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
- const struct gprs_sndcp_comp_field *comp_field);
-
-/* Terminate data compression */
-void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity);
-
-/* Expand packet */
-int gprs_sndcp_dcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp,
- const struct llist_head *comp_entities);
-
-/* Compress packet */
-int gprs_sndcp_dcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp,
- const struct llist_head *comp_entities,
- uint8_t nsapi);
diff --git a/openbsc/include/openbsc/gprs_sndcp_pcomp.h b/openbsc/include/openbsc/gprs_sndcp_pcomp.h
deleted file mode 100644
index 4e15b9be2..000000000
--- a/openbsc/include/openbsc/gprs_sndcp_pcomp.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* GPRS SNDCP header compression handler */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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/>.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <osmocom/core/linuxlist.h>
-#include <openbsc/gprs_sndcp_comp.h>
-
-/* Note: The decompressed packet may have a maximum size of:
- * Return value + MAX_DECOMPR_INCR */
-#define MAX_HDRDECOMPR_INCR 64
-
-/* Initalize header compression */
-int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
- const struct gprs_sndcp_comp_field *comp_field);
-
-/* Terminate header compression */
-void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity);
-
-/* Expand packet header */
-int gprs_sndcp_pcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp,
- const struct llist_head *comp_entities);
-
-/* Compress packet header */
-int gprs_sndcp_pcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp,
- const struct llist_head *comp_entities,
- uint8_t nsapi);
diff --git a/openbsc/include/openbsc/gprs_sndcp_xid.h b/openbsc/include/openbsc/gprs_sndcp_xid.h
deleted file mode 100644
index e64bc5237..000000000
--- a/openbsc/include/openbsc/gprs_sndcp_xid.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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/>.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <osmocom/core/linuxlist.h>
-
-#define DEFAULT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */
-#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit
- * for compression enitity number */
-
-#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */
-#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */
-#define MAX_ROHC 16 /* Maximum number of ROHC compression profiles */
-
-/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control
- * information compression field (Figure 7) and 3GPP TS 44.065,
- * 6.6.1.1 Format of the data compression field (Figure 9) */
-struct gprs_sndcp_comp_field {
- struct llist_head list;
-
- /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */
- unsigned int p;
-
- /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */
- unsigned int entity;
-
- /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */
- int algo;
-
- /* Number of contained PCOMP / DCOMP values */
- uint8_t comp_len;
-
- /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */
- uint8_t comp[MAX_COMP];
-
- /* Note: Only one of the following struct pointers may,
- be used. Unused pointers must be set to NULL! */
- struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params;
- struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params;
- struct gprs_sndcp_pcomp_rohc_params *rohc_params;
- struct gprs_sndcp_dcomp_v42bis_params *v42bis_params;
- struct gprs_sndcp_dcomp_v44_params *v44_params;
-};
-
-/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */
-enum gprs_sndcp_hdr_comp_algo {
- RFC_1144, /* TCP/IP header compression, see also 6.5.2 */
- RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */
- ROHC /* Robust Header Compression, see also 6.5.4 */
-};
-
-/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */
-enum gprs_sndcp_data_comp_algo {
- V42BIS, /* V.42bis data compression, see also 6.6.2 */
- V44 /* V44 data compression, see also: 6.6.3 */
-};
-
-/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */
-enum gprs_sndcp_xid_param_types {
- SNDCP_XID_VERSION_NUMBER,
- SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */
- SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */
-};
-
-/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */
-struct gprs_sndcp_pcomp_rfc1144_params {
- uint8_t nsapi_len; /* Number of applicable NSAPIs
- * (default 0) */
- uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
- int s01; /* (default 15) */
-};
-
-/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */
-enum gprs_sndcp_pcomp_rfc1144_pcomp {
- RFC1144_PCOMP1, /* Uncompressed TCP */
- RFC1144_PCOMP2, /* Compressed TCP */
- RFC1144_PCOMP_NUM /* Number of pcomp values */
-};
-
-/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */
-struct gprs_sndcp_pcomp_rfc2507_params {
- uint8_t nsapi_len; /* Number of applicable NSAPIs
- * (default 0) */
- uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
- int f_max_period; /* (default 256) */
- int f_max_time; /* (default 5) */
- int max_header; /* (default 168) */
- int tcp_space; /* (default 15) */
- int non_tcp_space; /* (default 15) */
-};
-
-/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */
-enum gprs_sndcp_pcomp_rfc2507_pcomp {
- RFC2507_PCOMP1, /* Full Header */
- RFC2507_PCOMP2, /* Compressed TCP */
- RFC2507_PCOMP3, /* Compressed TCP non delta */
- RFC2507_PCOMP4, /* Compressed non TCP */
- RFC2507_PCOMP5, /* Context state */
- RFC2507_PCOMP_NUM /* Number of pcomp values */
-};
-
-/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */
-struct gprs_sndcp_pcomp_rohc_params {
- uint8_t nsapi_len; /* Number of applicable NSAPIs
- * (default 0) */
- uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
- int max_cid; /* (default 15) */
- int max_header; /* (default 168) */
- uint8_t profile_len; /* (default 1) */
- uint16_t profile[MAX_ROHC]; /* (default 0, ROHC uncompressed) */
-};
-
-/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */
-enum gprs_sndcp_pcomp_rohc_pcomp {
- ROHC_PCOMP1, /* ROHC small CIDs */
- ROHC_PCOMP2, /* ROHC large CIDs */
- ROHC_PCOMP_NUM /* Number of pcomp values */
-};
-
-/* ROHC compression profiles, see also:
- http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */
-enum gprs_sndcp_xid_rohc_profiles {
- ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */
- ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */
- ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */
- ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */
- ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */
- ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */
- ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */
- ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */
- ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */
- ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */
- ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */
- ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */
- ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */
- ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */
- ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */
- ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */
-};
-
-/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */
-struct gprs_sndcp_dcomp_v42bis_params {
- uint8_t nsapi_len; /* Number of applicable NSAPIs
- * (default 0) */
- uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
- int p0; /* (default 3) */
- int p1; /* (default 2048) */
- int p2; /* (default 20) */
-
-};
-
-/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */
-enum gprs_sndcp_dcomp_v42bis_dcomp {
- V42BIS_DCOMP1, /* V.42bis enabled */
- V42BIS_DCOMP_NUM /* Number of dcomp values */
-};
-
-/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */
-struct gprs_sndcp_dcomp_v44_params {
- uint8_t nsapi_len; /* Number of applicable NSAPIs
- * (default 0) */
- uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */
- int c0; /* (default 10000000) */
- int p0; /* (default 3) */
- int p1t; /* Refer to subclause 6.6.3.1.4 */
- int p1r; /* Refer to subclause 6.6.3.1.5 */
- int p3t; /* (default 3 x p1t) */
- int p3r; /* (default 3 x p1r) */
-};
-
-/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */
-enum gprs_sndcp_dcomp_v44_dcomp {
- V44_DCOMP1, /* Packet method compressed */
- V44_DCOMP2, /* Multi packet method compressed */
- V44_DCOMP_NUM /* Number of dcomp values */
-};
-
-/* Transform a list with compression fields into an SNDCP-XID message (dst) */
-int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen,
- const struct llist_head *comp_fields, int version);
-
-/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */
-struct llist_head *gprs_sndcp_parse_xid(int *version,
- const void *ctx,
- const uint8_t *src,
- unsigned int src_len,
- const struct llist_head
- *comp_fields_req);
-
-/* Find out to which compression class the specified comp-field belongs
- * (header compression or data compression?) */
-int gprs_sndcp_get_compression_class(
- const struct gprs_sndcp_comp_field *comp_field);
-
-/* Dump a list with SNDCP-XID fields (Debug) */
-void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields,
- unsigned int logl);
-
diff --git a/openbsc/include/openbsc/gprs_subscriber.h b/openbsc/include/openbsc/gprs_subscriber.h
deleted file mode 100644
index be78febff..000000000
--- a/openbsc/include/openbsc/gprs_subscriber.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* GPRS subscriber details for use in SGSN land */
-#pragma once
-
-#include <stdint.h>
-
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/gsm/protocol/gsm_23_003.h>
-
-extern struct llist_head * const gprs_subscribers;
-
-struct gprs_subscr {
- struct llist_head entry;
- int use_count;
-
- char imsi[GSM23003_IMSI_MAX_DIGITS+1];
- uint32_t tmsi;
- char imei[GSM23003_IMEISV_NUM_DIGITS+1];
- bool authorized;
- bool keep_in_ram;
- uint32_t flags;
- uint16_t lac;
-
- struct sgsn_subscriber_data *sgsn_data;
-};
-
-struct gprs_subscr *_gprs_subscr_get(struct gprs_subscr *gsub,
- const char *file, int line);
-struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub,
- const char *file, int line);
-#define gprs_subscr_get(gsub) _gprs_subscr_get(gsub, __BASE_FILE__, __LINE__)
-#define gprs_subscr_put(gsub) _gprs_subscr_put(gsub, __BASE_FILE__, __LINE__)
diff --git a/openbsc/include/openbsc/gprs_utils.h b/openbsc/include/openbsc/gprs_utils.h
deleted file mode 100644
index 574f5c50c..000000000
--- a/openbsc/include/openbsc/gprs_utils.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* GPRS utility functions */
-
-/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010-2014 by On-Waves
- * (C) 2013 by Holger Hans Peter Freyther
- * 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/>.
- *
- */
-#pragma once
-
-#include <stdint.h>
-#include <sys/types.h>
-
-struct msgb;
-struct gprs_ra_id;
-
-struct msgb *gprs_msgb_copy(const struct msgb *msg, const char *name);
-int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area,
- size_t old_size, size_t new_size);
-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/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 7e656145a..df3eee65f 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -20,8 +20,6 @@
#define GSM_SUBSCRIBER_NO_EXPIRATION 0x0
struct vty;
-struct sgsn_mm_ctx;
-struct sgsn_subscriber_data;
struct subscr_request;
@@ -71,9 +69,6 @@ struct gsm_subscriber {
/* pending requests */
int is_paging;
struct llist_head requests;
-
- /* GPRS/SGSN related fields */
- struct sgsn_subscriber_data *sgsn_data;
};
enum gsm_subscriber_field {
diff --git a/openbsc/include/openbsc/gtphub.h b/openbsc/include/openbsc/gtphub.h
deleted file mode 100644
index 9cb7605f8..000000000
--- a/openbsc/include/openbsc/gtphub.h
+++ /dev/null
@@ -1,523 +0,0 @@
-/* GTP Hub Implementation */
-
-/* (C) 2015 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Neels Hofmeyr
- *
- * 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/>.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <sys/socket.h>
-
-#include <osmocom/core/select.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/core/rate_ctr.h>
-
-#include <openbsc/gprs_sgsn.h>
-
-
-/* support */
-
-/* TODO move to osmocom/core/socket.c ? */
-#include <netdb.h> /* for IPPROTO_* etc */
-struct osmo_sockaddr {
- struct sockaddr_storage a;
- socklen_t l;
-};
-
-/* TODO move to osmocom/core/socket.c ? */
-/*! \brief Initialize a sockaddr
- * \param[out] addr Valid osmo_sockaddr pointer to write result to
- * \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
- * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
- * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
- * \param[in] host Remote host name or IP address in string form
- * \param[in] port Remote port number in host byte order
- * \returns 0 on success, otherwise an error code (from getaddrinfo()).
- *
- * Copy the first result from a getaddrinfo() call with the given parameters to
- * *addr and *addr_len. On error, do not change *addr and return nonzero.
- */
-int osmo_sockaddr_init(struct osmo_sockaddr *addr,
- uint16_t family, uint16_t type, uint8_t proto,
- const char *host, uint16_t port);
-
-/* Conveniently pass AF_UNSPEC, SOCK_DGRAM and IPPROTO_UDP to
- * osmo_sockaddr_init(). */
-static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr,
- const char *host, uint16_t port)
-{
- return osmo_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
- host, port);
-}
-
-/*! \brief convert sockaddr to human readable string.
- * \param[out] addr_str Valid pointer to a buffer of length addr_str_len.
- * \param[in] addr_str_len Size of buffer addr_str points at.
- * \param[out] port_str Valid pointer to a buffer of length port_str_len.
- * \param[in] port_str_len Size of buffer port_str points at.
- * \param[in] addr Binary representation as returned by osmo_sockaddr_init().
- * \param[in] flags flags as passed to getnameinfo().
- * \returns 0 on success, an error code on error.
- *
- * Return the IPv4 or IPv6 address string and the port (a.k.a. service) string
- * representations of the given struct osmo_sockaddr in two caller provided
- * char buffers. Flags of (NI_NUMERICHOST | NI_NUMERICSERV) return numeric
- * address and port. Either one of addr_str or port_str may be NULL, in which
- * case nothing is returned there.
- *
- * See also osmo_sockaddr_to_str() (less flexible, but much more convenient). */
-int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
- char *port_str, size_t port_str_len,
- const struct osmo_sockaddr *addr,
- int flags);
-
-
-/*! \brief concatenate the parts returned by osmo_sockaddr_to_strs().
- * \param[in] addr Binary representation as returned by osmo_sockaddr_init().
- * \param[in] buf A buffer to use for string operations.
- * \param[in] buf_len Length of the buffer.
- * \returns Address string (in buffer).
- *
- * Compose a string of the numeric IP-address and port represented by *addr of
- * the form "<ip-addr> port <port>". The returned string is valid until the
- * next invocation of this function.
- */
-const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
- char *buf, size_t buf_len);
-
-/*! \brief conveniently return osmo_sockaddr_to_strb() in a static buffer.
- * \param[in] addr Binary representation as returned by osmo_sockaddr_init().
- * \returns Address string in static buffer.
- *
- * See osmo_sockaddr_to_strb().
- *
- * Note: only one osmo_sockaddr_to_str() call will work per print/log
- * statement. For two or more, use osmo_sockaddr_to_strb() with a separate
- * buffer each.
- */
-const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr);
-
-/*! \brief compare two osmo_sockaddr.
- * \param[in] a The first address to compare.
- * \param[in] b The other address to compare.
- * \returns 0 if equal, otherwise -1 or 1.
- */
-int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
- const struct osmo_sockaddr *b);
-
-/*! \brief Overwrite *dst with *src.
- * Like memcpy(), but copy only the valid bytes. */
-void osmo_sockaddr_copy(struct osmo_sockaddr *dst,
- const struct osmo_sockaddr *src);
-
-
-/* general */
-
-enum gtphub_plane_idx {
- GTPH_PLANE_CTRL = 0,
- GTPH_PLANE_USER = 1,
- GTPH_PLANE_N
-};
-
-enum gtphub_side_idx {
- GTPH_SIDE_SGSN = 0,
- GTPH_SIDE_GGSN = 1,
- GTPH_SIDE_N
-};
-
-#define for_each_side(I) for (I = 0; I < GTPH_SIDE_N; I++)
-#define for_each_plane(I) for (I = 0; I < GTPH_PLANE_N; I++)
-#define for_each_side_and_plane(I,J) for_each_side(I) for_each_plane(J)
-
-static inline int other_side_idx(int side_idx)
-{
- return (side_idx + 1) & 1;
-}
-
-extern const char* const gtphub_plane_idx_names[GTPH_PLANE_N];
-extern const uint16_t gtphub_plane_idx_default_port[GTPH_PLANE_N];
-
-extern const char* const gtphub_side_idx_names[GTPH_SIDE_N];
-
-/* A host address in the form that is expected in the 7.7.32 GSN Address IE.
- * len is either 4 (IPv4) or 16 (IPv6), any other value is invalid. If no
- * address is set, len shall be 0. */
-struct gsn_addr {
- uint16_t len;
- uint8_t buf[16];
-};
-
-void gsn_addr_copy(struct gsn_addr *gsna, const struct gsn_addr *src);
-int gsn_addr_from_str(struct gsn_addr *gsna, const char *numeric_addr_str);
-
-/* Return gsna in numeric string form, in a static buffer. */
-const char *gsn_addr_to_str(const struct gsn_addr *gsna);
-
-/* note: strbuf_len doesn't need to be larger than INET6_ADDRSTRLEN + 1. */
-const char *gsn_addr_to_strb(const struct gsn_addr *gsna,
- char *strbuf, int strbuf_len);
-
-/* Return 1 on match, zero otherwise. */
-int gsn_addr_same(const struct gsn_addr *a, const struct gsn_addr *b);
-
-/* Decode sa to gsna. Return 0 on success. If port is non-NULL, the port number
- * from sa is also returned. */
-int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
- const struct osmo_sockaddr *sa);
-
-/* expiry */
-
-struct expiring_item;
-typedef void (*del_cb_t)(struct expiring_item *);
-
-struct expiring_item {
- struct llist_head entry;
- time_t expiry;
- del_cb_t del_cb;
-};
-
-struct expiry {
- int expiry_in_seconds;
- struct llist_head items;
-};
-
-/* Initialize an expiry queue. */
-void expiry_init(struct expiry *exq, int expiry_in_seconds);
-
-/* Add a new mapping, or restart the expiry timeout for an already listed
- * mapping. */
-void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now);
-
-/* Initialize to all-empty; must be called before using the item in any way. */
-void expiring_item_init(struct expiring_item *item);
-
-/* Remove the given item from its expiry queue, and call item->del_cb, if set.
- * This sets item->del_cb to NULL and is harmless when run a second time on the
- * same item, so the del_cb may choose to call this function, too, to allow
- * deleting items from several code paths. */
-void expiring_item_del(struct expiring_item *item);
-
-/* Carry out due expiry of mappings. Must be invoked regularly.
- * 'now' is the current clock count in seconds and must correspond to the clock
- * count passed to nr_map_add(). A monotonous clock counter should be used. */
-int expiry_tick(struct expiry *exq, time_t now);
-
-/* Expire all items. */
-void expiry_clear(struct expiry *exq);
-
-
-/* number map */
-
-/* A number map assigns a "random" mapped number to each user provided number.
- * If the same number is requested multiple times, the same mapped number is
- * returned.
- *
- * Number maps plug into possibly shared pools and expiry queues, for example:
- *
- * mapA -----------+-> pool1 <-+-- mapB
- * {10->1, 11->5} | {1, 2, 3, ...} | {10->2, 11->3}
- * | |
- * | |
- * /-> \-> expiry1 <-/
- * | (30 seconds)
- * |
- * mapC -------+-----> pool2 <-+-- mapD
- * {10->1, 11->3} {1, 2, 3, ...} | {10->2, 11->5}
- * |
- * expiry2 <-/
- * (60 seconds)
- *
- * A map contains mappings ("10->1"). Each map needs a number pool, which can
- * be shared with other maps. Each new mapping receives a number from the pool,
- * which is then unavailable to any other map using the same pool.
- *
- * A map may point at an expiry queue, in which case all mappings added to it
- * are also appended to the expiry queue (using a separate llist entry in the
- * mapping). Any number of maps may submit to the same expiry queue, if they
- * desire the same expiry timeout. An expiry queue stores the mappings in
- * chronological order, so that expiry checking is needed only from the start
- * of the queue; hence only mappings with identical expiry timeout can be added
- * to the same expiry queue. Upon expiry, a mapping is dropped from the map it
- * was submitted at. expiry_tick() needs to be called regularly for each expiry
- * queue.
- *
- * A nr_mapping can be embedded in a larger struct: each mapping can have a
- * distinct destructor (del_cb), and each del_cb can figure out the container
- * struct's address and free that upon expiry or manual deletion. So in expiry
- * queues (and even maps), mappings of different container types can be mixed.
- * This can help to drastically reduce the amount of unnecessary visits during
- * expiry checking, for the case that no expiry is pending. An expiry queue
- * always knows which mappings to expire next, because they are right at the
- * start of its list.
- *
- * Mapping allocation and a del_cb are provided by the caller. If del_cb is
- * NULL, no deallocation will be done (allowing statically allocated entries).
- */
-
-typedef unsigned int nr_t;
-
-/* Generator for unused numbers. So far this counts upwards from zero, but the
- * implementation may change in the future. Treat this like an opaque struct.
- * If this becomes random, the tests need to be fixed. */
-struct nr_pool {
- nr_t last_nr;
- nr_t nr_min;
- nr_t nr_max;
-};
-
-struct nr_mapping {
- struct llist_head entry;
- struct expiring_item expiry_entry;
-
- void *origin;
- nr_t orig;
- nr_t repl;
-};
-
-struct nr_map {
- struct nr_pool *pool; /* multiple nr_maps can share a nr_pool. */
- struct expiry *add_items_to_expiry;
- struct llist_head mappings;
-};
-
-
-void nr_pool_init(struct nr_pool *pool, nr_t nr_min, nr_t nr_max);
-
-/* Return the next unused number from the nr_pool. */
-nr_t nr_pool_next(struct nr_pool *pool);
-
-/* Initialize the nr_mapping to zero/empty values. */
-void nr_mapping_init(struct nr_mapping *mapping);
-
-/* Remove the given mapping from its parent map and expiry queue, and call
- * mapping->del_cb, if set. */
-void nr_mapping_del(struct nr_mapping *mapping);
-
-/* Initialize an (already allocated) nr_map, and set the map's number pool.
- * Multiple nr_map instances may use the same nr_pool. Set the nr_map's expiry
- * queue to exq, so that all added mappings are automatically expired after the
- * time configured in exq. exq may be NULL to disable automatic expiry. */
-void nr_map_init(struct nr_map *map, struct nr_pool *pool,
- struct expiry *exq);
-
-/* Add a new entry to the map. mapping->orig, mapping->origin and
- * mapping->del_cb must be set before calling this function. The remaining
- * fields of *mapping will be overwritten. mapping->repl is set to the next
- * available mapped number from map->pool. 'now' is the current clock count in
- * seconds; if no map->expiry is used, just pass 0 for 'now'. */
-void nr_map_add(struct nr_map *map, struct nr_mapping *mapping,
- time_t now);
-
-/* Restart the timeout for the given mapping. mapping must be a member of map.
- */
-void nr_map_refresh(struct nr_map *map, struct nr_mapping *mapping,
- time_t now);
-
-/* Return a known mapping from nr_orig and the given origin. If nr_orig is
- * unknown, return NULL. */
-struct nr_mapping *nr_map_get(const struct nr_map *map,
- void *origin, nr_t nr_orig);
-
-/* Return a known mapping to nr_repl. If nr_repl is unknown, return NULL. */
-struct nr_mapping *nr_map_get_inv(const struct nr_map *map, nr_t nr_repl);
-
-/* Remove all mappings from map. */
-void nr_map_clear(struct nr_map *map);
-
-/* Return 1 if map has no entries, 0 otherwise. */
-int nr_map_empty(const struct nr_map *map);
-
-
-/* config */
-
-static const int GTPH_EXPIRE_QUICKLY_SECS = 30; /* TODO is there a spec for this? */
-static const int GTPH_EXPIRE_SLOWLY_MINUTES = 6 * 60; /* TODO is there a spec for this? */
-
-struct gtphub_cfg_addr {
- const char *addr_str;
- uint16_t port;
-};
-
-struct gtphub_cfg_bind {
- struct gtphub_cfg_addr bind;
-};
-
-struct gtphub_cfg {
- struct gtphub_cfg_bind to_gsns[GTPH_SIDE_N][GTPH_PLANE_N];
- struct gtphub_cfg_addr proxy[GTPH_SIDE_N][GTPH_PLANE_N];
- int sgsn_use_sender; /* Use sender, not GSN addr IE with std ports */
-};
-
-
-/* state */
-
-struct gtphub_peer {
- struct llist_head entry;
-
- struct llist_head addresses; /* Alternatives, not load balancing. */
- struct nr_pool seq_pool;
- struct nr_map seq_map;
-};
-
-struct gtphub_peer_addr {
- struct llist_head entry;
-
- struct gtphub_peer *peer;
- struct gsn_addr addr;
- struct llist_head ports;
-};
-
-struct gtphub_peer_port {
- struct llist_head entry;
-
- struct gtphub_peer_addr *peer_addr;
- uint16_t port;
- unsigned int ref_count; /* references from other peers' seq_maps */
- struct osmo_sockaddr sa; /* a "cache" for (peer_addr->addr, port) */
- int last_restart_count; /* 0..255 = valid, all else means unknown */
-
- struct rate_ctr_group *counters_io;
-};
-
-struct gtphub_tunnel_endpoint {
- struct gtphub_peer_port *peer;
- uint32_t tei_orig; /* from/to peer */
-
- struct rate_ctr_group *counters_io;
-};
-
-struct gtphub_tunnel {
- struct llist_head entry;
- struct expiring_item expiry_entry;
-
- uint32_t tei_repl; /* unique TEI to replace peers' TEIs */
- struct gtphub_tunnel_endpoint endpoint[GTPH_SIDE_N][GTPH_PLANE_N];
-};
-
-struct gtphub_bind {
- struct gsn_addr local_addr;
- uint16_t local_port;
- struct osmo_fd ofd;
-
- /* list of struct gtphub_peer */
- struct llist_head peers;
-
- const char *label; /* For logging */
- struct rate_ctr_group *counters_io;
-};
-
-struct gtphub_resolved_ggsn {
- struct llist_head entry;
- struct expiring_item expiry_entry;
-
- /* 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];
-
- /* Which address and port we resolved that to. */
- struct gtphub_peer_port *peer;
-};
-
-struct gtphub {
- struct gtphub_bind to_gsns[GTPH_SIDE_N][GTPH_PLANE_N];
-
- /* pointers to an entry of to_gsns[s][p].peers */
- struct gtphub_peer_port *proxy[GTPH_SIDE_N][GTPH_PLANE_N];
-
- /* The TEI numbers will simply wrap and be reused, which will work out
- * in practice. Problems would arise if one given peer maintained the
- * same TEI for a time long enough for the TEI nr map to wrap an entire
- * uint32_t; if a new TEI were mapped every second, this would take
- * more than 100 years (in which a single given TEI must not time out)
- * to cause a problem. */
- struct nr_pool tei_pool;
-
- struct llist_head tunnels; /* struct gtphub_tunnel */
- struct llist_head pending_deletes; /* opaque (gtphub.c) */
-
- struct llist_head ggsn_lookups; /* opaque (gtphub_ares.c) */
- struct llist_head resolved_ggsns; /* struct gtphub_resolved_ggsn */
-
- struct osmo_timer_list gc_timer;
- struct expiry expire_quickly;
- struct expiry expire_slowly;
-
- uint8_t restart_counter;
-
- int sgsn_use_sender;
-};
-
-struct gtp_packet_desc;
-
-
-/* api */
-
-int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg);
-int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file);
-
-/* Initialize and start gtphub: bind to ports, run expiry timers. */
-int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg,
- uint8_t restart_counter);
-
-/* Close all sockets, expire all maps and peers and free all allocations. The
- * struct is then unusable, unless gtphub_start() is run on it again. */
-void gtphub_stop(struct gtphub *hub);
-
-time_t gtphub_now(void);
-
-/* Remove expired items, empty peers, ... */
-void gtphub_gc(struct gtphub *hub, time_t now);
-
-/* Return the string of the first address for this peer. */
-const char *gtphub_peer_str(struct gtphub_peer *peer);
-
-/* Return a human readable description of tun in a static buffer. */
-const char *gtphub_tunnel_str(struct gtphub_tunnel *tun);
-
-/* Return 1 if all of tun's endpoints are fully established, 0 otherwise. */
-int gtphub_tunnel_complete(struct gtphub_tunnel *tun);
-
-int gtphub_handle_buf(struct gtphub *hub,
- unsigned int side_idx,
- unsigned int port_idx,
- const struct osmo_sockaddr *from_addr,
- uint8_t *buf,
- size_t received,
- time_t now,
- uint8_t **reply_buf,
- struct osmo_fd **to_ofd,
- struct osmo_sockaddr *to_addr);
-
-struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
- struct gtphub_bind *bind,
- const struct gsn_addr *addr,
- uint16_t port);
-
-struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
- const struct osmo_sockaddr *addr);
-
-void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
- struct gsn_addr *resolved_addr,
- time_t now);
-
-const char *gtphub_port_str(struct gtphub_peer_port *port);
-
-int gtphub_write(const struct osmo_fd *to,
- const struct osmo_sockaddr *to_addr,
- const uint8_t *buf, size_t buf_len);
diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h
deleted file mode 100644
index 1ede2c930..000000000
--- a/openbsc/include/openbsc/sgsn.h
+++ /dev/null
@@ -1,186 +0,0 @@
-#ifndef _SGSN_H
-#define _SGSN_H
-
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/crypt/gprs_cipher.h>
-#include <osmocom/gprs/gprs_ns.h>
-#include <openbsc/gprs_sgsn.h>
-#include <openbsc/oap_client.h>
-
-#include <ares.h>
-
-struct gprs_gsup_client;
-struct hostent;
-
-enum sgsn_auth_policy {
- SGSN_AUTH_POLICY_OPEN,
- SGSN_AUTH_POLICY_CLOSED,
- SGSN_AUTH_POLICY_ACL_ONLY,
- SGSN_AUTH_POLICY_REMOTE
-};
-
-
-enum sgsn_rate_ctr_keys {
- CTR_LLC_DL_BYTES,
- CTR_LLC_UL_BYTES,
- CTR_LLC_DL_PACKETS,
- CTR_LLC_UL_PACKETS,
- CTR_GPRS_ATTACH_REQUEST,
- CTR_GPRS_ATTACH_ACKED,
- CTR_GPRS_ATTACH_REJECTED,
- CTR_GPRS_DETACH_REQUEST,
- CTR_GPRS_DETACH_ACKED,
- CTR_GPRS_ROUTING_AREA_REQUEST,
- CTR_GPRS_ROUTING_AREA_ACKED,
- CTR_GPRS_ROUTING_AREA_REJECT,
- /* PDP single packet counter / GSM 04.08 9.5.1 - 9.5.9 */
- CTR_PDP_ACTIVATE_REQUEST,
- CTR_PDP_ACTIVATE_REJECT,
- CTR_PDP_ACTIVATE_ACCEPT,
- CTR_PDP_REQUEST_ACTIVATE, /* unused */
- CTR_PDP_REQUEST_ACTIVATE_REJ, /* unused */
- CTR_PDP_MODIFY_REQUEST, /* unsued */
- CTR_PDP_MODIFY_ACCEPT, /* unused */
- CTR_PDP_DL_DEACTIVATE_REQUEST,
- CTR_PDP_DL_DEACTIVATE_ACCEPT,
- CTR_PDP_UL_DEACTIVATE_REQUEST,
- CTR_PDP_UL_DEACTIVATE_ACCEPT,
-};
-
-struct sgsn_cdr {
- char *filename;
- int interval;
-};
-
-struct sgsn_config {
- /* parsed from config file */
-
- char *gtp_statedir;
- struct sockaddr_in gtp_listenaddr;
-
- /* misc */
- struct gprs_ns_inst *nsi;
-
- enum sgsn_auth_policy auth_policy;
- enum gprs_ciph_algo cipher;
- struct llist_head imsi_acl;
-
- struct sockaddr_in gsup_server_addr;
- int gsup_server_port;
-
- int require_authentication;
- int require_update_location;
-
- /* CDR configuration */
- struct sgsn_cdr cdr;
-
- struct {
- int T3312;
- int T3322;
- int T3350;
- int T3360;
- int T3370;
- int T3313;
- int T3314;
- int T3316;
- int T3385;
- int T3386;
- int T3395;
- int T3397;
- } timers;
-
- int dynamic_lookup;
-
- struct oap_client_config oap;
-
- /* RFC1144 TCP/IP header compression */
- struct {
- int active;
- int passive;
- int s01;
- } pcomp_rfc1144;
-
- /* V.42vis data compression */
- struct {
- int active;
- int passive;
- int p0;
- int p1;
- int p2;
- } dcomp_v42bis;
-};
-
-struct sgsn_instance {
- char *config_file;
- struct sgsn_config cfg;
- /* File descriptor wrappers for LibGTP */
- struct osmo_fd gtp_fd0;
- struct osmo_fd gtp_fd1c;
- struct osmo_fd gtp_fd1u;
- /* Timer for libGTP */
- struct osmo_timer_list gtp_timer;
- /* GSN instance for libgtp */
- struct gsn_t *gsn;
- /* Subscriber */
- struct gsup_client *gsup_client;
- /* LLME inactivity timer */
- struct osmo_timer_list llme_timer;
-
- /* c-ares event loop integration */
- struct osmo_timer_list ares_timer;
- struct llist_head ares_fds;
- ares_channel ares_channel;
- struct ares_addr_node *ares_servers;
-
- struct rate_ctr_group *rate_ctrs;
-};
-
-extern struct sgsn_instance *sgsn;
-
-/* sgsn_vty.c */
-
-int sgsn_vty_init(void);
-int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg);
-
-/* sgsn.c */
-
-/* Main input function for Gb proxy */
-int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
-
-
-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);
-
-/* 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);
-
-
-/*
- * CDR related functionality
- */
-int sgsn_cdr_init(struct sgsn_instance *sgsn);
-
-
-/*
- * C-ARES related functionality
- */
-int sgsn_ares_init(struct sgsn_instance *sgsn);
-int sgsn_ares_query(struct sgsn_instance *sgsm, const char *name, ares_host_callback cb, void *data);
-
-#endif
diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h
index d4ccf80da..974925062 100644
--- a/openbsc/include/openbsc/signal.h
+++ b/openbsc/include/openbsc/signal.h
@@ -45,8 +45,7 @@ enum signal_subsystems {
SS_RF,
SS_MSC,
SS_HO,
- SS_CCCH,
- SS_SGSN,
+ SS_CCCH
};
/* SS_PAGING signals */
@@ -241,22 +240,4 @@ struct ccch_signal_data {
uint16_t rach_access_count;
};
-/* GPRS SGSN signals SS_SGSN */
-enum signal_sgsn {
- S_SGSN_ATTACH,
- S_SGSN_DETACH,
- S_SGSN_UPDATE,
- S_SGSN_PDP_ACT,
- S_SGSN_PDP_DEACT,
- S_SGSN_PDP_TERMINATE,
- S_SGSN_PDP_FREE,
- S_SGSN_MM_FREE,
-};
-
-struct sgsn_mm_ctx;
-struct sgsn_signal_data {
- struct sgsn_mm_ctx *mm;
- struct sgsn_pdp_ctx *pdp; /* non-NULL for PDP_ACT, PDP_DEACT, PDP_FREE */
-};
-
#endif
diff --git a/openbsc/include/openbsc/slhc.h b/openbsc/include/openbsc/slhc.h
deleted file mode 100644
index cd5a47cf4..000000000
--- a/openbsc/include/openbsc/slhc.h
+++ /dev/null
@@ -1,187 +0,0 @@
-#ifndef _SLHC_H
-#define _SLHC_H
-/*
- * Definitions for tcp compression routines.
- *
- * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $
- *
- * Copyright (c) 1989 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
- * - Initial distribution.
- *
- *
- * modified for KA9Q Internet Software Package by
- * Katie Stevens (dkstevens@ucdavis.edu)
- * University of California, Davis
- * Computing Services
- * - 01-31-90 initial adaptation
- *
- * - Feb 1991 Bill_Simpson@um.cc.umich.edu
- * variable number of conversation slots
- * allow zero or one slots
- * separate routines
- * status display
- */
-
-/*
- * Compressed packet format:
- *
- * The first octet contains the packet type (top 3 bits), TCP
- * 'push' bit, and flags that indicate which of the 4 TCP sequence
- * numbers have changed (bottom 5 bits). The next octet is a
- * conversation number that associates a saved IP/TCP header with
- * the compressed packet. The next two octets are the TCP checksum
- * from the original datagram. The next 0 to 15 octets are
- * sequence number changes, one change per bit set in the header
- * (there may be no changes and there are two special cases where
- * the receiver implicitly knows what changed -- see below).
- *
- * There are 5 numbers which can change (they are always inserted
- * in the following order): TCP urgent pointer, window,
- * acknowledgment, sequence number and IP ID. (The urgent pointer
- * is different from the others in that its value is sent, not the
- * change in value.) Since typical use of SLIP links is biased
- * toward small packets (see comments on MTU/MSS below), changes
- * use a variable length coding with one octet for numbers in the
- * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
- * range 256 - 65535 or 0. (If the change in sequence number or
- * ack is more than 65535, an uncompressed packet is sent.)
- */
-
-/*
- * Packet types (must not conflict with IP protocol version)
- *
- * The top nibble of the first octet is the packet type. There are
- * three possible types: IP (not proto TCP or tcp with one of the
- * control flags set); uncompressed TCP (a normal IP/TCP packet but
- * with the 8-bit protocol field replaced by an 8-bit connection id --
- * this type of packet syncs the sender & receiver); and compressed
- * TCP (described above).
- *
- * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
- * is logically part of the 4-bit "changes" field that follows. Top
- * three bits are actual packet type. For backward compatibility
- * and in the interest of conserving bits, numbers are chosen so the
- * IP protocol version number (4) which normally appears in this nibble
- * means "IP packet".
- */
-
-
-#include <linux/ip.h>
-#include <linux/tcp.h>
-
-/* SLIP compression masks for len/vers byte */
-#define SL_TYPE_IP 0x40
-#define SL_TYPE_UNCOMPRESSED_TCP 0x70
-#define SL_TYPE_COMPRESSED_TCP 0x80
-#define SL_TYPE_ERROR 0x00
-
-/* Bits in first octet of compressed packet */
-#define NEW_C 0x40 /* flag bits for what changed in a packet */
-#define NEW_I 0x20
-#define NEW_S 0x08
-#define NEW_A 0x04
-#define NEW_W 0x02
-#define NEW_U 0x01
-
-/* reserved, special-case values of above */
-#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */
-#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */
-#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
-
-#define TCP_PUSH_BIT 0x10
-
-/*
- * data type and sizes conversion assumptions:
- *
- * VJ code KA9Q style generic
- * u_char byte_t unsigned char 8 bits
- * u_short int16 unsigned short 16 bits
- * u_int int16 unsigned short 16 bits
- * u_long unsigned long unsigned long 32 bits
- * int int32 long 32 bits
- */
-
-typedef __u8 byte_t;
-typedef __u32 int32;
-
-/*
- * "state" data for each active tcp conversation on the wire. This is
- * basically a copy of the entire IP/TCP header from the last packet
- * we saw from the conversation together with a small identifier
- * the transmit & receive ends of the line use to locate saved header.
- */
-struct cstate {
- byte_t cs_this; /* connection id number (xmit) */
- struct cstate *next; /* next in ring (xmit) */
- struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */
- struct tcphdr cs_tcp;
- unsigned char cs_ipopt[64];
- unsigned char cs_tcpopt[64];
- int cs_hsize;
-};
-#define NULLSLSTATE (struct cstate *)0
-
-/*
- * all the state data for one serial line (we need one of these per line).
- */
-struct slcompress {
- struct cstate *tstate; /* transmit connection states (array)*/
- struct cstate *rstate; /* receive connection states (array)*/
-
- byte_t tslot_limit; /* highest transmit slot id (0-l)*/
- byte_t rslot_limit; /* highest receive slot id (0-l)*/
-
- byte_t xmit_oldest; /* oldest xmit in ring */
- byte_t xmit_current; /* most recent xmit id */
- byte_t recv_current; /* most recent rcvd id */
-
- byte_t flags;
-#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */
-
- int32 sls_o_nontcp; /* outbound non-TCP packets */
- int32 sls_o_tcp; /* outbound TCP packets */
- int32 sls_o_uncompressed; /* outbound uncompressed packets */
- int32 sls_o_compressed; /* outbound compressed packets */
- int32 sls_o_searches; /* searches for connection state */
- int32 sls_o_misses; /* times couldn't find conn. state */
-
- int32 sls_i_uncompressed; /* inbound uncompressed packets */
- int32 sls_i_compressed; /* inbound compressed packets */
- int32 sls_i_error; /* inbound error packets */
- int32 sls_i_tossed; /* inbound packets tossed because of error */
-
- int32 sls_i_runt;
- int32 sls_i_badcheck;
-};
-#define NULLSLCOMPR (struct slcompress *)0
-
-/* In slhc.c: */
-struct slcompress *slhc_init(const void *ctx, int rslots, int tslots);
-
-void slhc_free(struct slcompress *comp);
-
-int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
- unsigned char *ocp, unsigned char **cpp, int compress_cid);
-int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize);
-int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize);
-int slhc_toss(struct slcompress *comp);
-
-void slhc_i_status(struct slcompress *comp);
-void slhc_o_status(struct slcompress *comp);
-
-#endif /* _SLHC_H */
diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h
deleted file mode 100644
index 607a58e51..000000000
--- a/openbsc/include/openbsc/v42bis.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * v42bis.h
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2005, 2011 Steve Underwood
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1,
- * as published by the Free Software Foundation.
- *
- * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*! \page v42bis_page V.42bis modem data compression
-\section v42bis_page_sec_1 What does it do?
-The v.42bis specification defines a data compression scheme, to work in
-conjunction with the error correction scheme defined in V.42.
-
-\section v42bis_page_sec_2 How does it work?
-*/
-
-#include <stdint.h>
-
-#if !defined(_SPANDSP_V42BIS_H_)
-#define _SPANDSP_V42BIS_H_
-
-#define SPAN_DECLARE(x) x
-
-#define V42BIS_MIN_STRING_SIZE 6
-#define V42BIS_MAX_STRING_SIZE 250
-#define V42BIS_MIN_DICTIONARY_SIZE 512
-#define V42BIS_MAX_BITS 12
-#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */
-#define V42BIS_MAX_OUTPUT_LENGTH 1024
-
-enum
-{
- V42BIS_P0_NEITHER_DIRECTION = 0,
- V42BIS_P0_INITIATOR_RESPONDER,
- V42BIS_P0_RESPONDER_INITIATOR,
- V42BIS_P0_BOTH_DIRECTIONS
-};
-
-enum
-{
- V42BIS_COMPRESSION_MODE_DYNAMIC = 0,
- V42BIS_COMPRESSION_MODE_ALWAYS,
- V42BIS_COMPRESSION_MODE_NEVER
-};
-
-typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len);
-
-/*!
- V.42bis compression/decompression descriptor. This defines the working state for a
- single instance of V.42bis compress/decompression.
-*/
-typedef struct v42bis_state_s v42bis_state_t;
-
-#if defined(__cplusplus)
-extern "C"
-{
-#endif
-
-/*! Compress a block of octets.
- \param s The V.42bis context.
- \param buf The data to be compressed.
- \param len The length of the data buffer.
- \return 0 */
-SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t buf[], int len);
-
-/*! Flush out any data remaining in a compression buffer.
- \param s The V.42bis context.
- \return 0 */
-SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s);
-
-/*! Decompress a block of octets.
- \param s The V.42bis context.
- \param buf The data to be decompressed.
- \param len The length of the data buffer.
- \return 0 */
-SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t buf[], int len);
-
-/*! Flush out any data remaining in the decompression buffer.
- \param s The V.42bis context.
- \return 0 */
-SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s);
-
-/*! Set the compression mode.
- \param s The V.42bis context.
- \param mode One of the V.42bis compression modes -
- V42BIS_COMPRESSION_MODE_DYNAMIC,
- V42BIS_COMPRESSION_MODE_ALWAYS,
- V42BIS_COMPRESSION_MODE_NEVER */
-SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode);
-
-/*! Initialise a V.42bis context.
- \param s The V.42bis context.
- \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec.
- \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec.
- \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec.
- \param encode_handler Encode callback handler.
- \param encode_user_data An opaque pointer passed to the encode callback handler.
- \param max_encode_len The maximum length that should be passed to the encode handler.
- \param decode_handler Decode callback handler.
- \param decode_user_data An opaque pointer passed to the decode callback handler.
- \param max_decode_len The maximum length that should be passed to the decode handler.
- \return The V.42bis context. */
-SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx,
- v42bis_state_t *s,
- int negotiated_p0,
- int negotiated_p1,
- int negotiated_p2,
- put_msg_func_t encode_handler,
- void *encode_user_data,
- int max_encode_len,
- put_msg_func_t decode_handler,
- void *decode_user_data,
- int max_decode_len);
-
-/*! Release a V.42bis context.
- \param s The V.42bis context.
- \return 0 if OK */
-SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s);
-
-/*! Free a V.42bis context.
- \param s The V.42bis context.
- \return 0 if OK */
-SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
-/*- End of file ------------------------------------------------------------*/
diff --git a/openbsc/include/openbsc/v42bis_private.h b/openbsc/include/openbsc/v42bis_private.h
deleted file mode 100644
index daa5ea315..000000000
--- a/openbsc/include/openbsc/v42bis_private.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * private/v42bis.h
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2005 Steve Underwood
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1,
- * as published by the Free Software Foundation.
- *
- * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#if !defined(_SPANDSP_PRIVATE_V42BIS_H_)
-#define _SPANDSP_PRIVATE_V42BIS_H_
-
-/*!
- V.42bis dictionary node.
- Note that 0 is not a valid node to point to (0 is always a control code), so 0 is used
- as a "no such value" marker in this structure.
-*/
-typedef struct
-{
- /*! \brief The value of the octet represented by the current dictionary node */
- uint8_t node_octet;
- /*! \brief The parent of this node */
- uint16_t parent;
- /*! \brief The first child of this node */
- uint16_t child;
- /*! \brief The next node at the same depth */
- uint16_t next;
-} v42bis_dict_node_t;
-
-/*!
- V.42bis compression or decompression. This defines the working state for a single instance
- of V.42bis compression or decompression.
-*/
-typedef struct
-{
- /*! \brief Compression enabled. */
- int v42bis_parm_p0;
- /*! \brief Compression mode. */
- int compression_mode;
- /*! \brief Callback function to handle output data. */
- put_msg_func_t handler;
- /*! \brief An opaque pointer passed in calls to the data handler. */
- void *user_data;
- /*! \brief The maximum amount to be passed to the data handler. */
- int max_output_len;
-
- /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
- int transparent;
- /*! \brief Next empty dictionary entry */
- uint16_t v42bis_parm_c1;
- /*! \brief Current codeword size */
- uint16_t v42bis_parm_c2;
- /*! \brief Threshold for codeword size change */
- uint16_t v42bis_parm_c3;
- /*! \brief The current update point in the dictionary */
- uint16_t update_at;
- /*! \brief The last entry matched in the dictionary */
- uint16_t last_matched;
- /*! \brief The last entry added to the dictionary */
- uint16_t last_added;
- /*! \brief Total number of codewords in the dictionary */
- int v42bis_parm_n2;
- /*! \brief Maximum permitted string length */
- int v42bis_parm_n7;
- /*! \brief The dictionary */
- v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
-
- /*! \brief The octet string in progress */
- uint8_t string[V42BIS_MAX_STRING_SIZE];
- /*! \brief The current length of the octet string in progress */
- int string_length;
- /*! \brief The amount of the octet string in progress which has already
- been flushed out of the buffer */
- int flushed_length;
-
- /*! \brief Compression performance metric */
- uint16_t compression_performance;
-
- /*! \brief Outgoing bit buffer (compression), or incoming bit buffer (decompression) */
- uint32_t bit_buffer;
- /*! \brief Outgoing bit count (compression), or incoming bit count (decompression) */
- int bit_count;
-
- /*! \brief The output composition buffer */
- uint8_t output_buf[V42BIS_MAX_OUTPUT_LENGTH];
- /*! \brief The length of the contents of the output composition buffer */
- int output_octet_count;
-
- /*! \brief The current value of the escape code */
- uint8_t escape_code;
- /*! \brief TRUE if we just hit an escape code, and are waiting for the following octet */
- int escaped;
-} v42bis_comp_state_t;
-
-/*!
- V.42bis compression/decompression descriptor. This defines the working state for a
- single instance of V.42bis compress/decompression.
-*/
-struct v42bis_state_s
-{
- /*! \brief Compression state. */
- v42bis_comp_state_t compress;
- /*! \brief Decompression state. */
- v42bis_comp_state_t decompress;
-
- /*! \brief Error and flow logging control */
-};
-
-#endif
-/*- End of file ------------------------------------------------------------*/
diff --git a/openbsc/osmoappdesc.py b/openbsc/osmoappdesc.py
index 76f03fc58..ba6d954ae 100644
--- a/openbsc/osmoappdesc.py
+++ b/openbsc/osmoappdesc.py
@@ -31,25 +31,18 @@ app_configs = {
"osmo-bsc": ["doc/examples/osmo-bsc/osmo-bsc.cfg"],
"nat": ["doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg"],
"mgcp": ["doc/examples/osmo-bsc_mgcp/mgcp.cfg"],
- "gbproxy": ["doc/examples/osmo-gbproxy/osmo-gbproxy.cfg",
- "doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg"],
- "sgsn": ["doc/examples/osmo-sgsn/osmo-sgsn.cfg"],
"nitb": ["doc/examples/osmo-nitb/nanobts/openbsc-multitrx.cfg",
"doc/examples/osmo-nitb/nanobts/openbsc.cfg"],
- "gtphub": ["doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg"]
}
apps = [(4242, "src/osmo-bsc/osmo-bsc", "OsmoBSC", "osmo-bsc"),
(4244, "src/osmo-bsc_nat/osmo-bsc_nat", "OsmoBSCNAT", "nat"),
(4243, "src/osmo-bsc_mgcp/osmo-bsc_mgcp", "OpenBSC MGCP", "mgcp"),
- (4246, "src/gprs/osmo-gbproxy", "OsmoGbProxy", "gbproxy"),
- (4245, "src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn"),
(4242, "src/osmo-nitb/osmo-nitb", "OpenBSC", "nitb"),
- (4253, "src/gprs/osmo-gtphub", "OsmoGTPhub", "gtphub")
]
vty_command = ["./src/osmo-nitb/osmo-nitb", "-c",
"doc/examples/osmo-nitb/nanobts/openbsc.cfg"]
-vty_app = apps[5] # reference apps[] entry for osmo-nitb
+vty_app = apps[3] # reference apps[] entry for osmo-nitb
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index cfad7dfea..e579ea0fc 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -43,7 +43,6 @@ SUBDIRS += \
osmo-bsc_mgcp \
utils \
ipaccess \
- gprs \
$(NULL)
# Conditional Programs
diff --git a/openbsc/src/gprs/.gitignore b/openbsc/src/gprs/.gitignore
deleted file mode 100644
index 7cfefbac2..000000000
--- a/openbsc/src/gprs/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-gsn_restart
-osmo_*.cfg*
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
deleted file mode 100644
index cb0997902..000000000
--- a/openbsc/src/gprs/Makefile.am
+++ /dev/null
@@ -1,132 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- -I$(top_builddir) \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- -fno-strict-aliasing \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOVTY_CFLAGS) \
- $(LIBOSMOCTRL_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
- $(LIBOSMOGB_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(LIBCARES_CFLAGS) \
- $(LIBCRYPTO_CFLAGS) \
- $(LIBGTP_CFLAGS) \
- $(NULL)
-if BUILD_IU
-AM_CFLAGS += \
- $(LIBASN1C_CFLAGS) \
- $(LIBOSMOSIGTRAN_CFLAGS) \
- $(LIBOSMORANAP_CFLAGS) \
- $(NULL)
-endif
-
-OSMO_LIBS = \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOABIS_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMOVTY_LIBS) \
- $(LIBOSMOCTRL_LIBS) \
- $(LIBOSMOGB_LIBS) \
- $(LIBGTP_LIBS) \
- $(NULL)
-
-bin_PROGRAMS = \
- osmo-gbproxy \
- $(NULL)
-if HAVE_LIBGTP
-if HAVE_LIBCARES
-bin_PROGRAMS += \
- osmo-sgsn \
- osmo-gtphub \
- $(NULL)
-endif
-endif
-
-osmo_gbproxy_SOURCES = \
- gb_proxy.c \
- gb_proxy_main.c \
- gb_proxy_vty.c \
- gb_proxy_patch.c \
- gb_proxy_tlli.c \
- gb_proxy_peer.c \
- gprs_gb_parse.c \
- gprs_llc_parse.c \
- crc24.c \
- gprs_utils.c \
- $(NULL)
-osmo_gbproxy_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(OSMO_LIBS) \
- $(LIBCRYPTO_LIBS) \
- -lrt \
- $(NULL)
-
-osmo_sgsn_SOURCES = \
- gprs_gmm.c \
- gprs_sgsn.c \
- gprs_sndcp.c \
- gprs_sndcp_comp.c \
- gprs_sndcp_dcomp.c \
- gprs_sndcp_pcomp.c \
- gprs_sndcp_vty.c \
- gprs_sndcp_xid.c \
- sgsn_main.c \
- sgsn_vty.c \
- sgsn_libgtp.c \
- gprs_llc.c \
- gprs_llc_parse.c \
- gprs_llc_vty.c \
- crc24.c \
- sgsn_ctrl.c \
- sgsn_auth.c \
- gprs_subscriber.c \
- gprs_utils.c \
- sgsn_cdr.c \
- sgsn_ares.c \
- slhc.c \
- gprs_llc_xid.c \
- v42bis.c \
- $(NULL)
-osmo_sgsn_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(OSMO_LIBS) \
- $(LIBOSMOABIS_LIBS) \
- $(LIBCARES_LIBS) \
- $(LIBCRYPTO_LIBS) \
- $(LIBGTP_LIBS) \
- -lrt \
- -lm \
- $(NULL)
-if BUILD_IU
-osmo_sgsn_LDADD += \
- $(top_builddir)/src/libiu/libiu.a \
- $(LIBOSMOSIGTRAN_LIBS) \
- $(LIBOSMORANAP_LIBS) \
- $(LIBASN1C_LIBS) \
- $(NULL)
-endif
-
-osmo_gtphub_SOURCES = \
- gtphub_main.c \
- gtphub.c \
- gtphub_sock.c \
- gtphub_ares.c \
- gtphub_vty.c \
- sgsn_ares.c \
- gprs_utils.c \
- $(NULL)
-osmo_gtphub_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMOVTY_LIBS) \
- $(LIBCARES_LIBS) \
- $(LIBGTP_LIBS) \
- -lrt \
- $(NULL)
diff --git a/openbsc/src/gprs/crc24.c b/openbsc/src/gprs/crc24.c
deleted file mode 100644
index 1a420ed66..000000000
--- a/openbsc/src/gprs/crc24.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/* GPRS LLC CRC-24 Implementation */
-
-/* (C) 2008-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 <openbsc/crc24.h>
-
-/* CRC24 table - FCS */
-static const uint32_t tbl_crc24[256] = {
- 0x00000000, 0x00d6a776, 0x00f64557, 0x0020e221, 0x00b78115, 0x00612663, 0x0041c442, 0x00976334,
- 0x00340991, 0x00e2aee7, 0x00c24cc6, 0x0014ebb0, 0x00838884, 0x00552ff2, 0x0075cdd3, 0x00a36aa5,
- 0x00681322, 0x00beb454, 0x009e5675, 0x0048f103, 0x00df9237, 0x00093541, 0x0029d760, 0x00ff7016,
- 0x005c1ab3, 0x008abdc5, 0x00aa5fe4, 0x007cf892, 0x00eb9ba6, 0x003d3cd0, 0x001ddef1, 0x00cb7987,
- 0x00d02644, 0x00068132, 0x00266313, 0x00f0c465, 0x0067a751, 0x00b10027, 0x0091e206, 0x00474570,
- 0x00e42fd5, 0x003288a3, 0x00126a82, 0x00c4cdf4, 0x0053aec0, 0x008509b6, 0x00a5eb97, 0x00734ce1,
- 0x00b83566, 0x006e9210, 0x004e7031, 0x0098d747, 0x000fb473, 0x00d91305, 0x00f9f124, 0x002f5652,
- 0x008c3cf7, 0x005a9b81, 0x007a79a0, 0x00acded6, 0x003bbde2, 0x00ed1a94, 0x00cdf8b5, 0x001b5fc3,
- 0x00fb4733, 0x002de045, 0x000d0264, 0x00dba512, 0x004cc626, 0x009a6150, 0x00ba8371, 0x006c2407,
- 0x00cf4ea2, 0x0019e9d4, 0x00390bf5, 0x00efac83, 0x0078cfb7, 0x00ae68c1, 0x008e8ae0, 0x00582d96,
- 0x00935411, 0x0045f367, 0x00651146, 0x00b3b630, 0x0024d504, 0x00f27272, 0x00d29053, 0x00043725,
- 0x00a75d80, 0x0071faf6, 0x005118d7, 0x0087bfa1, 0x0010dc95, 0x00c67be3, 0x00e699c2, 0x00303eb4,
- 0x002b6177, 0x00fdc601, 0x00dd2420, 0x000b8356, 0x009ce062, 0x004a4714, 0x006aa535, 0x00bc0243,
- 0x001f68e6, 0x00c9cf90, 0x00e92db1, 0x003f8ac7, 0x00a8e9f3, 0x007e4e85, 0x005eaca4, 0x00880bd2,
- 0x00437255, 0x0095d523, 0x00b53702, 0x00639074, 0x00f4f340, 0x00225436, 0x0002b617, 0x00d41161,
- 0x00777bc4, 0x00a1dcb2, 0x00813e93, 0x005799e5, 0x00c0fad1, 0x00165da7, 0x0036bf86, 0x00e018f0,
- 0x00ad85dd, 0x007b22ab, 0x005bc08a, 0x008d67fc, 0x001a04c8, 0x00cca3be, 0x00ec419f, 0x003ae6e9,
- 0x00998c4c, 0x004f2b3a, 0x006fc91b, 0x00b96e6d, 0x002e0d59, 0x00f8aa2f, 0x00d8480e, 0x000eef78,
- 0x00c596ff, 0x00133189, 0x0033d3a8, 0x00e574de, 0x007217ea, 0x00a4b09c, 0x008452bd, 0x0052f5cb,
- 0x00f19f6e, 0x00273818, 0x0007da39, 0x00d17d4f, 0x00461e7b, 0x0090b90d, 0x00b05b2c, 0x0066fc5a,
- 0x007da399, 0x00ab04ef, 0x008be6ce, 0x005d41b8, 0x00ca228c, 0x001c85fa, 0x003c67db, 0x00eac0ad,
- 0x0049aa08, 0x009f0d7e, 0x00bfef5f, 0x00694829, 0x00fe2b1d, 0x00288c6b, 0x00086e4a, 0x00dec93c,
- 0x0015b0bb, 0x00c317cd, 0x00e3f5ec, 0x0035529a, 0x00a231ae, 0x007496d8, 0x005474f9, 0x0082d38f,
- 0x0021b92a, 0x00f71e5c, 0x00d7fc7d, 0x00015b0b, 0x0096383f, 0x00409f49, 0x00607d68, 0x00b6da1e,
- 0x0056c2ee, 0x00806598, 0x00a087b9, 0x007620cf, 0x00e143fb, 0x0037e48d, 0x001706ac, 0x00c1a1da,
- 0x0062cb7f, 0x00b46c09, 0x00948e28, 0x0042295e, 0x00d54a6a, 0x0003ed1c, 0x00230f3d, 0x00f5a84b,
- 0x003ed1cc, 0x00e876ba, 0x00c8949b, 0x001e33ed, 0x008950d9, 0x005ff7af, 0x007f158e, 0x00a9b2f8,
- 0x000ad85d, 0x00dc7f2b, 0x00fc9d0a, 0x002a3a7c, 0x00bd5948, 0x006bfe3e, 0x004b1c1f, 0x009dbb69,
- 0x0086e4aa, 0x005043dc, 0x0070a1fd, 0x00a6068b, 0x003165bf, 0x00e7c2c9, 0x00c720e8, 0x0011879e,
- 0x00b2ed3b, 0x00644a4d, 0x0044a86c, 0x00920f1a, 0x00056c2e, 0x00d3cb58, 0x00f32979, 0x00258e0f,
- 0x00eef788, 0x003850fe, 0x0018b2df, 0x00ce15a9, 0x0059769d, 0x008fd1eb, 0x00af33ca, 0x007994bc,
- 0x00dafe19, 0x000c596f, 0x002cbb4e, 0x00fa1c38, 0x006d7f0c, 0x00bbd87a, 0x009b3a5b, 0x004d9d2d
-};
-
-#define INIT_CRC24 0xffffff
-
-uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len)
-{
- while (len--)
- fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff];
- return fcs;
-}
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
deleted file mode 100644
index cd38d23bf..000000000
--- a/openbsc/src/gprs/gb_proxy.c
+++ /dev/null
@@ -1,1438 +0,0 @@
-/* NS-over-IP proxy */
-
-/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010-2013 by On-Waves
- * (C) 2013 by Holger Hans Peter Freyther
- * 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 <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <errno.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-#include <arpa/inet.h>
-#include <time.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/stats.h>
-
-#include <osmocom/gprs/gprs_ns.h>
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#include <osmocom/gsm/gsm_utils.h>
-
-#include <openbsc/signal.h>
-#include <openbsc/debug.h>
-#include <openbsc/gprs_gb_parse.h>
-#include <openbsc/gb_proxy.h>
-
-#include <openbsc/gprs_llc.h>
-#include <openbsc/gsm_04_08.h>
-#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
-#include <openbsc/gprs_utils.h>
-
-#include <openssl/rand.h>
-
-static const struct rate_ctr_desc global_ctr_description[] = {
- { "inv-bvci", "Invalid BVC Identifier " },
- { "inv-lai", "Invalid Location Area Identifier" },
- { "inv-rai", "Invalid Routing Area Identifier " },
- { "inv-nsei", "No BVC established for NSEI " },
- { "proto-err.bss", "BSSGP protocol error (BSS )" },
- { "proto-err.sgsn", "BSSGP protocol error (SGSN)" },
- { "not-supp.bss", "Feature not supported (BSS )" },
- { "not-supp.sgsn", "Feature not supported (SGSN)" },
- { "restart.sgsn", "Restarted RESET procedure (SGSN)" },
- { "tx-err.sgsn", "NS Transmission error (SGSN)" },
- { "error", "Other error " },
- { "mod-peer-err", "Patch error: no peer " },
-};
-
-static const struct rate_ctr_group_desc global_ctrg_desc = {
- .group_name_prefix = "gbproxy.global",
- .group_description = "GBProxy Global Statistics",
- .num_ctr = ARRAY_SIZE(global_ctr_description),
- .ctr_desc = global_ctr_description,
- .class_id = OSMO_STATS_CLASS_GLOBAL,
-};
-
-static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_peer *peer,
- uint16_t ns_bvci);
-static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
- uint16_t ns_bvci, uint16_t sgsn_nsei);
-static void gbproxy_reset_imsi_acquisition(struct gbproxy_link_info* link_info);
-
-static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei)
-{
- if (peer->nsei != nsei) {
- LOGP(DGPRS, LOGL_NOTICE, "Peer entry doesn't match current NSEI "
- "BVCI=%u via NSEI=%u (expected NSEI=%u)\n",
- peer->bvci, nsei, peer->nsei);
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_INV_NSEI]);
- return 0;
- }
-
- return 1;
-}
-
-/* strip off the NS header */
-static void strip_ns_hdr(struct msgb *msg)
-{
- int strip_len = msgb_bssgph(msg) - msg->data;
- msgb_pull(msg, strip_len);
-}
-
-/* Transmit Chapter 9.2.10 Identity Request */
-static void gprs_put_identity_req(struct msgb *msg, uint8_t id_type)
-{
- struct gsm48_hdr *gh;
-
- id_type &= GSM_MI_TYPE_MASK;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_ID_REQ;
- gh->data[0] = id_type;
-}
-
-/* Transmit Chapter 9.4.6.2 Detach Accept (mobile originated detach) */
-static void gprs_put_mo_detach_acc(struct msgb *msg)
-{
- struct gsm48_hdr *gh;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_DETACH_ACK;
- gh->data[0] = 0; /* no force to standby */
-}
-
-static void gprs_push_llc_ui(struct msgb *msg,
- int is_uplink, unsigned sapi, unsigned nu)
-{
- const uint8_t e_bit = 0;
- const uint8_t pm_bit = 1;
- const uint8_t cr_bit = is_uplink ? 0 : 1;
- uint8_t *llc;
- uint8_t *fcs_field;
- uint32_t fcs;
-
- nu &= 0x01ff; /* 9 Bit */
-
- llc = msgb_push(msg, 3);
- llc[0] = (cr_bit << 6) | (sapi & 0x0f);
- llc[1] = 0xc0 | (nu >> 6); /* UI frame */
- llc[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1);
-
- fcs = gprs_llc_fcs(llc, msgb_length(msg));
- fcs_field = msgb_put(msg, 3);
- fcs_field[0] = (uint8_t)(fcs >> 0);
- fcs_field[1] = (uint8_t)(fcs >> 8);
- fcs_field[2] = (uint8_t)(fcs >> 16);
-}
-
-static void gprs_push_bssgp_dl_unitdata(struct msgb *msg,
- uint32_t tlli)
-{
- struct bssgp_ud_hdr *budh;
- uint8_t *llc = msgb_data(msg);
- size_t llc_size = msgb_length(msg);
- const size_t llc_ie_hdr_size = 3;
- const uint8_t qos_profile[] = {0x00, 0x50, 0x20}; /* hard-coded */
- const uint8_t lifetime[] = {0x02, 0x58}; /* 6s hard-coded */
-
- const size_t bssgp_overhead = sizeof(*budh) +
- TVLV_GROSS_LEN(sizeof(lifetime)) + llc_ie_hdr_size;
- uint8_t *ie;
- uint32_t tlli_be = htonl(tlli);
-
- budh = (struct bssgp_ud_hdr *)msgb_push(msg, bssgp_overhead);
-
- budh->pdu_type = BSSGP_PDUT_DL_UNITDATA;
- memcpy(&budh->tlli, &tlli_be, sizeof(budh->tlli));
- memcpy(&budh->qos_profile, qos_profile, sizeof(budh->qos_profile));
-
- ie = budh->data;
- tvlv_put(ie, BSSGP_IE_PDU_LIFETIME, sizeof(lifetime), lifetime);
- ie += TVLV_GROSS_LEN(sizeof(lifetime));
-
- /* Note: Add alignment before the LLC IE if inserting other IE */
-
- *(ie++) = BSSGP_IE_LLC_PDU;
- *(ie++) = llc_size / 256;
- *(ie++) = llc_size % 256;
-
- OSMO_ASSERT(ie == llc);
-
- msgb_bssgph(msg) = (uint8_t *)budh;
- msgb_tlli(msg) = tlli;
-}
-
-/* update peer according to the BSS message */
-static void gbprox_update_current_raid(uint8_t *raid_enc,
- struct gbproxy_peer *peer,
- const char *log_text)
-{
- struct gbproxy_patch_state *state = &peer->patch_state;
- const int old_local_mcc = state->local_mcc;
- const int old_local_mnc = state->local_mnc;
- struct gprs_ra_id raid;
-
- if (!raid_enc)
- return;
-
- gsm48_parse_ra(&raid, raid_enc);
-
- /* save source side MCC/MNC */
- if (!peer->cfg->core_mcc || raid.mcc == peer->cfg->core_mcc) {
- state->local_mcc = 0;
- } else {
- state->local_mcc = raid.mcc;
- }
-
- if (!peer->cfg->core_mnc || raid.mnc == peer->cfg->core_mnc) {
- state->local_mnc = 0;
- } else {
- state->local_mnc = raid.mnc;
- }
-
- if (old_local_mcc != state->local_mcc ||
- old_local_mnc != state->local_mnc)
- LOGP(DGPRS, LOGL_NOTICE,
- "Patching RAID %sactivated, msg: %s, "
- "local: %d-%d, core: %d-%d\n",
- state->local_mcc || state->local_mnc ?
- "" : "de",
- log_text,
- state->local_mcc, state->local_mnc,
- peer->cfg->core_mcc, peer->cfg->core_mnc);
-}
-
-uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer,
- uint32_t sgsn_ptmsi)
-{
- uint32_t bss_ptmsi;
- int max_retries = 23;
- if (!peer->cfg->patch_ptmsi) {
- bss_ptmsi = sgsn_ptmsi;
- } else {
- do {
- if (RAND_bytes((uint8_t *) &bss_ptmsi, sizeof(bss_ptmsi)) != 1) {
- bss_ptmsi = GSM_RESERVED_TMSI;
- break;
- }
-
- bss_ptmsi = bss_ptmsi | 0xC0000000;
-
- if (gbproxy_link_info_by_ptmsi(peer, bss_ptmsi))
- bss_ptmsi = GSM_RESERVED_TMSI;
- } while (bss_ptmsi == GSM_RESERVED_TMSI && max_retries--);
- }
-
- if (bss_ptmsi == GSM_RESERVED_TMSI)
- LOGP(DGPRS, LOGL_ERROR, "Failed to allocate a BSS P-TMSI\n");
-
- return bss_ptmsi;
-}
-
-uint32_t gbproxy_make_sgsn_tlli(struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info,
- uint32_t bss_tlli)
-{
- uint32_t sgsn_tlli;
- int max_retries = 23;
- if (!peer->cfg->patch_ptmsi) {
- sgsn_tlli = bss_tlli;
- } else if (link_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI &&
- gprs_tlli_type(bss_tlli) == TLLI_FOREIGN) {
- sgsn_tlli = gprs_tmsi2tlli(link_info->sgsn_tlli.ptmsi,
- TLLI_FOREIGN);
- } else if (link_info->sgsn_tlli.ptmsi != GSM_RESERVED_TMSI &&
- gprs_tlli_type(bss_tlli) == TLLI_LOCAL) {
- sgsn_tlli = gprs_tmsi2tlli(link_info->sgsn_tlli.ptmsi,
- TLLI_LOCAL);
- } else {
- do {
- /* create random TLLI, 0b01111xxx... */
- if (RAND_bytes((uint8_t *) &sgsn_tlli, sizeof(sgsn_tlli)) != 1) {
- sgsn_tlli = 0;
- break;
- }
-
- sgsn_tlli = (sgsn_tlli & 0x7fffffff) | 0x78000000;
-
- if (gbproxy_link_info_by_any_sgsn_tlli(peer, sgsn_tlli))
- sgsn_tlli = 0;
- } while (!sgsn_tlli && max_retries--);
- }
-
- if (!sgsn_tlli)
- LOGP(DGPRS, LOGL_ERROR, "Failed to allocate an SGSN TLLI\n");
-
- return sgsn_tlli;
-}
-
-void gbproxy_reset_link(struct gbproxy_link_info *link_info)
-{
- gbproxy_reset_imsi_acquisition(link_info);
-}
-
-/* Returns != 0 iff IMSI acquisition was in progress */
-static int gbproxy_restart_imsi_acquisition(struct gbproxy_link_info* link_info)
-{
- int in_progress = 0;
- if (!link_info)
- return 0;
-
- if (link_info->imsi_acq_pending)
- in_progress = 1;
-
- gbproxy_link_info_discard_messages(link_info);
- link_info->imsi_acq_pending = 0;
-
- return in_progress;
-}
-
-static void gbproxy_reset_imsi_acquisition(struct gbproxy_link_info* link_info)
-{
- gbproxy_restart_imsi_acquisition(link_info);
- link_info->vu_gen_tx_bss = GBPROXY_INIT_VU_GEN_TX;
-}
-
-static int gbproxy_flush_stored_messages(struct gbproxy_peer *peer,
- struct msgb *msg,
- time_t now,
- struct gbproxy_link_info* link_info,
- struct gprs_gb_parse_context *parse_ctx)
-{
- int rc;
- struct msgb *stored_msg;
- /* Got identity response with IMSI, assuming the request had
- * been generated by the gbproxy */
-
- LOGP(DLLC, LOGL_DEBUG,
- "NSEI=%d(BSS) IMSI acquisition succeeded, "
- "flushing stored messages\n",
- msgb_nsei(msg));
-
- /* Patch and flush stored messages towards the SGSN */
- while ((stored_msg = msgb_dequeue(&link_info->stored_msgs))) {
- struct gprs_gb_parse_context tmp_parse_ctx = {0};
- tmp_parse_ctx.to_bss = 0;
- tmp_parse_ctx.peer_nsei = msgb_nsei(stored_msg);
- int len_change = 0;
-
- gprs_gb_parse_bssgp(msgb_bssgph(stored_msg),
- msgb_bssgp_len(stored_msg),
- &tmp_parse_ctx);
- gbproxy_patch_bssgp(msg, msgb_bssgph(stored_msg),
- msgb_bssgp_len(stored_msg),
- peer, link_info, &len_change,
- &tmp_parse_ctx);
-
- rc = gbproxy_update_link_state_after(peer, link_info, now,
- &tmp_parse_ctx);
- if (rc == 1) {
- LOGP(DLLC, LOGL_NOTICE, "link_info deleted while flushing stored messages\n");
- msgb_free(stored_msg);
- return -1;
- }
-
- rc = gbprox_relay2sgsn(peer->cfg, stored_msg,
- msgb_bvci(msg), link_info->sgsn_nsei);
-
- if (rc < 0)
- LOGP(DLLC, LOGL_ERROR,
- "NSEI=%d(BSS) failed to send stored message "
- "(%s)\n",
- msgb_nsei(msg),
- parse_ctx->llc_msg_name ?
- parse_ctx->llc_msg_name : "BSSGP");
- msgb_free(stored_msg);
- }
-
- return 0;
-}
-
-static int gbproxy_gsm48_to_peer(struct gbproxy_peer *peer,
- struct gbproxy_link_info* link_info,
- uint16_t bvci,
- struct msgb *msg /* Takes msg ownership */)
-{
- int rc;
-
- /* Workaround to avoid N(U) collisions and to enable a restart
- * of the IMSI acquisition procedure. This will work unless the
- * SGSN has an initial V(UT) within [256-32, 256+n_retries]
- * (see GSM 04.64, 8.4.2). */
- gprs_push_llc_ui(msg, 0, GPRS_SAPI_GMM, link_info->vu_gen_tx_bss);
- link_info->vu_gen_tx_bss = (link_info->vu_gen_tx_bss + 1) % 512;
-
- gprs_push_bssgp_dl_unitdata(msg, link_info->tlli.current);
- rc = gbprox_relay2peer(msg, peer, bvci);
- msgb_free(msg);
- return rc;
-}
-
-static void gbproxy_acquire_imsi(struct gbproxy_peer *peer,
- struct gbproxy_link_info* link_info,
- uint16_t bvci)
-{
- struct msgb *idreq_msg;
-
- /* Send IDENT REQ */
- idreq_msg = gsm48_msgb_alloc_name("GSM 04.08 ACQ IMSI");
- gprs_put_identity_req(idreq_msg, GSM_MI_TYPE_IMSI);
- gbproxy_gsm48_to_peer(peer, link_info, bvci, idreq_msg);
-}
-
-static void gbproxy_tx_detach_acc(struct gbproxy_peer *peer,
- struct gbproxy_link_info* link_info,
- uint16_t bvci)
-{
- struct msgb *detacc_msg;
-
- /* Send DETACH ACC */
- detacc_msg = gsm48_msgb_alloc_name("GSM 04.08 DET ACC");
- gprs_put_mo_detach_acc(detacc_msg);
- gbproxy_gsm48_to_peer(peer, link_info, bvci, detacc_msg);
-}
-
-/* Return != 0 iff msg still needs to be processed */
-static int gbproxy_imsi_acquisition(struct gbproxy_peer *peer,
- struct msgb *msg,
- time_t now,
- struct gbproxy_link_info* link_info,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct msgb *stored_msg;
-
- if (!link_info)
- return 1;
-
- if (!link_info->imsi_acq_pending && link_info->imsi_len > 0)
- return 1;
-
- if (parse_ctx->g48_hdr)
- switch (parse_ctx->g48_hdr->msg_type)
- {
- case GSM48_MT_GMM_RA_UPD_REQ:
- case GSM48_MT_GMM_ATTACH_REQ:
- if (gbproxy_restart_imsi_acquisition(link_info)) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(BSS) IMSI acquisition was in progress "
- "when receiving an %s.\n",
- msgb_nsei(msg), parse_ctx->llc_msg_name);
- }
- break;
- case GSM48_MT_GMM_DETACH_REQ:
- /* Nothing has been sent to the SGSN yet */
- if (link_info->imsi_acq_pending) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(BSS) IMSI acquisition was in progress "
- "when receiving a DETACH_REQ.\n",
- msgb_nsei(msg));
- }
- if (!parse_ctx->invalidate_tlli) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(BSS) IMSI not yet acquired, "
- "faking a DETACH_ACC.\n",
- msgb_nsei(msg));
- gbproxy_tx_detach_acc(peer, link_info, msgb_bvci(msg));
- parse_ctx->invalidate_tlli = 1;
- }
- gbproxy_reset_imsi_acquisition(link_info);
- gbproxy_update_link_state_after(peer, link_info, now,
- parse_ctx);
- return 0;
- }
-
- if (link_info->imsi_acq_pending && link_info->imsi_len > 0) {
- int is_ident_resp =
- parse_ctx->g48_hdr &&
- gsm48_hdr_pdisc(parse_ctx->g48_hdr) == GSM48_PDISC_MM_GPRS &&
- gsm48_hdr_msg_type(parse_ctx->g48_hdr) == GSM48_MT_GMM_ID_RESP;
-
- /* The IMSI is now available. If flushing the messages fails,
- * then link_info has been deleted and we should return
- * immediately. */
- if (gbproxy_flush_stored_messages(peer, msg, now, link_info,
- parse_ctx) < 0)
- return 0;
-
- gbproxy_reset_imsi_acquisition(link_info);
-
- /* This message is most probably the response to the ident
- * request sent by gbproxy_acquire_imsi(). Don't forward it to
- * the SGSN. */
- return !is_ident_resp;
- }
-
- /* The message cannot be processed since the IMSI is still missing */
-
- /* Enqueue unpatched messages */
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(BSS) IMSI acquisition in progress, "
- "storing message (%s)\n",
- msgb_nsei(msg),
- parse_ctx->llc_msg_name ? parse_ctx->llc_msg_name : "BSSGP");
-
- stored_msg = gprs_msgb_copy(msg, "process_bssgp_ul");
- msgb_enqueue(&link_info->stored_msgs, stored_msg);
-
- if (!link_info->imsi_acq_pending) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(BSS) IMSI is required but not available, "
- "initiating identification procedure (%s)\n",
- msgb_nsei(msg),
- parse_ctx->llc_msg_name ? parse_ctx->llc_msg_name : "BSSGP");
-
- gbproxy_acquire_imsi(peer, link_info, msgb_bvci(msg));
-
- /* There is no explicit retransmission handling, the
- * implementation relies on the MS doing proper retransmissions
- * of the triggering message instead */
-
- link_info->imsi_acq_pending = 1;
- }
-
- return 0;
-}
-
-struct gbproxy_peer *gbproxy_find_peer(struct gbproxy_config *cfg,
- struct msgb *msg,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gbproxy_peer *peer = NULL;
-
- if (msgb_bvci(msg) >= 2)
- peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg));
-
- if (!peer && !parse_ctx->to_bss)
- peer = gbproxy_peer_by_nsei(cfg, msgb_nsei(msg));
-
- if (!peer)
- peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx->bssgp_tp);
-
- if (!peer) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(%s) patching: didn't find peer for message, "
- "PDU %d\n",
- msgb_nsei(msg), parse_ctx->to_bss ? "BSS" : "SGSN",
- parse_ctx->pdu_type);
- /* Increment counter */
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
- }
- return peer;
-}
-
-/* patch BSSGP message */
-static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
- struct msgb *msg,
- struct gbproxy_peer *peer)
-{
- struct gprs_gb_parse_context parse_ctx = {0};
- int rc;
- int len_change = 0;
- time_t now;
- struct timespec ts = {0,};
- struct gbproxy_link_info *link_info = NULL;
- uint32_t sgsn_nsei = cfg->nsip_sgsn_nsei;
-
- if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn &&
- !cfg->acquire_imsi && !cfg->patch_ptmsi && !cfg->route_to_sgsn2)
- return 1;
-
- parse_ctx.to_bss = 0;
- parse_ctx.peer_nsei = msgb_nsei(msg);
-
- /* Parse BSSGP/LLC */
- rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg),
- &parse_ctx);
-
- if (!rc && !parse_ctx.need_decryption) {
- LOGP(DGPRS, LOGL_ERROR,
- "NSEI=%u(BSS) patching: failed to parse invalid %s message\n",
- msgb_nsei(msg), gprs_gb_message_name(&parse_ctx, "NS_UNITDATA"));
- gprs_gb_log_parse_context(LOGL_NOTICE, &parse_ctx, "NS_UNITDATA");
- LOGP(DGPRS, LOGL_NOTICE,
- "NSEI=%u(BSS) invalid message was: %s\n",
- msgb_nsei(msg), msgb_hexdump(msg));
- return 0;
- }
-
- /* Get peer */
- if (!peer)
- peer = gbproxy_find_peer(cfg, msg, &parse_ctx);
-
- if (!peer)
- return 0;
-
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
- now = ts.tv_sec;
-
- gbprox_update_current_raid(parse_ctx.bssgp_raid_enc, peer,
- parse_ctx.llc_msg_name);
-
- gprs_gb_log_parse_context(LOGL_DEBUG, &parse_ctx, "NS_UNITDATA");
-
- link_info = gbproxy_update_link_state_ul(peer, now, &parse_ctx);
-
- if (parse_ctx.g48_hdr) {
- switch (parse_ctx.g48_hdr->msg_type) {
- case GSM48_MT_GMM_ATTACH_REQ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REQS]);
- break;
- case GSM48_MT_GMM_DETACH_REQ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_DETACH_REQS]);
- break;
- case GSM48_MT_GMM_ATTACH_COMPL:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_COMPLS]);
- break;
- case GSM48_MT_GMM_RA_UPD_REQ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_REQS]);
- break;
- case GSM48_MT_GMM_RA_UPD_COMPL:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_COMPLS]);
- break;
- case GSM48_MT_GMM_STATUS:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_GMM_STATUS_BSS]);
- break;
- case GSM48_MT_GSM_ACT_PDP_REQ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_REQS]);
- break;
- case GSM48_MT_GSM_DEACT_PDP_REQ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_DEACT_REQS]);
- break;
-
- default:
- break;
- }
- }
-
- if (link_info && cfg->route_to_sgsn2) {
- if (cfg->acquire_imsi && link_info->imsi_len == 0)
- sgsn_nsei = 0xffff;
- else if (gbproxy_imsi_matches(cfg, GBPROX_MATCH_ROUTING,
- link_info))
- sgsn_nsei = cfg->nsip_sgsn2_nsei;
- }
-
- if (link_info)
- link_info->sgsn_nsei = sgsn_nsei;
-
- /* Handle IMSI acquisition */
- if (cfg->acquire_imsi) {
- rc = gbproxy_imsi_acquisition(peer, msg, now, link_info,
- &parse_ctx);
- if (rc <= 0)
- return rc;
- }
-
- gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg),
- peer, link_info, &len_change, &parse_ctx);
-
- gbproxy_update_link_state_after(peer, link_info, now, &parse_ctx);
-
- if (sgsn_nsei != cfg->nsip_sgsn_nsei) {
- /* Send message directly to the selected SGSN */
- rc = gbprox_relay2sgsn(cfg, msg, msgb_bvci(msg), sgsn_nsei);
- /* Don't let the calling code handle the transmission */
- return 0;
- }
-
- return 1;
-}
-
-/* patch BSSGP message to use core_mcc/mnc on the SGSN side */
-static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg,
- struct msgb *msg,
- struct gbproxy_peer *peer)
-{
- struct gprs_gb_parse_context parse_ctx = {0};
- int rc;
- int len_change = 0;
- time_t now;
- struct timespec ts = {0,};
- struct gbproxy_link_info *link_info = NULL;
-
- if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn &&
- !cfg->acquire_imsi && !cfg->patch_ptmsi && !cfg->route_to_sgsn2)
- return;
-
- parse_ctx.to_bss = 1;
- parse_ctx.peer_nsei = msgb_nsei(msg);
-
- rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg),
- &parse_ctx);
-
- if (!rc && !parse_ctx.need_decryption) {
- LOGP(DGPRS, LOGL_ERROR,
- "NSEI=%u(SGSN) patching: failed to parse invalid %s message\n",
- msgb_nsei(msg), gprs_gb_message_name(&parse_ctx, "NS_UNITDATA"));
- gprs_gb_log_parse_context(LOGL_NOTICE, &parse_ctx, "NS_UNITDATA");
- LOGP(DGPRS, LOGL_NOTICE,
- "NSEI=%u(SGSN) invalid message was: %s\n",
- msgb_nsei(msg), msgb_hexdump(msg));
- return;
- }
-
- /* Get peer */
- if (!peer)
- peer = gbproxy_find_peer(cfg, msg, &parse_ctx);
-
- if (!peer)
- return;
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
- now = ts.tv_sec;
-
- if (parse_ctx.g48_hdr) {
- switch (parse_ctx.g48_hdr->msg_type) {
- case GSM48_MT_GMM_ATTACH_ACK:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_ACKS]);
- break;
- case GSM48_MT_GMM_ATTACH_REJ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REJS]);
- break;
- case GSM48_MT_GMM_DETACH_ACK:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_DETACH_ACKS]);
- break;
- case GSM48_MT_GMM_RA_UPD_ACK:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_ACKS]);
- break;
- case GSM48_MT_GMM_RA_UPD_REJ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_RA_UPD_REJS]);
- break;
- case GSM48_MT_GMM_STATUS:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_GMM_STATUS_SGSN]);
- break;
- case GSM48_MT_GSM_ACT_PDP_ACK:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_ACKS]);
- break;
- case GSM48_MT_GSM_ACT_PDP_REJ:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_ACT_REJS]);
- break;
- case GSM48_MT_GSM_DEACT_PDP_ACK:
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_PDP_DEACT_ACKS]);
- break;
-
- default:
- break;
- }
- }
-
- gprs_gb_log_parse_context(LOGL_DEBUG, &parse_ctx, "NS_UNITDATA");
-
- link_info = gbproxy_update_link_state_dl(peer, now, &parse_ctx);
-
- gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg),
- peer, link_info, &len_change, &parse_ctx);
-
- gbproxy_update_link_state_after(peer, link_info, now, &parse_ctx);
-
- return;
-}
-
-/* feed a message down the NS-VC associated with the specified peer */
-static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
- uint16_t ns_bvci, uint16_t sgsn_nsei)
-{
- /* create a copy of the message so the old one can
- * be free()d safely when we return from gbprox_rcvmsg() */
- struct msgb *msg = gprs_msgb_copy(old_msg, "msgb_relay2sgsn");
- int rc;
-
- DEBUGP(DGPRS, "NSEI=%u proxying BTS->SGSN (NS_BVCI=%u, NSEI=%u)\n",
- msgb_nsei(msg), ns_bvci, sgsn_nsei);
-
- msgb_bvci(msg) = ns_bvci;
- msgb_nsei(msg) = sgsn_nsei;
-
- strip_ns_hdr(msg);
-
- rc = gprs_ns_sendmsg(bssgp_nsi, msg);
- if (rc < 0)
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_TX_ERR_SGSN]);
-
- return rc;
-}
-
-/* feed a message down the NS-VC associated with the specified peer */
-static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_peer *peer,
- uint16_t ns_bvci)
-{
- /* create a copy of the message so the old one can
- * be free()d safely when we return from gbprox_rcvmsg() */
- struct msgb *msg = gprs_msgb_copy(old_msg, "msgb_relay2peer");
- int rc;
-
- DEBUGP(DGPRS, "NSEI=%u proxying SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n",
- msgb_nsei(msg), ns_bvci, peer->nsei);
-
- msgb_bvci(msg) = ns_bvci;
- msgb_nsei(msg) = peer->nsei;
-
- /* Strip the old NS header, it will be replaced with a new one */
- strip_ns_hdr(msg);
-
- rc = gprs_ns_sendmsg(bssgp_nsi, msg);
- if (rc < 0)
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_TX_ERR]);
-
- return rc;
-}
-
-static int block_unblock_peer(struct gbproxy_config *cfg, uint16_t ptp_bvci, uint8_t pdu_type)
-{
- struct gbproxy_peer *peer;
-
- peer = gbproxy_peer_by_bvci(cfg, ptp_bvci);
- if (!peer) {
- LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n",
- ptp_bvci);
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);
- return -ENOENT;
- }
-
- switch (pdu_type) {
- case BSSGP_PDUT_BVC_BLOCK_ACK:
- peer->blocked = 1;
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_BLOCKED]);
- break;
- case BSSGP_PDUT_BVC_UNBLOCK_ACK:
- peer->blocked = 0;
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_UNBLOCKED]);
- break;
- default:
- break;
- }
- return 0;
-}
-
-/* Send a message to a peer identified by ptp_bvci but using ns_bvci
- * in the NS hdr */
-static int gbprox_relay2bvci(struct gbproxy_config *cfg, struct msgb *msg, uint16_t ptp_bvci,
- uint16_t ns_bvci)
-{
- struct gbproxy_peer *peer;
-
- peer = gbproxy_peer_by_bvci(cfg, ptp_bvci);
- if (!peer) {
- LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n",
- ptp_bvci);
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_BVCI]);
- return -ENOENT;
- }
-
- return gbprox_relay2peer(msg, peer, ns_bvci);
-}
-
-int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
-{
- return 0;
-}
-
-/* Receive an incoming PTP message from a BSS-side NS-VC */
-static int gbprox_rx_ptp_from_bss(struct gbproxy_config *cfg,
- struct msgb *msg, uint16_t nsei,
- uint16_t nsvci, uint16_t ns_bvci)
-{
- struct gbproxy_peer *peer;
- struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
- uint8_t pdu_type = bgph->pdu_type;
- int rc;
-
- peer = gbproxy_peer_by_bvci(cfg, ns_bvci);
- if (!peer) {
- LOGP(DGPRS, LOGL_NOTICE, "Didn't find peer for "
- "BVCI=%u for PTP message from NSVC=%u/NSEI=%u (BSS), "
- "discarding message\n",
- ns_bvci, nsvci, nsei);
- return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
- &ns_bvci, msg);
- }
-
- check_peer_nsei(peer, nsei);
-
- rc = gbprox_process_bssgp_ul(cfg, msg, peer);
- if (!rc)
- return 0;
-
- switch (pdu_type) {
- case BSSGP_PDUT_FLOW_CONTROL_BVC:
- if (!cfg->route_to_sgsn2)
- break;
-
- /* Send a copy to the secondary SGSN */
- gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn2_nsei);
- break;
- default:
- break;
- }
-
-
- return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);
-}
-
-/* Receive an incoming PTP message from a SGSN-side NS-VC */
-static int gbprox_rx_ptp_from_sgsn(struct gbproxy_config *cfg,
- struct msgb *msg, uint16_t nsei,
- uint16_t nsvci, uint16_t ns_bvci)
-{
- struct gbproxy_peer *peer;
- struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
- uint8_t pdu_type = bgph->pdu_type;
-
- peer = gbproxy_peer_by_bvci(cfg, ns_bvci);
-
- /* Send status messages before patching */
-
- if (!peer) {
- LOGP(DGPRS, LOGL_INFO, "Didn't find peer for "
- "BVCI=%u for message from NSVC=%u/NSEI=%u (SGSN)\n",
- ns_bvci, nsvci, nsei);
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_INV_BVCI]);
- return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
- &ns_bvci, msg);
- }
-
- if (peer->blocked) {
- LOGP(DGPRS, LOGL_NOTICE, "Dropping PDU for "
- "blocked BVCI=%u via NSVC=%u/NSEI=%u\n",
- ns_bvci, nsvci, nsei);
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_DROPPED]);
- return bssgp_tx_status(BSSGP_CAUSE_BVCI_BLOCKED, &ns_bvci, msg);
- }
-
- switch (pdu_type) {
- case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
- case BSSGP_PDUT_BVC_BLOCK_ACK:
- case BSSGP_PDUT_BVC_UNBLOCK_ACK:
- if (cfg->route_to_sgsn2 && nsei == cfg->nsip_sgsn2_nsei)
- /* Hide ACKs from the secondary SGSN, the primary SGSN
- * is responsible to send them. */
- return 0;
- break;
- default:
- break;
- }
-
- /* Optionally patch the message */
- gbprox_process_bssgp_dl(cfg, msg, peer);
-
- return gbprox_relay2peer(msg, peer, ns_bvci);
-}
-
-/* Receive an incoming signalling message from a BSS-side NS-VC */
-static int gbprox_rx_sig_from_bss(struct gbproxy_config *cfg,
- struct msgb *msg, uint16_t nsei,
- uint16_t ns_bvci)
-{
- struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
- struct tlv_parsed tp;
- uint8_t pdu_type = bgph->pdu_type;
- int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
- struct gbproxy_peer *from_peer = NULL;
- struct gprs_ra_id raid;
- int copy_to_sgsn2 = 0;
- int rc;
-
- if (ns_bvci != 0 && ns_bvci != 1) {
- LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u BVCI=%u is not signalling\n",
- nsei, ns_bvci);
- return -EINVAL;
- }
-
- /* we actually should never see those two for BVCI == 0, but double-check
- * just to make sure */
- if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
- pdu_type == BSSGP_PDUT_DL_UNITDATA) {
- LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u UNITDATA not allowed in "
- "signalling\n", nsei);
- return -EINVAL;
- }
-
- bssgp_tlv_parse(&tp, bgph->data, data_len);
-
- switch (pdu_type) {
- case BSSGP_PDUT_SUSPEND:
- case BSSGP_PDUT_RESUME:
- /* We implement RAI snooping during SUSPEND/RESUME, since it
- * establishes a relationsip between BVCI/peer and the routeing
- * area identification. The snooped information is then used
- * for routing the {SUSPEND,RESUME}_[N]ACK back to the correct
- * BSSGP */
- if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
- goto err_mand_ie;
- from_peer = gbproxy_peer_by_nsei(cfg, nsei);
- if (!from_peer)
- goto err_no_peer;
- memcpy(from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
- sizeof(from_peer->ra));
- gsm48_parse_ra(&raid, from_peer->ra);
- LOGP(DGPRS, LOGL_INFO, "NSEI=%u BSSGP SUSPEND/RESUME "
- "RAI snooping: RAI %u-%u-%u-%u behind BVCI=%u\n",
- nsei, raid.mcc, raid.mnc, raid.lac,
- raid.rac , from_peer->bvci);
- /* FIXME: This only supports one BSS per RA */
- break;
- case BSSGP_PDUT_BVC_RESET:
- /* If we receive a BVC reset on the signalling endpoint, we
- * don't want the SGSN to reset, as the signalling endpoint
- * is common for all point-to-point BVCs (and thus all BTS) */
- if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) {
- uint16_t bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
- LOGP(DGPRS, LOGL_INFO, "NSEI=%u Rx BVC RESET (BVCI=%u)\n",
- nsei, bvci);
- if (bvci == 0) {
- /* FIXME: only do this if SGSN is alive! */
- LOGP(DGPRS, LOGL_INFO, "NSEI=%u Tx fake "
- "BVC RESET ACK of BVCI=0\n", nsei);
- return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
- nsei, 0, ns_bvci);
- }
- from_peer = gbproxy_peer_by_bvci(cfg, bvci);
- if (!from_peer) {
- /* if a PTP-BVC is reset, and we don't know that
- * PTP-BVCI yet, we should allocate a new peer */
- LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for "
- "BVCI=%u via NSEI=%u\n", bvci, nsei);
- from_peer = gbproxy_peer_alloc(cfg, bvci);
- from_peer->nsei = nsei;
- }
-
- if (!check_peer_nsei(from_peer, nsei))
- from_peer->nsei = nsei;
-
- if (TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID)) {
- struct gprs_ra_id raid;
- /* We have a Cell Identifier present in this
- * PDU, this means we can extend our local
- * state information about this particular cell
- * */
- memcpy(from_peer->ra,
- TLVP_VAL(&tp, BSSGP_IE_CELL_ID),
- sizeof(from_peer->ra));
- gsm48_parse_ra(&raid, from_peer->ra);
- LOGP(DGPRS, LOGL_INFO, "NSEI=%u/BVCI=%u "
- "Cell ID %u-%u-%u-%u\n", nsei,
- bvci, raid.mcc, raid.mnc, raid.lac,
- raid.rac);
- }
- if (cfg->route_to_sgsn2)
- copy_to_sgsn2 = 1;
- }
- break;
- }
-
- /* Normally, we can simply pass on all signalling messages from BSS to
- * SGSN */
- rc = gbprox_process_bssgp_ul(cfg, msg, from_peer);
- if (!rc)
- return 0;
-
- if (copy_to_sgsn2)
- gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn2_nsei);
-
- return gbprox_relay2sgsn(cfg, msg, ns_bvci, cfg->nsip_sgsn_nsei);
-err_no_peer:
- LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) cannot find peer based on NSEI\n",
- nsei);
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_INV_NSEI]);
- return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, msg);
-err_mand_ie:
- LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) missing mandatory RA IE\n",
- nsei);
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PROTO_ERR_BSS]);
- return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
-}
-
-/* Receive paging request from SGSN, we need to relay to proper BSS */
-static int gbprox_rx_paging(struct gbproxy_config *cfg, struct msgb *msg, struct tlv_parsed *tp,
- uint32_t nsei, uint16_t ns_bvci)
-{
- struct gbproxy_peer *peer = NULL;
- int errctr = GBPROX_GLOB_CTR_PROTO_ERR_SGSN;
-
- LOGP(DGPRS, LOGL_INFO, "NSEI=%u(SGSN) BSSGP PAGING ",
- nsei);
- if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
- uint16_t bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
- LOGPC(DGPRS, LOGL_INFO, "routing by BVCI to peer BVCI=%u\n",
- bvci);
- errctr = GBPROX_GLOB_CTR_OTHER_ERR;
- } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
- peer = gbproxy_peer_by_rai(cfg, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
- LOGPC(DGPRS, LOGL_INFO, "routing by RAI to peer BVCI=%u\n",
- peer ? peer->bvci : -1);
- errctr = GBPROX_GLOB_CTR_INV_RAI;
- } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
- peer = gbproxy_peer_by_lai(cfg, TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA));
- LOGPC(DGPRS, LOGL_INFO, "routing by LAI to peer BVCI=%u\n",
- peer ? peer->bvci : -1);
- errctr = GBPROX_GLOB_CTR_INV_LAI;
- } else
- LOGPC(DGPRS, LOGL_INFO, "\n");
-
- if (!peer) {
- LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) BSSGP PAGING: "
- "unable to route, missing IE\n", nsei);
- rate_ctr_inc(&cfg->ctrg->ctr[errctr]);
- return -EINVAL;
- }
- return gbprox_relay2peer(msg, peer, ns_bvci);
-}
-
-/* Receive an incoming BVC-RESET message from the SGSN */
-static int rx_reset_from_sgsn(struct gbproxy_config *cfg,
- struct msgb *orig_msg,
- struct msgb *msg, struct tlv_parsed *tp,
- uint32_t nsei, uint16_t ns_bvci)
-{
- struct gbproxy_peer *peer;
- uint16_t ptp_bvci;
-
- if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
- return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE,
- NULL, orig_msg);
- }
- ptp_bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
-
- if (ptp_bvci >= 2) {
- /* A reset for a PTP BVC was received, forward it to its
- * respective peer */
- peer = gbproxy_peer_by_bvci(cfg, ptp_bvci);
- if (!peer) {
- LOGP(DGPRS, LOGL_ERROR, "NSEI=%u BVCI=%u: Cannot find BSS\n",
- nsei, ptp_bvci);
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_INV_BVCI]);
- return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI,
- &ptp_bvci, orig_msg);
- }
- return gbprox_relay2peer(msg, peer, ns_bvci);
- }
-
- /* A reset for the Signalling entity has been received
- * from the SGSN. As the signalling BVCI is shared
- * among all the BSS's that we multiplex, it needs to
- * be relayed */
- llist_for_each_entry(peer, &cfg->bts_peers, list)
- gbprox_relay2peer(msg, peer, ns_bvci);
-
- return 0;
-}
-
-/* Receive an incoming signalling message from the SGSN-side NS-VC */
-static int gbprox_rx_sig_from_sgsn(struct gbproxy_config *cfg,
- struct msgb *orig_msg, uint32_t nsei,
- uint16_t ns_bvci)
-{
- struct bssgp_normal_hdr *bgph =
- (struct bssgp_normal_hdr *) msgb_bssgph(orig_msg);
- struct tlv_parsed tp;
- uint8_t pdu_type = bgph->pdu_type;
- int data_len;
- struct gbproxy_peer *peer;
- uint16_t bvci;
- struct msgb *msg;
- int rc = 0;
- int cause;
-
- if (ns_bvci != 0 && ns_bvci != 1) {
- LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI=%u is not "
- "signalling\n", nsei, ns_bvci);
- /* FIXME: Send proper error message */
- return -EINVAL;
- }
-
- /* we actually should never see those two for BVCI == 0, but double-check
- * just to make sure */
- if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
- pdu_type == BSSGP_PDUT_DL_UNITDATA) {
- LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) UNITDATA not allowed in "
- "signalling\n", nsei);
- return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
- }
-
- msg = gprs_msgb_copy(orig_msg, "rx_sig_from_sgsn");
- gbprox_process_bssgp_dl(cfg, msg, NULL);
- /* Update message info */
- bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg);
- data_len = msgb_bssgp_len(orig_msg) - sizeof(*bgph);
- rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
-
- switch (pdu_type) {
- case BSSGP_PDUT_BVC_RESET:
- rc = rx_reset_from_sgsn(cfg, msg, orig_msg, &tp, nsei, ns_bvci);
- break;
- case BSSGP_PDUT_BVC_RESET_ACK:
- if (cfg->route_to_sgsn2 && nsei == cfg->nsip_sgsn2_nsei)
- break;
- /* fall through */
- case BSSGP_PDUT_FLUSH_LL:
- /* simple case: BVCI IE is mandatory */
- if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
- goto err_mand_ie;
- bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
- rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
- break;
- case BSSGP_PDUT_PAGING_PS:
- case BSSGP_PDUT_PAGING_CS:
- /* process the paging request (LAI/RAI lookup) */
- rc = gbprox_rx_paging(cfg, msg, &tp, nsei, ns_bvci);
- break;
- case BSSGP_PDUT_STATUS:
- /* Some exception has occurred */
- LOGP(DGPRS, LOGL_NOTICE,
- "NSEI=%u(SGSN) BSSGP STATUS ", nsei);
- if (!TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) {
- LOGPC(DGPRS, LOGL_NOTICE, "\n");
- goto err_mand_ie;
- }
- cause = *TLVP_VAL(&tp, BSSGP_IE_CAUSE);
- LOGPC(DGPRS, LOGL_NOTICE,
- "cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE),
- bssgp_cause_str(cause));
- if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) {
- bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
- LOGPC(DGPRS, LOGL_NOTICE, "BVCI=%u\n", bvci);
-
- if (cause == BSSGP_CAUSE_UNKNOWN_BVCI)
- rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
- } else
- LOGPC(DGPRS, LOGL_NOTICE, "\n");
- break;
- /* those only exist in the SGSN -> BSS direction */
- case BSSGP_PDUT_SUSPEND_ACK:
- case BSSGP_PDUT_SUSPEND_NACK:
- case BSSGP_PDUT_RESUME_ACK:
- case BSSGP_PDUT_RESUME_NACK:
- /* RAI IE is mandatory */
- if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
- goto err_mand_ie;
- peer = gbproxy_peer_by_rai(cfg, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA));
- if (!peer)
- goto err_no_peer;
- rc = gbprox_relay2peer(msg, peer, ns_bvci);
- break;
- case BSSGP_PDUT_BVC_BLOCK_ACK:
- case BSSGP_PDUT_BVC_UNBLOCK_ACK:
- if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
- goto err_mand_ie;
- bvci = ntohs(tlvp_val16_unal(&tp, BSSGP_IE_BVCI));
- if (bvci == 0) {
- LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BSSGP "
- "%sBLOCK_ACK for signalling BVCI ?!?\n", nsei,
- pdu_type == BSSGP_PDUT_BVC_UNBLOCK_ACK ? "UN":"");
- /* should we send STATUS ? */
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_INV_BVCI]);
- } else {
- /* Mark BVC as (un)blocked */
- block_unblock_peer(cfg, bvci, pdu_type);
- }
- rc = gbprox_relay2bvci(cfg, msg, bvci, ns_bvci);
- break;
- case BSSGP_PDUT_SGSN_INVOKE_TRACE:
- LOGP(DGPRS, LOGL_ERROR,
- "NSEI=%u(SGSN) BSSGP INVOKE TRACE not supported\n",nsei);
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN]);
- rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, orig_msg);
- break;
- default:
- LOGP(DGPRS, LOGL_NOTICE, "BSSGP PDU type %s not supported\n", bssgp_pdu_str(pdu_type));
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
- rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg);
- break;
- }
-
- msgb_free(msg);
-
- return rc;
-err_mand_ie:
- LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) missing mandatory IE\n",
- nsei);
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]);
- msgb_free(msg);
- return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, orig_msg);
-err_no_peer:
- LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAI\n",
- nsei);
- rate_ctr_inc(&cfg->ctrg-> ctr[GBPROX_GLOB_CTR_INV_RAI]);
- msgb_free(msg);
- return bssgp_tx_status(BSSGP_CAUSE_INV_MAND_INF, NULL, orig_msg);
-}
-
-static int gbproxy_is_sgsn_nsei(struct gbproxy_config *cfg, uint16_t nsei)
-{
- return nsei == cfg->nsip_sgsn_nsei ||
- (cfg->route_to_sgsn2 && nsei == cfg->nsip_sgsn2_nsei);
-}
-
-/* Main input function for Gb proxy */
-int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei,
- uint16_t ns_bvci, uint16_t nsvci)
-{
- int rc;
- int remote_end_is_sgsn = gbproxy_is_sgsn_nsei(cfg, nsei);
-
- /* Only BVCI=0 messages need special treatment */
- if (ns_bvci == 0 || ns_bvci == 1) {
- if (remote_end_is_sgsn)
- rc = gbprox_rx_sig_from_sgsn(cfg, msg, nsei, ns_bvci);
- else
- rc = gbprox_rx_sig_from_bss(cfg, msg, nsei, ns_bvci);
- } else {
- /* All other BVCI are PTP */
- if (remote_end_is_sgsn)
- rc = gbprox_rx_ptp_from_sgsn(cfg, msg, nsei, nsvci,
- ns_bvci);
- else
- rc = gbprox_rx_ptp_from_bss(cfg, msg, nsei, nsvci,
- ns_bvci);
- }
-
- return rc;
-}
-
-int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi)
-{
- struct gprs_nsvc *nsvc;
-
- llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
- if (!nsvc->persistent)
- continue;
- gprs_nsvc_reset(nsvc, NS_CAUSE_OM_INTERVENTION);
- }
- return 0;
-}
-
-/* Signal handler for signals from NS layer */
-int gbprox_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gbproxy_config *cfg = handler_data;
- struct ns_signal_data *nssd = signal_data;
- struct gprs_nsvc *nsvc = nssd->nsvc;
- struct gbproxy_peer *peer;
- int remote_end_is_sgsn = gbproxy_is_sgsn_nsei(cfg, nsvc->nsei);
-
- if (subsys != SS_L_NS)
- return 0;
-
- if (signal == S_NS_RESET && remote_end_is_sgsn) {
- /* We have received a NS-RESET from the NSEI and NSVC
- * of the SGSN. This might happen with SGSN that start
- * their own NS-RESET procedure without waiting for our
- * NS-RESET */
- nsvc->remote_end_is_sgsn = 1;
- }
-
- if (signal == S_NS_ALIVE_EXP && nsvc->remote_end_is_sgsn) {
- LOGP(DGPRS, LOGL_NOTICE, "Tns alive expired too often, "
- "re-starting RESET procedure\n");
- rate_ctr_inc(&cfg->ctrg->
- ctr[GBPROX_GLOB_CTR_RESTART_RESET_SGSN]);
- gprs_ns_nsip_connect(nsvc->nsi, &nsvc->ip.bts_addr,
- nsvc->nsei, nsvc->nsvci);
- }
-
- if (!nsvc->remote_end_is_sgsn) {
- /* from BSS to SGSN */
- peer = gbproxy_peer_by_nsei(cfg, nsvc->nsei);
- if (!peer) {
- LOGP(DGPRS, LOGL_NOTICE, "signal '%s' for unknown peer NSEI=%u/NSVCI=%u\n",
- get_value_string(gprs_ns_signal_ns_names, signal), nsvc->nsei, nsvc->nsvci);
- return 0;
- }
- switch (signal) {
- case S_NS_RESET:
- case S_NS_BLOCK:
- if (!peer->blocked)
- break;
- LOGP(DGPRS, LOGL_NOTICE, "Converting '%s' from NSEI=%u/NSVCI=%u into BSSGP_BVC_BLOCK to SGSN\n",
- get_value_string(gprs_ns_signal_ns_names, signal), nsvc->nsei, nsvc->nsvci);
- bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, nsvc->nsei,
- peer->bvci, 0);
- break;
- }
- } else {
- /* Forward this message to all NS-VC to BSS */
- struct gprs_ns_inst *nsi = cfg->nsi;
- struct gprs_nsvc *next_nsvc;
-
- llist_for_each_entry(next_nsvc, &nsi->gprs_nsvcs, list) {
- if (next_nsvc->remote_end_is_sgsn)
- continue;
-
- /* Note that the following does not start the full
- * procedures including timer based retransmissions. */
- switch (signal) {
- case S_NS_RESET:
- gprs_ns_tx_reset(next_nsvc, nssd->cause);
- break;
- case S_NS_BLOCK:
- gprs_ns_tx_block(next_nsvc, nssd->cause);
- break;
- case S_NS_UNBLOCK:
- gprs_ns_tx_unblock(next_nsvc);
- break;
- }
- }
- }
- return 0;
-}
-
-void gbprox_reset(struct gbproxy_config *cfg)
-{
- struct gbproxy_peer *peer, *tmp;
-
- llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list)
- gbproxy_peer_free(peer);
-
- rate_ctr_group_free(cfg->ctrg);
- gbproxy_init_config(cfg);
-}
-
-int gbproxy_init_config(struct gbproxy_config *cfg)
-{
- struct timespec tp;
-
- INIT_LLIST_HEAD(&cfg->bts_peers);
- cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0);
- if (!cfg->ctrg) {
- LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n");
- return -1;
- }
- clock_gettime(CLOCK_REALTIME, &tp);
-
- return 0;
-}
diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c
deleted file mode 100644
index caff27f6f..000000000
--- a/openbsc/src/gprs/gb_proxy_main.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/* NS-over-IP proxy */
-
-/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010 by On-Waves
- * 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 <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <osmocom/core/application.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/stats.h>
-
-#include <osmocom/gprs/gprs_ns.h>
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#include <openbsc/signal.h>
-#include <openbsc/debug.h>
-#include <openbsc/vty.h>
-#include <openbsc/gb_proxy.h>
-
-#include <osmocom/vty/command.h>
-#include <osmocom/vty/telnet_interface.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/stats.h>
-#include <osmocom/vty/ports.h>
-
-#include "../../bscconfig.h"
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-void *tall_bsc_ctx;
-
-const char *openbsc_copyright =
- "Copyright (C) 2010 Harald Welte and On-Waves\r\n"
- "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
- "This is free software: you are free to change and redistribute it.\r\n"
- "There is NO WARRANTY, to the extent permitted by law.\r\n";
-
-static char *config_file = "osmo_gbproxy.cfg";
-struct gbproxy_config gbcfg = {0};
-static int daemonize = 0;
-
-/* Pointer to the SGSN peer */
-extern struct gbprox_peer *gbprox_peer_sgsn;
-
-/* call-back function for the NS protocol */
-static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
- struct msgb *msg, uint16_t bvci)
-{
- int rc = 0;
-
- switch (event) {
- case GPRS_NS_EVT_UNIT_DATA:
- rc = gbprox_rcvmsg(&gbcfg, msg, nsvc->nsei, bvci, nsvc->nsvci);
- break;
- default:
- LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
- if (msg)
- msgb_free(msg);
- rc = -EIO;
- break;
- }
- return rc;
-}
-
-static void signal_handler(int signal)
-{
- fprintf(stdout, "signal %u received\n", signal);
-
- switch (signal) {
- case SIGINT:
- case SIGTERM:
- osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
- sleep(1);
- exit(0);
- break;
- case SIGABRT:
- /* in case of abort, we want to obtain a talloc report
- * and then return to the caller, who will abort the process */
- case SIGUSR1:
- talloc_report(tall_vty_ctx, stderr);
- talloc_report_full(tall_bsc_ctx, stderr);
- break;
- case SIGUSR2:
- talloc_report_full(tall_vty_ctx, stderr);
- break;
- default:
- break;
- }
-}
-
-static void print_usage()
-{
- printf("Usage: bsc_hack\n");
-}
-
-static void print_help()
-{
- printf(" Some useful help...\n");
- printf(" -h --help this text\n");
- printf(" -d option --debug=DNS:DGPRS,0:0 enable debugging\n");
- printf(" -D --daemonize Fork the process into a background daemon\n");
- printf(" -c --config-file filename The config file to use.\n");
- printf(" -s --disable-color\n");
- printf(" -T --timestamp Prefix every log line with a timestamp\n");
- printf(" -V --version. Print the version of OpenBSC.\n");
- printf(" -e --log-level number. Set a global loglevel.\n");
-}
-
-static void handle_options(int argc, char **argv)
-{
- while (1) {
- int option_index = 0, c;
- static struct option long_options[] = {
- { "help", 0, 0, 'h' },
- { "debug", 1, 0, 'd' },
- { "daemonize", 0, 0, 'D' },
- { "config-file", 1, 0, 'c' },
- { "disable-color", 0, 0, 's' },
- { "timestamp", 0, 0, 'T' },
- { "version", 0, 0, 'V' },
- { "log-level", 1, 0, 'e' },
- { 0, 0, 0, 0 }
- };
-
- c = getopt_long(argc, argv, "hd:Dc:sTVe:",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_usage();
- print_help();
- exit(0);
- case 's':
- log_set_use_color(osmo_stderr_target, 0);
- break;
- case 'd':
- log_parse_category_mask(osmo_stderr_target, optarg);
- break;
- case 'D':
- daemonize = 1;
- break;
- case 'c':
- config_file = optarg;
- break;
- case 'T':
- log_set_print_timestamp(osmo_stderr_target, 1);
- break;
- case 'e':
- log_set_log_level(osmo_stderr_target, atoi(optarg));
- break;
- case 'V':
- print_version(1);
- exit(0);
- break;
- default:
- break;
- }
- }
-}
-
-extern int bsc_vty_go_parent(struct vty *vty);
-
-static struct vty_app_info vty_info = {
- .name = "OsmoGbProxy",
- .version = PACKAGE_VERSION,
- .go_parent_cb = bsc_vty_go_parent,
- .is_config_node = bsc_vty_is_config_node,
-};
-
-/* default categories */
-static struct log_info_cat gprs_categories[] = {
- [DGPRS] = {
- .name = "DGPRS",
- .description = "GPRS Packet Service",
- .enabled = 1, .loglevel = LOGL_DEBUG,
- },
- [DNS] = {
- .name = "DNS",
- .description = "GPRS Network Service (NS)",
- .enabled = 1, .loglevel = LOGL_INFO,
- },
- [DBSSGP] = {
- .name = "DBSSGP",
- .description = "GPRS BSS Gateway Protocol (BSSGP)",
- .enabled = 1, .loglevel = LOGL_DEBUG,
- },
-};
-
-static const struct log_info gprs_log_info = {
- .filter_fn = gprs_log_filter_fn,
- .cat = gprs_categories,
- .num_cat = ARRAY_SIZE(gprs_categories),
-};
-
-int main(int argc, char **argv)
-{
- struct gsm_network dummy_network;
- int rc;
-
- tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
- msgb_talloc_ctx_init(tall_bsc_ctx, 0);
-
- signal(SIGINT, &signal_handler);
- signal(SIGTERM, &signal_handler);
- signal(SIGABRT, &signal_handler);
- signal(SIGUSR1, &signal_handler);
- signal(SIGUSR2, &signal_handler);
- osmo_init_ignore_signals();
-
- osmo_init_logging(&gprs_log_info);
-
- vty_info.copyright = openbsc_copyright;
- vty_init(&vty_info);
- logging_vty_add_cmds(NULL);
- osmo_stats_vty_add_cmds(&gprs_log_info);
- gbproxy_vty_init();
-
- handle_options(argc, argv);
-
- rate_ctr_init(tall_bsc_ctx);
- osmo_stats_init(tall_bsc_ctx);
-
- bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb, tall_bsc_ctx);
- if (!bssgp_nsi) {
- LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
- exit(1);
- }
- gbproxy_init_config(&gbcfg);
- gbcfg.nsi = bssgp_nsi;
- gprs_ns_vty_init(bssgp_nsi);
- gprs_ns_set_log_ss(DNS);
- bssgp_set_log_ss(DBSSGP);
- osmo_signal_register_handler(SS_L_NS, &gbprox_signal, &gbcfg);
-
- rc = gbproxy_parse_config(config_file, &gbcfg);
- if (rc < 0) {
- LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n");
- exit(2);
- }
-
- /* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network,
- vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY);
- if (rc < 0)
- exit(1);
-
- if (!gprs_nsvc_by_nsei(gbcfg.nsi, gbcfg.nsip_sgsn_nsei)) {
- LOGP(DGPRS, LOGL_FATAL, "You cannot proxy to NSEI %u "
- "without creating that NSEI before\n",
- gbcfg.nsip_sgsn_nsei);
- exit(2);
- }
-
- rc = gprs_ns_nsip_listen(bssgp_nsi);
- if (rc < 0) {
- LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n");
- exit(2);
- }
-
- rc = gprs_ns_frgre_listen(bssgp_nsi);
- if (rc < 0) {
- LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen GRE "
- "socket. Do you have CAP_NET_RAW?\n");
- exit(2);
- }
-
- if (daemonize) {
- rc = osmo_daemonize();
- if (rc < 0) {
- perror("Error during daemonize");
- exit(1);
- }
- }
-
- /* Reset all the persistent NS-VCs that we've read from the config */
- gbprox_reset_persistent_nsvcs(bssgp_nsi);
-
- while (1) {
- rc = osmo_select_main(0);
- if (rc < 0)
- exit(3);
- }
-
- exit(0);
-}
diff --git a/openbsc/src/gprs/gb_proxy_patch.c b/openbsc/src/gprs/gb_proxy_patch.c
deleted file mode 100644
index 210fb2b96..000000000
--- a/openbsc/src/gprs/gb_proxy_patch.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/* Gb-proxy message patching */
-
-/* (C) 2014 by On-Waves
- * 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 <openbsc/gb_proxy.h>
-
-#include <openbsc/gprs_utils.h>
-#include <openbsc/gprs_gb_parse.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-
-#include <osmocom/gprs/protocol/gsm_08_18.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/gsm/apn.h>
-
-/* patch RA identifier in place */
-static void gbproxy_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer,
- int to_bss, const char *log_text)
-{
- struct gbproxy_patch_state *state = &peer->patch_state;
- int old_mcc;
- int old_mnc;
- struct gprs_ra_id raid;
- enum gbproxy_peer_ctr counter =
- to_bss ?
- GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
- GBPROX_PEER_CTR_RAID_PATCHED_BSS;
-
- if (!state->local_mcc || !state->local_mnc)
- return;
-
- gsm48_parse_ra(&raid, raid_enc);
-
- old_mcc = raid.mcc;
- old_mnc = raid.mnc;
-
- if (!to_bss) {
- /* BSS -> SGSN */
- if (state->local_mcc)
- raid.mcc = peer->cfg->core_mcc;
-
- if (state->local_mnc)
- raid.mnc = peer->cfg->core_mnc;
- } else {
- /* SGSN -> BSS */
- if (state->local_mcc)
- raid.mcc = state->local_mcc;
-
- if (state->local_mnc)
- raid.mnc = state->local_mnc;
- }
-
- LOGP(DGPRS, LOGL_DEBUG,
- "Patching %s to %s: "
- "%d-%d-%d-%d -> %d-%d-%d-%d\n",
- log_text,
- to_bss ? "BSS" : "SGSN",
- old_mcc, old_mnc, raid.lac, raid.rac,
- raid.mcc, raid.mnc, raid.lac, raid.rac);
-
- gsm48_construct_ra(raid_enc, &raid);
- rate_ctr_inc(&peer->ctrg->ctr[counter]);
-}
-
-static void gbproxy_patch_apn_ie(struct msgb *msg,
- uint8_t *apn_ie, size_t apn_ie_len,
- struct gbproxy_peer *peer,
- size_t *new_apn_ie_len, const char *log_text)
-{
- struct apn_ie_hdr {
- uint8_t iei;
- uint8_t apn_len;
- uint8_t apn[0];
- } *hdr = (void *)apn_ie;
-
- size_t apn_len = hdr->apn_len;
- uint8_t *apn = hdr->apn;
-
- OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));
- OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);
-
- if (peer->cfg->core_apn_size == 0) {
- char str1[110];
- /* Remove the IE */
- LOGP(DGPRS, LOGL_DEBUG,
- "Patching %s to SGSN: Removing APN '%s'\n",
- log_text,
- osmo_apn_to_str(str1, apn, apn_len));
-
- *new_apn_ie_len = 0;
- gprs_msgb_resize_area(msg, apn_ie, apn_ie_len, 0);
- } else {
- /* Resize the IE */
- char str1[110];
- char str2[110];
-
- OSMO_ASSERT(peer->cfg->core_apn_size <= 100);
-
- LOGP(DGPRS, LOGL_DEBUG,
- "Patching %s to SGSN: "
- "Replacing APN '%s' -> '%s'\n",
- log_text,
- osmo_apn_to_str(str1, apn, apn_len),
- osmo_apn_to_str(str2, peer->cfg->core_apn,
- peer->cfg->core_apn_size));
-
- *new_apn_ie_len = peer->cfg->core_apn_size + 2;
- gprs_msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);
- memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);
- hdr->apn_len = peer->cfg->core_apn_size;
- }
-
- rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
-}
-
-static int gbproxy_patch_tlli(uint8_t *tlli_enc,
- struct gbproxy_peer *peer,
- uint32_t new_tlli,
- int to_bss, const char *log_text)
-{
- uint32_t tlli_be;
- uint32_t tlli;
- enum gbproxy_peer_ctr counter =
- to_bss ?
- GBPROX_PEER_CTR_TLLI_PATCHED_SGSN :
- GBPROX_PEER_CTR_TLLI_PATCHED_BSS;
-
- memcpy(&tlli_be, tlli_enc, sizeof(tlli_be));
- tlli = ntohl(tlli_be);
-
- if (tlli == new_tlli)
- return 0;
-
- LOGP(DGPRS, LOGL_DEBUG,
- "Patching %ss: "
- "Replacing %08x -> %08x\n",
- log_text, tlli, new_tlli);
-
- tlli_be = htonl(new_tlli);
- memcpy(tlli_enc, &tlli_be, sizeof(tlli_be));
-
- rate_ctr_inc(&peer->ctrg->ctr[counter]);
-
- return 1;
-}
-
-static int gbproxy_patch_ptmsi(uint8_t *ptmsi_enc,
- struct gbproxy_peer *peer,
- uint32_t new_ptmsi,
- int to_bss, const char *log_text)
-{
- uint32_t ptmsi_be;
- uint32_t ptmsi;
- enum gbproxy_peer_ctr counter =
- to_bss ?
- GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN :
- GBPROX_PEER_CTR_PTMSI_PATCHED_BSS;
- memcpy(&ptmsi_be, ptmsi_enc, sizeof(ptmsi_be));
- ptmsi = ntohl(ptmsi_be);
-
- if (ptmsi == new_ptmsi)
- return 0;
-
- LOGP(DGPRS, LOGL_DEBUG,
- "Patching %ss: "
- "Replacing %08x -> %08x\n",
- log_text, ptmsi, new_ptmsi);
-
- ptmsi_be = htonl(new_ptmsi);
- memcpy(ptmsi_enc, &ptmsi_be, sizeof(ptmsi_be));
-
- rate_ctr_inc(&peer->ctrg->ctr[counter]);
-
- return 1;
-}
-
-int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
- struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info, int *len_change,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
- int have_patched = 0;
- int fcs;
- struct gbproxy_config *cfg = peer->cfg;
-
- if (parse_ctx->ptmsi_enc && link_info &&
- !parse_ctx->old_raid_is_foreign && peer->cfg->patch_ptmsi) {
- uint32_t ptmsi;
- if (parse_ctx->to_bss)
- ptmsi = link_info->tlli.ptmsi;
- else
- ptmsi = link_info->sgsn_tlli.ptmsi;
-
- if (ptmsi != GSM_RESERVED_TMSI) {
- if (gbproxy_patch_ptmsi(parse_ctx->ptmsi_enc, peer,
- ptmsi, parse_ctx->to_bss, "P-TMSI"))
- have_patched = 1;
- } else {
- /* TODO: invalidate old RAI if present (see below) */
- }
- }
-
- if (parse_ctx->new_ptmsi_enc && link_info && cfg->patch_ptmsi) {
- uint32_t ptmsi;
- if (parse_ctx->to_bss)
- ptmsi = link_info->tlli.ptmsi;
- else
- ptmsi = link_info->sgsn_tlli.ptmsi;
-
- OSMO_ASSERT(ptmsi);
- if (gbproxy_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer,
- ptmsi, parse_ctx->to_bss, "new P-TMSI"))
- have_patched = 1;
- }
-
- if (parse_ctx->raid_enc) {
- gbproxy_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss,
- parse_ctx->llc_msg_name);
- have_patched = 1;
- }
-
- if (parse_ctx->old_raid_enc && !parse_ctx->old_raid_is_foreign) {
- /* TODO: Patch to invalid if P-TMSI unknown. */
- gbproxy_patch_raid(parse_ctx->old_raid_enc, peer, parse_ctx->to_bss,
- parse_ctx->llc_msg_name);
- have_patched = 1;
- }
-
- if (parse_ctx->apn_ie &&
- cfg->core_apn &&
- !parse_ctx->to_bss &&
- gbproxy_imsi_matches(cfg, GBPROX_MATCH_PATCHING, link_info) &&
- cfg->core_apn) {
- size_t new_len;
- gbproxy_patch_apn_ie(msg,
- parse_ctx->apn_ie, parse_ctx->apn_ie_len,
- peer, &new_len, parse_ctx->llc_msg_name);
- *len_change += (int)new_len - (int)parse_ctx->apn_ie_len;
-
- have_patched = 1;
- }
-
- if (have_patched) {
- llc_len += *len_change;
- ghp->crc_length += *len_change;
-
- /* Fix FCS */
- fcs = gprs_llc_fcs(llc, ghp->crc_length);
- LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n",
- ghp->fcs, fcs);
-
- llc[llc_len - 3] = fcs & 0xff;
- llc[llc_len - 2] = (fcs >> 8) & 0xff;
- llc[llc_len - 1] = (fcs >> 16) & 0xff;
- }
-
- return have_patched;
-}
-
-/* patch BSSGP message to use core_mcc/mnc on the SGSN side */
-void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
- struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info, int *len_change,
- struct gprs_gb_parse_context *parse_ctx)
-{
- const char *err_info = NULL;
- int err_ctr = -1;
-
- if (parse_ctx->bssgp_raid_enc)
- gbproxy_patch_raid(parse_ctx->bssgp_raid_enc, peer,
- parse_ctx->to_bss, "BSSGP");
-
- if (parse_ctx->need_decryption &&
- (peer->cfg->patch_ptmsi || peer->cfg->core_apn)) {
- /* Patching LLC messages has been requested
- * explicitly, but the message (including the
- * type) is encrypted, so we possibly fail to
- * patch the LLC part of the message. */
- err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR;
- err_info = "GMM message is encrypted";
- goto patch_error;
- }
-
- if (!link_info && parse_ctx->tlli_enc && parse_ctx->to_bss) {
- /* Happens with unknown (not cached) TLLI coming from
- * the SGSN */
- /* TODO: What shall be done with the message in this case? */
- err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN;
- err_info = "TLLI sent by the SGSN is unknown";
- goto patch_error;
- }
-
- if (!link_info)
- return;
-
- if (parse_ctx->tlli_enc && peer->cfg->patch_ptmsi) {
- uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,
- link_info, parse_ctx->to_bss);
-
- if (tlli) {
- gbproxy_patch_tlli(parse_ctx->tlli_enc, peer, tlli,
- parse_ctx->to_bss, "TLLI");
- parse_ctx->tlli = tlli;
- } else {
- /* Internal error */
- err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
- err_info = "Replacement TLLI is 0";
- goto patch_error;
- }
- }
-
- if (parse_ctx->bssgp_ptmsi_enc && peer->cfg->patch_ptmsi) {
- uint32_t ptmsi;
- if (parse_ctx->to_bss)
- ptmsi = link_info->tlli.ptmsi;
- else
- ptmsi = link_info->sgsn_tlli.ptmsi;
-
- if (ptmsi != GSM_RESERVED_TMSI)
- gbproxy_patch_ptmsi(
- parse_ctx->bssgp_ptmsi_enc, peer,
- ptmsi, parse_ctx->to_bss, "BSSGP P-TMSI");
- }
-
- if (parse_ctx->llc) {
- uint8_t *llc = parse_ctx->llc;
- size_t llc_len = parse_ctx->llc_len;
- int llc_len_change = 0;
-
- gbproxy_patch_llc(msg, llc, llc_len, peer, link_info,
- &llc_len_change, parse_ctx);
- /* Note that the APN might have been resized here, but no
- * pointer int the parse_ctx will refer to an adress after the
- * APN. So it's possible to patch first and do the TLLI
- * handling afterwards. */
-
- if (llc_len_change) {
- llc_len += llc_len_change;
-
- /* Fix LLC IE len */
- /* TODO: This is a kludge, but the a pointer to the
- * start of the IE is not available here */
- if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) {
- /* most probably a one byte length */
- if (llc_len > 127) {
- err_info = "Cannot increase size";
- err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
- goto patch_error;
- }
- llc[-1] = llc_len | 0x80;
- } else {
- llc[-2] = (llc_len >> 8) & 0x7f;
- llc[-1] = llc_len & 0xff;
- }
- *len_change += llc_len_change;
- }
- /* Note that the tp struct might contain invalid pointers here
- * if the LLC field has changed its size */
- parse_ctx->llc_len = llc_len;
- }
- return;
-
-patch_error:
- OSMO_ASSERT(err_ctr >= 0);
- rate_ctr_inc(&peer->ctrg->ctr[err_ctr]);
- LOGP(DGPRS, LOGL_ERROR,
- "NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n",
- msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS",
- err_info);
-}
-
-void gbproxy_clear_patch_filter(struct gbproxy_match *match)
-{
- if (match->enable) {
- regfree(&match->re_comp);
- match->enable = 0;
- }
- talloc_free(match->re_str);
- match->re_str = NULL;
-}
-
-int gbproxy_set_patch_filter(struct gbproxy_match *match, const char *filter,
- const char **err_msg)
-{
- static char err_buf[300];
- int rc;
-
- gbproxy_clear_patch_filter(match);
-
- if (!filter)
- return 0;
-
- rc = regcomp(&match->re_comp, filter,
- REG_EXTENDED | REG_NOSUB | REG_ICASE);
-
- if (rc == 0) {
- match->enable = 1;
- match->re_str = talloc_strdup(tall_bsc_ctx, filter);
- return 0;
- }
-
- if (err_msg) {
- regerror(rc, &match->re_comp,
- err_buf, sizeof(err_buf));
- *err_msg = err_buf;
- }
-
- return -1;
-}
-
-int gbproxy_check_imsi(struct gbproxy_match *match,
- const uint8_t *imsi, size_t imsi_len)
-{
- char mi_buf[200];
- int rc;
-
- if (!match->enable)
- return 1;
-
- rc = gprs_is_mi_imsi(imsi, imsi_len);
- if (rc > 0)
- rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);
- if (rc <= 0) {
- LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",
- osmo_hexdump(imsi, imsi_len));
- return -1;
- }
-
- LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);
-
- rc = regexec(&match->re_comp, mi_buf, 0, NULL, 0);
- if (rc == REG_NOMATCH) {
- LOGP(DGPRS, LOGL_INFO,
- "IMSI '%s' doesn't match pattern '%s'\n",
- mi_buf, match->re_str);
- return 0;
- }
-
- return 1;
-}
-
diff --git a/openbsc/src/gprs/gb_proxy_peer.c b/openbsc/src/gprs/gb_proxy_peer.c
deleted file mode 100644
index 890968717..000000000
--- a/openbsc/src/gprs/gb_proxy_peer.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/* Gb proxy peer handling */
-
-/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010-2013 by On-Waves
- * (C) 2013 by Holger Hans Peter Freyther
- * 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 <openbsc/gb_proxy.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_data_shared.h>
-#include <openbsc/debug.h>
-
-#include <osmocom/gprs/protocol/gsm_08_18.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/stats.h>
-#include <osmocom/core/talloc.h>
-
-#include <string.h>
-
-static const struct rate_ctr_desc peer_ctr_description[] = {
- { "blocked", "BVC Block " },
- { "unblocked", "BVC Unblock " },
- { "dropped", "BVC blocked, dropped packet " },
- { "inv-nsei", "NSEI mismatch " },
- { "tx-err", "NS Transmission error " },
- { "raid-mod.bss", "RAID patched (BSS )" },
- { "raid-mod.sgsn", "RAID patched (SGSN)" },
- { "apn-mod.sgsn", "APN patched " },
- { "tlli-mod.bss", "TLLI patched (BSS )" },
- { "tlli-mod.sgsn", "TLLI patched (SGSN)" },
- { "ptmsi-mod.bss", "P-TMSI patched (BSS )" },
- { "ptmsi-mod.sgsn","P-TMSI patched (SGSN)" },
- { "mod-crypt-err", "Patch error: encrypted " },
- { "mod-err", "Patch error: other " },
- { "attach-reqs", "Attach Request count " },
- { "attach-rejs", "Attach Reject count " },
- { "attach-acks", "Attach Accept count " },
- { "attach-cpls", "Attach Completed count " },
- { "ra-upd-reqs", "RoutingArea Update Request count" },
- { "ra-upd-rejs", "RoutingArea Update Reject count " },
- { "ra-upd-acks", "RoutingArea Update Accept count " },
- { "ra-upd-cpls", "RoutingArea Update Compltd count" },
- { "gmm-status", "GMM Status count (BSS)" },
- { "gmm-status", "GMM Status count (SGSN)" },
- { "detach-reqs", "Detach Request count " },
- { "detach-acks", "Detach Accept count " },
- { "pdp-act-reqs", "PDP Activation Request count " },
- { "pdp-act-rejs", "PDP Activation Reject count " },
- { "pdp-act-acks", "PDP Activation Accept count " },
- { "pdp-deact-reqs","PDP Deactivation Request count " },
- { "pdp-deact-acks","PDP Deactivation Accept count " },
- { "tlli-unknown", "TLLI from SGSN unknown " },
- { "tlli-cache", "TLLI cache size " },
-};
-
-osmo_static_assert(ARRAY_SIZE(peer_ctr_description) == GBPROX_PEER_CTR_LAST, everything_described);
-
-static const struct rate_ctr_group_desc peer_ctrg_desc = {
- .group_name_prefix = "gbproxy.peer",
- .group_description = "GBProxy Peer Statistics",
- .num_ctr = ARRAY_SIZE(peer_ctr_description),
- .ctr_desc = peer_ctr_description,
- .class_id = OSMO_STATS_CLASS_PEER,
-};
-
-
-/* Find the gbprox_peer by its BVCI */
-struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (peer->bvci == bvci)
- return peer;
- }
- return NULL;
-}
-
-/* Find the gbprox_peer by its NSEI */
-struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,
- uint16_t nsei)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (peer->nsei == nsei)
- return peer;
- }
- return NULL;
-}
-
-/* look-up a peer by its Routeing Area Identification (RAI) */
-struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,
- const uint8_t *ra)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, ra, 6))
- return peer;
- }
- return NULL;
-}
-
-/* look-up a peer by its Location Area Identification (LAI) */
-struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,
- const uint8_t *la)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra, la, 5))
- return peer;
- }
- return NULL;
-}
-
-/* look-up a peer by its Location Area Code (LAC) */
-struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg,
- const uint8_t *la)
-{
- struct gbproxy_peer *peer;
- llist_for_each_entry(peer, &cfg->bts_peers, list) {
- if (!memcmp(peer->ra + 3, la + 3, 2))
- return peer;
- }
- return NULL;
-}
-
-struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(struct gbproxy_config *cfg,
- struct tlv_parsed *tp)
-{
- if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
- uint16_t bvci;
-
- bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
- if (bvci >= 2)
- return gbproxy_peer_by_bvci(cfg, bvci);
- }
-
- if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
- uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
- /* Only compare LAC part, since MCC/MNC are possibly patched.
- * Since the LAC of different BSS must be different when
- * MCC/MNC are patched, collisions shouldn't happen. */
- return gbproxy_peer_by_lac(cfg, rai);
- }
-
- if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
- uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA);
- return gbproxy_peer_by_lac(cfg, lai);
- }
-
- return NULL;
-}
-
-
-struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
-{
- struct gbproxy_peer *peer;
-
- peer = talloc_zero(tall_bsc_ctx, struct gbproxy_peer);
- if (!peer)
- return NULL;
-
- peer->bvci = bvci;
- peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci);
- if (!peer->ctrg) {
- talloc_free(peer);
- return NULL;
- }
- peer->cfg = cfg;
-
- llist_add(&peer->list, &cfg->bts_peers);
-
- INIT_LLIST_HEAD(&peer->patch_state.logical_links);
-
- return peer;
-}
-
-void gbproxy_peer_free(struct gbproxy_peer *peer)
-{
- llist_del(&peer->list);
-
- gbproxy_delete_link_infos(peer);
-
- rate_ctr_group_free(peer->ctrg);
- peer->ctrg = NULL;
-
- talloc_free(peer);
-}
-
-int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
-{
- int counter = 0;
- struct gbproxy_peer *peer, *tmp;
-
- llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {
- if (peer->nsei != nsei)
- continue;
- if (bvci && peer->bvci != bvci)
- continue;
-
- gbproxy_peer_free(peer);
- counter += 1;
- }
-
- return counter;
-}
-
diff --git a/openbsc/src/gprs/gb_proxy_tlli.c b/openbsc/src/gprs/gb_proxy_tlli.c
deleted file mode 100644
index 3b3b976a5..000000000
--- a/openbsc/src/gprs/gb_proxy_tlli.c
+++ /dev/null
@@ -1,723 +0,0 @@
-/* Gb-proxy TLLI state handling */
-
-/* (C) 2014 by On-Waves
- * 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/gsm/gsm48.h>
-
-#include <openbsc/gb_proxy.h>
-
-#include <openbsc/gprs_utils.h>
-#include <openbsc/gprs_gb_parse.h>
-
-#include <openbsc/debug.h>
-
-#include <osmocom/gsm/gsm_utils.h>
-
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/talloc.h>
-
-struct gbproxy_link_info *gbproxy_link_info_by_tlli(struct gbproxy_peer *peer,
- uint32_t tlli)
-{
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- if (!tlli)
- return NULL;
-
- llist_for_each_entry(link_info, &state->logical_links, list)
- if (link_info->tlli.current == tlli ||
- link_info->tlli.assigned == tlli)
- return link_info;
-
- return NULL;
-}
-
-struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
- struct gbproxy_peer *peer,
- uint32_t ptmsi)
-{
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- if (ptmsi == GSM_RESERVED_TMSI)
- return NULL;
-
- llist_for_each_entry(link_info, &state->logical_links, list)
- if (link_info->tlli.ptmsi == ptmsi)
- return link_info;
-
- return NULL;
-}
-
-struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
- struct gbproxy_peer *peer,
- uint32_t tlli)
-{
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- if (!tlli)
- return NULL;
-
- /* Don't care about the NSEI */
- llist_for_each_entry(link_info, &state->logical_links, list)
- if (link_info->sgsn_tlli.current == tlli ||
- link_info->sgsn_tlli.assigned == tlli)
- return link_info;
-
- return NULL;
-}
-
-struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
- struct gbproxy_peer *peer,
- uint32_t tlli, uint32_t sgsn_nsei)
-{
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- if (!tlli)
- return NULL;
-
- llist_for_each_entry(link_info, &state->logical_links, list)
- if ((link_info->sgsn_tlli.current == tlli ||
- link_info->sgsn_tlli.assigned == tlli) &&
- link_info->sgsn_nsei == sgsn_nsei)
- return link_info;
-
- return NULL;
-}
-
-struct gbproxy_link_info *gbproxy_link_info_by_imsi(
- struct gbproxy_peer *peer,
- const uint8_t *imsi,
- size_t imsi_len)
-{
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- if (!gprs_is_mi_imsi(imsi, imsi_len))
- return NULL;
-
- llist_for_each_entry(link_info, &state->logical_links, list) {
- if (link_info->imsi_len != imsi_len)
- continue;
- if (memcmp(link_info->imsi, imsi, imsi_len) != 0)
- continue;
-
- return link_info;
- }
-
- return NULL;
-}
-
-void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info)
-{
- struct msgb *msg, *nxt;
-
- llist_for_each_entry_safe(msg, nxt, &link_info->stored_msgs, list) {
- llist_del(&msg->list);
- msgb_free(msg);
- }
-}
-
-void gbproxy_delete_link_info(struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info)
-{
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- gbproxy_link_info_discard_messages(link_info);
-
- llist_del(&link_info->list);
- talloc_free(link_info);
- state->logical_link_count -= 1;
-
- peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
- state->logical_link_count;
-}
-
-void gbproxy_delete_link_infos(struct gbproxy_peer *peer)
-{
- struct gbproxy_link_info *link_info, *nxt;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list)
- gbproxy_delete_link_info(peer, link_info);
-
- OSMO_ASSERT(state->logical_link_count == 0);
- OSMO_ASSERT(llist_empty(&state->logical_links));
-}
-
-void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
- struct gbproxy_link_info *link_info)
-{
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- link_info->timestamp = now;
- llist_add(&link_info->list, &state->logical_links);
- state->logical_link_count += 1;
-
- peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
- state->logical_link_count;
-}
-
-int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
-{
- struct gbproxy_patch_state *state = &peer->patch_state;
- int exceeded_max_len = 0;
- int deleted_count = 0;
- int check_for_age;
-
- if (peer->cfg->tlli_max_len > 0)
- exceeded_max_len =
- state->logical_link_count - peer->cfg->tlli_max_len;
-
- check_for_age = peer->cfg->tlli_max_age > 0;
-
- for (; exceeded_max_len > 0; exceeded_max_len--) {
- struct gbproxy_link_info *link_info;
- OSMO_ASSERT(!llist_empty(&state->logical_links));
- link_info = llist_entry(state->logical_links.prev,
- struct gbproxy_link_info,
- list);
- LOGP(DGPRS, LOGL_INFO,
- "Removing TLLI %08x from list "
- "(stale, length %d, max_len exceeded)\n",
- link_info->tlli.current, state->logical_link_count);
-
- gbproxy_delete_link_info(peer, link_info);
- deleted_count += 1;
- }
-
- while (check_for_age && !llist_empty(&state->logical_links)) {
- time_t age;
- struct gbproxy_link_info *link_info;
- link_info = llist_entry(state->logical_links.prev,
- struct gbproxy_link_info,
- list);
- age = now - link_info->timestamp;
- /* age < 0 only happens after system time jumps, discard entry */
- if (age <= peer->cfg->tlli_max_age && age >= 0) {
- check_for_age = 0;
- continue;
- }
-
- LOGP(DGPRS, LOGL_INFO,
- "Removing TLLI %08x from list "
- "(stale, age %d, max_age exceeded)\n",
- link_info->tlli.current, (int)age);
-
- gbproxy_delete_link_info(peer, link_info);
- deleted_count += 1;
- }
-
- return deleted_count;
-}
-
-struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer)
-{
- struct gbproxy_link_info *link_info;
-
- link_info = talloc_zero(peer, struct gbproxy_link_info);
- link_info->tlli.ptmsi = GSM_RESERVED_TMSI;
- link_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
-
- link_info->vu_gen_tx_bss = GBPROXY_INIT_VU_GEN_TX;
-
- INIT_LLIST_HEAD(&link_info->stored_msgs);
-
- return link_info;
-}
-
-void gbproxy_detach_link_info(
- struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info)
-{
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- llist_del(&link_info->list);
- OSMO_ASSERT(state->logical_link_count > 0);
- state->logical_link_count -= 1;
-
- peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
- state->logical_link_count;
-}
-
-void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
- const uint8_t *imsi, size_t imsi_len)
-{
- if (!gprs_is_mi_imsi(imsi, imsi_len))
- return;
-
- link_info->imsi_len = imsi_len;
- link_info->imsi =
- talloc_realloc_size(link_info, link_info->imsi, imsi_len);
- OSMO_ASSERT(link_info->imsi != NULL);
- memcpy(link_info->imsi, imsi, imsi_len);
-}
-
-void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
- struct gbproxy_peer *peer, uint32_t new_tlli)
-{
- if (new_tlli == tlli_state->current)
- return;
-
- LOGP(DGPRS, LOGL_INFO,
- "The TLLI has been reassigned from %08x to %08x\n",
- tlli_state->current, new_tlli);
-
- /* Remember assigned TLLI */
- tlli_state->assigned = new_tlli;
- tlli_state->bss_validated = 0;
- tlli_state->net_validated = 0;
-}
-
-uint32_t gbproxy_map_tlli(uint32_t other_tlli,
- struct gbproxy_link_info *link_info, int to_bss)
-{
- uint32_t tlli = 0;
- struct gbproxy_tlli_state *src, *dst;
- if (to_bss) {
- src = &link_info->sgsn_tlli;
- dst = &link_info->tlli;
- } else {
- src = &link_info->tlli;
- dst = &link_info->sgsn_tlli;
- }
- if (src->current == other_tlli)
- tlli = dst->current;
- else if (src->assigned == other_tlli)
- tlli = dst->assigned;
-
- return tlli;
-}
-
-static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
- uint32_t tlli, int to_bss)
-{
- LOGP(DGPRS, LOGL_DEBUG,
- "%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n",
- __func__, tlli_state->current, tlli_state->assigned,
- tlli_state->net_validated, tlli_state->bss_validated, tlli);
-
- if (!tlli_state->assigned || tlli_state->assigned != tlli)
- return;
-
- /* TODO: Is this ok? Check spec */
- if (gprs_tlli_type(tlli) != TLLI_LOCAL)
- return;
-
- /* See GSM 04.08, 4.7.1.5 */
- if (to_bss)
- tlli_state->net_validated = 1;
- else
- tlli_state->bss_validated = 1;
-
- if (!tlli_state->bss_validated || !tlli_state->net_validated)
- return;
-
- LOGP(DGPRS, LOGL_INFO,
- "The TLLI %08x has been validated (was %08x)\n",
- tlli_state->assigned, tlli_state->current);
-
- tlli_state->current = tlli;
- tlli_state->assigned = 0;
-}
-
-static void gbproxy_touch_link_info(struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info,
- time_t now)
-{
- gbproxy_detach_link_info(peer, link_info);
- gbproxy_attach_link_info(peer, now, link_info);
-}
-
-static int gbproxy_unregister_link_info(struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info)
-{
- if (!link_info)
- return 1;
-
- if (link_info->tlli.ptmsi == GSM_RESERVED_TMSI && !link_info->imsi_len) {
- LOGP(DGPRS, LOGL_INFO,
- "Removing TLLI %08x from list (P-TMSI or IMSI are not set)\n",
- link_info->tlli.current);
- gbproxy_delete_link_info(peer, link_info);
- return 1;
- }
-
- link_info->tlli.current = 0;
- link_info->tlli.assigned = 0;
- link_info->sgsn_tlli.current = 0;
- link_info->sgsn_tlli.assigned = 0;
-
- link_info->is_deregistered = 1;
-
- gbproxy_reset_link(link_info);
-
- return 0;
-}
-
-int gbproxy_imsi_matches(struct gbproxy_config *cfg,
- enum gbproxy_match_id match_id,
- struct gbproxy_link_info *link_info)
-{
- struct gbproxy_match *match;
- OSMO_ASSERT(match_id >= 0 && match_id < ARRAY_SIZE(cfg->matches));
-
- match = &cfg->matches[match_id];
- if (!match->enable)
- return 1;
-
- return link_info != NULL && link_info->is_matching[match_id];
-}
-
-void gbproxy_assign_imsi(struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info,
- struct gprs_gb_parse_context *parse_ctx)
-{
- int imsi_matches;
- struct gbproxy_link_info *other_link_info;
- enum gbproxy_match_id match_id;
-
- /* Make sure that there is a second entry with the same IMSI */
- other_link_info = gbproxy_link_info_by_imsi(
- peer, parse_ctx->imsi, parse_ctx->imsi_len);
-
- if (other_link_info && other_link_info != link_info) {
- char mi_buf[200];
- mi_buf[0] = '\0';
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- parse_ctx->imsi, parse_ctx->imsi_len);
- LOGP(DGPRS, LOGL_INFO,
- "Removing TLLI %08x from list (IMSI %s re-used)\n",
- other_link_info->tlli.current, mi_buf);
- gbproxy_delete_link_info(peer, other_link_info);
- }
-
- /* Update the IMSI field */
- gbproxy_update_link_info(link_info,
- parse_ctx->imsi, parse_ctx->imsi_len);
-
- /* Check, whether the IMSI matches */
- OSMO_ASSERT(ARRAY_SIZE(link_info->is_matching) ==
- ARRAY_SIZE(peer->cfg->matches));
- for (match_id = 0; match_id < ARRAY_SIZE(link_info->is_matching);
- ++match_id) {
- imsi_matches = gbproxy_check_imsi(
- &peer->cfg->matches[match_id],
- parse_ctx->imsi, parse_ctx->imsi_len);
- if (imsi_matches >= 0)
- link_info->is_matching[match_id] = imsi_matches;
- }
-}
-
-static int gbproxy_tlli_match(const struct gbproxy_tlli_state *a,
- const struct gbproxy_tlli_state *b)
-{
- if (a->current && a->current == b->current)
- return 1;
-
- if (a->assigned && a->assigned == b->assigned)
- return 1;
-
- if (a->ptmsi != GSM_RESERVED_TMSI && a->ptmsi == b->ptmsi)
- return 1;
-
- return 0;
-}
-
-static void gbproxy_remove_matching_link_infos(
- struct gbproxy_peer *peer, struct gbproxy_link_info *link_info)
-{
- struct gbproxy_link_info *info, *nxt;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- /* Make sure that there is no second entry with the same P-TMSI or TLLI */
- llist_for_each_entry_safe(info, nxt, &state->logical_links, list) {
- if (info == link_info)
- continue;
-
- if (!gbproxy_tlli_match(&link_info->tlli, &info->tlli) &&
- (link_info->sgsn_nsei != info->sgsn_nsei ||
- !gbproxy_tlli_match(&link_info->sgsn_tlli, &info->sgsn_tlli)))
- continue;
-
- LOGP(DGPRS, LOGL_INFO,
- "Removing TLLI %08x from list (P-TMSI/TLLI re-used)\n",
- info->tlli.current);
- gbproxy_delete_link_info(peer, info);
- }
-}
-
-static struct gbproxy_link_info *gbproxy_get_link_info_ul(
- struct gbproxy_peer *peer,
- int *tlli_is_valid,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gbproxy_link_info *link_info = NULL;
-
- if (parse_ctx->tlli_enc) {
- link_info = gbproxy_link_info_by_tlli(peer, parse_ctx->tlli);
-
- if (link_info) {
- *tlli_is_valid = 1;
- return link_info;
- }
- }
-
- *tlli_is_valid = 0;
-
- if (!link_info && parse_ctx->imsi) {
- link_info = gbproxy_link_info_by_imsi(
- peer, parse_ctx->imsi, parse_ctx->imsi_len);
- }
-
- if (!link_info && parse_ctx->ptmsi_enc && !parse_ctx->old_raid_is_foreign) {
- uint32_t bss_ptmsi;
- gprs_parse_tmsi(parse_ctx->ptmsi_enc, &bss_ptmsi);
- link_info = gbproxy_link_info_by_ptmsi(peer, bss_ptmsi);
- }
-
- if (!link_info)
- return NULL;
-
- link_info->is_deregistered = 0;
-
- return link_info;
-}
-
-struct gbproxy_link_info *gbproxy_update_link_state_ul(
- struct gbproxy_peer *peer,
- time_t now,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gbproxy_link_info *link_info;
- int tlli_is_valid;
-
- link_info = gbproxy_get_link_info_ul(peer, &tlli_is_valid, parse_ctx);
-
- if (parse_ctx->tlli_enc && parse_ctx->llc) {
- uint32_t sgsn_tlli;
-
- if (!link_info) {
- LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n",
- parse_ctx->tlli);
- link_info = gbproxy_link_info_alloc(peer);
- gbproxy_attach_link_info(peer, now, link_info);
-
- /* Setup TLLIs */
- sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
- parse_ctx->tlli);
- link_info->sgsn_tlli.current = sgsn_tlli;
- link_info->tlli.current = parse_ctx->tlli;
- } else if (!tlli_is_valid) {
- /* New TLLI (info found by IMSI or P-TMSI) */
- link_info->tlli.current = parse_ctx->tlli;
- link_info->tlli.assigned = 0;
- link_info->sgsn_tlli.current =
- gbproxy_make_sgsn_tlli(peer, link_info,
- parse_ctx->tlli);
- link_info->sgsn_tlli.assigned = 0;
- gbproxy_touch_link_info(peer, link_info, now);
- } else {
- sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, link_info, 0);
- if (!sgsn_tlli)
- sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
- parse_ctx->tlli);
-
- gbproxy_validate_tlli(&link_info->tlli,
- parse_ctx->tlli, 0);
- gbproxy_validate_tlli(&link_info->sgsn_tlli,
- sgsn_tlli, 0);
- gbproxy_touch_link_info(peer, link_info, now);
- }
- } else if (link_info) {
- gbproxy_touch_link_info(peer, link_info, now);
- }
-
- if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
- gbproxy_assign_imsi(peer, link_info, parse_ctx);
-
- return link_info;
-}
-
-static struct gbproxy_link_info *gbproxy_get_link_info_dl(
- struct gbproxy_peer *peer,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gbproxy_link_info *link_info = NULL;
-
- /* Which key to use depends on its availability only, if that fails, do
- * not retry it with another key (e.g. IMSI). */
- if (parse_ctx->tlli_enc)
- link_info = gbproxy_link_info_by_sgsn_tlli(peer, parse_ctx->tlli,
- parse_ctx->peer_nsei);
-
- /* TODO: Get link_info by (SGSN) P-TMSI if that is available (see
- * GSM 08.18, 7.2) instead of using the IMSI as key. */
- else if (parse_ctx->imsi)
- link_info = gbproxy_link_info_by_imsi(
- peer, parse_ctx->imsi, parse_ctx->imsi_len);
-
- if (link_info)
- link_info->is_deregistered = 0;
-
- return link_info;
-}
-
-struct gbproxy_link_info *gbproxy_update_link_state_dl(
- struct gbproxy_peer *peer,
- time_t now,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gbproxy_link_info *link_info = NULL;
-
- link_info = gbproxy_get_link_info_dl(peer, parse_ctx);
-
- if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && link_info) {
- /* A new P-TMSI has been signalled in the message,
- * register new TLLI */
- uint32_t new_sgsn_ptmsi;
- uint32_t new_bss_ptmsi = GSM_RESERVED_TMSI;
- gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_sgsn_ptmsi);
-
- if (link_info->sgsn_tlli.ptmsi == new_sgsn_ptmsi)
- new_bss_ptmsi = link_info->tlli.ptmsi;
-
- if (new_bss_ptmsi == GSM_RESERVED_TMSI)
- new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
-
- LOGP(DGPRS, LOGL_INFO,
- "Got new PTMSI %08x from SGSN, using %08x for BSS\n",
- new_sgsn_ptmsi, new_bss_ptmsi);
- /* Setup PTMSIs */
- link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
- link_info->tlli.ptmsi = new_bss_ptmsi;
- } else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&
- !peer->cfg->patch_ptmsi) {
- /* A new P-TMSI has been signalled in the message with an unknown
- * TLLI, create a new link_info */
- /* TODO: Add a test case for this branch */
- uint32_t new_ptmsi;
- gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
-
- LOGP(DGPRS, LOGL_INFO,
- "Adding TLLI %08x to list (SGSN, new P-TMSI is %08x)\n",
- parse_ctx->tlli, new_ptmsi);
-
- link_info = gbproxy_link_info_alloc(peer);
- link_info->sgsn_tlli.current = parse_ctx->tlli;
- link_info->tlli.current = parse_ctx->tlli;
- link_info->sgsn_tlli.ptmsi = new_ptmsi;
- link_info->tlli.ptmsi = new_ptmsi;
- gbproxy_attach_link_info(peer, now, link_info);
- } else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&
- !peer->cfg->patch_ptmsi) {
- /* Unknown SGSN TLLI, create a new link_info */
- uint32_t new_ptmsi;
- link_info = gbproxy_link_info_alloc(peer);
- LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
- parse_ctx->tlli);
-
- gbproxy_attach_link_info(peer, now, link_info);
-
- /* Setup TLLIs */
- link_info->sgsn_tlli.current = parse_ctx->tlli;
- link_info->tlli.current = parse_ctx->tlli;
-
- if (!parse_ctx->new_ptmsi_enc)
- return link_info;
- /* A new P-TMSI has been signalled in the message */
-
- gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
- LOGP(DGPRS, LOGL_INFO,
- "Assigning new P-TMSI %08x\n", new_ptmsi);
- /* Setup P-TMSIs */
- link_info->sgsn_tlli.ptmsi = new_ptmsi;
- link_info->tlli.ptmsi = new_ptmsi;
- } else if (parse_ctx->tlli_enc && parse_ctx->llc && link_info) {
- uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
- link_info, 1);
- gbproxy_validate_tlli(&link_info->sgsn_tlli, parse_ctx->tlli, 1);
- gbproxy_validate_tlli(&link_info->tlli, bss_tlli, 1);
- gbproxy_touch_link_info(peer, link_info, now);
- } else if (link_info) {
- gbproxy_touch_link_info(peer, link_info, now);
- }
-
- if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
- gbproxy_assign_imsi(peer, link_info, parse_ctx);
-
- return link_info;
-}
-
-int gbproxy_update_link_state_after(
- struct gbproxy_peer *peer,
- struct gbproxy_link_info *link_info,
- time_t now,
- struct gprs_gb_parse_context *parse_ctx)
-{
- int rc = 0;
- if (parse_ctx->invalidate_tlli && link_info) {
- int keep_info =
- peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
- (peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
- parse_ctx->await_reattach) ||
- (peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
- link_info->imsi_len > 0);
- if (keep_info) {
- LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
- link_info->tlli.current);
- rc = gbproxy_unregister_link_info(peer, link_info);
- } else {
- LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list\n",
- link_info->tlli.current);
- gbproxy_delete_link_info(peer, link_info);
- rc = 1;
- }
- } else if (parse_ctx->to_bss && parse_ctx->tlli_enc &&
- parse_ctx->new_ptmsi_enc && link_info) {
- /* A new PTMSI has been signaled in the message,
- * register new TLLI */
- uint32_t new_sgsn_ptmsi = link_info->sgsn_tlli.ptmsi;
- uint32_t new_bss_ptmsi = link_info->tlli.ptmsi;
- uint32_t new_sgsn_tlli;
- uint32_t new_bss_tlli = 0;
-
- new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
- if (new_bss_ptmsi != GSM_RESERVED_TMSI)
- new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
- LOGP(DGPRS, LOGL_INFO,
- "Assigning new TLLI %08x to SGSN, %08x to BSS\n",
- new_sgsn_tlli, new_bss_tlli);
-
- gbproxy_reassign_tlli(&link_info->sgsn_tlli,
- peer, new_sgsn_tlli);
- gbproxy_reassign_tlli(&link_info->tlli,
- peer, new_bss_tlli);
- gbproxy_remove_matching_link_infos(peer, link_info);
- }
-
- gbproxy_remove_stale_link_infos(peer, now);
-
- return rc;
-}
-
-
diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c
deleted file mode 100644
index 86d65a8e3..000000000
--- a/openbsc/src/gprs/gb_proxy_vty.c
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010 by On-Waves
- * 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 <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <time.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/rate_ctr.h>
-
-#include <openbsc/gsm_04_08.h>
-#include <osmocom/gprs/gprs_ns.h>
-#include <osmocom/gsm/apn.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gb_proxy.h>
-#include <openbsc/gprs_utils.h>
-#include <openbsc/vty.h>
-
-#include <osmocom/vty/command.h>
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/misc.h>
-
-static struct gbproxy_config *g_cfg = NULL;
-
-/*
- * vty code for mgcp below
- */
-static struct cmd_node gbproxy_node = {
- GBPROXY_NODE,
- "%s(config-gbproxy)# ",
- 1,
-};
-
-static const struct value_string keep_modes[] = {
- {GBPROX_KEEP_NEVER, "never"},
- {GBPROX_KEEP_REATTACH, "re-attach"},
- {GBPROX_KEEP_IDENTIFIED, "identified"},
- {GBPROX_KEEP_ALWAYS, "always"},
- {0, NULL}
-};
-
-static const struct value_string match_ids[] = {
- {GBPROX_MATCH_PATCHING, "patching"},
- {GBPROX_MATCH_ROUTING, "routing"},
- {0, NULL}
-};
-
-static void gbprox_vty_print_peer(struct vty *vty, struct gbproxy_peer *peer)
-{
- struct gprs_ra_id raid;
- gsm48_parse_ra(&raid, peer->ra);
-
- vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
- "RAI %u-%u-%u-%u",
- peer->nsei, peer->bvci,
- raid.mcc, raid.mnc, raid.lac, raid.rac);
- if (peer->blocked)
- vty_out(vty, " [BVC-BLOCKED]");
-
- vty_out(vty, "%s", VTY_NEWLINE);
-}
-
-static int config_write_gbproxy(struct vty *vty)
-{
- enum gbproxy_match_id match_id;
-
- vty_out(vty, "gbproxy%s", VTY_NEWLINE);
-
- vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
- VTY_NEWLINE);
-
- if (g_cfg->core_mcc > 0)
- vty_out(vty, " core-mobile-country-code %d%s",
- g_cfg->core_mcc, VTY_NEWLINE);
- if (g_cfg->core_mnc > 0)
- vty_out(vty, " core-mobile-network-code %d%s",
- g_cfg->core_mnc, VTY_NEWLINE);
-
- for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id) {
- struct gbproxy_match *match = &g_cfg->matches[match_id];
- if (match->re_str)
- vty_out(vty, " match-imsi %s %s%s",
- get_value_string(match_ids, match_id),
- match->re_str, VTY_NEWLINE);
- }
-
- if (g_cfg->core_apn != NULL) {
- if (g_cfg->core_apn_size > 0) {
- char str[500] = {0};
- vty_out(vty, " core-access-point-name %s%s",
- osmo_apn_to_str(str, g_cfg->core_apn,
- g_cfg->core_apn_size),
- VTY_NEWLINE);
- } else {
- vty_out(vty, " core-access-point-name none%s",
- VTY_NEWLINE);
- }
- }
-
- if (g_cfg->route_to_sgsn2)
- vty_out(vty, " secondary-sgsn nsei %u%s", g_cfg->nsip_sgsn2_nsei,
- VTY_NEWLINE);
-
- if (g_cfg->tlli_max_age > 0)
- vty_out(vty, " link-list max-age %d%s",
- g_cfg->tlli_max_age, VTY_NEWLINE);
- if (g_cfg->tlli_max_len > 0)
- vty_out(vty, " link-list max-length %d%s",
- g_cfg->tlli_max_len, VTY_NEWLINE);
- vty_out(vty, " link-list keep-mode %s%s",
- get_value_string(keep_modes, g_cfg->keep_link_infos),
- VTY_NEWLINE);
-
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy,
- cfg_gbproxy_cmd,
- "gbproxy",
- "Configure the Gb proxy")
-{
- vty->node = GBPROXY_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nsip_sgsn_nsei,
- cfg_nsip_sgsn_nsei_cmd,
- "sgsn nsei <0-65534>",
- "SGSN information\n"
- "NSEI to be used in the connection with the SGSN\n"
- "The NSEI\n")
-{
- unsigned int nsei = atoi(argv[0]);
-
- if (g_cfg->route_to_sgsn2 && g_cfg->nsip_sgsn2_nsei == nsei) {
- vty_out(vty, "SGSN NSEI %d conflicts with secondary SGSN NSEI%s",
- nsei, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- g_cfg->nsip_sgsn_nsei = nsei;
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_CORE_MNC_STR "Use this network code for the core network\n"
-
-DEFUN(cfg_gbproxy_core_mnc,
- cfg_gbproxy_core_mnc_cmd,
- "core-mobile-network-code <1-999>",
- GBPROXY_CORE_MNC_STR "NCC value\n")
-{
- g_cfg->core_mnc = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_no_core_mnc,
- cfg_gbproxy_no_core_mnc_cmd,
- "no core-mobile-network-code",
- NO_STR GBPROXY_CORE_MNC_STR)
-{
- g_cfg->core_mnc = 0;
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_CORE_MCC_STR "Use this country code for the core network\n"
-
-DEFUN(cfg_gbproxy_core_mcc,
- cfg_gbproxy_core_mcc_cmd,
- "core-mobile-country-code <1-999>",
- GBPROXY_CORE_MCC_STR "MCC value\n")
-{
- g_cfg->core_mcc = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_no_core_mcc,
- cfg_gbproxy_no_core_mcc_cmd,
- "no core-mobile-country-code",
- NO_STR GBPROXY_CORE_MCC_STR)
-{
- g_cfg->core_mcc = 0;
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_MATCH_IMSI_STR "Restrict actions to certain IMSIs\n"
-
-DEFUN(cfg_gbproxy_match_imsi,
- cfg_gbproxy_match_imsi_cmd,
- "match-imsi (patching|routing) .REGEXP",
- GBPROXY_MATCH_IMSI_STR
- "Patch MS related information elements on match only\n"
- "Route to the secondary SGSN on match only\n"
- "Regular expression for the IMSI match\n")
-{
- const char *filter = argv[1];
- const char *err_msg = NULL;
- struct gbproxy_match *match;
- enum gbproxy_match_id match_id = get_string_value(match_ids, argv[0]);
-
- OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
- match_id < GBPROX_MATCH_LAST);
- match = &g_cfg->matches[match_id];
-
- if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
- vty_out(vty, "Match expression invalid: %s%s",
- err_msg, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- g_cfg->acquire_imsi = 1;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_no_match_imsi,
- cfg_gbproxy_no_match_imsi_cmd,
- "no match-imsi",
- NO_STR GBPROXY_MATCH_IMSI_STR)
-{
- enum gbproxy_match_id match_id;
-
- for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id)
- gbproxy_clear_patch_filter(&g_cfg->matches[match_id]);
-
- g_cfg->acquire_imsi = 0;
-
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_CORE_APN_STR "Use this access point name (APN) for the backbone\n"
-#define GBPROXY_CORE_APN_ARG_STR "Replace APN by this string\n" "Remove APN\n"
-
-static int set_core_apn(struct vty *vty, const char *apn)
-{
- int apn_len;
-
- if (!apn) {
- talloc_free(g_cfg->core_apn);
- g_cfg->core_apn = NULL;
- g_cfg->core_apn_size = 0;
- return CMD_SUCCESS;
- }
-
- apn_len = strlen(apn);
-
- if (apn_len >= 100) {
- vty_out(vty, "APN string too long (max 99 chars)%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (apn_len == 0) {
- talloc_free(g_cfg->core_apn);
- /* TODO: replace NULL */
- g_cfg->core_apn = talloc_zero_size(NULL, 2);
- g_cfg->core_apn_size = 0;
- } else {
- /* TODO: replace NULL */
- g_cfg->core_apn =
- talloc_realloc_size(NULL, g_cfg->core_apn, apn_len + 1);
- g_cfg->core_apn_size =
- gprs_str_to_apn(g_cfg->core_apn, apn_len + 1, apn);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_core_apn,
- cfg_gbproxy_core_apn_cmd,
- "core-access-point-name (APN|none)",
- GBPROXY_CORE_APN_STR GBPROXY_CORE_APN_ARG_STR)
-{
- if (strcmp(argv[0], "none") == 0)
- return set_core_apn(vty, "");
- else
- return set_core_apn(vty, argv[0]);
-}
-
-DEFUN(cfg_gbproxy_no_core_apn,
- cfg_gbproxy_no_core_apn_cmd,
- "no core-access-point-name",
- NO_STR GBPROXY_CORE_APN_STR)
-{
- return set_core_apn(vty, NULL);
-}
-
-/* TODO: Remove the patch-ptmsi command, since P-TMSI patching is enabled
- * automatically when needed. This command is only left for manual testing
- * (e.g. doing P-TMSI patching without using a secondary SGSN)
- */
-#define GBPROXY_PATCH_PTMSI_STR "Patch P-TMSI/TLLI\n"
-
-DEFUN(cfg_gbproxy_patch_ptmsi,
- cfg_gbproxy_patch_ptmsi_cmd,
- "patch-ptmsi",
- GBPROXY_PATCH_PTMSI_STR)
-{
- g_cfg->patch_ptmsi = 1;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_no_patch_ptmsi,
- cfg_gbproxy_no_patch_ptmsi_cmd,
- "no patch-ptmsi",
- NO_STR GBPROXY_PATCH_PTMSI_STR)
-{
- g_cfg->patch_ptmsi = 0;
-
- return CMD_SUCCESS;
-}
-
-/* TODO: Remove the acquire-imsi command, since that feature is enabled
- * automatically when IMSI matching is enabled. This command is only left for
- * manual testing (e.g. doing IMSI acquisition without IMSI based patching)
- */
-#define GBPROXY_ACQUIRE_IMSI_STR "Acquire the IMSI before establishing a LLC connection (Experimental)\n"
-
-DEFUN(cfg_gbproxy_acquire_imsi,
- cfg_gbproxy_acquire_imsi_cmd,
- "acquire-imsi",
- GBPROXY_ACQUIRE_IMSI_STR)
-{
- g_cfg->acquire_imsi = 1;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_no_acquire_imsi,
- cfg_gbproxy_no_acquire_imsi_cmd,
- "no acquire-imsi",
- NO_STR GBPROXY_ACQUIRE_IMSI_STR)
-{
- g_cfg->acquire_imsi = 0;
-
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_SECOND_SGSN_STR "Route matching LLC connections to a second SGSN (Experimental)\n"
-
-DEFUN(cfg_gbproxy_secondary_sgsn,
- cfg_gbproxy_secondary_sgsn_cmd,
- "secondary-sgsn nsei <0-65534>",
- GBPROXY_SECOND_SGSN_STR
- "NSEI to be used in the connection with the SGSN\n"
- "The NSEI\n")
-{
- unsigned int nsei = atoi(argv[0]);
-
- if (g_cfg->nsip_sgsn_nsei == nsei) {
- vty_out(vty, "Secondary SGSN NSEI %d conflicts with primary SGSN NSEI%s",
- nsei, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- g_cfg->route_to_sgsn2 = 1;
- g_cfg->nsip_sgsn2_nsei = nsei;
-
- g_cfg->patch_ptmsi = 1;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_no_secondary_sgsn,
- cfg_gbproxy_no_secondary_sgsn_cmd,
- "no secondary-sgsn",
- NO_STR GBPROXY_SECOND_SGSN_STR)
-{
- g_cfg->route_to_sgsn2 = 0;
- g_cfg->nsip_sgsn2_nsei = 0xFFFF;
-
- g_cfg->patch_ptmsi = 0;
-
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_LINK_LIST_STR "Set TLLI list parameters\n"
-#define GBPROXY_MAX_AGE_STR "Limit maximum age\n"
-
-DEFUN(cfg_gbproxy_link_list_max_age,
- cfg_gbproxy_link_list_max_age_cmd,
- "link-list max-age <1-999999>",
- GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR
- "Maximum age in seconds\n")
-{
- g_cfg->tlli_max_age = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_link_list_no_max_age,
- cfg_gbproxy_link_list_no_max_age_cmd,
- "no link-list max-age",
- NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR)
-{
- g_cfg->tlli_max_age = 0;
-
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_MAX_LEN_STR "Limit list length\n"
-
-DEFUN(cfg_gbproxy_link_list_max_len,
- cfg_gbproxy_link_list_max_len_cmd,
- "link-list max-length <1-99999>",
- GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR
- "Maximum number of logical links in the list\n")
-{
- g_cfg->tlli_max_len = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_link_list_no_max_len,
- cfg_gbproxy_link_list_no_max_len_cmd,
- "no link-list max-length",
- NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR)
-{
- g_cfg->tlli_max_len = 0;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_gbproxy_link_list_keep_mode,
- cfg_gbproxy_link_list_keep_mode_cmd,
- "link-list keep-mode (never|re-attach|identified|always)",
- GBPROXY_LINK_LIST_STR "How to keep entries for detached logical links\n"
- "Discard entry immediately after detachment\n"
- "Keep entry if a re-attachment has be requested\n"
- "Keep entry if it associated with an IMSI\n"
- "Don't discard entries after detachment\n")
-{
- int val = get_string_value(keep_modes, argv[0]);
- OSMO_ASSERT(val >= GBPROX_KEEP_NEVER && val <= GBPROX_KEEP_ALWAYS);
- g_cfg->keep_link_infos = val;
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
- SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
-{
- struct gbproxy_peer *peer;
- int show_stats = argc >= 1;
-
- if (show_stats)
- vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
-
- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
- gbprox_vty_print_peer(vty, peer);
-
- if (show_stats)
- vty_out_rate_ctr_group(vty, " ", peer->ctrg);
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
- SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
-{
- struct gbproxy_peer *peer;
- char mi_buf[200];
- time_t now;
- struct timespec ts = {0,};
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
- now = ts.tv_sec;
-
- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
- struct gbproxy_link_info *link_info;
- struct gbproxy_patch_state *state = &peer->patch_state;
-
- gbprox_vty_print_peer(vty, peer);
-
- llist_for_each_entry(link_info, &state->logical_links, list) {
- time_t age = now - link_info->timestamp;
- int stored_msgs = 0;
- struct llist_head *iter;
- llist_for_each(iter, &link_info->stored_msgs)
- stored_msgs++;
-
- if (link_info->imsi > 0) {
- snprintf(mi_buf, sizeof(mi_buf), "(invalid)");
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- link_info->imsi,
- link_info->imsi_len);
- } else {
- snprintf(mi_buf, sizeof(mi_buf), "(none)");
- }
- vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",
- link_info->tlli.current, mi_buf, (int)age);
-
- if (stored_msgs)
- vty_out(vty, ", STORED %d", stored_msgs);
-
- if (g_cfg->route_to_sgsn2)
- vty_out(vty, ", SGSN NSEI %d",
- link_info->sgsn_nsei);
-
- if (link_info->is_deregistered)
- vty_out(vty, ", DE-REGISTERED");
-
- vty_out(vty, "%s", VTY_NEWLINE);
- }
- }
- return CMD_SUCCESS;
-}
-
-DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
- "delete-gbproxy-peer <0-65534> bvci <2-65534>",
- "Delete a GBProxy peer by NSEI and optionally BVCI\n"
- "NSEI number\n"
- "Only delete peer with a matching BVCI\n"
- "BVCI number\n")
-{
- const uint16_t nsei = atoi(argv[0]);
- const uint16_t bvci = atoi(argv[1]);
- int counter;
-
- counter = gbproxy_cleanup_peers(g_cfg, nsei, bvci);
-
- if (counter == 0) {
- vty_out(vty, "BVC not found%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
- "delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
- "Delete a GBProxy peer by NSEI and optionally BVCI\n"
- "NSEI number\n"
- "Only delete BSSGP connections (BVC)\n"
- "Only delete dynamic NS connections (NS-VC)\n"
- "Delete BVC and dynamic NS connections\n"
- "Show what would be deleted instead of actually deleting\n"
- )
-{
- const uint16_t nsei = atoi(argv[0]);
- const char *mode = argv[1];
- int dry_run = argc > 2;
- int delete_bvc = 0;
- int delete_nsvc = 0;
- int counter;
-
- if (strcmp(mode, "only-bvc") == 0)
- delete_bvc = 1;
- else if (strcmp(mode, "only-nsvc") == 0)
- delete_nsvc = 1;
- else
- delete_bvc = delete_nsvc = 1;
-
- if (delete_bvc) {
- if (!dry_run)
- counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);
- else {
- struct gbproxy_peer *peer;
- counter = 0;
- llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
- if (peer->nsei != nsei)
- continue;
-
- vty_out(vty, "BVC: ");
- gbprox_vty_print_peer(vty, peer);
- counter += 1;
- }
- }
- vty_out(vty, "%sDeleted %d BVC%s",
- dry_run ? "Not " : "", counter, VTY_NEWLINE);
- }
-
- if (delete_nsvc) {
- struct gprs_ns_inst *nsi = g_cfg->nsi;
- struct gprs_nsvc *nsvc, *nsvc2;
-
- counter = 0;
- llist_for_each_entry_safe(nsvc, nsvc2, &nsi->gprs_nsvcs, list) {
- if (nsvc->nsei != nsei)
- continue;
- if (nsvc->persistent)
- continue;
-
- if (!dry_run)
- gprs_nsvc_delete(nsvc);
- else
- vty_out(vty, "NS-VC: NSEI %5u, NS-VCI %5u, "
- "remote %s%s",
- nsvc->nsei, nsvc->nsvci,
- gprs_ns_ll_str(nsvc), VTY_NEWLINE);
- counter += 1;
- }
- vty_out(vty, "%sDeleted %d NS-VC%s",
- dry_run ? "Not " : "", counter, VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_DELETE_LINK_STR \
- "Delete a GBProxy logical link entry by NSEI and identification\nNSEI number\n"
-
-DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
- "delete-gbproxy-link <0-65534> (tlli|imsi|sgsn-nsei) IDENT",
- GBPROXY_DELETE_LINK_STR
- "Delete entries with a matching TLLI (hex)\n"
- "Delete entries with a matching IMSI\n"
- "Delete entries with a matching SGSN NSEI\n"
- "Identification to match\n")
-{
- const uint16_t nsei = atoi(argv[0]);
- enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_SGSN = 's'} match;
- uint32_t ident = 0;
- const char *imsi = NULL;
- struct gbproxy_peer *peer = 0;
- struct gbproxy_link_info *link_info, *nxt;
- struct gbproxy_patch_state *state;
- char mi_buf[200];
- int found = 0;
-
- match = argv[1][0];
-
- switch (match) {
- case MATCH_TLLI: ident = strtoll(argv[2], NULL, 16); break;
- case MATCH_IMSI: imsi = argv[2]; break;
- case MATCH_SGSN: ident = strtoll(argv[2], NULL, 0); break;
- };
-
- peer = gbproxy_peer_by_nsei(g_cfg, nsei);
- if (!peer) {
- vty_out(vty, "Didn't find peer with NSEI %d%s",
- nsei, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- state = &peer->patch_state;
-
- llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list) {
- switch (match) {
- case MATCH_TLLI:
- if (link_info->tlli.current != ident)
- continue;
- break;
- case MATCH_SGSN:
- if (link_info->sgsn_nsei != ident)
- continue;
- break;
- case MATCH_IMSI:
- if (!link_info->imsi)
- continue;
- mi_buf[0] = '\0';
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- link_info->imsi,
- link_info->imsi_len);
-
- if (strcmp(mi_buf, imsi) != 0)
- continue;
- break;
- }
-
- vty_out(vty, "Deleting link with TLLI %08x%s", link_info->tlli.current,
- VTY_NEWLINE);
- gbproxy_delete_link_info(peer, link_info);
- found += 1;
- }
-
- if (!found && argc >= 2) {
- vty_out(vty, "Didn't find link entry with %s %s%s",
- argv[1], argv[2], VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(delete_gb_link, delete_gb_link_cmd,
- "delete-gbproxy-link <0-65534> (stale|de-registered)",
- GBPROXY_DELETE_LINK_STR
- "Delete stale entries\n"
- "Delete de-registered entries\n")
-{
- const uint16_t nsei = atoi(argv[0]);
- enum {MATCH_STALE = 's', MATCH_DEREGISTERED = 'd'} match;
- struct gbproxy_peer *peer = 0;
- struct gbproxy_link_info *link_info, *nxt;
- struct gbproxy_patch_state *state;
- time_t now;
- struct timespec ts = {0,};
-
- int found = 0;
-
- match = argv[1][0];
-
- peer = gbproxy_peer_by_nsei(g_cfg, nsei);
- if (!peer) {
- vty_out(vty, "Didn't find peer with NSEI %d%s",
- nsei, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- state = &peer->patch_state;
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
- now = ts.tv_sec;
-
- if (match == MATCH_STALE) {
- found = gbproxy_remove_stale_link_infos(peer, now);
- if (found)
- vty_out(vty, "Deleted %d stale logical link%s%s",
- found, found == 1 ? "" : "s", VTY_NEWLINE);
- } else {
- llist_for_each_entry_safe(link_info, nxt,
- &state->logical_links, list) {
- if (!link_info->is_deregistered)
- continue;
-
- gbproxy_delete_link_info(peer, link_info);
- found += 1;
- }
- }
-
- if (found)
- vty_out(vty, "Deleted %d %s logical link%s%s",
- found, argv[1], found == 1 ? "" : "s", VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-/*
- * legacy commands to provide an upgrade path from "broken" releases
- * or pre-releases
- */
-DEFUN_DEPRECATED(cfg_gbproxy_broken_apn_match,
- cfg_gbproxy_broken_apn_match_cmd,
- "core-access-point-name none match-imsi .REGEXP",
- GBPROXY_CORE_APN_STR GBPROXY_MATCH_IMSI_STR "Remove APN\n"
- "Patch MS related information elements on match only\n"
- "Route to the secondary SGSN on match only\n"
- "Regular expression for the IMSI match\n")
-{
- const char *filter = argv[0];
- const char *err_msg = NULL;
- struct gbproxy_match *match;
- enum gbproxy_match_id match_id = get_string_value(match_ids, "patching");
-
- /* apply APN none */
- set_core_apn(vty, "");
-
- /* do the matching... with copy and paste */
- OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
- match_id < GBPROX_MATCH_LAST);
- match = &g_cfg->matches[match_id];
-
- if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
- vty_out(vty, "Match expression invalid: %s%s",
- err_msg, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- g_cfg->acquire_imsi = 1;
-
- return CMD_SUCCESS;
-}
-
-#define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n"
-#define GBPROXY_MAX_LEN_STR "Limit list length\n"
-DEFUN_DEPRECATED(cfg_gbproxy_depr_tlli_list_max_len,
- cfg_gbproxy_depr_tlli_list_max_len_cmd,
- "tlli-list max-length <1-99999>",
- GBPROXY_TLLI_LIST_STR GBPROXY_MAX_LEN_STR
- "Maximum number of TLLIs in the list\n")
-{
- g_cfg->tlli_max_len = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-int gbproxy_vty_init(void)
-{
- install_element_ve(&show_gbproxy_cmd);
- install_element_ve(&show_gbproxy_links_cmd);
-
- install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
- install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
- install_element(ENABLE_NODE, &delete_gb_link_by_id_cmd);
- install_element(ENABLE_NODE, &delete_gb_link_cmd);
-
- install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
- install_node(&gbproxy_node, config_write_gbproxy);
- vty_install_default(GBPROXY_NODE);
- install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_core_mcc_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_match_imsi_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_secondary_sgsn_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_acquire_imsi_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_age_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_len_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_keep_mode_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_no_match_imsi_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_no_secondary_sgsn_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_no_acquire_imsi_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_age_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_len_cmd);
-
- /* broken or deprecated to allow an upgrade path */
- install_element(GBPROXY_NODE, &cfg_gbproxy_broken_apn_match_cmd);
- install_element(GBPROXY_NODE, &cfg_gbproxy_depr_tlli_list_max_len_cmd);
-
- return 0;
-}
-
-int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg)
-{
- int rc;
-
- g_cfg = cfg;
- rc = vty_read_config_file(config_file, NULL);
- if (rc < 0) {
- fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
- return rc;
- }
-
- return 0;
-}
-
diff --git a/openbsc/src/gprs/gprs_gb_parse.c b/openbsc/src/gprs/gprs_gb_parse.c
deleted file mode 100644
index d5a122bda..000000000
--- a/openbsc/src/gprs/gprs_gb_parse.c
+++ /dev/null
@@ -1,636 +0,0 @@
-/* GPRS Gb message parser */
-
-/* (C) 2014 by On-Waves
- * 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/gsm/gsm48.h>
-#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
-
-#include <openbsc/gprs_gb_parse.h>
-
-#include <openbsc/gprs_utils.h>
-
-#include <openbsc/debug.h>
-
-#include <osmocom/gprs/gprs_bssgp.h>
-
-static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
- size_t value_len;
-
- parse_ctx->llc_msg_name = "ATTACH_REQ";
-
- /* Skip MS network capability */
- if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
- value_len < 1 || value_len > 8)
- /* invalid */
- return 0;
-
- /* Skip Attach type */
- /* Skip Ciphering key sequence number */
- /* Skip DRX parameter */
- osmo_shift_v_fixed(&data, &data_len, 3, NULL);
-
- /* Get Mobile identity */
- if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
- value_len < 5 || value_len > 8)
- /* invalid */
- return 0;
-
- if (gprs_is_mi_tmsi(value, value_len)) {
- parse_ctx->ptmsi_enc = value + 1;
- } else if (gprs_is_mi_imsi(value, value_len)) {
- parse_ctx->imsi = value;
- parse_ctx->imsi_len = value_len;
- }
-
- if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
- return 0;
-
- parse_ctx->old_raid_enc = value;
-
- return 1;
-}
-
-static int gprs_gb_parse_gmm_attach_ack(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
- size_t value_len;
-
- parse_ctx->llc_msg_name = "ATTACH_ACK";
-
- /* Skip Attach result */
- /* Skip Force to standby */
- /* Skip Periodic RA update timer */
- /* Skip Radio priority for SMS */
- /* Skip Spare half octet */
- osmo_shift_v_fixed(&data, &data_len, 3, NULL);
-
- if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
- return 0;
-
- parse_ctx->raid_enc = value;
-
- /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
- osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
-
- /* Skip Negotiated READY timer value (GPRS timer, opt, TV, length 2) */
- osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL);
-
- /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
- if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
- &value, &value_len) > 0 &&
- gprs_is_mi_tmsi(value, value_len))
- parse_ctx->new_ptmsi_enc = value + 1;
- return 1;
-}
-
-static int gprs_gb_parse_gmm_attach_rej(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
-
- parse_ctx->llc_msg_name = "ATTACH_REJ";
-
- /* GMM cause */
- if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
- return 0;
-
- parse_ctx->invalidate_tlli = 1;
-
- return 1;
-}
-
-
-static int gprs_gb_parse_gmm_detach_req(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
- size_t value_len;
- int detach_type;
- int power_off;
-
- parse_ctx->llc_msg_name = "DETACH_REQ";
-
- /* Skip spare half octet */
- /* Get Detach type */
- if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
- /* invalid */
- return 0;
-
- detach_type = *value & 0x07;
- power_off = *value & 0x08 ? 1 : 0;
-
- if (parse_ctx->to_bss) {
- /* Network originated */
- if (detach_type == GPRS_DET_T_MT_REATT_REQ)
- parse_ctx->await_reattach = 1;
- } else {
- /* Mobile originated */
-
- if (power_off)
- parse_ctx->invalidate_tlli = 1;
-
- /* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */
- if (osmo_match_shift_tlv(&data, &data_len,
- GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0)
- {
- if (gprs_is_mi_tmsi(value, value_len))
- parse_ctx->ptmsi_enc = value + 1;
- }
- }
-
- return 1;
-}
-
-static int gprs_gb_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
-
- parse_ctx->llc_msg_name = "RA_UPD_REQ";
-
- /* Skip Update type */
- /* Skip GPRS ciphering key sequence number */
- osmo_shift_v_fixed(&data, &data_len, 1, NULL);
-
- if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
- return 0;
-
- parse_ctx->old_raid_enc = value;
-
- return 1;
-}
-
-static int gprs_gb_parse_gmm_ra_upd_rej(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
- uint8_t cause;
- int force_standby;
-
- parse_ctx->llc_msg_name = "RA_UPD_REJ";
-
- /* GMM cause */
- if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
- return 0;
-
- cause = value[0];
-
- /* Force to standby, 1/2 */
- /* spare bits, 1/2 */
- if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
- return 0;
-
- force_standby = (value[0] & 0x07) == 0x01;
-
- if (cause == GMM_CAUSE_IMPL_DETACHED && !force_standby)
- parse_ctx->await_reattach = 1;
-
- parse_ctx->invalidate_tlli = 1;
-
- return 1;
-}
-
-static int gprs_gb_parse_gmm_ra_upd_ack(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
- size_t value_len;
-
- parse_ctx->llc_msg_name = "RA_UPD_ACK";
-
- /* Skip Force to standby */
- /* Skip Update result */
- /* Skip Periodic RA update timer */
- osmo_shift_v_fixed(&data, &data_len, 2, NULL);
-
- if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
- return 0;
-
- parse_ctx->raid_enc = value;
-
- /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
- osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
-
- /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
- if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
- &value, &value_len) > 0 &&
- gprs_is_mi_tmsi(value, value_len))
- parse_ctx->new_ptmsi_enc = value + 1;
-
- return 1;
-}
-
-static int gprs_gb_parse_gmm_ptmsi_reall_cmd(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
- size_t value_len;
-
- parse_ctx->llc_msg_name = "PTMSI_REALL_CMD";
-
- LOGP(DLLC, LOGL_NOTICE,
- "Got P-TMSI Reallocation Command which is not covered by unit tests yet.\n");
-
- /* Allocated P-TMSI */
- if (osmo_shift_lv(&data, &data_len, &value, &value_len) > 0 &&
- gprs_is_mi_tmsi(value, value_len))
- parse_ctx->new_ptmsi_enc = value + 1;
-
- if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
- return 0;
-
- parse_ctx->raid_enc = value;
-
- return 1;
-}
-
-static int gprs_gb_parse_gmm_id_resp(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- uint8_t *value;
- size_t value_len;
-
- parse_ctx->llc_msg_name = "ID_RESP";
-
- /* Mobile identity, Mobile identity 10.5.1.4, M LV 2-10 */
- if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
- value_len < 1 || value_len > 9)
- /* invalid */
- return 0;
-
- if (gprs_is_mi_tmsi(value, value_len)) {
- parse_ctx->ptmsi_enc = value + 1;
- } else if (gprs_is_mi_imsi(value, value_len)) {
- parse_ctx->imsi = value;
- parse_ctx->imsi_len = value_len;
- }
-
- return 1;
-}
-
-static int gprs_gb_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- ssize_t old_len;
- uint8_t *value;
- size_t value_len;
-
- parse_ctx->llc_msg_name = "ACT_PDP_REQ";
-
- /* Skip Requested NSAPI */
- /* Skip Requested LLC SAPI */
- osmo_shift_v_fixed(&data, &data_len, 2, NULL);
-
- /* Skip Requested QoS (support 04.08 and 24.008) */
- if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
- value_len < 4 || value_len > 14)
- /* invalid */
- return 0;
-
- /* Skip Requested PDP address */
- if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
- value_len < 2 || value_len > 18)
- /* invalid */
- return 0;
-
- /* Access point name */
- old_len = osmo_match_shift_tlv(&data, &data_len,
- GSM48_IE_GSM_APN, &value, &value_len);
-
- if (old_len > 0 && value_len >=1 && value_len <= 100) {
- parse_ctx->apn_ie = data - old_len;
- parse_ctx->apn_ie_len = old_len;
- }
-
- return 1;
-}
-
-int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gsm48_hdr *g48h;
- uint8_t pdisc;
- uint8_t msg_type;
-
- if (osmo_shift_v_fixed(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0)
- return 0;
-
- parse_ctx->g48_hdr = g48h;
-
- pdisc = gsm48_hdr_pdisc(g48h);
- if (pdisc != GSM48_PDISC_MM_GPRS && pdisc != GSM48_PDISC_SM_GPRS)
- return 1;
-
- msg_type = gsm48_hdr_msg_type(g48h);
- switch (msg_type) {
- case GSM48_MT_GMM_ATTACH_REQ:
- return gprs_gb_parse_gmm_attach_req(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_ATTACH_REJ:
- return gprs_gb_parse_gmm_attach_rej(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_ATTACH_ACK:
- return gprs_gb_parse_gmm_attach_ack(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_RA_UPD_REQ:
- return gprs_gb_parse_gmm_ra_upd_req(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_RA_UPD_REJ:
- return gprs_gb_parse_gmm_ra_upd_rej(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_RA_UPD_ACK:
- return gprs_gb_parse_gmm_ra_upd_ack(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_PTMSI_REALL_CMD:
- return gprs_gb_parse_gmm_ptmsi_reall_cmd(data, data_len, parse_ctx);
-
- case GSM48_MT_GSM_ACT_PDP_REQ:
- return gprs_gb_parse_gsm_act_pdp_req(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_ID_RESP:
- return gprs_gb_parse_gmm_id_resp(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_DETACH_REQ:
- return gprs_gb_parse_gmm_detach_req(data, data_len, parse_ctx);
-
- case GSM48_MT_GMM_DETACH_ACK:
- parse_ctx->llc_msg_name = "DETACH_ACK";
- parse_ctx->invalidate_tlli = 1;
- break;
-
- default:
- LOGP(DLLC, LOGL_NOTICE,
- "Unhandled GSM 04.08 message type %s for protocol discriminator %s.\n",
- get_value_string(gprs_msgt_gmm_names, msg_type), get_value_string(gsm48_pdisc_names, pdisc));
- break;
- };
-
- return 1;
-}
-
-int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
- int rc;
- int fcs;
-
- /* parse LLC */
- rc = gprs_llc_hdr_parse(ghp, llc, llc_len);
- gprs_llc_hdr_dump(ghp, NULL);
- if (rc != 0) {
- LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n");
- return 0;
- }
-
- fcs = gprs_llc_fcs(llc, ghp->crc_length);
- LOGP(DLLC, LOGL_DEBUG, "Got LLC message, CRC: %06x (computed %06x)\n",
- ghp->fcs, fcs);
-
- if (!ghp->data)
- return 0;
-
- if (ghp->sapi != GPRS_SAPI_GMM)
- return 1;
-
- if (ghp->cmd != GPRS_LLC_UI)
- return 1;
-
- if (ghp->is_encrypted) {
- parse_ctx->need_decryption = 1;
- return 0;
- }
-
- return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx);
-}
-
-int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
- struct gprs_gb_parse_context *parse_ctx)
-{
- struct bssgp_normal_hdr *bgph;
- struct bssgp_ud_hdr *budh = NULL;
- struct tlv_parsed *tp = &parse_ctx->bssgp_tp;
- uint8_t pdu_type;
- uint8_t *data;
- size_t data_len;
- int rc;
-
- if (bssgp_len < sizeof(struct bssgp_normal_hdr))
- return 0;
-
- bgph = (struct bssgp_normal_hdr *)bssgp;
- pdu_type = bgph->pdu_type;
-
- if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
- pdu_type == BSSGP_PDUT_DL_UNITDATA) {
- if (bssgp_len < sizeof(struct bssgp_ud_hdr))
- return 0;
- budh = (struct bssgp_ud_hdr *)bssgp;
- bgph = NULL;
- data = budh->data;
- data_len = bssgp_len - sizeof(*budh);
- } else {
- data = bgph->data;
- data_len = bssgp_len - sizeof(*bgph);
- }
-
- parse_ctx->pdu_type = pdu_type;
- parse_ctx->bud_hdr = budh;
- parse_ctx->bgp_hdr = bgph;
- parse_ctx->bssgp_data = data;
- parse_ctx->bssgp_data_len = data_len;
-
- if (bssgp_tlv_parse(tp, data, data_len) < 0)
- return 0;
-
- if (budh)
- parse_ctx->tlli_enc = (uint8_t *)&budh->tlli;
-
- if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA))
- parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
-
- if (TLVP_PRESENT(tp, BSSGP_IE_CELL_ID))
- parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_CELL_ID);
-
- if (TLVP_PRESENT(tp, BSSGP_IE_IMSI)) {
- parse_ctx->imsi = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_IMSI);
- parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
- }
-
- if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) {
- if (parse_ctx->tlli_enc)
- /* This is TLLI old, don't confuse it with TLLI current */
- parse_ctx->old_tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
- else
- parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
- }
-
- if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS)
- parse_ctx->bssgp_ptmsi_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TMSI);
-
- if (TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) {
- uint8_t *llc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
- size_t llc_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
-
- rc = gprs_gb_parse_llc(llc, llc_len, parse_ctx);
- if (!rc)
- return 0;
-
- parse_ctx->llc = llc;
- parse_ctx->llc_len = llc_len;
- }
-
- if (parse_ctx->tlli_enc) {
- uint32_t tmp_tlli;
- memcpy(&tmp_tlli, parse_ctx->tlli_enc, sizeof(tmp_tlli));
- parse_ctx->tlli = ntohl(tmp_tlli);
- }
-
- if (parse_ctx->bssgp_raid_enc && parse_ctx->old_raid_enc &&
- memcmp(parse_ctx->bssgp_raid_enc, parse_ctx->old_raid_enc, 6) != 0)
- parse_ctx->old_raid_is_foreign = 1;
-
- return 1;
-}
-
-void gprs_gb_log_parse_context(int log_level,
- struct gprs_gb_parse_context *parse_ctx,
- const char *default_msg_name)
-{
- const char *msg_name;
- const char *sep = "";
-
- if (!parse_ctx->tlli_enc &&
- !parse_ctx->ptmsi_enc &&
- !parse_ctx->new_ptmsi_enc &&
- !parse_ctx->bssgp_ptmsi_enc &&
- !parse_ctx->imsi)
- return;
-
- msg_name = gprs_gb_message_name(parse_ctx, default_msg_name);
-
- if (parse_ctx->llc_msg_name)
- msg_name = parse_ctx->llc_msg_name;
-
- LOGP(DGPRS, log_level, "%s: Got", msg_name);
-
- if (parse_ctx->tlli_enc) {
- LOGPC(DGPRS, log_level, "%s TLLI %08x", sep, parse_ctx->tlli);
- sep = ",";
- }
-
- if (parse_ctx->old_tlli_enc) {
- LOGPC(DGPRS, log_level, "%s old TLLI %02x%02x%02x%02x", sep,
- parse_ctx->old_tlli_enc[0],
- parse_ctx->old_tlli_enc[1],
- parse_ctx->old_tlli_enc[2],
- parse_ctx->old_tlli_enc[3]);
- sep = ",";
- }
-
- if (parse_ctx->bssgp_raid_enc) {
- struct gprs_ra_id raid;
- gsm48_parse_ra(&raid, parse_ctx->bssgp_raid_enc);
- LOGPC(DGPRS, log_level, "%s BSSGP RAID %u-%u-%u-%u", sep,
- raid.mcc, raid.mnc, raid.lac, raid.rac);
- sep = ",";
- }
-
- if (parse_ctx->raid_enc) {
- struct gprs_ra_id raid;
- gsm48_parse_ra(&raid, parse_ctx->raid_enc);
- LOGPC(DGPRS, log_level, "%s RAID %u-%u-%u-%u", sep,
- raid.mcc, raid.mnc, raid.lac, raid.rac);
- sep = ",";
- }
-
- if (parse_ctx->old_raid_enc) {
- struct gprs_ra_id raid;
- gsm48_parse_ra(&raid, parse_ctx->old_raid_enc);
- LOGPC(DGPRS, log_level, "%s old RAID %u-%u-%u-%u", sep,
- raid.mcc, raid.mnc, raid.lac, raid.rac);
- sep = ",";
- }
-
- if (parse_ctx->bssgp_ptmsi_enc) {
- uint32_t ptmsi = GSM_RESERVED_TMSI;
- gprs_parse_tmsi(parse_ctx->bssgp_ptmsi_enc, &ptmsi);
- LOGPC(DGPRS, log_level, "%s BSSGP PTMSI %08x", sep, ptmsi);
- sep = ",";
- }
-
- if (parse_ctx->ptmsi_enc) {
- uint32_t ptmsi = GSM_RESERVED_TMSI;
- gprs_parse_tmsi(parse_ctx->ptmsi_enc, &ptmsi);
- LOGPC(DGPRS, log_level, "%s PTMSI %08x", sep, ptmsi);
- sep = ",";
- }
-
- if (parse_ctx->new_ptmsi_enc) {
- uint32_t new_ptmsi = GSM_RESERVED_TMSI;
- gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
- LOGPC(DGPRS, log_level, "%s new PTMSI %08x", sep, new_ptmsi);
- sep = ",";
- }
-
- if (parse_ctx->imsi) {
- char mi_buf[200];
- mi_buf[0] = '\0';
- gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
- parse_ctx->imsi, parse_ctx->imsi_len);
- LOGPC(DGPRS, log_level, "%s IMSI %s",
- sep, mi_buf);
- sep = ",";
- }
- if (parse_ctx->invalidate_tlli) {
- LOGPC(DGPRS, log_level, "%s invalidate", sep);
- sep = ",";
- }
- if (parse_ctx->await_reattach) {
- LOGPC(DGPRS, log_level, "%s re-attach", sep);
- sep = ",";
- }
-
- LOGPC(DGPRS, log_level, "\n");
-}
-
-const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
- const char *default_msg_name)
-{
- if (parse_ctx->llc_msg_name)
- return parse_ctx->llc_msg_name;
-
- if (parse_ctx->g48_hdr)
- return "GMM";
-
- if (parse_ctx->llc)
- return "LLC";
-
- if (parse_ctx->bud_hdr)
- return "BSSGP-UNITDATA";
-
- if (parse_ctx->bgp_hdr)
- return "BSSGP";
-
- return "unknown";
-}
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
deleted file mode 100644
index e6751db7c..000000000
--- a/openbsc/src/gprs/gprs_gmm.c
+++ /dev/null
@@ -1,2939 +0,0 @@
-/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
- * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
-
-/* (C) 2009-2015 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010 by On-Waves
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#include <openssl/rand.h>
-
-#include "bscconfig.h"
-
-#include <openbsc/db.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/gsm/gsm_utils.h>
-#include <osmocom/core/signal.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/crypt/auth.h>
-#include <osmocom/gsm/apn.h>
-#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
-
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#ifdef BUILD_IU
-#include <osmocom/ranap/ranap_ies_defs.h>
-#include <osmocom/ranap/ranap_msg_factory.h>
-#endif
-
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/paging.h>
-#include <openbsc/transaction.h>
-#include <openbsc/gprs_llc.h>
-#include <openbsc/gprs_sgsn.h>
-#include <openbsc/gprs_gmm.h>
-#include <openbsc/gprs_utils.h>
-#include <openbsc/gprs_subscriber.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/signal.h>
-#include <openbsc/iu.h>
-#include <openbsc/gprs_sndcp.h>
-
-#include <pdp.h>
-
-#define PTMSI_ALLOC
-
-extern struct sgsn_instance *sgsn;
-
-static const struct tlv_definition gsm48_gmm_att_tlvdef = {
- .def = {
- [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 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 },
- [GSM48_IE_GMM_AUTH_RAND] = { TLV_TYPE_FIXED, 16 },
- [GSM48_IE_GMM_AUTH_SRES] = { TLV_TYPE_FIXED, 4 },
- [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_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 },
- [GSM48_IE_GMM_PS_LCS_CAPA] = { TLV_TYPE_TLV, 0 },
- [GSM48_IE_GMM_GMM_MBMS_CTX_ST] = { TLV_TYPE_TLV, 0 },
- },
-};
-
-static const struct tlv_definition gsm48_sm_att_tlvdef = {
- .def = {
- [GSM48_IE_GSM_APN] = { TLV_TYPE_TLV, 0 },
- [GSM48_IE_GSM_PROTO_CONF_OPT] = { TLV_TYPE_TLV, 0 },
- [GSM48_IE_GSM_PDP_ADDR] = { TLV_TYPE_TLV, 0 },
- [GSM48_IE_GSM_AA_TMR] = { TLV_TYPE_TV, 1 },
- [GSM48_IE_GSM_NAME_FULL] = { TLV_TYPE_TLV, 0 },
- [GSM48_IE_GSM_NAME_SHORT] = { TLV_TYPE_TLV, 0 },
- [GSM48_IE_GSM_TIMEZONE] = { TLV_TYPE_FIXED, 1 },
- [GSM48_IE_GSM_UTC_AND_TZ] = { TLV_TYPE_FIXED, 7 },
- [GSM48_IE_GSM_LSA_ID] = { TLV_TYPE_TLV, 0 },
- },
-};
-
-static const struct value_string gprs_pmm_state_names[] = {
- { PMM_DETACHED, "PMM DETACH" },
- { PMM_CONNECTED, "PMM CONNECTED" },
- { PMM_IDLE, "PMM IDLE" },
- { MM_IDLE, "MM IDLE" },
- { MM_READY, "MM READY" },
- { MM_STANDBY, "MM STANDBY" },
- { 0, NULL }
-};
-
-static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx);
-
-static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx)
-{
- struct sgsn_pdp_ctx *pdp;
- llist_for_each_entry(pdp, &mm_ctx->pdp_list, list) {
- sgsn_pdp_upd_gtp_u(pdp,
- &sgsn->cfg.gtp_listenaddr.sin_addr,
- sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
- }
-}
-
-void mmctx_set_pmm_state(struct sgsn_mm_ctx *ctx, enum gprs_pmm_state state)
-{
- if (ctx->ran_type != MM_CTX_T_UTRAN_Iu)
- return;
-
- if (ctx->pmm_state == state)
- return;
-
- LOGMMCTXP(LOGL_INFO, ctx, "Changing PMM state from %s to %s\n",
- get_value_string(gprs_pmm_state_names, ctx->pmm_state),
- get_value_string(gprs_pmm_state_names, state));
-
- switch (state) {
- case PMM_IDLE:
- /* TODO: start RA Upd timer */
- mmctx_change_gtpu_endpoints_to_sgsn(ctx);
- break;
- case PMM_CONNECTED:
- break;
- default:
- break;
- }
-
- ctx->pmm_state = state;
-}
-
-void mmctx_set_mm_state(struct sgsn_mm_ctx *ctx, enum gprs_pmm_state state)
-{
- if (ctx->ran_type != MM_CTX_T_GERAN_Gb)
- return;
-
- if (ctx->pmm_state == state)
- return;
-
- LOGMMCTXP(LOGL_INFO, ctx, "Changing MM state from %s to %s\n",
- get_value_string(gprs_pmm_state_names, ctx->pmm_state),
- get_value_string(gprs_pmm_state_names, state));
-
- ctx->pmm_state = state;
-}
-
-#ifdef BUILD_IU
-int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies);
-int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data)
-{
- struct sgsn_mm_ctx *mm;
- int rc = -1;
-
- mm = sgsn_mm_ctx_by_ue_ctx(ctx);
- if (!mm) {
- LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type);
- return rc;
- }
-
- switch (type) {
- case IU_EVENT_RAB_ASSIGN:
- rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data);
- break;
- case IU_EVENT_IU_RELEASE:
- /* fall thru */
- case IU_EVENT_LINK_INVALIDATED:
- /* Clean up ue_conn_ctx here */
- LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
- if (mm->pmm_state == PMM_CONNECTED)
- mmctx_set_pmm_state(mm, PMM_IDLE);
- rc = 0;
- break;
- case IU_EVENT_SECURITY_MODE_COMPLETE:
- /* Continue authentication here */
- mm->iu.ue_ctx->integrity_active = 1;
- rc = gsm48_gmm_authorize(mm);
- break;
- default:
- LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type);
- rc = -1;
- break;
- }
- return rc;
-}
-#endif
-
-
-/* Our implementation, should be kept in SGSN */
-
-static void mmctx_timer_cb(void *_mm);
-
-static void mmctx_timer_start(struct sgsn_mm_ctx *mm, unsigned int T,
- unsigned int seconds)
-{
- if (osmo_timer_pending(&mm->timer))
- LOGMMCTXP(LOGL_ERROR, mm, "Starting MM timer %u while old "
- "timer %u pending\n", T, mm->T);
- mm->T = T;
- mm->num_T_exp = 0;
-
- /* FIXME: we should do this only once ? */
- osmo_timer_setup(&mm->timer, mmctx_timer_cb, mm);
- osmo_timer_schedule(&mm->timer, seconds, 0);
-}
-
-static void mmctx_timer_stop(struct sgsn_mm_ctx *mm, unsigned int T)
-{
- if (mm->T != T)
- LOGMMCTXP(LOGL_ERROR, mm, "Stopping MM timer %u but "
- "%u is running\n", T, mm->T);
- osmo_timer_del(&mm->timer);
-}
-
-time_t gprs_max_time_to_idle(void)
-{
- return sgsn->cfg.timers.T3314 + (sgsn->cfg.timers.T3312 + 4 * 60);
-}
-
-/* Send a message through the underlying layer.
- * For param encryptable, see 3GPP TS 24.008 § 4.7.1.2 and
- * gsm48_hdr_gmm_cipherable(). Pass false for not cipherable messages. */
-static int gsm48_gmm_sendmsg(struct msgb *msg, int command,
- struct sgsn_mm_ctx *mm, bool encryptable)
-{
- if (mm) {
- rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
-#ifdef BUILD_IU
- if (mm->ran_type == MM_CTX_T_UTRAN_Iu)
- return iu_tx(msg, GPRS_SAPI_GMM);
-#endif
- }
-
-#ifdef BUILD_IU
- /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb mode
- * dst is empty. */
- /* FIXME: have a more explicit indicator for Iu messages */
- if (msg->dst)
- return iu_tx(msg, GPRS_SAPI_GMM);
-#endif
-
- /* caller needs to provide TLLI, BVCI and NSEI */
- return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm, encryptable);
-}
-
-/* copy identifiers from old message to new message, this
- * is required so lower layers can route it correctly */
-static void gmm_copy_id(struct msgb *msg, const struct msgb *old)
-{
- msgb_tlli(msg) = msgb_tlli(old);
- msgb_bvci(msg) = msgb_bvci(old);
- msgb_nsei(msg) = msgb_nsei(old);
- msg->dst = old->dst;
-}
-
-/* Store BVCI/NSEI in MM context */
-static void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg)
-{
- mm->gb.bvci = msgb_bvci(msg);
- mm->gb.nsei = msgb_nsei(msg);
- /* In case a Iu connection is reconnected we need to update the ue ctx */
- mm->iu.ue_ctx = msg->dst;
-}
-
-/* Store BVCI/NSEI in MM context */
-static void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm)
-{
- msgb_tlli(msg) = mm->gb.tlli;
- msgb_bvci(msg) = mm->gb.bvci;
- msgb_nsei(msg) = mm->gb.nsei;
- msg->dst = mm->iu.ue_ctx;
-}
-
-static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
-{
- LOGMMCTXP(LOGL_INFO, ctx, "Cleaning MM context due to %s\n", log_text);
-
- /* Mark MM state as deregistered */
- ctx->gmm_state = GMM_DEREGISTERED;
- mmctx_set_pmm_state(ctx, PMM_DETACHED);
- mmctx_set_pmm_state(ctx, MM_IDLE);
-
- sgsn_mm_ctx_cleanup_free(ctx);
-}
-
-/* Chapter 9.4.18 */
-static int _tx_status(struct msgb *msg, uint8_t cause,
- struct sgsn_mm_ctx *mmctx, int sm)
-{
- struct gsm48_hdr *gh;
-
- /* MMCTX might be NULL! */
-
- DEBUGP(DMM, "<- GPRS MM STATUS (cause: %s)\n",
- get_value_string(gsm48_gmm_cause_names, cause));
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- if (sm) {
- gh->proto_discr = GSM48_PDISC_SM_GPRS;
- gh->msg_type = GSM48_MT_GSM_STATUS;
- } else {
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_STATUS;
- }
- gh->data[0] = cause;
-
- return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
-}
-
-static int gsm48_tx_gmm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 GMM STATUS");
-
- mmctx2msgid(msg, mmctx);
- return _tx_status(msg, cause, mmctx, 0);
-}
-
-static int gsm48_tx_sm_status(struct sgsn_mm_ctx *mmctx, uint8_t cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SM STATUS");
-
- mmctx2msgid(msg, mmctx);
- return _tx_status(msg, cause, mmctx, 1);
-}
-
-static int _tx_detach_req(struct msgb *msg, uint8_t detach_type, uint8_t cause,
- struct sgsn_mm_ctx *mmctx)
-{
- struct gsm48_hdr *gh;
-
- /* MMCTX might be NULL! */
-
- DEBUGP(DMM, "<- GPRS MM DETACH REQ (type: %s, cause: %s)\n",
- get_value_string(gprs_det_t_mt_strs, detach_type),
- get_value_string(gsm48_gmm_cause_names, cause));
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
-
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_DETACH_REQ;
- gh->data[0] = detach_type & 0x07;
-
- msgb_tv_put(msg, GSM48_IE_GMM_CAUSE, cause);
-
- return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
-}
-
-static int gsm48_tx_gmm_detach_req(struct sgsn_mm_ctx *mmctx,
- uint8_t detach_type, uint8_t cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 DET REQ");
-
- mmctx2msgid(msg, mmctx);
- return _tx_detach_req(msg, detach_type, cause, mmctx);
-}
-
-static int gsm48_tx_gmm_detach_req_oldmsg(struct msgb *oldmsg,
- uint8_t detach_type, uint8_t cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 DET OLD");
-
- gmm_copy_id(msg, oldmsg);
- return _tx_detach_req(msg, detach_type, cause, NULL);
-}
-
-static struct gsm48_qos default_qos = {
- .delay_class = 4, /* best effort */
- .reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT,
- .peak_tput = GSM48_QOS_PEAK_TPUT_32000bps,
- .preced_class = GSM48_QOS_PC_NORMAL,
- .mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT,
- .traf_class = GSM48_QOS_TC_INTERACTIVE,
- .deliv_order = GSM48_QOS_DO_UNORDERED,
- .deliv_err_sdu = GSM48_QOS_ERRSDU_YES,
- .max_sdu_size = GSM48_QOS_MAXSDU_1520,
- .max_bitrate_up = GSM48_QOS_MBRATE_63k,
- .max_bitrate_down = GSM48_QOS_MBRATE_63k,
- .resid_ber = GSM48_QOS_RBER_5e_2,
- .sdu_err_ratio = GSM48_QOS_SERR_1e_2,
- .handling_prio = 3,
- .xfer_delay = 0x10, /* 200ms */
- .guar_bitrate_up = GSM48_QOS_MBRATE_0k,
- .guar_bitrate_down = GSM48_QOS_MBRATE_0k,
- .sig_ind = 0, /* not optimised for signalling */
- .max_bitrate_down_ext = 0, /* use octet 9 */
- .guar_bitrate_down_ext = 0, /* use octet 13 */
-};
-
-/* Chapter 9.4.2: Attach accept */
-static int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT ACK");
- struct gsm48_hdr *gh;
- struct gsm48_attach_ack *aa;
- uint8_t *mid;
-#if 0
- uint8_t *ptsig;
-#endif
-
- LOGMMCTXP(LOGL_INFO, mm, "<- GPRS ATTACH ACCEPT (new P-TMSI=0x%08x)\n", mm->p_tmsi);
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_ACKED]);
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_ATTACH_ACK;
-
- aa = (struct gsm48_attach_ack *) msgb_put(msg, sizeof(*aa));
- aa->force_stby = 0; /* not indicated */
- aa->att_result = 1; /* GPRS only */
- aa->ra_upd_timer = gprs_secs_to_tmr_floor(sgsn->cfg.timers.T3312);
- aa->radio_prio = 4; /* lowest */
- gsm48_construct_ra(aa->ra_id.digits, &mm->ra);
-
-#if 0
- /* Optional: P-TMSI signature */
- msgb_v_put(msg, GSM48_IE_GMM_PTMSI_SIG);
- ptsig = msgb_put(msg, 3);
- ptsig[0] = mm->p_tmsi_sig >> 16;
- ptsig[1] = mm->p_tmsi_sig >> 8;
- ptsig[2] = mm->p_tmsi_sig & 0xff;
-
-#endif
- /* Optional: Negotiated Ready timer value
- * (fixed 44s, default value, GSM 04.08, table 11.4a) to safely limit
- * the inactivity time READY->STANDBY.
- */
- msgb_tv_put(msg, GSM48_IE_GMM_TIMER_READY,
- gprs_secs_to_tmr_floor(sgsn->cfg.timers.T3314));
-
-#ifdef PTMSI_ALLOC
- /* Optional: Allocated P-TMSI */
- mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
- gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
- mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
-#endif
-
- /* Optional: MS-identity (combined attach) */
- /* Optional: GMM cause (partial attach result for combined attach) */
-
- return gsm48_gmm_sendmsg(msg, 0, mm, true);
-}
-
-/* Chapter 9.4.5: Attach reject */
-static int _tx_gmm_att_rej(struct msgb *msg, uint8_t gmm_cause,
- const struct sgsn_mm_ctx *mm)
-{
- struct gsm48_hdr *gh;
-
- LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS ATTACH REJECT: %s\n",
- get_value_string(gsm48_gmm_cause_names, gmm_cause));
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REJECTED]);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_ATTACH_REJ;
- gh->data[0] = gmm_cause;
-
- return gsm48_gmm_sendmsg(msg, 0, NULL, false);
-}
-static int gsm48_tx_gmm_att_rej_oldmsg(const struct msgb *old_msg,
- uint8_t gmm_cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT REJ OLD");
- gmm_copy_id(msg, old_msg);
- return _tx_gmm_att_rej(msg, gmm_cause, NULL);
-}
-static int gsm48_tx_gmm_att_rej(struct sgsn_mm_ctx *mm,
- uint8_t gmm_cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT REJ");
- mmctx2msgid(msg, mm);
- return _tx_gmm_att_rej(msg, gmm_cause, mm);
-}
-
-/* Chapter 9.4.6.2 Detach accept */
-static int _tx_detach_ack(struct msgb *msg, uint8_t force_stby,
- struct sgsn_mm_ctx *mm)
-{
- struct gsm48_hdr *gh;
-
- /* MMCTX might be NULL! */
-
- DEBUGP(DMM, "<- GPRS MM DETACH ACC (force-standby: %d)\n", force_stby);
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_ACKED]);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_DETACH_ACK;
- gh->data[0] = force_stby;
-
- return gsm48_gmm_sendmsg(msg, 0, mm, true);
-}
-
-static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 DET ACK");
-
- mmctx2msgid(msg, mm);
- return _tx_detach_ack(msg, force_stby, mm);
-}
-
-static int gsm48_tx_gmm_det_ack_oldmsg(struct msgb *oldmsg, uint8_t force_stby)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 DET ACK OLD");
-
- gmm_copy_id(msg, oldmsg);
- return _tx_detach_ack(msg, force_stby, NULL);
-}
-
-/* Transmit Chapter 9.4.12 Identity Request */
-static int gsm48_tx_gmm_id_req(struct sgsn_mm_ctx *mm, uint8_t id_type)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ");
- struct gsm48_hdr *gh;
-
- LOGMMCTXP(LOGL_DEBUG, mm, "<- GPRS IDENTITY REQUEST: mi_type=%s\n",
- gsm48_mi_type_name(id_type));
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_ID_REQ;
- /* 10.5.5.9 ID type 2 + identity type and 10.5.5.7 'force to standby' IE */
- gh->data[0] = id_type & 0xf;
-
- return gsm48_gmm_sendmsg(msg, 1, mm, false);
-}
-
-/* determine if the MS/UE supports R99 or later */
-static bool mmctx_is_r99(const struct sgsn_mm_ctx *mm)
-{
- if (mm->ms_network_capa.len < 1)
- return false;
- if (mm->ms_network_capa.buf[0] & 0x01)
- return true;
- return false;
-}
-
-/* 3GPP TS 24.008 Section 9.4.9: Authentication and Ciphering Request */
-static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
- const struct osmo_auth_vector *vec,
- uint8_t key_seq, bool force_standby)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REQ");
- struct gsm48_hdr *gh;
- struct gsm48_auth_ciph_req *acreq;
- uint8_t *m_rand, *m_cksn, rbyte;
-
- LOGMMCTXP(LOGL_INFO, mm, "<- GPRS AUTH AND CIPHERING REQ (rand = %s",
- osmo_hexdump(vec->rand, sizeof(vec->rand)));
- if (mmctx_is_r99(mm) && vec
- && (vec->auth_types & OSMO_AUTH_TYPE_UMTS)) {
- LOGPC(DMM, LOGL_INFO, ", autn = %s)\n",
- osmo_hexdump(vec->autn, sizeof(vec->autn)));
- } else
- LOGPC(DMM, LOGL_INFO, ")\n");
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_AUTH_CIPH_REQ;
-
- acreq = (struct gsm48_auth_ciph_req *) msgb_put(msg, sizeof(*acreq));
- acreq->ciph_alg = mm->ciph_algo & 0xf;
- /* § 10.5.5.10: */
- acreq->imeisv_req = 0x1;
- /* § 10.5.5.7: */
- acreq->force_stby = force_standby;
- /* 3GPP TS 24.008 § 10.5.5.19: */
- if (RAND_bytes(&rbyte, 1) != 1) {
- LOGP(DMM, LOGL_NOTICE, "RAND_bytes failed for A&C ref, falling "
- "back to rand()\n");
- acreq->ac_ref_nr = rand();
- } else
- acreq->ac_ref_nr = rbyte;
- mm->ac_ref_nr_used = acreq->ac_ref_nr;
-
- /* Only if authentication is requested we need to set RAND + CKSN */
- if (vec) {
- m_rand = msgb_put(msg, sizeof(vec->rand) + 1);
- m_rand[0] = GSM48_IE_GMM_AUTH_RAND;
- memcpy(m_rand + 1, vec->rand, sizeof(vec->rand));
-
- /* § 10.5.1.2: */
- m_cksn = msgb_put(msg, 1);
- m_cksn[0] = (GSM48_IE_GMM_CIPH_CKSN << 4) | (key_seq & 0x07);
-
- /* A Release99 or higher MS/UE must be able to handle
- * the optional AUTN IE. If a classic GSM SIM is
- * inserted, it will simply ignore AUTN and just use
- * RAND */
- if (mmctx_is_r99(mm) &&
- (vec->auth_types & OSMO_AUTH_TYPE_UMTS)) {
- msgb_tlv_put(msg, GSM48_IE_GMM_AUTN,
- sizeof(vec->autn), vec->autn);
- }
- }
-
- return gsm48_gmm_sendmsg(msg, 1, mm, false);
-}
-
-/* Section 9.4.11: Authentication and Ciphering Reject */
-static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REJ");
- struct gsm48_hdr *gh;
-
- LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS AUTH AND CIPH REJECT\n");
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_AUTH_CIPH_REJ;
-
- return gsm48_gmm_sendmsg(msg, 0, mm, false);
-}
-
-/* check if the received authentication response matches */
-static bool check_auth_resp(struct sgsn_mm_ctx *ctx,
- bool is_utran,
- const struct osmo_auth_vector *vec,
- const uint8_t *res, uint8_t res_len)
-{
- const uint8_t *expect_res;
- uint8_t expect_res_len;
- enum osmo_sub_auth_type expect_type;
- const char *expect_str;
-
- if (!vec)
- return true; /* really!? */
-
- /* On UTRAN (3G) we always expect UMTS AKA. On GERAN (2G) we sent AUTN
- * and expect UMTS AKA if there is R99 capability and our vector
- * supports UMTS AKA, otherwise we expect GSM AKA. */
- if (is_utran
- || (mmctx_is_r99(ctx) && (vec->auth_types & OSMO_AUTH_TYPE_UMTS))) {
- expect_type = OSMO_AUTH_TYPE_UMTS;
- expect_str = "UMTS RES";
- expect_res = vec->res;
- expect_res_len = vec->res_len;
- } else {
- expect_type = OSMO_AUTH_TYPE_GSM;
- expect_str = "GSM SRES";
- expect_res = vec->sres;
- expect_res_len = sizeof(vec->sres);
- }
-
- if (!(vec->auth_types & expect_type)) {
- LOGMMCTXP(LOGL_ERROR, ctx, "Auth error: auth vector does"
- " not provide the expected auth type:"
- " expected %s = 0x%x, auth_types are 0x%x\n",
- expect_str, expect_type, vec->auth_types);
- return false;
- }
-
- if (!res)
- goto auth_mismatch;
-
- if (res_len != expect_res_len)
- goto auth_mismatch;
-
- if (memcmp(res, expect_res, res_len) != 0)
- goto auth_mismatch;
-
- /* Authorized! */
- return true;
-
-auth_mismatch:
- LOGMMCTXP(LOGL_ERROR, ctx, "Auth mismatch: expected %s = %s\n",
- expect_str, osmo_hexdump_nospc(expect_res, expect_res_len));
- return false;
-}
-
-/* Section 9.4.10: Authentication and Ciphering Response */
-static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
- struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- struct gsm48_auth_ciph_resp *acr = (struct gsm48_auth_ciph_resp *)gh->data;
- struct tlv_parsed tp;
- struct gsm_auth_tuple *at;
- const char *res_name = "(no response)";
- uint8_t res[16];
- uint8_t res_len;
- int rc;
-
- LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH RESPONSE\n");
-
- if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Unexpected Auth & Ciph Response (ignored)\n");
- return 0;
- }
-
- if (acr->ac_ref_nr != ctx->ac_ref_nr_used) {
- LOGMMCTXP(LOGL_NOTICE, ctx, "Reference mismatch for Auth & Ciph"
- " Response: %u received, %u expected\n",
- acr->ac_ref_nr, ctx->ac_ref_nr_used);
- return 0;
- }
-
- /* Stop T3360 */
- mmctx_timer_stop(ctx, 3360);
-
- tlv_parse(&tp, &gsm48_gmm_att_tlvdef, acr->data,
- (msg->data + msg->len) - acr->data, 0, 0);
-
- if (!TLVP_PRESENT(&tp, GSM48_IE_GMM_AUTH_SRES) ||
- !TLVP_PRESENT(&tp, GSM48_IE_GMM_IMEISV) ||
- TLVP_LEN(&tp,GSM48_IE_GMM_AUTH_SRES) != 4) {
- /* TODO: missing mandatory IE, return STATUS or REJ? */
- LOGMMCTXP(LOGL_ERROR, ctx, "Missing mandantory IE\n");
- return -EINVAL;
- }
-
- /* Start with the good old 4-byte SRES */
- memcpy(res, TLVP_VAL(&tp, GSM48_IE_GMM_AUTH_SRES), 4);
- res_len = 4;
- res_name = "GSM SRES";
-
- /* Append extended RES as part of UMTS AKA, if any */
- if (TLVP_PRESENT(&tp, GSM48_IE_GMM_AUTH_RES_EXT)) {
- unsigned int l = TLVP_LEN(&tp, GSM48_IE_GMM_AUTH_RES_EXT);
- if (l > sizeof(res)-4)
- l = sizeof(res)-4;
- memcpy(res+4, TLVP_VAL(&tp, GSM48_IE_GMM_AUTH_RES_EXT), l);
- res_len += l;
- res_name = "UMTS RES";
- }
-
- at = &ctx->auth_triplet;
-
- LOGMMCTXP(LOGL_DEBUG, ctx, "checking auth: received %s = %s\n",
- res_name, osmo_hexdump(res, res_len));
- rc = check_auth_resp(ctx, false, &at->vec, res, res_len);
- if (!rc) {
- rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
- mm_ctx_cleanup_free(ctx, "GPRS AUTH AND CIPH REJECT");
- return rc;
- }
-
- ctx->is_authenticated = 1;
-
- if (ctx->ran_type == MM_CTX_T_UTRAN_Iu)
- ctx->iu.new_key = 1;
-
- /* FIXME: enable LLC cipheirng */
-
- /* Check if we can let the mobile station enter */
- return gsm48_gmm_authorize(ctx);
-}
-
-/* Section 9.4.10: Authentication and Ciphering Failure */
-static int gsm48_rx_gmm_auth_ciph_fail(struct sgsn_mm_ctx *ctx,
- struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- struct tlv_parsed tp;
- const uint8_t gmm_cause = gh->data[0];
- const uint8_t *auts;
- int rc;
-
- LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS AUTH AND CIPH FAILURE (cause = %s)\n",
- get_value_string(gsm48_gmm_cause_names, gmm_cause));
-
- tlv_parse(&tp, &gsm48_gmm_att_tlvdef, gh->data+1, msg->len - 1, 0, 0);
-
- /* Only if GMM cause is present and the AUTS is provided, we can
- * start re-sync procedure */
- if (gmm_cause == GMM_CAUSE_SYNC_FAIL &&
- TLVP_PRESENT(&tp, GSM48_IE_GMM_AUTH_FAIL_PAR)) {
- if (TLVP_LEN(&tp, GSM48_IE_GMM_AUTH_FAIL_PAR) != 14) {
- LOGMMCTXP(LOGL_ERROR, ctx, "AUTS IE has wrong size:"
- " expected %d, got %u\n", 14,
- TLVP_LEN(&tp, GSM48_IE_GMM_AUTH_FAIL_PAR));
- return -EINVAL;
- }
- auts = TLVP_VAL(&tp, GSM48_IE_GMM_AUTH_FAIL_PAR);
-
- LOGMMCTXP(LOGL_INFO, ctx,
- "R99 AUTHENTICATION SYNCH (AUTS = %s)\n",
- osmo_hexdump_nospc(auts, 14));
-
- /* make sure we'll refresh the auth_triplet in
- * sgsn_auth_update() */
- ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
-
- /* make sure we'll retry authentication after the resync */
- ctx->auth_state = SGSN_AUTH_UMTS_RESYNC;
-
- /* Send AUTS to HLR and wait for new Auth Info Result */
- rc = gprs_subscr_request_auth_info(ctx, auts,
- ctx->auth_triplet.vec.rand);
- if (!rc)
- return 0;
- /* on error, fall through to send a reject */
- LOGMMCTXP(LOGL_ERROR, ctx,
- "Sending AUTS to HLR failed (rc = %d)\n", rc);
- }
-
- LOGMMCTXP(LOGL_NOTICE, ctx, "Authentication failed\n");
- rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
- mm_ctx_cleanup_free(ctx, "GPRS AUTH FAILURE");
- return rc;
-}
-
-static void extract_subscr_msisdn(struct sgsn_mm_ctx *ctx)
-{
- struct gsm_mncc_number called;
- uint8_t msisdn[sizeof(ctx->subscr->sgsn_data->msisdn) + 1];
-
- /* Convert MSISDN from encoded to string.. */
- if (!ctx->subscr)
- return;
-
- if (ctx->subscr->sgsn_data->msisdn_len < 1)
- return;
-
- /* prepare the data for the decoder */
- memset(&called, 0, sizeof(called));
- msisdn[0] = ctx->subscr->sgsn_data->msisdn_len;
- memcpy(&msisdn[1], ctx->subscr->sgsn_data->msisdn,
- ctx->subscr->sgsn_data->msisdn_len);
-
- /* decode the string now */
- gsm48_decode_called(&called, msisdn);
-
- /* Prepend a '+' for international numbers */
- if (called.plan == 1 && called.type == 1) {
- ctx->msisdn[0] = '+';
- osmo_strlcpy(&ctx->msisdn[1], called.number,
- sizeof(ctx->msisdn));
- } else {
- osmo_strlcpy(ctx->msisdn, called.number, sizeof(ctx->msisdn));
- }
-}
-
-static void extract_subscr_hlr(struct sgsn_mm_ctx *ctx)
-{
- struct gsm_mncc_number called;
- uint8_t hlr_number[sizeof(ctx->subscr->sgsn_data->hlr) + 1];
-
- if (!ctx->subscr)
- return;
-
- if (ctx->subscr->sgsn_data->hlr_len < 1)
- return;
-
- /* prepare the data for the decoder */
- memset(&called, 0, sizeof(called));
- hlr_number[0] = ctx->subscr->sgsn_data->hlr_len;
- memcpy(&hlr_number[1], ctx->subscr->sgsn_data->hlr,
- ctx->subscr->sgsn_data->hlr_len);
-
- /* decode the string now */
- gsm48_decode_called(&called, hlr_number);
-
- if (called.plan != 1) {
- LOGMMCTXP(LOGL_ERROR, ctx,
- "Numbering plan(%d) not allowed\n",
- called.plan);
- return;
- }
-
- if (called.type != 1) {
- LOGMMCTXP(LOGL_ERROR, ctx,
- "Numbering type(%d) not allowed\n",
- called.type);
- return;
- }
-
- osmo_strlcpy(ctx->hlr, called.number, sizeof(ctx->hlr));
-}
-
-#ifdef BUILD_IU
-/* Chapter 9.4.21: Service accept */
-static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK");
- struct gsm48_hdr *gh;
-
- LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_SERVICE_ACK;
-
- /* Optional: PDP context status */
- /* Optional: MBMS context status */
-
- return gsm48_gmm_sendmsg(msg, 0, mm, false);
-}
-#endif
-
-/* Chapter 9.4.22: Service reject */
-static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause,
- const struct sgsn_mm_ctx *mm)
-{
- struct gsm48_hdr *gh;
-
- LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n",
- get_value_string(gsm48_gmm_cause_names, gmm_cause));
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_SERVICE_REJ;
- gh->data[0] = gmm_cause;
-
- return gsm48_gmm_sendmsg(msg, 0, NULL, true);
-}
-static int gsm48_tx_gmm_service_rej_oldmsg(const struct msgb *old_msg,
- uint8_t gmm_cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ OLD");
- gmm_copy_id(msg, old_msg);
- return _tx_gmm_service_rej(msg, gmm_cause, NULL);
-}
-#if 0
--- currently unused --
-static int gsm48_tx_gmm_service_rej(struct sgsn_mm_ctx *mm,
- uint8_t gmm_cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ");
- mmctx2msgid(msg, mm);
- return _tx_gmm_service_rej(msg, gmm_cause, mm);
-}
-#endif
-
-static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm);
-
-#ifdef BUILD_IU
-void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
-{
- /* Send RAB activation requests for all PDP contexts */
- struct sgsn_pdp_ctx *pdp;
- llist_for_each_entry(pdp, &ctx->pdp_list, list) {
- iu_rab_act_ps(pdp->nsapi, pdp, 1);
- }
-}
-#endif
-
-/* Check if we can already authorize a subscriber */
-static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
-{
-#ifdef BUILD_IU
- int rc;
-#endif
-#ifndef PTMSI_ALLOC
- struct sgsn_signal_data sig_data;
-#endif
-
- /* Request IMSI and IMEI from the MS if they are unknown */
- if (!strlen(ctx->imei)) {
- ctx->t3370_id_type = GSM_MI_TYPE_IMEI;
- mmctx_timer_start(ctx, 3370, sgsn->cfg.timers.T3370);
- return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMEI);
- }
- if (!strlen(ctx->imsi)) {
- ctx->t3370_id_type = GSM_MI_TYPE_IMSI;
- mmctx_timer_start(ctx, 3370, sgsn->cfg.timers.T3370);
- return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMSI);
- }
-
- /* All information required for authentication is available */
- ctx->t3370_id_type = GSM_MI_TYPE_NONE;
-
- if (ctx->auth_state == SGSN_AUTH_UNKNOWN) {
- /* Request authorization, this leads to a call to
- * sgsn_auth_update which in turn calls
- * gsm0408_gprs_access_granted or gsm0408_gprs_access_denied */
-
- sgsn_auth_request(ctx);
- /* Note that gsm48_gmm_authorize can be called recursively via
- * sgsn_auth_request iff ctx->auth_info changes to AUTH_ACCEPTED
- */
- return 0;
- }
-
- if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && !ctx->is_authenticated) {
- struct gsm_auth_tuple *at = &ctx->auth_triplet;
-
- mmctx_timer_start(ctx, 3360, sgsn->cfg.timers.T3360);
- return gsm48_tx_gmm_auth_ciph_req(ctx, &at->vec, at->key_seq,
- false);
- }
-
- if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && ctx->is_authenticated &&
- ctx->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
- /* Check again for authorization */
- sgsn_auth_request(ctx);
- return 0;
- }
-
- if (ctx->auth_state != SGSN_AUTH_ACCEPTED) {
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "authorization is denied, aborting procedure\n");
- return -EACCES;
- }
-
- /* The MS is authorized */
-#ifdef BUILD_IU
- if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) {
- rc = iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet, 0, ctx->iu.new_key);
- ctx->iu.new_key = 0;
- return rc;
- }
-#endif
-
- switch (ctx->pending_req) {
- case 0:
- LOGMMCTXP(LOGL_INFO, ctx,
- "no pending request, authorization completed\n");
- break;
- case GSM48_MT_GMM_ATTACH_REQ:
- ctx->pending_req = 0;
-
- extract_subscr_msisdn(ctx);
- extract_subscr_hlr(ctx);
-#ifdef PTMSI_ALLOC
- /* Start T3350 and re-transmit up to 5 times until ATTACH COMPLETE */
- mmctx_timer_start(ctx, 3350, sgsn->cfg.timers.T3350);
- ctx->t3350_mode = GMM_T3350_MODE_ATT;
-#else
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = mmctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
- ctx->gmm_state = GMM_REGISTERED_NORMAL;
-#endif
-
- return gsm48_tx_gmm_att_ack(ctx);
-#ifdef BUILD_IU
- case GSM48_MT_GMM_SERVICE_REQ:
- ctx->pending_req = 0;
- mmctx_set_pmm_state(ctx, PMM_CONNECTED);
- rc = gsm48_tx_gmm_service_ack(ctx);
-
- if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
- activate_pdp_rabs(ctx);
-
- return rc;
-#endif
- case GSM48_MT_GMM_RA_UPD_REQ:
- ctx->pending_req = 0;
- /* Send RA UPDATE ACCEPT */
- return gsm48_tx_gmm_ra_upd_ack(ctx);
-
- default:
- LOGMMCTXP(LOGL_ERROR, ctx,
- "only Attach Request is supported yet, "
- "got request type %u\n", ctx->pending_req);
- break;
- }
-
- return 0;
-}
-
-void gsm0408_gprs_authenticate(struct sgsn_mm_ctx *ctx)
-{
- ctx->is_authenticated = 0;
-
- gsm48_gmm_authorize(ctx);
-}
-
-void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *ctx)
-{
- switch (ctx->gmm_state) {
- case GMM_COMMON_PROC_INIT:
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Authorized, continuing procedure, IMSI=%s\n",
- ctx->imsi);
- /* Continue with the authorization */
- gsm48_gmm_authorize(ctx);
- break;
- default:
- LOGMMCTXP(LOGL_INFO, ctx,
- "Authorized, ignored, IMSI=%s\n",
- ctx->imsi);
- }
-}
-
-void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *ctx, int gmm_cause)
-{
- if (gmm_cause == SGSN_ERROR_CAUSE_NONE)
- gmm_cause = GMM_CAUSE_GPRS_NOTALLOWED;
-
- switch (ctx->gmm_state) {
- case GMM_COMMON_PROC_INIT:
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Not authorized, rejecting ATTACH REQUEST "
- "with cause '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gmm_cause),
- gmm_cause);
- gsm48_tx_gmm_att_rej(ctx, gmm_cause);
- mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJECT");
- break;
- case GMM_REGISTERED_NORMAL:
- case GMM_REGISTERED_SUSPENDED:
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Authorization lost, detaching "
- "with cause '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gmm_cause),
- gmm_cause);
- gsm48_tx_gmm_detach_req(
- ctx, GPRS_DET_T_MT_REATT_NOTREQ, gmm_cause);
-
- mm_ctx_cleanup_free(ctx, "auth lost");
- break;
- default:
- LOGMMCTXP(LOGL_INFO, ctx,
- "Authorization lost, cause is '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gmm_cause),
- gmm_cause);
- mm_ctx_cleanup_free(ctx, "auth lost");
- }
-}
-
-void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *ctx, int gmm_cause)
-{
- if (gmm_cause != SGSN_ERROR_CAUSE_NONE) {
- LOGMMCTXP(LOGL_INFO, ctx,
- "Cancelled with cause '%s' (%d), deleting context\n",
- get_value_string(gsm48_gmm_cause_names, gmm_cause),
- gmm_cause);
- gsm0408_gprs_access_denied(ctx, gmm_cause);
- return;
- }
-
- LOGMMCTXP(LOGL_INFO, ctx, "Cancelled, deleting context silently\n");
- mm_ctx_cleanup_free(ctx, "access cancelled");
-}
-
-/* Parse Chapter 9.4.13 Identity Response */
-static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
- char mi_string[GSM48_MI_SIZE];
-
- gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
- if (!ctx) {
- DEBUGP(DMM, "from unknown TLLI 0x%08x?!? This should not happen\n", msgb_tlli(msg));
- return -EINVAL;
- }
-
- LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI(%s)=%s\n",
- gsm48_mi_type_name(mi_type), mi_string);
-
- if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) {
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Got unexpected IDENTITY RESPONSE: MI(%s)=%s, "
- "ignoring message\n",
- gsm48_mi_type_name(mi_type), mi_string);
- return -EINVAL;
- }
-
- if (mi_type == ctx->t3370_id_type)
- mmctx_timer_stop(ctx, 3370);
-
- switch (mi_type) {
- case GSM_MI_TYPE_IMSI:
- /* we already have a mm context with current TLLI, but no
- * P-TMSI / IMSI yet. What we now need to do is to fill
- * this initial context with data from the HLR */
- if (strlen(ctx->imsi) == 0) {
- /* Check if we already have a MM context for this IMSI */
- struct sgsn_mm_ctx *ictx;
- ictx = sgsn_mm_ctx_by_imsi(mi_string);
- if (ictx) {
- /* Handle it like in gsm48_rx_gmm_det_req,
- * except that no messages are sent to the BSS */
-
- LOGMMCTXP(LOGL_NOTICE, ctx, "Deleting old MM Context for same IMSI "
- "p_tmsi_old=0x%08x\n",
- ictx->p_tmsi);
-
- mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
- }
- }
- osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
- break;
- case GSM_MI_TYPE_IMEI:
- osmo_strlcpy(ctx->imei, mi_string, sizeof(ctx->imei));
- break;
- case GSM_MI_TYPE_IMEISV:
- break;
- }
-
- /* Check if we can let the mobile station enter */
- return gsm48_gmm_authorize(ctx);
-}
-
-/* Section 9.4.1 Attach request */
-static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
- struct gprs_llc_llme *llme)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t *cur = gh->data, *msnc, *mi, *ms_ra_acc_cap;
- uint8_t msnc_len, att_type, mi_len, mi_type, ms_ra_acc_cap_len;
- uint16_t drx_par;
- uint32_t tmsi;
- char mi_string[GSM48_MI_SIZE];
- struct gprs_ra_id ra_id;
- uint16_t cid = 0;
- enum gsm48_gmm_cause reject_cause;
- int rc;
-
- LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ATTACH_REQUEST]);
-
- /* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either
- * with a foreign TLLI (P-TMSI that was allocated to the MS before),
- * or with random TLLI. */
-
- /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb mode
- * dst is empty. */
- /* FIXME: have a more explicit indicator for Iu messages */
- if (!msg->dst) {
- /* Gb mode */
- cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
- } else
- ra_id = ((struct ue_conn_ctx*)msg->dst)->ra_id;
-
- /* MS network capability 10.5.5.12 */
- msnc_len = *cur++;
- msnc = cur;
- if (msnc_len > sizeof(ctx->ms_network_capa.buf))
- goto err_inval;
- cur += msnc_len;
-
- /* TODO: In iu mode - handle follow-on request */
-
- /* aTTACH Type 10.5.5.2 */
- att_type = *cur++ & 0x07;
-
- /* DRX parameter 10.5.5.6 */
- drx_par = *cur++ << 8;
- drx_par |= *cur++;
-
- /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
- mi_len = *cur++;
- mi = cur;
- if (mi_len > 8)
- goto err_inval;
- mi_type = *mi & GSM_MI_TYPE_MASK;
- cur += mi_len;
-
- gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
-
- DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
- get_value_string(gprs_att_t_strs, att_type));
-
- /* Old routing area identification 10.5.5.15. Skip it */
- cur += 6;
-
- /* MS Radio Access Capability 10.5.5.12a */
- ms_ra_acc_cap_len = *cur++;
- ms_ra_acc_cap = cur;
- if (ms_ra_acc_cap_len > sizeof(ctx->ms_radio_access_capa.buf))
- goto err_inval;
- cur += ms_ra_acc_cap_len;
-
- LOGPC(DMM, LOGL_INFO, "\n");
-
- /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */
-
- switch (mi_type) {
- case GSM_MI_TYPE_IMSI:
- /* Try to find MM context based on IMSI */
- if (!ctx)
- ctx = sgsn_mm_ctx_by_imsi(mi_string);
- if (!ctx) {
-#if 0
- return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN);
-#else
- if (msg->dst)
- ctx = sgsn_mm_ctx_alloc_iu(msg->dst);
- else
- ctx = sgsn_mm_ctx_alloc_gb(0, &ra_id);
- if (!ctx) {
- reject_cause = GMM_CAUSE_NET_FAIL;
- goto rejected;
- }
- osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
-#endif
- }
- if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
- ctx->gb.tlli = msgb_tlli(msg);
- ctx->gb.llme = llme;
- }
- msgid2mmctx(ctx, msg);
- break;
- case GSM_MI_TYPE_TMSI:
- memcpy(&tmsi, mi+1, 4);
- tmsi = ntohl(tmsi);
- /* Try to find MM context based on P-TMSI */
- if (!ctx)
- ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
- if (!ctx) {
- /* Allocate a context as most of our code expects one.
- * Context will not have an IMSI ultil ID RESP is received */
- if (msg->dst)
- ctx = sgsn_mm_ctx_alloc_iu(msg->dst);
- else
- ctx = sgsn_mm_ctx_alloc_gb(msgb_tlli(msg), &ra_id);
- ctx->p_tmsi = tmsi;
- }
- if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
- ctx->gb.tlli = msgb_tlli(msg);
- ctx->gb.llme = llme;
- }
- msgid2mmctx(ctx, msg);
- break;
- default:
- LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with "
- "MI type %s\n", gsm48_mi_type_name(mi_type));
- reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
- goto rejected;
- }
- /* Update MM Context with currient RA and Cell ID */
- ctx->ra = ra_id;
- if (ctx->ran_type == MM_CTX_T_GERAN_Gb)
- ctx->gb.cell_id = cid;
- else if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) {
- /* DEVELOPMENT HACK: Our current HLR does not support 3G
- * authentication tokens. A new HLR/VLR implementation is being
- * developed. Until it is ready and actual milenage
- * authentication is properly supported, we are hardcoding a
- * fixed Ki and use 2G auth. */
- unsigned char tmp_rand[16];
- /* Ki 000102030405060708090a0b0c0d0e0f */
- struct osmo_sub_auth_data auth = {
- .type = OSMO_AUTH_TYPE_GSM,
- .algo = OSMO_AUTH_ALG_COMP128v1,
- .u.gsm.ki = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0e, 0x0f
- },
- };
- /* XXX: Hack to make 3G auth work with special SIM card */
- ctx->auth_state = SGSN_AUTH_AUTHENTICATE;
-
- RAND_bytes(tmp_rand, 16);
-
- memset(&ctx->auth_triplet.vec, 0, sizeof(ctx->auth_triplet.vec));
- osmo_auth_gen_vec(&ctx->auth_triplet.vec, &auth, tmp_rand);
-
- ctx->auth_triplet.key_seq = 0;
- }
-
- /* Update MM Context with other data */
- ctx->drx_parms = drx_par;
- ctx->ms_radio_access_capa.len = ms_ra_acc_cap_len;
- memcpy(ctx->ms_radio_access_capa.buf, ms_ra_acc_cap,
- ctx->ms_radio_access_capa.len);
- ctx->ms_network_capa.len = msnc_len;
- memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
- if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len,
- ctx->ciph_algo)) {
- reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
- LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
- "type %s because MS do not support required %s "
- "encryption\n", gsm48_mi_type_name(mi_type),
- get_value_string(gprs_cipher_names,ctx->ciph_algo));
- goto rejected;
- }
-#ifdef PTMSI_ALLOC
- /* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
- /* Don't change the P-TMSI if a P-TMSI re-assignment is under way */
- if (ctx->gmm_state != GMM_COMMON_PROC_INIT) {
- ctx->p_tmsi_old = ctx->p_tmsi;
- ctx->p_tmsi = sgsn_alloc_ptmsi();
- }
- ctx->gmm_state = GMM_COMMON_PROC_INIT;
-#endif
-
- if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Even if there is no P-TMSI allocated, the MS will
- * switch from foreign TLLI to local TLLI */
- ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
-
- /* Inform LLC layer about new TLLI but keep old active */
- if (ctx->is_authenticated)
- gprs_llme_copy_key(ctx, ctx->gb.llme);
-
- gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new);
- }
-
- ctx->pending_req = GSM48_MT_GMM_ATTACH_REQ;
- return gsm48_gmm_authorize(ctx);
-
-err_inval:
- LOGPC(DMM, LOGL_INFO, "\n");
- reject_cause = GMM_CAUSE_SEM_INCORR_MSG;
-
-rejected:
- /* Send ATTACH REJECT */
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Rejecting Attach Request with cause '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
- rc = gsm48_tx_gmm_att_rej_oldmsg(msg, reject_cause);
- if (ctx)
- mm_ctx_cleanup_free(ctx, "GPRS ATTACH REJ");
- else
- gprs_llgmm_unassign(llme);
-
- return rc;
-
-}
-
-/* Section 4.7.4.1 / 9.4.5.2 MO Detach request */
-static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t detach_type, power_off;
- int rc = 0;
-
- detach_type = gh->data[0] & 0x7;
- power_off = gh->data[0] & 0x8;
-
- /* FIXME: In 24.008 there is an optional P-TMSI and P-TMSI signature IE */
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_DETACH_REQUEST]);
- LOGMMCTXP(LOGL_INFO, ctx, "-> GMM DETACH REQUEST TLLI=0x%08x type=%s %s\n",
- msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type),
- power_off ? "Power-off" : "");
-
- /* Only send the Detach Accept (MO) if power off isn't indicated,
- * see 04.08, 4.7.4.1.2/3 for details */
- if (!power_off) {
- /* force_stby = 0 */
- if (ctx)
- rc = gsm48_tx_gmm_det_ack(ctx, 0);
- else
- rc = gsm48_tx_gmm_det_ack_oldmsg(msg, 0);
- }
-
- if (ctx) {
- struct sgsn_signal_data sig_data;
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = ctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data);
- mm_ctx_cleanup_free(ctx, "GPRS DETACH REQUEST");
- }
-
- return rc;
-}
-
-/* Chapter 9.4.15: Routing area update accept */
-static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 UPD ACK");
- struct gsm48_hdr *gh;
- struct gsm48_ra_upd_ack *rua;
- uint8_t *mid;
-
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
- LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_RA_UPD_ACK;
-
- rua = (struct gsm48_ra_upd_ack *) msgb_put(msg, sizeof(*rua));
- rua->force_stby = 0; /* not indicated */
- rua->upd_result = 0; /* RA updated */
- rua->ra_upd_timer = gprs_secs_to_tmr_floor(sgsn->cfg.timers.T3312);
-
- gsm48_construct_ra(rua->ra_id.digits, &mm->ra);
-
-#if 0
- /* Optional: P-TMSI signature */
- msgb_v_put(msg, GSM48_IE_GMM_PTMSI_SIG);
- ptsig = msgb_put(msg, 3);
- ptsig[0] = mm->p_tmsi_sig >> 16;
- ptsig[1] = mm->p_tmsi_sig >> 8;
- ptsig[2] = mm->p_tmsi_sig & 0xff;
-#endif
-
-#ifdef PTMSI_ALLOC
- /* Optional: Allocated P-TMSI */
- mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
- gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
- mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
-#endif
-
- /* Optional: Negotiated READY timer value */
- msgb_tv_put(msg, GSM48_IE_GMM_TIMER_READY,
- gprs_secs_to_tmr_floor(sgsn->cfg.timers.T3314));
-
- /* Option: MS ID, ... */
- return gsm48_gmm_sendmsg(msg, 0, mm, true);
-}
-
-/* Chapter 9.4.17: Routing area update reject */
-static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 RA UPD REJ");
- struct gsm48_hdr *gh;
-
- LOGP(DMM, LOGL_NOTICE, "<- ROUTING AREA UPDATE REJECT\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REJECT]);
-
- gmm_copy_id(msg, old_msg);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2);
- gh->proto_discr = GSM48_PDISC_MM_GPRS;
- gh->msg_type = GSM48_MT_GMM_RA_UPD_REJ;
- gh->data[0] = cause;
- gh->data[1] = 0; /* ? */
-
- /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */
- return gsm48_gmm_sendmsg(msg, 0, NULL, false);
-}
-
-static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
- const uint8_t *pdp_status)
-{
- struct sgsn_pdp_ctx *pdp, *pdp2;
- /* 24.008 4.7.5.1.3: If the PDP context status information element is
- * included in ROUTING AREA UPDATE REQUEST message, then the network
- * shall deactivate all those PDP contexts locally (without peer to
- * peer signalling between the MS and the network), which are not in SM
- * state PDP-INACTIVE on network side but are indicated by the MS as
- * being in state PDP-INACTIVE. */
-
- llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
- if (pdp->nsapi < 8) {
- if (!(pdp_status[0] & (1 << pdp->nsapi))) {
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
- "due to PDP CTX STATUS IE= 0x%02x%02x\n",
- pdp->nsapi, pdp_status[1], pdp_status[0]);
- sgsn_delete_pdp_ctx(pdp);
- }
- } else {
- if (!(pdp_status[1] & (1 << (pdp->nsapi - 8)))) {
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
- "due to PDP CTX STATUS IE= 0x%02x%02x\n",
- pdp->nsapi, pdp_status[1], pdp_status[0]);
- sgsn_delete_pdp_ctx(pdp);
- }
- }
- }
-}
-
-/* Chapter 9.4.14: Routing area update request */
-static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
- struct gprs_llc_llme *llme)
-{
-#ifndef PTMSI_ALLOC
- struct sgsn_signal_data sig_data;
-#endif
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t *cur = gh->data;
- uint8_t ms_ra_acc_cap_len;
- struct gprs_ra_id old_ra_id;
- struct tlv_parsed tp;
- uint8_t upd_type;
- enum gsm48_gmm_cause reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
- int rc;
-
- /* TODO: In iu mode - handle follow-on request */
-
- /* Update Type 10.5.5.18 */
- upd_type = *cur++ & 0x07;
-
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_REQUEST]);
- LOGP(DMM, LOGL_INFO, "-> GMM RA UPDATE REQUEST type=\"%s\"\n",
- get_value_string(gprs_upd_t_strs, upd_type));
-
- /* Old routing area identification 10.5.5.15 */
- gsm48_parse_ra(&old_ra_id, cur);
- cur += 6;
-
- /* MS Radio Access Capability 10.5.5.12a */
- ms_ra_acc_cap_len = *cur++;
- if (ms_ra_acc_cap_len > 52) {
- reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
- goto rejected;
- }
- cur += ms_ra_acc_cap_len;
-
- /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status,
- * DRX parameter, MS network capability */
- tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur,
- (msg->data + msg->len) - cur, 0, 0);
-
- switch (upd_type) {
- case GPRS_UPD_T_RA_LA:
- case GPRS_UPD_T_RA_LA_IMSI_ATT:
- LOGP(DMM, LOGL_NOTICE, "Update type %i unsupported in Mode III, is your SI13 corrupt?\n", upd_type);
- reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
- goto rejected;
- case GPRS_UPD_T_RA:
- case GPRS_UPD_T_PERIODIC:
- break;
- }
-
- if (!mmctx) {
- /* BSSGP doesn't give us an mmctx */
-
- /* TODO: Check if there is an MM CTX with old_ra_id and
- * the P-TMSI (if given, reguired for UMTS) or as last resort
- * if the TLLI matches foreign_tlli (P-TMSI). Note that this
- * is an optimization to avoid the RA reject (impl detached)
- * below, which will cause a new attach cycle. */
- /* Look-up the MM context based on old RA-ID and TLLI */
- /* In Iu mode, msg->dst contains the ue_conn_ctx pointer, in Gb
- * mode dst is empty. */
- /* FIXME: have a more explicit indicator for Iu messages */
- if (!msg->dst) {
- mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id);
- } else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
-#ifdef BUILD_IU
- /* In Iu mode search only for ptmsi */
- char mi_string[GSM48_MI_SIZE];
- uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
- uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
- uint8_t mi_type = *mi & GSM_MI_TYPE_MASK;
- uint32_t tmsi;
-
- gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
-
- if (mi_type == GSM_MI_TYPE_TMSI) {
- memcpy(&tmsi, mi+1, 4);
- tmsi = ntohl(tmsi);
- mmctx = sgsn_mm_ctx_by_ptmsi(tmsi);
- }
-#else
- goto rejected;
-#endif
- }
- if (mmctx) {
- LOGMMCTXP(LOGL_INFO, mmctx,
- "Looked up by matching TLLI and P_TMSI. "
- "BSSGP TLLI: %08x, P-TMSI: %08x (%08x), "
- "TLLI: %08x (%08x), RA: %d-%d-%d-%d\n",
- msgb_tlli(msg),
- mmctx->p_tmsi, mmctx->p_tmsi_old,
- mmctx->gb.tlli, mmctx->gb.tlli_new,
- mmctx->ra.mcc, mmctx->ra.mnc,
- mmctx->ra.lac, mmctx->ra.rac);
-
- mmctx->gmm_state = GMM_COMMON_PROC_INIT;
- }
- } else if (!gprs_ra_id_equals(&mmctx->ra, &old_ra_id) ||
- mmctx->gmm_state == GMM_DEREGISTERED)
- {
- /* We cannot use the mmctx */
- LOGMMCTXP(LOGL_INFO, mmctx,
- "The MM context cannot be used, RA: %d-%d-%d-%d\n",
- mmctx->ra.mcc, mmctx->ra.mnc,
- mmctx->ra.lac, mmctx->ra.rac);
- mmctx = NULL;
- }
-
- if (!mmctx) {
- if (llme) {
- /* send a XID reset to re-set all LLC sequence numbers
- * in the MS */
- LOGMMCTXP(LOGL_NOTICE, mmctx, "LLC XID RESET\n");
- gprs_llgmm_reset(llme);
- }
- /* The MS has to perform GPRS attach */
- /* Device is still IMSI attached for CS but initiate GPRS ATTACH,
- * see GSM 04.08, 4.7.5.1.4 and G.6 */
- reject_cause = GMM_CAUSE_IMPL_DETACHED;
- goto rejected;
- }
-
- /* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
- msgid2mmctx(mmctx, msg);
- /* Bump the statistics of received signalling msgs for this MM context */
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
-
- /* Update the MM context with the new RA-ID */
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
- bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
- /* Update the MM context with the new (i.e. foreign) TLLI */
- mmctx->gb.tlli = msgb_tlli(msg);
- }
- /* FIXME: Update the MM context with the MS radio acc capabilities */
- /* FIXME: Update the MM context with the MS network capabilities */
-
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_RA_UPDATE]);
-
-#ifdef PTMSI_ALLOC
- /* Don't change the P-TMSI if a P-TMSI re-assignment is under way */
- if (mmctx->gmm_state != GMM_COMMON_PROC_INIT) {
- mmctx->p_tmsi_old = mmctx->p_tmsi;
- mmctx->p_tmsi = sgsn_alloc_ptmsi();
- }
- /* Start T3350 and re-transmit up to 5 times until ATTACH COMPLETE */
- mmctx->t3350_mode = GMM_T3350_MODE_RAU;
- mmctx_timer_start(mmctx, 3350, sgsn->cfg.timers.T3350);
-
- mmctx->gmm_state = GMM_COMMON_PROC_INIT;
-#else
- /* Make sure we are NORMAL (i.e. not SUSPENDED anymore) */
- mmctx->gmm_state = GMM_REGISTERED_NORMAL;
-
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = mmctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_UPDATE, &sig_data);
-#endif
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Even if there is no P-TMSI allocated, the MS will switch from
- * foreign TLLI to local TLLI */
- mmctx->gb.tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL);
-
- /* Inform LLC layer about new TLLI but keep old active */
- gprs_llgmm_assign(mmctx->gb.llme, mmctx->gb.tlli,
- mmctx->gb.tlli_new);
- }
-
- /* Look at PDP Context Status IE and see if MS's view of
- * activated/deactivated NSAPIs agrees with our view */
- if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
- const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
- process_ms_ctx_status(mmctx, pdp_status);
- }
-
- /* Send RA UPDATE ACCEPT. In Iu, the RA upd request can be called from
- * a new Iu connection, so we might need to re-authenticate the
- * connection as well as turn on integrity protection. */
- mmctx->pending_req = GSM48_MT_GMM_RA_UPD_REQ;
- return gsm48_gmm_authorize(mmctx);
-
-rejected:
- /* Send RA UPDATE REJECT */
- LOGMMCTXP(LOGL_NOTICE, mmctx,
- "Rejecting RA Update Request with cause '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
- rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
- if (mmctx)
- mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
- else {
- if (llme)
- gprs_llgmm_unassign(llme);
- }
-
- return rc;
-}
-
-/* 3GPP TS 24.008 Section 9.4.20 Service request.
- * In Iu, a UE in PMM-IDLE mode can use GSM48_MT_GMM_SERVICE_REQ to switch back
- * to PMM-CONNECTED mode. */
-static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t *cur = gh->data, *mi;
- uint8_t ciph_seq_nr, service_type, mi_len, mi_type;
- uint32_t tmsi;
- struct tlv_parsed tp;
- char mi_string[GSM48_MI_SIZE];
- enum gsm48_gmm_cause reject_cause;
- int rc;
-
- LOGMMCTXP(LOGL_INFO, ctx, "-> GMM SERVICE REQUEST ");
-
- /* This message is only valid in Iu mode */
- if (!msg->dst) {
- LOGPC(DMM, LOGL_INFO, "Invalid if not in Iu mode\n");
- return -1;
- }
-
- /* Skip Ciphering key sequence number 10.5.1.2 */
- ciph_seq_nr = *cur & 0x07;
-
- /* Service type 10.5.5.20 */
- service_type = (*cur++ >> 4) & 0x07;
-
- /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
- mi_len = *cur++;
- mi = cur;
- if (mi_len > 8)
- goto err_inval;
- mi_type = *mi & GSM_MI_TYPE_MASK;
- cur += mi_len;
-
- gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
-
- DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
- get_value_string(gprs_service_t_strs, service_type));
-
- LOGPC(DMM, LOGL_INFO, "\n");
-
- /* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */
- tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0);
-
- switch (mi_type) {
- case GSM_MI_TYPE_IMSI:
- /* Try to find MM context based on IMSI */
- if (!ctx)
- ctx = sgsn_mm_ctx_by_imsi(mi_string);
- if (!ctx) {
- /* FIXME: We need to have a context for service request? */
- reject_cause = GMM_CAUSE_NET_FAIL;
- goto rejected;
- }
- msgid2mmctx(ctx, msg);
- break;
- case GSM_MI_TYPE_TMSI:
- memcpy(&tmsi, mi+1, 4);
- tmsi = ntohl(tmsi);
- /* Try to find MM context based on P-TMSI */
- if (!ctx)
- ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
- if (!ctx) {
- /* FIXME: We need to have a context for service request? */
- reject_cause = GMM_CAUSE_NET_FAIL;
- goto rejected;
- }
- msgid2mmctx(ctx, msg);
- break;
- default:
- LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "
- "MI type %s\n", gsm48_mi_type_name(mi_type));
- reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
- goto rejected;
- }
-
- ctx->gmm_state = GMM_COMMON_PROC_INIT;
-
- ctx->iu.service.type = service_type;
-
- /* TODO: Handle those only in case of accept? */
- /* Look at PDP Context Status IE and see if MS's view of
- * activated/deactivated NSAPIs agrees with our view */
- if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
- const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
- process_ms_ctx_status(ctx, pdp_status);
- }
-
-
- ctx->pending_req = GSM48_MT_GMM_SERVICE_REQ;
- return gsm48_gmm_authorize(ctx);
-
-err_inval:
- LOGPC(DMM, LOGL_INFO, "\n");
- reject_cause = GMM_CAUSE_SEM_INCORR_MSG;
-
-rejected:
- /* Send SERVICE REJECT */
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Rejecting Service Request with cause '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
- rc = gsm48_tx_gmm_service_rej_oldmsg(msg, reject_cause);
-
- return rc;
-
-}
-
-
-static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- LOGMMCTXP(LOGL_INFO, mmctx, "-> GPRS MM STATUS (cause: %s)\n",
- get_value_string(gsm48_gmm_cause_names, gh->data[0]));
-
- return 0;
-}
-
-/* GPRS Mobility Management */
-static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
- struct gprs_llc_llme *llme, bool drop_cipherable)
-{
- struct sgsn_signal_data sig_data;
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- int rc;
-
- /* MMCTX can be NULL when called */
- if (drop_cipherable && gsm48_hdr_gmm_cipherable(gh)) {
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping cleartext GMM %s which "
- "is expected to be encrypted for TLLI 0x%08x\n",
- get_value_string(gprs_msgt_gmm_names, gh->msg_type),
- llme->tlli);
- return -EBADMSG;
- }
-
- if (llme && !mmctx &&
- gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
- gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) {
- LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
- /* 4.7.10 */
- if (gh->msg_type == GSM48_MT_GMM_STATUS) {
- /* TLLI unassignment */
- gprs_llgmm_unassign(llme);
- return 0;
- }
-
- /* Don't reply or establish a LLME on DETACH_ACK */
- if (gh->msg_type == GSM48_MT_GMM_DETACH_ACK)
- return gprs_llgmm_unassign(llme);
-
- gprs_llgmm_reset(llme);
-
- /* Don't force it into re-attachment */
- if (gh->msg_type == GSM48_MT_GMM_DETACH_REQ) {
- /* Handle Detach Request */
- rc = gsm48_rx_gmm_det_req(NULL, msg);
-
- /* TLLI unassignment */
- gprs_llgmm_unassign(llme);
- return rc;
- }
-
- /* Force the MS to re-attach */
- rc = gsm0408_gprs_force_reattach_oldmsg(msg, llme);
-
- /* TLLI unassignment */
- gprs_llgmm_unassign(llme);
- return rc;
- }
-
- /*
- * For a few messages, mmctx may be NULL. For most, we want to ensure a
- * non-NULL mmctx. At the same time, we want to keep the message
- * validity check intact, so that all message types appear in the
- * switch statement and the default case thus means "unknown message".
- * If we split the switch in two parts to check non-NULL halfway, the
- * unknown-message check breaks, or we'd need to duplicate the switch
- * cases in both parts. Just keep one large switch and add some gotos.
- */
- switch (gh->msg_type) {
- case GSM48_MT_GMM_RA_UPD_REQ:
- rc = gsm48_rx_gmm_ra_upd_req(mmctx, msg, llme);
- break;
- case GSM48_MT_GMM_ATTACH_REQ:
- rc = gsm48_rx_gmm_att_req(mmctx, msg, llme);
- break;
- case GSM48_MT_GMM_SERVICE_REQ:
- rc = gsm48_rx_gmm_service_req(mmctx, msg);
- break;
- /* For all the following types mmctx can not be NULL */
- case GSM48_MT_GMM_ID_RESP:
- if (!mmctx)
- goto null_mmctx;
- rc = gsm48_rx_gmm_id_resp(mmctx, msg);
- break;
- case GSM48_MT_GMM_STATUS:
- if (!mmctx)
- goto null_mmctx;
- rc = gsm48_rx_gmm_status(mmctx, msg);
- break;
- case GSM48_MT_GMM_DETACH_REQ:
- if (!mmctx)
- goto null_mmctx;
- rc = gsm48_rx_gmm_det_req(mmctx, msg);
- break;
- case GSM48_MT_GMM_DETACH_ACK:
- if (!mmctx)
- goto null_mmctx;
- LOGMMCTXP(LOGL_INFO, mmctx, "-> DETACH ACK\n");
- mm_ctx_cleanup_free(mmctx, "GPRS DETACH ACK");
- rc = 0;
- break;
- case GSM48_MT_GMM_ATTACH_COMPL:
- if (!mmctx)
- goto null_mmctx;
- /* only in case SGSN offered new P-TMSI */
- LOGMMCTXP(LOGL_INFO, mmctx, "-> ATTACH COMPLETE\n");
- mmctx_timer_stop(mmctx, 3350);
- mmctx->t3350_mode = GMM_T3350_MODE_NONE;
- mmctx->p_tmsi_old = 0;
- mmctx->pending_req = 0;
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Unassign the old TLLI */
- mmctx->gb.tlli = mmctx->gb.tlli_new;
- gprs_llme_copy_key(mmctx, mmctx->gb.llme);
- gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
- mmctx->gb.tlli_new);
- }
- mmctx->gmm_state = GMM_REGISTERED_NORMAL;
- mmctx_set_pmm_state(mmctx, PMM_CONNECTED);
- mmctx_set_mm_state(mmctx, MM_READY);
- rc = 0;
-
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = mmctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
- break;
- case GSM48_MT_GMM_RA_UPD_COMPL:
- if (!mmctx)
- goto null_mmctx;
- /* only in case SGSN offered new P-TMSI */
- LOGMMCTXP(LOGL_INFO, mmctx, "-> ROUTING AREA UPDATE COMPLETE\n");
- mmctx_timer_stop(mmctx, 3350);
- mmctx->t3350_mode = GMM_T3350_MODE_NONE;
- mmctx->p_tmsi_old = 0;
- mmctx->pending_req = 0;
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Unassign the old TLLI */
- mmctx->gb.tlli = mmctx->gb.tlli_new;
- gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
- mmctx->gb.tlli_new);
- }
- mmctx->gmm_state = GMM_REGISTERED_NORMAL;
- mmctx_set_pmm_state(mmctx, PMM_CONNECTED);
- mmctx_set_mm_state(mmctx, MM_READY);
- rc = 0;
-
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = mmctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_UPDATE, &sig_data);
- break;
- case GSM48_MT_GMM_PTMSI_REALL_COMPL:
- if (!mmctx)
- goto null_mmctx;
- LOGMMCTXP(LOGL_INFO, mmctx, "-> PTMSI REALLLICATION COMPLETE\n");
- mmctx_timer_stop(mmctx, 3350);
- mmctx->t3350_mode = GMM_T3350_MODE_NONE;
- mmctx->p_tmsi_old = 0;
- mmctx->pending_req = 0;
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Unassign the old TLLI */
- mmctx->gb.tlli = mmctx->gb.tlli_new;
- //gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new, GPRS_ALGO_GEA0, NULL);
- }
- rc = 0;
- break;
- case GSM48_MT_GMM_AUTH_CIPH_RESP:
- if (!mmctx)
- goto null_mmctx;
- rc = gsm48_rx_gmm_auth_ciph_resp(mmctx, msg);
- break;
- case GSM48_MT_GMM_AUTH_CIPH_FAIL:
- rc = gsm48_rx_gmm_auth_ciph_fail(mmctx, msg);
- break;
- default:
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Unknown GSM 04.08 GMM msg type 0x%02x\n",
- gh->msg_type);
- if (mmctx)
- rc = gsm48_tx_gmm_status(mmctx, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
- else
- rc = -EINVAL;
- break;
- }
-
- return rc;
-
-null_mmctx:
- LOGP(DMM, LOGL_ERROR,
- "Received GSM 04.08 message type 0x%02x,"
- " but no MM context available\n",
- gh->msg_type);
- return -EINVAL;
-}
-
-static void mmctx_timer_cb(void *_mm)
-{
- struct sgsn_mm_ctx *mm = _mm;
- struct gsm_auth_tuple *at;
-
- mm->num_T_exp++;
-
- switch (mm->T) {
- case 3350: /* waiting for ATTACH COMPLETE */
- if (mm->num_T_exp >= 5) {
- LOGMMCTXP(LOGL_NOTICE, mm, "T3350 expired >= 5 times\n");
- mm_ctx_cleanup_free(mm, "T3350");
- /* FIXME: should we return some error? */
- break;
- }
- /* re-transmit the respective msg and re-start timer */
- switch (mm->t3350_mode) {
- case GMM_T3350_MODE_ATT:
- gsm48_tx_gmm_att_ack(mm);
- break;
- case GMM_T3350_MODE_RAU:
- gsm48_tx_gmm_ra_upd_ack(mm);
- break;
- case GMM_T3350_MODE_PTMSI_REALL:
- /* FIXME */
- break;
- case GMM_T3350_MODE_NONE:
- LOGMMCTXP(LOGL_NOTICE, mm,
- "T3350 mode wasn't set, ignoring timeout\n");
- break;
- }
- osmo_timer_schedule(&mm->timer, sgsn->cfg.timers.T3350, 0);
- break;
- case 3360: /* waiting for AUTH AND CIPH RESP */
- if (mm->num_T_exp >= 5) {
- LOGMMCTXP(LOGL_NOTICE, mm, "T3360 expired >= 5 times\n");
- mm_ctx_cleanup_free(mm, "T3360");
- break;
- }
- /* Re-transmit the respective msg and re-start timer */
- if (mm->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
- LOGMMCTXP(LOGL_ERROR, mm,
- "timeout: invalid auth triplet reference\n");
- mm_ctx_cleanup_free(mm, "T3360");
- break;
- }
- at = &mm->auth_triplet;
-
- gsm48_tx_gmm_auth_ciph_req(mm, &at->vec, at->key_seq, false);
- osmo_timer_schedule(&mm->timer, sgsn->cfg.timers.T3360, 0);
- break;
- case 3370: /* waiting for IDENTITY RESPONSE */
- if (mm->num_T_exp >= 5) {
- LOGMMCTXP(LOGL_NOTICE, mm, "T3370 expired >= 5 times\n");
- gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED);
- mm_ctx_cleanup_free(mm, "GPRS ATTACH REJECT (T3370)");
- break;
- }
- /* re-tranmit IDENTITY REQUEST and re-start timer */
- gsm48_tx_gmm_id_req(mm, mm->t3370_id_type);
- osmo_timer_schedule(&mm->timer, sgsn->cfg.timers.T3370, 0);
- break;
- default:
- LOGMMCTXP(LOGL_ERROR, mm, "timer expired in unknown mode %u\n",
- mm->T);
- }
-}
-
-/* GPRS SESSION MANAGEMENT */
-
-static void pdpctx_timer_cb(void *_mm);
-
-static void pdpctx_timer_start(struct sgsn_pdp_ctx *pdp, unsigned int T,
- unsigned int seconds)
-{
- if (osmo_timer_pending(&pdp->timer))
- LOGPDPCTXP(LOGL_ERROR, pdp, "Starting PDP timer %u while old "
- "timer %u pending\n", T, pdp->T);
- pdp->T = T;
- pdp->num_T_exp = 0;
-
- /* FIXME: we should do this only once ? */
- osmo_timer_setup(&pdp->timer, pdpctx_timer_cb, pdp);
- osmo_timer_schedule(&pdp->timer, seconds, 0);
-}
-
-static void pdpctx_timer_stop(struct sgsn_pdp_ctx *pdp, unsigned int T)
-{
- if (pdp->T != T)
- LOGPDPCTXP(LOGL_ERROR, pdp, "Stopping PDP timer %u but "
- "%u is running\n", T, pdp->T);
- osmo_timer_del(&pdp->timer);
-}
-
-#if 0
-static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr)
-{
- uint8_t v[6];
-
- v[0] = PDP_TYPE_ORG_IETF;
- v[1] = PDP_TYPE_N_IETF_IPv4;
- *(uint32_t *)(v+2) = htonl(ipaddr);
-
- msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);
-}
-
-static void msgb_put_pdp_addr_ppp(struct msgb *msg)
-{
- uint8_t v[2];
-
- v[0] = PDP_TYPE_ORG_ETSI;
- v[1] = PDP_TYPE_N_ETSI_PPP;
-
- msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v);
-}
-#endif
-
-/* Section 9.5.2: Activate PDP Context Accept */
-int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP ACC");
- struct gsm48_hdr *gh;
- uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */
-
- LOGPDPCTXP(LOGL_INFO, pdp, "<- ACTIVATE PDP CONTEXT ACK\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_ACCEPT]);
-
- mmctx2msgid(msg, pdp->mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
- gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK;
-
- /* Negotiated LLC SAPI */
- msgb_v_put(msg, pdp->sapi);
-
- /* FIXME: copy QoS parameters from original request */
- //msgb_lv_put(msg, pdp->lib->qos_neg.l, pdp->lib->qos_neg.v);
- msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);
-
- /* Radio priority 10.5.7.2 */
- msgb_v_put(msg, pdp->lib->radio_pri);
-
- /* PDP address */
- /* Highest 4 bits of first byte need to be set to 1, otherwise
- * the IE is identical with the 04.08 PDP Address IE */
- pdp->lib->eua.v[0] &= ~0xf0;
- msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR,
- pdp->lib->eua.l, pdp->lib->eua.v);
- pdp->lib->eua.v[0] |= 0xf0;
-
- /* Optional: Protocol configuration options (FIXME: why 'req') */
- if (pdp->lib->pco_req.l)
- msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT,
- pdp->lib->pco_req.l, pdp->lib->pco_req.v);
-
- /* Optional: Packet Flow Identifier */
-
- return gsm48_gmm_sendmsg(msg, 0, pdp->mm, true);
-}
-
-/* Section 9.5.3: Activate PDP Context reject */
-int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
- uint8_t cause, uint8_t pco_len, uint8_t *pco_v)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP REJ");
- struct gsm48_hdr *gh;
- uint8_t transaction_id = tid ^ 0x8; /* flip */
-
- LOGMMCTXP(LOGL_NOTICE, mm, "<- ACTIVATE PDP CONTEXT REJ(cause=%u)\n", cause);
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REJECT]);
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
- gh->msg_type = GSM48_MT_GSM_ACT_PDP_REJ;
-
- msgb_v_put(msg, cause);
- if (pco_len && pco_v)
- msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);
-
- return gsm48_gmm_sendmsg(msg, 0, mm, true);
-}
-
-/* Section 9.5.8: Deactivate PDP Context Request */
-static int _gsm48_tx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, uint8_t tid,
- uint8_t sm_cause)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET REQ");
- struct gsm48_hdr *gh;
- uint8_t transaction_id = tid ^ 0x8; /* flip */
-
- LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT REQ\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_REQUEST]);
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
- gh->msg_type = GSM48_MT_GSM_DEACT_PDP_REQ;
-
- msgb_v_put(msg, sm_cause);
-
- return gsm48_gmm_sendmsg(msg, 0, mm, true);
-}
-int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause)
-{
- pdpctx_timer_start(pdp, 3395, sgsn->cfg.timers.T3395);
-
- return _gsm48_tx_gsm_deact_pdp_req(pdp->mm, pdp->ti, sm_cause);
-}
-
-/* Section 9.5.9: Deactivate PDP Context Accept */
-static int _gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mm, uint8_t tid)
-{
- struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 PDP DET ACC");
- struct gsm48_hdr *gh;
- uint8_t transaction_id = tid ^ 0x8; /* flip */
-
- LOGMMCTXP(LOGL_INFO, mm, "<- DEACTIVATE PDP CONTEXT ACK\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_DL_DEACTIVATE_ACCEPT]);
-
- mmctx2msgid(msg, mm);
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
- gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK;
-
- return gsm48_gmm_sendmsg(msg, 0, mm, true);
-}
-int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp)
-{
- return _gsm48_tx_gsm_deact_pdp_acc(pdp->mm, pdp->ti);
-}
-
-static int activate_ggsn(struct sgsn_mm_ctx *mmctx,
- struct sgsn_ggsn_ctx *ggsn, const uint8_t transaction_id,
- const uint8_t req_nsapi, const uint8_t req_llc_sapi,
- struct tlv_parsed *tp, int destroy_ggsn)
-{
- struct sgsn_pdp_ctx *pdp;
-
- LOGMMCTXP(LOGL_DEBUG, mmctx, "Using GGSN %u\n", ggsn->id);
- ggsn->gsn = sgsn->gsn;
- pdp = sgsn_create_pdp_ctx(ggsn, mmctx, req_nsapi, tp);
- if (!pdp)
- return -1;
-
- /* Store SAPI and Transaction Identifier */
- pdp->sapi = req_llc_sapi;
- pdp->ti = transaction_id;
- pdp->destroy_ggsn = destroy_ggsn;
-
- return 0;
-}
-
-static void ggsn_lookup_cb(void *arg, int status, int timeouts, struct hostent *hostent)
-{
- struct sgsn_ggsn_ctx *ggsn;
- struct sgsn_ggsn_lookup *lookup = arg;
- struct in_addr *addr = NULL;
-
- /* The context is gone while we made a request */
- if (!lookup->mmctx) {
- talloc_free(lookup->orig_msg);
- talloc_free(lookup);
- return;
- }
-
- if (status != ARES_SUCCESS) {
- struct sgsn_mm_ctx *mmctx = lookup->mmctx;
-
- LOGMMCTXP(LOGL_ERROR, mmctx, "DNS query failed.\n");
-
- /* Need to try with three digits now */
- if (lookup->state == SGSN_GGSN_2DIGIT) {
- char *hostname;
- int rc;
-
- lookup->state = SGSN_GGSN_3DIGIT;
- hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,
- lookup->apn_str, 1);
- LOGMMCTXP(LOGL_DEBUG, mmctx,
- "Going to query %s\n", hostname);
- rc = sgsn_ares_query(sgsn, hostname,
- ggsn_lookup_cb, lookup);
- if (rc != 0) {
- LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't start GGSN\n");
- goto reject_due_failure;
- }
- return;
- }
-
- LOGMMCTXP(LOGL_ERROR, mmctx, "Couldn't resolve GGSN\n");
- goto reject_due_failure;
- }
-
- if (hostent->h_length != sizeof(struct in_addr)) {
- LOGMMCTXP(LOGL_ERROR, lookup->mmctx,
- "Wrong addr size(%zu)\n", sizeof(struct in_addr));
- goto reject_due_failure;
- }
-
- /* Get the first addr from the list */
- addr = (struct in_addr *) hostent->h_addr_list[0];
- if (!addr) {
- LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "No host address.\n");
- goto reject_due_failure;
- }
-
- ggsn = sgsn_ggsn_ctx_alloc(UINT32_MAX);
- if (!ggsn) {
- LOGMMCTXP(LOGL_ERROR, lookup->mmctx, "Failed to create ggsn.\n");
- goto reject_due_failure;
- }
- ggsn->remote_addr = *addr;
- LOGMMCTXP(LOGL_NOTICE, lookup->mmctx,
- "Selected %s as GGSN.\n", inet_ntoa(*addr));
-
- /* forget about the ggsn look-up */
- lookup->mmctx->ggsn_lookup = NULL;
-
- activate_ggsn(lookup->mmctx, ggsn, lookup->ti, lookup->nsapi,
- lookup->sapi, &lookup->tp, 1);
-
- /* Now free it */
- talloc_free(lookup->orig_msg);
- talloc_free(lookup);
- return;
-
-reject_due_failure:
- gsm48_tx_gsm_act_pdp_rej(lookup->mmctx, lookup->ti,
- GMM_CAUSE_NET_FAIL, 0, NULL);
- lookup->mmctx->ggsn_lookup = NULL;
- talloc_free(lookup->orig_msg);
- talloc_free(lookup);
-}
-
-static int do_act_pdp_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, bool *delete)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data;
- uint8_t req_qos_len, req_pdpa_len;
- uint8_t *req_qos, *req_pdpa;
- struct tlv_parsed tp;
- uint8_t transaction_id = gsm48_hdr_trans_id(gh);
- struct sgsn_ggsn_ctx *ggsn;
- struct sgsn_pdp_ctx *pdp;
- enum gsm48_gsm_cause gsm_cause;
- char apn_str[GSM_APN_LENGTH] = { 0, };
- char *hostname;
- int rc;
- struct gprs_llc_lle *lle;
-
- LOGMMCTXP(LOGL_INFO, mmctx, "-> ACTIVATE PDP CONTEXT REQ: SAPI=%u NSAPI=%u ",
- act_req->req_llc_sapi, act_req->req_nsapi);
-
- /* FIXME: length checks! */
- req_qos_len = act_req->data[0];
- req_qos = act_req->data + 1; /* 10.5.6.5 */
- req_pdpa_len = act_req->data[1 + req_qos_len];
- req_pdpa = act_req->data + 1 + req_qos_len + 1; /* 10.5.6.4 */
-
- switch (req_pdpa[0] & 0xf) {
- case 0x0:
- DEBUGPC(DMM, "ETSI ");
- break;
- case 0x1:
- DEBUGPC(DMM, "IETF ");
- break;
- case 0xf:
- DEBUGPC(DMM, "Empty ");
- break;
- }
-
- switch (req_pdpa[1]) {
- case 0x21:
- DEBUGPC(DMM, "IPv4 ");
- if (req_pdpa_len >= 6) {
- struct in_addr ia;
- ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2)));
- DEBUGPC(DMM, "%s ", inet_ntoa(ia));
- }
- break;
- case 0x57:
- DEBUGPC(DMM, "IPv6 ");
- if (req_pdpa_len >= 18) {
- /* FIXME: print IPv6 address */
- }
- break;
- default:
- DEBUGPC(DMM, "0x%02x ", req_pdpa[1]);
- break;
- }
-
- LOGPC(DMM, LOGL_INFO, "\n");
-
- /* Check if NSAPI is out of range (TS 04.65 / 7.2) */
- if (act_req->req_nsapi < 5 || act_req->req_nsapi > 15) {
- /* Send reject with GSM_CAUSE_INV_MAND_INFO */
- return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
- GSM_CAUSE_INV_MAND_INFO,
- 0, NULL);
- }
-
- /* Optional: Access Point Name, Protocol Config Options */
- if (req_pdpa + req_pdpa_len < msg->data + msg->len)
- tlv_parse(&tp, &gsm48_sm_att_tlvdef, req_pdpa + req_pdpa_len,
- (msg->data + msg->len) - (req_pdpa + req_pdpa_len), 0, 0);
- else
- memset(&tp, 0, sizeof(tp));
-
-
- /* put the non-TLV elements in the TLV parser structure to
- * pass them on to the SGSN / GTP code */
- tp.lv[OSMO_IE_GSM_REQ_QOS].len = req_qos_len;
- tp.lv[OSMO_IE_GSM_REQ_QOS].val = req_qos;
- tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].len = req_pdpa_len;
- tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].val = req_pdpa;
-
- /* Check if NSAPI is already in use */
- pdp = sgsn_pdp_ctx_by_nsapi(mmctx, act_req->req_nsapi);
- if (pdp) {
- /* We already have a PDP context for this TLLI + NSAPI tuple */
- if (pdp->sapi == act_req->req_llc_sapi &&
- pdp->ti == transaction_id) {
- /* This apparently is a re-transmission of a PDP CTX
- * ACT REQ (our ACT ACK must have got dropped) */
- rc = gsm48_tx_gsm_act_pdp_acc(pdp);
- if (rc < 0)
- return rc;
-
- if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Also re-transmit the SNDCP XID message */
- lle = &pdp->mm->gb.llme->lle[pdp->sapi];
- rc = sndcp_sn_xid_req(lle,pdp->nsapi);
- if (rc < 0)
- return rc;
- }
-
- return 0;
- }
-
- /* Send reject with GSM_CAUSE_NSAPI_IN_USE */
- return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
- GSM_CAUSE_NSAPI_IN_USE,
- 0, NULL);
- }
-
- if (mmctx->ggsn_lookup) {
- if (mmctx->ggsn_lookup->sapi == act_req->req_llc_sapi &&
- mmctx->ggsn_lookup->ti == transaction_id) {
- LOGMMCTXP(LOGL_NOTICE, mmctx,
- "Re-transmission while doing look-up. Ignoring.\n");
- return 0;
- }
- }
-
- /* Only increment counter for a real activation, after we checked
- * for re-transmissions */
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PDP_CTX_ACT]);
-
- /* Determine GGSN based on APN and subscription options */
- ggsn = sgsn_mm_ctx_find_ggsn_ctx(mmctx, &tp, &gsm_cause, apn_str);
- if (ggsn)
- return activate_ggsn(mmctx, ggsn, transaction_id,
- act_req->req_nsapi, act_req->req_llc_sapi,
- &tp, 0);
-
- if (strlen(apn_str) == 0)
- goto no_context;
- if (!sgsn->cfg.dynamic_lookup)
- goto no_context;
-
- /* schedule a dynamic look-up */
- mmctx->ggsn_lookup = talloc_zero(tall_bsc_ctx, struct sgsn_ggsn_lookup);
- if (!mmctx->ggsn_lookup)
- goto no_context;
-
- mmctx->ggsn_lookup->state = SGSN_GGSN_2DIGIT;
- mmctx->ggsn_lookup->mmctx = mmctx;
- strcpy(mmctx->ggsn_lookup->apn_str, apn_str);
-
- mmctx->ggsn_lookup->orig_msg = msg;
- mmctx->ggsn_lookup->tp = tp;
-
- mmctx->ggsn_lookup->ti = transaction_id;
- mmctx->ggsn_lookup->nsapi = act_req->req_nsapi;
- mmctx->ggsn_lookup->sapi = act_req->req_llc_sapi;
-
- hostname = osmo_apn_qualify_from_imsi(mmctx->imsi,
- mmctx->ggsn_lookup->apn_str, 0);
-
- LOGMMCTXP(LOGL_DEBUG, mmctx, "Going to query %s\n", hostname);
- rc = sgsn_ares_query(sgsn, hostname,
- ggsn_lookup_cb, mmctx->ggsn_lookup);
- if (rc != 0) {
- LOGMMCTXP(LOGL_ERROR, mmctx, "Failed to start ares query.\n");
- goto no_context;
- }
- *delete = 0;
-
- return 0;
-
-no_context:
- LOGMMCTXP(LOGL_ERROR, mmctx, "No GGSN context found!\n");
- return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
- gsm_cause, 0, NULL);
-}
-
-/* Section 9.5.1: Activate PDP Context Request */
-static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
- struct msgb *_msg)
-{
- bool delete = 1;
- struct msgb *msg;
- int rc;
-
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_ACTIVATE_REQUEST]);
-
- /*
- * This is painful. We might not have a static GGSN
- * configuration and then would need to copy the msg
- * and re-do most of this routine (or call it again
- * and make sure it only goes through the dynamic
- * resolving. The question is what to optimize for
- * and the dynamic resolution will be the right thing
- * in the long run.
- */
- msg = gprs_msgb_copy(_msg, __func__);
- if (!msg) {
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(_msg);
- uint8_t transaction_id = gsm48_hdr_trans_id(gh);
-
- LOGMMCTXP(LOGL_ERROR, mmctx, "-> ACTIVATE PDP CONTEXT REQ failed copy.\n");
- /* Send reject with GSM_CAUSE_INV_MAND_INFO */
- return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
- GSM_CAUSE_NET_FAIL,
- 0, NULL);
- }
-
- rc = do_act_pdp_req(mmctx, msg, &delete);
- if (delete)
- msgb_free(msg);
- return rc;
-}
-
-/* Section 9.5.8: Deactivate PDP Context Request */
-static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t transaction_id = gsm48_hdr_trans_id(gh);
- struct sgsn_pdp_ctx *pdp;
-
- LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n",
- get_value_string(gsm48_gsm_cause_names, gh->data[0]));
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_REQUEST]);
-
- pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
- if (!pdp) {
- LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Request for "
- "non-existing PDP Context (IMSI=%s, TI=%u)\n",
- mm->imsi, transaction_id);
- return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);
- }
-
- return sgsn_delete_pdp_ctx(pdp);
-}
-
-/* Section 9.5.9: Deactivate PDP Context Accept */
-static int gsm48_rx_gsm_deact_pdp_ack(struct sgsn_mm_ctx *mm, struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t transaction_id = gsm48_hdr_trans_id(gh);
- struct sgsn_pdp_ctx *pdp;
-
- LOGMMCTXP(LOGL_INFO, mm, "-> DEACTIVATE PDP CONTEXT ACK\n");
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_PDP_UL_DEACTIVATE_ACCEPT]);
-
- pdp = sgsn_pdp_ctx_by_tid(mm, transaction_id);
- if (!pdp) {
- LOGMMCTXP(LOGL_NOTICE, mm, "Deactivate PDP Context Accept for "
- "non-existing PDP Context (IMSI=%s, TI=%u)\n",
- mm->imsi, transaction_id);
- return 0;
- }
- /* stop timer 3395 */
- pdpctx_timer_stop(pdp, 3395);
- return sgsn_delete_pdp_ctx(pdp);
-}
-
-static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- LOGMMCTXP(LOGL_INFO, ctx, "-> GPRS SM STATUS (cause: %s)\n",
- get_value_string(gsm48_gsm_cause_names, gh->data[0]));
-
- return 0;
-}
-
-static void pdpctx_timer_cb(void *_pdp)
-{
- struct sgsn_pdp_ctx *pdp = _pdp;
-
- pdp->num_T_exp++;
-
- switch (pdp->T) {
- case 3395: /* waiting for PDP CTX DEACT ACK */
- if (pdp->num_T_exp >= 4) {
- LOGPDPCTXP(LOGL_NOTICE, pdp, "T3395 expired >= 5 times\n");
- pdp->state = PDP_STATE_INACTIVE;
- sgsn_delete_pdp_ctx(pdp);
- break;
- }
- gsm48_tx_gsm_deact_pdp_req(pdp, GSM_CAUSE_NET_FAIL);
- break;
- default:
- LOGPDPCTXP(LOGL_ERROR, pdp, "timer expired in unknown mode %u\n",
- pdp->T);
- }
-}
-
-
-/* GPRS Session Management */
-static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
- struct gprs_llc_llme *llme)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- int rc;
-
- /* MMCTX can be NULL when called */
-
- if (!mmctx) {
- LOGP(DMM, LOGL_NOTICE, "Cannot handle SM for unknown MM CTX\n");
- /* 6.1.3.6 */
- if (gh->msg_type == GSM48_MT_GSM_STATUS)
- return 0;
-
- return gsm0408_gprs_force_reattach_oldmsg(msg, llme);
- }
-
- switch (gh->msg_type) {
- case GSM48_MT_GSM_ACT_PDP_REQ:
- rc = gsm48_rx_gsm_act_pdp_req(mmctx, msg);
- break;
- case GSM48_MT_GSM_DEACT_PDP_REQ:
- rc = gsm48_rx_gsm_deact_pdp_req(mmctx, msg);
- break;
- case GSM48_MT_GSM_DEACT_PDP_ACK:
- rc = gsm48_rx_gsm_deact_pdp_ack(mmctx, msg);
- break;
- case GSM48_MT_GSM_STATUS:
- rc = gsm48_rx_gsm_status(mmctx, msg);
- break;
- case GSM48_MT_GSM_REQ_PDP_ACT_REJ:
- case GSM48_MT_GSM_ACT_AA_PDP_REQ:
- case GSM48_MT_GSM_DEACT_AA_PDP_REQ:
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Unimplemented GSM 04.08 GSM msg type 0x%02x: %s\n",
- gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
- rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
- break;
- default:
- LOGMMCTXP(LOGL_NOTICE, mmctx, "Unknown GSM 04.08 GSM msg type 0x%02x: %s\n",
- gh->msg_type, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
- rc = gsm48_tx_sm_status(mmctx, GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
- break;
-
- }
-
- return rc;
-}
-
-int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
- struct gprs_llc_llme *llme)
-{
- int rc;
- if (llme)
- gprs_llgmm_reset_oldmsg(msg, GPRS_SAPI_GMM, llme);
-
- rc = gsm48_tx_gmm_detach_req_oldmsg(
- msg, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED);
-
- return rc;
-}
-
-int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx)
-{
- int rc;
- if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
- gprs_llgmm_reset(mmctx->gb.llme);
-
- rc = gsm48_tx_gmm_detach_req(
- mmctx, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED);
-
- mm_ctx_cleanup_free(mmctx, "forced reattach");
-
- return rc;
-}
-
-/* Main entry point for incoming 04.08 GPRS messages from Iu */
-int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
- uint16_t *sai)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t pdisc = gsm48_hdr_pdisc(gh);
- struct sgsn_mm_ctx *mmctx;
- int rc = -EINVAL;
-
- mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst);
- if (mmctx) {
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
- if (ra_id)
- memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
- }
-
- /* MMCTX can be NULL */
-
- switch (pdisc) {
- case GSM48_PDISC_MM_GPRS:
- rc = gsm0408_rcv_gmm(mmctx, msg, NULL, false);
-#warning "set drop_cipherable arg for gsm0408_rcv_gmm() from IuPS?"
- break;
- case GSM48_PDISC_SM_GPRS:
- rc = gsm0408_rcv_gsm(mmctx, msg, NULL);
- 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;
-}
-
-/* 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) {
- msgid2mmctx(mmctx, msg);
- rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
- mmctx->gb.llme = llme;
- }
-
- /* 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_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli)
-{
- struct sgsn_mm_ctx *mmctx;
-
- mmctx = sgsn_mm_ctx_by_tlli(tlli, raid);
- if (!mmctx) {
- LOGP(DMM, LOGL_NOTICE, "SUSPEND request for unknown "
- "TLLI=%08x\n", tlli);
- return -EINVAL;
- }
-
- if (mmctx->gmm_state != GMM_REGISTERED_NORMAL &&
- mmctx->gmm_state != GMM_REGISTERED_SUSPENDED) {
- LOGMMCTXP(LOGL_NOTICE, mmctx, "SUSPEND request while state "
- "!= REGISTERED (TLLI=%08x)\n", tlli);
- return -EINVAL;
- }
-
- /* Transition from REGISTERED_NORMAL to REGISTERED_SUSPENDED */
- mmctx->gmm_state = GMM_REGISTERED_SUSPENDED;
- return 0;
-}
-
-int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
- uint8_t suspend_ref)
-{
- struct sgsn_mm_ctx *mmctx;
-
- /* FIXME: make use of suspend reference? */
-
- mmctx = sgsn_mm_ctx_by_tlli(tlli, raid);
- if (!mmctx) {
- LOGP(DMM, LOGL_NOTICE, "RESUME request for unknown "
- "TLLI=%08x\n", tlli);
- return -EINVAL;
- }
-
- if (mmctx->gmm_state != GMM_REGISTERED_NORMAL &&
- mmctx->gmm_state != GMM_REGISTERED_SUSPENDED) {
- LOGMMCTXP(LOGL_NOTICE, mmctx, "RESUME request while state "
- "!= SUSPENDED (TLLI=%08x)\n", tlli);
- /* FIXME: should we not simply ignore it? */
- return -EINVAL;
- }
-
- /* Transition from SUSPENDED to NORMAL */
- mmctx->gmm_state = GMM_REGISTERED_NORMAL;
- return 0;
-}
-
-#ifdef BUILD_IU
-int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap)
-{
- struct msgb *msg;
- struct sgsn_mm_ctx *mm = pdp->mm;
- struct ue_conn_ctx *uectx;
- uint32_t ggsn_ip;
-
- uectx = mm->iu.ue_ctx;
-
- /* Get the IP address for ggsn user plane */
- memcpy(&ggsn_ip, pdp->lib->gsnru.v, pdp->lib->gsnru.l);
- ggsn_ip = htonl(ggsn_ip);
-
- LOGP(DRANAP, LOGL_DEBUG, "Assigning RAB: rab_id=%d, ggsn_ip=%x,"
- " teid_gn=%x, use_x213_nsap=%d\n",
- rab_id, ggsn_ip, pdp->lib->teid_gn, use_x213_nsap);
-
- msg = ranap_new_msg_rab_assign_data(rab_id, ggsn_ip,
- pdp->lib->teid_gn, use_x213_nsap);
- msg->l2h = msg->data;
- return iu_rab_act(uectx, msg);
-}
-#endif
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
deleted file mode 100644
index 2be663f98..000000000
--- a/openbsc/src/gprs/gprs_llc.c
+++ /dev/null
@@ -1,1132 +0,0 @@
-/* GPRS LLC protocol implementation as per 3GPP TS 04.64 */
-
-/* (C) 2009-2010 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 <errno.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#include <openssl/rand.h>
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/gprs_sgsn.h>
-#include <openbsc/gprs_gmm.h>
-#include <openbsc/gprs_llc.h>
-#include <openbsc/crc24.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gprs_llc_xid.h>
-#include <openbsc/gprs_sndcp_comp.h>
-#include <openbsc/gprs_sndcp.h>
-
-static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
-static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
- int command);
-static int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi,
- int command, enum gprs_llc_u_cmd u_cmd, int pf_bit);
-
-/* BEGIN XID RELATED */
-
-/* Generate XID message */
-static int gprs_llc_generate_xid(uint8_t *bytes, int bytes_len,
- struct gprs_llc_xid_field *l3_xid_field,
- struct gprs_llc_llme *llme)
-{
- /* Note: Called by gprs_ll_xid_req() */
-
- LLIST_HEAD(xid_fields);
-
- struct gprs_llc_xid_field xid_version;
- struct gprs_llc_xid_field xid_n201u;
- struct gprs_llc_xid_field xid_n201i;
-
- xid_version.type = GPRS_LLC_XID_T_VERSION;
- xid_version.data = (uint8_t *) "\x00";
- xid_version.data_len = 1;
-
- xid_n201u.type = GPRS_LLC_XID_T_N201_U;
- xid_n201u.data = (uint8_t *) "\x05\xf0";
- xid_n201u.data_len = 2;
-
- xid_n201i.type = GPRS_LLC_XID_T_N201_I;
- xid_n201i.data = (uint8_t *) "\x05\xf0";
- xid_n201i.data_len = 2;
-
- /* Add locally managed XID Fields */
- llist_add(&xid_version.list, &xid_fields);
- llist_add(&xid_n201u.list, &xid_fields);
- llist_add(&xid_n201i.list, &xid_fields);
-
- /* Append layer 3 XID field (if present) */
- if (l3_xid_field) {
- /* Enforce layer 3 XID type (just to be sure) */
- l3_xid_field->type = GPRS_LLC_XID_T_L3_PAR;
-
- /* Add Layer 3 XID field to the list */
- llist_add(&l3_xid_field->list, &xid_fields);
- }
-
- /* Store generated XID for later reference */
- talloc_free(llme->xid);
- llme->xid = gprs_llc_copy_xid(llme, &xid_fields);
-
- return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields);
-}
-
-/* Generate XID message that will cause the GMM to reset */
-static int gprs_llc_generate_xid_for_gmm_reset(uint8_t *bytes,
- int bytes_len, uint32_t iov_ui,
- struct gprs_llc_llme *llme)
-{
- /* Called by gprs_llgmm_reset() and
- * gprs_llgmm_reset_oldmsg() */
-
- LLIST_HEAD(xid_fields);
-
- struct gprs_llc_xid_field xid_reset;
- struct gprs_llc_xid_field xid_iovui;
-
- /* First XID component must be RESET */
- xid_reset.type = GPRS_LLC_XID_T_RESET;
- xid_reset.data = NULL;
- xid_reset.data_len = 0;
-
- /* Add new IOV-UI */
- xid_iovui.type = GPRS_LLC_XID_T_IOV_UI;
- xid_iovui.data = (uint8_t *) & iov_ui;
- xid_iovui.data_len = 4;
-
- /* Add locally managed XID Fields */
- llist_add(&xid_iovui.list, &xid_fields);
- llist_add(&xid_reset.list, &xid_fields);
-
- /* Store generated XID for later reference */
- talloc_free(llme->xid);
- llme->xid = gprs_llc_copy_xid(llme, &xid_fields);
-
- return gprs_llc_compile_xid(bytes, bytes_len, &xid_fields);
-}
-
-/* Process an incoming XID confirmation */
-static int gprs_llc_process_xid_conf(uint8_t *bytes, int bytes_len,
- struct gprs_llc_lle *lle)
-{
- /* Note: This function handles the response of a network originated
- * XID-Request. There XID messages reflected by the MS are analyzed
- * and processed here. The caller is called by rx_llc_xid(). */
-
- struct llist_head *xid_fields;
- struct gprs_llc_xid_field *xid_field;
- struct gprs_llc_xid_field *xid_field_request;
- struct gprs_llc_xid_field *xid_field_request_l3 = NULL;
-
- /* Pick layer3 XID from the XID request we have sent last */
- if (lle->llme->xid) {
- llist_for_each_entry(xid_field_request, lle->llme->xid, list) {
- if (xid_field_request->type == GPRS_LLC_XID_T_L3_PAR)
- xid_field_request_l3 = xid_field_request;
- }
- }
-
- /* Parse and analyze XID-Response */
- xid_fields = gprs_llc_parse_xid(NULL, bytes, bytes_len);
-
- if (xid_fields) {
-
- gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG);
- llist_for_each_entry(xid_field, xid_fields, list) {
-
- /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */
- if (xid_field->type == GPRS_LLC_XID_T_L3_PAR &&
- xid_field_request_l3) {
- sndcp_sn_xid_conf(xid_field,
- xid_field_request_l3, lle);
- }
-
- /* Process LLC-XID fields: */
- else {
-
- /* FIXME: Do something more useful with the
- * echoed XID-Information. Currently we
- * just ignore the response completely and
- * by doing so we blindly accept any changes
- * the MS might have done to the our XID
- * inquiry. There is a remainig risk of
- * malfunction! */
- LOGP(DLLC, LOGL_NOTICE,
- "Ignoring XID-Field: XID: type %s, data_len=%d, data=%s\n",
- get_value_string(gprs_llc_xid_type_names,
- xid_field->type),
- xid_field->data_len,
- osmo_hexdump_nospc(xid_field->data,
- xid_field->data_len));
- }
- }
- talloc_free(xid_fields);
- }
-
- /* Flush pending XID fields */
- talloc_free(lle->llme->xid);
- lle->llme->xid = NULL;
-
- return 0;
-}
-
-/* Process an incoming XID indication and generate an appropiate response */
-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)
-{
- /* Note: This function computes the response that is sent back to the
- * MS when a mobile originated XID is received. The function is
- * called by rx_llc_xid() */
-
- int rc = -EINVAL;
-
- struct llist_head *xid_fields;
- struct llist_head *xid_fields_response;
-
- struct gprs_llc_xid_field *xid_field;
- struct gprs_llc_xid_field *xid_field_response;
-
- /* Parse and analyze XID-Request */
- xid_fields =
- gprs_llc_parse_xid(lle->llme, bytes_request, bytes_request_len);
- if (xid_fields) {
- xid_fields_response = talloc_zero(lle->llme, struct llist_head);
- INIT_LLIST_HEAD(xid_fields_response);
- gprs_llc_dump_xid_fields(xid_fields, LOGL_DEBUG);
-
- /* Process LLC-XID fields: */
- llist_for_each_entry(xid_field, xid_fields, list) {
-
- if (xid_field->type != GPRS_LLC_XID_T_L3_PAR) {
- /* FIXME: Check the incoming XID parameters for
- * for validity. Currently we just blindly
- * accept all XID fields by just echoing them.
- * There is a remaining risk of malfunction
- * when a MS submits values which defer from
- * the default! */
- LOGP(DLLC, LOGL_NOTICE,
- "Echoing XID-Field: XID: type %s, data_len=%d, data=%s\n",
- get_value_string(gprs_llc_xid_type_names,
- xid_field->type),
- xid_field->data_len,
- osmo_hexdump_nospc(xid_field->data,
- xid_field->data_len));
- xid_field_response =
- gprs_llc_dup_xid_field
- (lle->llme, xid_field);
- llist_add(&xid_field_response->list,
- xid_fields_response);
- }
- }
-
- /* Forward SNDCP-XID fields to Layer 3 (SNDCP) */
- llist_for_each_entry(xid_field, xid_fields, list) {
- if (xid_field->type == GPRS_LLC_XID_T_L3_PAR) {
-
- xid_field_response =
- talloc_zero(lle->llme,
- struct gprs_llc_xid_field);
- rc = sndcp_sn_xid_ind(xid_field,
- xid_field_response, lle);
- if (rc == 0)
- llist_add(&xid_field_response->list,
- xid_fields_response);
- else
- talloc_free(xid_field_response);
- }
- }
-
- rc = gprs_llc_compile_xid(bytes_response,
- bytes_response_maxlen,
- xid_fields_response);
- talloc_free(xid_fields_response);
- talloc_free(xid_fields);
- }
-
- return rc;
-}
-
-/* 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)
-{
- uint8_t response[1024];
- int response_len;
-
- /* FIXME: 8.5.3.3: check if XID is invalid */
- if (gph->is_cmd) {
- LOGP(DLLC, LOGL_NOTICE,
- "Received XID indication from MS.\n");
-
- struct msgb *resp;
- uint8_t *xid;
- resp = msgb_alloc_headroom(4096, 1024, "LLC_XID");
-
- response_len =
- gprs_llc_process_xid_ind(gph->data, gph->data_len,
- response, sizeof(response),
- lle);
- if (response_len < 0) {
- LOGP(DLLC, LOGL_ERROR,
- "invalid XID indication received!\n");
- } else {
- xid = msgb_put(resp, response_len);
- memcpy(xid, response, response_len);
- }
- gprs_llc_tx_xid(lle, resp, 0);
- } else {
- LOGP(DLLC, LOGL_NOTICE,
- "Received XID confirmation from MS.\n");
- gprs_llc_process_xid_conf(gph->data, gph->data_len, lle);
- /* FIXME: if we had sent a XID reset, send
- * LLGMM-RESET.conf to GMM */
- }
-}
-
-/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */
-int gprs_ll_xid_req(struct gprs_llc_lle *lle,
- struct gprs_llc_xid_field *l3_xid_field)
-{
- /* Note: This functions is calle from gprs_sndcp.c */
-
- uint8_t xid_bytes[1024];;
- int xid_bytes_len;
- uint8_t *xid;
- struct msgb *msg;
- const char *ftype;
-
- /* Generate XID */
- xid_bytes_len =
- gprs_llc_generate_xid(xid_bytes, sizeof(xid_bytes),
- l3_xid_field, lle->llme);
-
- /* Only perform XID sending if the XID message contains something */
- if (xid_bytes_len > 0) {
- /* Transmit XID bytes */
- msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
- xid = msgb_put(msg, xid_bytes_len);
- memcpy(xid, xid_bytes, xid_bytes_len);
- if (l3_xid_field)
- ftype = get_value_string(gprs_llc_xid_type_names,
- l3_xid_field->type);
- else
- ftype = "NULL";
- LOGP(DLLC, LOGL_NOTICE, "Sending XID type %s (%d bytes) request"
- " to MS...\n", ftype, xid_bytes_len);
- gprs_llc_tx_xid(lle, msg, 1);
- } else {
- LOGP(DLLC, LOGL_ERROR,
- "XID-Message generation failed, XID not sent!\n");
- return -EINVAL;
- }
-
- return 0;
-}
-/* END XID RELATED */
-
-
-
-
-/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU
- * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */
-static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
-{
- struct bssgp_dl_ud_par dup;
- const uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x20 };
-
- memset(&dup, 0, sizeof(dup));
- /* before we have received some identity from the MS, we might
- * not yet have a MMC context (e.g. XID negotiation of primarly
- * LLC connection from GMM sapi). */
- if (mmctx) {
- dup.imsi = mmctx->imsi;
- dup.drx_parms = mmctx->drx_parms;
- dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
- dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
-
- /* make sure we only send it to the right llme */
- OSMO_ASSERT(msgb_tlli(msg) == mmctx->gb.llme->tlli
- || msgb_tlli(msg) == mmctx->gb.llme->old_tlli);
- }
- memcpy(&dup.qos_profile, qos_profile_default,
- sizeof(qos_profile_default));
-
- return bssgp_tx_dl_ud(msg, 1000, &dup);
-}
-
-
-/* Section 8.9.9 LLC layer parameter default values */
-static const struct gprs_llc_params llc_default_params[NUM_SAPIS] = {
- [1] = {
- .t200_201 = 5,
- .n200 = 3,
- .n201_u = 400,
- },
- [2] = {
- .t200_201 = 5,
- .n200 = 3,
- .n201_u = 270,
- },
- [3] = {
- .iov_i_exp = 27,
- .t200_201 = 5,
- .n200 = 3,
- .n201_u = 500,
- .n201_i = 1503,
- .mD = 1520,
- .mU = 1520,
- .kD = 16,
- .kU = 16,
- },
- [5] = {
- .iov_i_exp = 27,
- .t200_201 = 10,
- .n200 = 3,
- .n201_u = 500,
- .n201_i = 1503,
- .mD = 760,
- .mU = 760,
- .kD = 8,
- .kU = 8,
- },
- [7] = {
- .t200_201 = 20,
- .n200 = 3,
- .n201_u = 270,
- },
- [8] = {
- .t200_201 = 20,
- .n200 = 3,
- .n201_u = 270,
- },
- [9] = {
- .iov_i_exp = 27,
- .t200_201 = 20,
- .n200 = 3,
- .n201_u = 500,
- .n201_i = 1503,
- .mD = 380,
- .mU = 380,
- .kD = 4,
- .kU = 4,
- },
- [11] = {
- .iov_i_exp = 27,
- .t200_201 = 40,
- .n200 = 3,
- .n201_u = 500,
- .n201_i = 1503,
- .mD = 190,
- .mU = 190,
- .kD = 2,
- .kU = 2,
- },
-};
-
-LLIST_HEAD(gprs_llc_llmes);
-void *llc_tall_ctx;
-
-/* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */
-static struct gprs_llc_lle *lle_by_tlli_sapi(const uint32_t tlli, uint8_t sapi)
-{
- struct gprs_llc_llme *llme;
-
- llist_for_each_entry(llme, &gprs_llc_llmes, list) {
- if (llme->tlli == tlli || llme->old_tlli == tlli)
- return &llme->lle[sapi];
- }
- return NULL;
-}
-
-struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi)
-{
- struct gprs_llc_llme *llme;
- struct gprs_llc_lle *lle;
-
- lle = lle_by_tlli_sapi(tlli, sapi);
- if (lle)
- return lle;
-
- LOGP(DLLC, LOGL_NOTICE, "LLC: unknown TLLI 0x%08x, "
- "creating LLME on the fly\n", tlli);
- llme = llme_alloc(tlli);
- lle = &llme->lle[sapi];
- return lle;
-}
-
-struct llist_head *gprs_llme_list(void)
-{
- return &gprs_llc_llmes;
-}
-
-/* lookup LLC Entity for RX based on DLCI (TLLI+SAPI tuple) */
-static struct gprs_llc_lle *lle_for_rx_by_tlli_sapi(const uint32_t tlli,
- uint8_t sapi, enum gprs_llc_cmd cmd)
-{
- struct gprs_llc_lle *lle;
-
- /* We already know about this TLLI */
- lle = lle_by_tlli_sapi(tlli, sapi);
- if (lle)
- return lle;
-
- /* Maybe it is a routing area update but we already know this sapi? */
- if (gprs_tlli_type(tlli) == TLLI_FOREIGN) {
- lle = lle_by_tlli_sapi(tlli, sapi);
- if (lle) {
- LOGP(DLLC, LOGL_NOTICE,
- "LLC RX: Found a local entry for TLLI 0x%08x\n",
- tlli);
- return lle;
- }
- }
-
- /* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
- * except UID and XID frames with SAPI=1 */
- if (sapi == GPRS_SAPI_GMM &&
- (cmd == GPRS_LLC_XID || cmd == GPRS_LLC_UI)) {
- struct gprs_llc_llme *llme;
- /* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
- llme = llme_alloc(tlli);
- LOGP(DLLC, LOGL_NOTICE, "LLC RX: unknown TLLI 0x%08x, "
- "creating LLME on the fly\n", tlli);
- lle = &llme->lle[sapi];
- return lle;
- }
-
- LOGP(DLLC, LOGL_NOTICE,
- "unknown TLLI(0x%08x)/SAPI(%d): Silently dropping\n",
- tlli, sapi);
- return NULL;
-}
-
-static void lle_init(struct gprs_llc_llme *llme, uint8_t sapi)
-{
- struct gprs_llc_lle *lle = &llme->lle[sapi];
-
- lle->llme = llme;
- lle->sapi = sapi;
- lle->state = GPRS_LLES_UNASSIGNED;
-
- /* Initialize according to parameters */
- memcpy(&lle->params, &llc_default_params[sapi], sizeof(lle->params));
-}
-
-static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
-{
- struct gprs_llc_llme *llme;
- uint32_t i;
-
- llme = talloc_zero(llc_tall_ctx, struct gprs_llc_llme);
- if (!llme)
- return NULL;
-
- llme->tlli = tlli;
- llme->old_tlli = 0xffffffff;
- llme->state = GPRS_LLMS_UNASSIGNED;
- llme->age_timestamp = GPRS_LLME_RESET_AGE;
- llme->cksn = GSM_KEY_SEQ_INVAL;
-
- for (i = 0; i < ARRAY_SIZE(llme->lle); i++)
- lle_init(llme, i);
-
- llist_add(&llme->list, &gprs_llc_llmes);
-
- llme->comp.proto = gprs_sndcp_comp_alloc(llme);
- llme->comp.data = gprs_sndcp_comp_alloc(llme);
-
- return llme;
-}
-
-static void llme_free(struct gprs_llc_llme *llme)
-{
- gprs_sndcp_comp_free(llme->comp.proto);
- gprs_sndcp_comp_free(llme->comp.data);
- talloc_free(llme->xid);
- llist_del(&llme->list);
- talloc_free(llme);
-}
-
-#if 0
-/* FIXME: Unused code... */
-static void t200_expired(void *data)
-{
- struct gprs_llc_lle *lle = data;
-
- /* 8.5.1.3: Expiry of T200 */
-
- if (lle->retrans_ctr >= lle->params.n200) {
- /* FIXME: LLGM-STATUS-IND, LL-RELEASE-IND/CNF */
- lle->state = GPRS_LLES_ASSIGNED_ADM;
- }
-
- switch (lle->state) {
- case GPRS_LLES_LOCAL_EST:
- /* FIXME: retransmit SABM */
- /* FIXME: re-start T200 */
- lle->retrans_ctr++;
- break;
- case GPRS_LLES_LOCAL_REL:
- /* FIXME: retransmit DISC */
- /* FIXME: re-start T200 */
- lle->retrans_ctr++;
- break;
- default:
- LOGP(DLLC, LOGL_ERROR, "LLC unhandled state: %d\n", lle->state);
- break;
- }
-
-}
-
-static void t201_expired(void *data)
-{
- struct gprs_llc_lle *lle = data;
-
- if (lle->retrans_ctr < lle->params.n200) {
- /* FIXME: transmit apropriate supervisory frame (8.6.4.1) */
- /* FIXME: set timer T201 */
- lle->retrans_ctr++;
- }
-}
-#endif
-
-int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
- enum gprs_llc_u_cmd u_cmd, int pf_bit)
-{
- uint8_t *fcs, *llch;
- uint8_t addr, ctrl;
- uint32_t fcs_calc;
-
- /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
-
- /* Address Field */
- addr = sapi & 0xf;
- if (command)
- addr |= 0x40;
-
- /* 6.3 Figure 8 */
- ctrl = 0xe0 | u_cmd;
- if (pf_bit)
- ctrl |= 0x10;
-
- /* prepend LLC UI header */
- llch = msgb_push(msg, 2);
- llch[0] = addr;
- llch[1] = ctrl;
-
- /* append FCS to end of frame */
- fcs = msgb_put(msg, 3);
- fcs_calc = gprs_llc_fcs(llch, fcs - llch);
- fcs[0] = fcs_calc & 0xff;
- fcs[1] = (fcs_calc >> 8) & 0xff;
- fcs[2] = (fcs_calc >> 16) & 0xff;
-
- /* Identifiers passed down: (BVCI, NSEI) */
-
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
- rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
-
- /* Send BSSGP-DL-UNITDATA.req */
- return _bssgp_tx_dl_ud(msg, NULL);
-}
-
-/* Send XID response to LLE */
-static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
- int command)
-{
- /* copy identifiers from LLE to ensure lower layers can route */
- msgb_tlli(msg) = lle->llme->tlli;
- msgb_bvci(msg) = lle->llme->bvci;
- msgb_nsei(msg) = lle->llme->nsei;
-
- return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
-}
-
-/* encrypt information field + FCS, if needed! */
-static int apply_gea(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];
-
- if (lle->llme->algo == GPRS_ALGO_GEA0)
- return -EINVAL;
-
- /* Compute the 'Input' Paraemeter */
- uint32_t fcs_calc, iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, sapi,
- nu, oc);
- /* Compute gamma that we need to XOR with the data */
- int r = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,
- lle->llme->kc, iv,
- fcs ? GPRS_CIPH_SGSN2MS : GPRS_CIPH_MS2SGSN);
- if (r < 0) {
- LOGP(DLLC, LOGL_ERROR, "Error producing %s gamma for UI "
- "frame: %d\n", get_value_string(gprs_cipher_names,
- lle->llme->algo), r);
- return -ENOMSG;
- }
-
- if (fcs) {
- /* Mark frame as encrypted and update FCS */
- data[2] |= 0x02;
- fcs_calc = gprs_llc_fcs(data, fcs - data);
- fcs[0] = fcs_calc & 0xff;
- fcs[1] = (fcs_calc >> 8) & 0xff;
- fcs[2] = (fcs_calc >> 16) & 0xff;
- data += 3;
- }
-
- /* XOR the cipher output with the data */
- for (r = 0; r < crypt_len; r++)
- *(data + r) ^= cipher_out[r];
-
- return 0;
-}
-
-/* Transmit a UI frame over the given SAPI:
- 'encryptable' indicates whether particular message can be encrypted according
- to 3GPP TS 24.008 § 4.7.1.2
- */
-int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
- struct sgsn_mm_ctx *mmctx, bool encryptable)
-{
- struct gprs_llc_lle *lle;
- uint8_t *fcs, *llch;
- uint8_t addr, ctrl[2];
- uint32_t fcs_calc;
- uint16_t nu = 0;
- uint32_t oc;
-
- /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
-
- /* look-up or create the LL Entity for this (TLLI, SAPI) tuple */
- lle = gprs_lle_get_or_create(msgb_tlli(msg), sapi);
-
- if (msg->len > lle->params.n201_u) {
- LOGP(DLLC, LOGL_ERROR, "Cannot Tx %u bytes (N201-U=%u)\n",
- msg->len, lle->params.n201_u);
- msgb_free(msg);
- return -EFBIG;
- }
-
- gprs_llme_copy_key(mmctx, lle->llme);
-
- /* Update LLE's (BVCI, NSEI) tuple */
- lle->llme->bvci = msgb_bvci(msg);
- lle->llme->nsei = msgb_nsei(msg);
-
- /* Obtain current values for N(u) and OC */
- nu = lle->vu_send;
- oc = lle->oc_ui_send;
- /* Increment V(U) */
- lle->vu_send = (lle->vu_send + 1) % 512;
- /* Increment Overflow Counter, if needed */
- if ((lle->vu_send + 1) / 512)
- lle->oc_ui_send += 512;
-
- /* Address Field */
- addr = sapi & 0xf;
- if (command)
- addr |= 0x40;
-
- /* Control Field */
- ctrl[0] = 0xc0;
- ctrl[0] |= nu >> 6;
- ctrl[1] = (nu << 2) & 0xfc;
- ctrl[1] |= 0x01; /* Protected Mode */
-
- /* prepend LLC UI header */
- llch = msgb_push(msg, 3);
- llch[0] = addr;
- llch[1] = ctrl[0];
- llch[2] = ctrl[1];
-
- /* append FCS to end of frame */
- fcs = msgb_put(msg, 3);
- fcs_calc = gprs_llc_fcs(llch, fcs - llch);
- fcs[0] = fcs_calc & 0xff;
- fcs[1] = (fcs_calc >> 8) & 0xff;
- fcs[2] = (fcs_calc >> 16) & 0xff;
-
- if (lle->llme->algo != GPRS_ALGO_GEA0 && encryptable) {
- int rc = apply_gea(lle, fcs - llch, nu, oc, sapi, fcs, llch);
- if (rc < 0) {
- msgb_free(msg);
- return rc;
- }
- }
-
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_PACKETS]);
- rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_DL_BYTES], msg->len);
-
- /* Identifiers passed down: (BVCI, NSEI) */
-
- /* Send BSSGP-DL-UNITDATA.req */
- return _bssgp_tx_dl_ud(msg, mmctx);
-}
-
-static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
- struct gprs_llc_lle *lle)
-{
- switch (gph->cmd) {
- case GPRS_LLC_SABM: /* Section 6.4.1.1 */
- lle->v_sent = lle->v_ack = lle->v_recv = 0;
- if (lle->state == GPRS_LLES_ASSIGNED_ADM) {
- /* start re-establishment (8.7.1) */
- }
- lle->state = GPRS_LLES_REMOTE_EST;
- /* FIXME: Send UA */
- lle->state = GPRS_LLES_ABM;
- /* FIXME: process data */
- break;
- case GPRS_LLC_DISC: /* Section 6.4.1.2 */
- /* FIXME: Send UA */
- /* terminate ABM */
- lle->state = GPRS_LLES_ASSIGNED_ADM;
- break;
- case GPRS_LLC_UA: /* Section 6.4.1.3 */
- if (lle->state == GPRS_LLES_LOCAL_EST)
- lle->state = GPRS_LLES_ABM;
- break;
- case GPRS_LLC_DM: /* Section 6.4.1.4: ABM cannot be performed */
- if (lle->state == GPRS_LLES_LOCAL_EST)
- lle->state = GPRS_LLES_ASSIGNED_ADM;
- break;
- case GPRS_LLC_FRMR: /* Section 6.4.1.5 */
- break;
- case GPRS_LLC_XID: /* Section 6.4.1.6 */
- rx_llc_xid(lle, gph);
- break;
- case GPRS_LLC_UI:
- if (gprs_llc_is_retransmit(gph->seq_tx, lle->vu_recv)) {
- LOGP(DLLC, LOGL_NOTICE,
- "TLLI=%08x dropping UI, N(U=%d) not in window V(URV(UR:%d).\n",
- lle->llme ? lle->llme->tlli : -1,
- gph->seq_tx, lle->vu_recv);
-
- /* HACK: non-standard recovery handling. If remote LLE
- * is re-transmitting the same sequence number for
- * three times, don't discard the frame but pass it on
- * and 'learn' the new sequence number */
- if (gph->seq_tx != lle->vu_recv_last) {
- lle->vu_recv_last = gph->seq_tx;
- lle->vu_recv_duplicates = 0;
- } else {
- lle->vu_recv_duplicates++;
- if (lle->vu_recv_duplicates < 3)
- return -EIO;
- LOGP(DLLC, LOGL_NOTICE, "TLLI=%08x recovering "
- "N(U=%d) after receiving %u duplicates\n",
- lle->llme ? lle->llme->tlli : -1,
- gph->seq_tx, lle->vu_recv_duplicates);
- }
- }
- /* Increment the sequence number that we expect in the next frame */
- lle->vu_recv = (gph->seq_tx + 1) % 512;
- /* Increment Overflow Counter */
- if ((gph->seq_tx + 1) / 512)
- lle->oc_ui_recv += 512;
- break;
- default:
- LOGP(DLLC, LOGL_NOTICE, "Unhandled command: %d\n", gph->cmd);
- break;
- }
-
- return 0;
-}
-
-/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */
-int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
-{
- struct gprs_llc_hdr *lh = (struct gprs_llc_hdr *) msgb_llch(msg);
- struct gprs_llc_hdr_parsed llhp;
- struct gprs_llc_lle *lle = NULL;
- bool drop_cipherable = false;
- int rc = 0;
-
- /* Identifiers from DOWN: NSEI, BVCI, TLLI */
-
- memset(&llhp, 0, sizeof(llhp));
- rc = gprs_llc_hdr_parse(&llhp, (uint8_t *) lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU));
- if (rc < 0) {
- LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n");
- return rc;
- }
-
- switch (gprs_tlli_type(msgb_tlli(msg))) {
- case TLLI_LOCAL:
- case TLLI_FOREIGN:
- case TLLI_RANDOM:
- case TLLI_AUXILIARY:
- break;
- default:
- LOGP(DLLC, LOGL_ERROR,
- "Discarding frame with strange TLLI type\n");
- break;
- }
-
- /* find the LLC Entity for this TLLI+SAPI tuple */
- lle = lle_for_rx_by_tlli_sapi(msgb_tlli(msg), llhp.sapi, llhp.cmd);
- if (!lle) {
- switch (llhp.sapi) {
- case GPRS_SAPI_SNDCP3:
- case GPRS_SAPI_SNDCP5:
- case GPRS_SAPI_SNDCP9:
- case GPRS_SAPI_SNDCP11:
- /* Ask an upper layer for help. */
- return gsm0408_gprs_force_reattach_oldmsg(msg, NULL);
- default:
- break;
- }
- return 0;
- }
- gprs_llc_hdr_dump(&llhp, lle);
- /* reset age computation */
- lle->llme->age_timestamp = GPRS_LLME_RESET_AGE;
-
- /* decrypt information field + FCS, if needed! */
- if (llhp.is_encrypted) {
- if (lle->llme->algo != GPRS_ALGO_GEA0) {
- rc = apply_gea(lle, llhp.data_len + 3, llhp.seq_tx,
- lle->oc_ui_recv, lle->sapi, NULL,
- 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;
- } else {
- LOGP(DLLC, LOGL_NOTICE, "encrypted frame for LLC that "
- "has no KC/Algo! Dropping.\n");
- return 0;
- }
- } else {
- if (lle->llme->algo != GPRS_ALGO_GEA0 &&
- lle->llme->cksn != GSM_KEY_SEQ_INVAL)
- drop_cipherable = true;
- }
-
- /* We have to do the FCS check _after_ decryption */
- llhp.fcs_calc = gprs_llc_fcs((uint8_t *)lh, llhp.crc_length);
- if (llhp.fcs != llhp.fcs_calc) {
- LOGP(DLLC, LOGL_INFO, "Dropping frame with invalid FCS\n");
- return -EIO;
- }
-
- /* Update LLE's (BVCI, NSEI) tuple */
- lle->llme->bvci = msgb_bvci(msg);
- lle->llme->nsei = msgb_nsei(msg);
-
- /* Receive and Process the actual LLC frame */
- rc = gprs_llc_hdr_rx(&llhp, lle);
- if (rc < 0)
- return rc;
-
- rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_PACKETS]);
- rate_ctr_add(&sgsn->rate_ctrs->ctr[CTR_LLC_UL_BYTES], msg->len);
-
- /* llhp.data is only set when we need to send LL_[UNIT]DATA_IND up */
- if (llhp.cmd == GPRS_LLC_UI && llhp.data && llhp.data_len) {
- msgb_gmmh(msg) = llhp.data;
- switch (llhp.sapi) {
- case GPRS_SAPI_GMM:
- /* send LL_UNITDATA_IND to GMM */
- rc = gsm0408_gprs_rcvmsg_gb(msg, lle->llme,
- drop_cipherable);
- break;
- case GPRS_SAPI_SNDCP3:
- case GPRS_SAPI_SNDCP5:
- 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);
- break;
- case GPRS_SAPI_SMS:
- /* FIXME */
- case GPRS_SAPI_TOM2:
- case GPRS_SAPI_TOM8:
- /* FIXME: send LL_DATA_IND/LL_UNITDATA_IND to TOM */
- default:
- LOGP(DLLC, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi);
- rc = -EINVAL;
- break;
- }
- }
-
- return rc;
-}
-
-/* Propagate crypto parameters MM -> LLME */
-void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme)
-{
- if (!mm)
- return;
- if (mm->ciph_algo != GPRS_ALGO_GEA0) {
- llme->algo = mm->ciph_algo;
- if (llme->cksn != mm->auth_triplet.key_seq &&
- mm->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
- memcpy(llme->kc, mm->auth_triplet.vec.kc,
- gprs_cipher_key_length(mm->ciph_algo));
- llme->cksn = mm->auth_triplet.key_seq;
- }
- } else
- llme->cksn = GSM_KEY_SEQ_INVAL;
-}
-
-/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
-int gprs_llgmm_assign(struct gprs_llc_llme *llme,
- uint32_t old_tlli, uint32_t new_tlli)
-{
- unsigned int i;
-
- if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) {
- /* TLLI Assignment 8.3.1 */
- /* New TLLI shall be assigned and used when (re)transmitting LLC frames */
- /* If old TLLI != 0xffffffff was assigned to LLME, then TLLI
- * old is unassigned. Only TLLI new shall be accepted when
- * received from peer. */
- if (llme->old_tlli != 0xffffffff) {
- llme->old_tlli = 0xffffffff;
- llme->tlli = new_tlli;
- } else {
- /* If TLLI old == 0xffffffff was assigned to LLME, then this is
- * TLLI assignmemt according to 8.3.1 */
- llme->old_tlli = 0xffffffff;
- llme->tlli = new_tlli;
- llme->state = GPRS_LLMS_ASSIGNED;
- /* 8.5.3.1 For all LLE's */
- for (i = 0; i < ARRAY_SIZE(llme->lle); i++) {
- struct gprs_llc_lle *l = &llme->lle[i];
- l->vu_send = l->vu_recv = 0;
- l->retrans_ctr = 0;
- l->state = GPRS_LLES_ASSIGNED_ADM;
- /* FIXME Set parameters according to table 9 */
- }
- }
- } else if (old_tlli != 0xffffffff && new_tlli != 0xffffffff) {
- /* TLLI Change 8.3.2 */
- /* Both TLLI Old and TLLI New are assigned; use New when
- * (re)transmitting. Accept both Old and New on Rx */
- llme->old_tlli = old_tlli;
- llme->tlli = new_tlli;
- llme->state = GPRS_LLMS_ASSIGNED;
- } else if (old_tlli != 0xffffffff && new_tlli == 0xffffffff) {
- /* TLLI Unassignment 8.3.3) */
- llme->tlli = llme->old_tlli = 0;
- llme->state = GPRS_LLMS_UNASSIGNED;
- for (i = 0; i < ARRAY_SIZE(llme->lle); i++) {
- struct gprs_llc_lle *l = &llme->lle[i];
- l->state = GPRS_LLES_UNASSIGNED;
- }
- llme_free(llme);
- } else
- return -EINVAL;
-
- return 0;
-}
-
-/* TLLI unassignment */
-int gprs_llgmm_unassign(struct gprs_llc_llme *llme)
-{
- return gprs_llgmm_assign(llme, llme->tlli, 0xffffffff);
-}
-
-/* Chapter 7.2.1.2 LLGMM-RESET.req */
-int gprs_llgmm_reset(struct gprs_llc_llme *llme)
-{
- struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
- struct gprs_llc_lle *lle = &llme->lle[1];
- uint8_t xid_bytes[1024];
- int xid_bytes_len;
- uint8_t *xid;
-
- LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n");
- if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) {
- LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, "
- "falling back to rand()\n");
- llme->iov_ui = rand();
- }
-
- /* Generate XID message */
- xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes,
- sizeof(xid_bytes),llme->iov_ui,llme);
- if (xid_bytes_len < 0)
- return -EINVAL;
- xid = msgb_put(msg, xid_bytes_len);
- memcpy(xid, xid_bytes, xid_bytes_len);
-
- /* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */
- lle->vu_recv = 0;
- lle->vu_send = 0;
- lle->oc_ui_send = 0;
- lle->oc_ui_recv = 0;
-
- /* FIXME: Start T200, wait for XID response */
- return gprs_llc_tx_xid(lle, msg, 1);
-}
-
-int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi,
- struct gprs_llc_llme *llme)
-{
- struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
- uint8_t xid_bytes[1024];
- int xid_bytes_len;
- uint8_t *xid;
-
- LOGP(DLLC, LOGL_NOTICE, "LLGM Reset\n");
- if (RAND_bytes((uint8_t *) &llme->iov_ui, 4) != 1) {
- LOGP(DLLC, LOGL_NOTICE, "RAND_bytes failed for LLC XID reset, "
- "falling back to rand()\n");
- llme->iov_ui = rand();
- }
-
- /* Generate XID message */
- xid_bytes_len = gprs_llc_generate_xid_for_gmm_reset(xid_bytes,
- sizeof(xid_bytes),llme->iov_ui,llme);
- if (xid_bytes_len < 0)
- return -EINVAL;
- xid = msgb_put(msg, xid_bytes_len);
- memcpy(xid, xid_bytes, xid_bytes_len);
-
- /* FIXME: Start T200, wait for XID response */
-
- msgb_tlli(msg) = msgb_tlli(oldmsg);
- msgb_bvci(msg) = msgb_bvci(oldmsg);
- msgb_nsei(msg) = msgb_nsei(oldmsg);
-
- return gprs_llc_tx_u(msg, sapi, 1, GPRS_LLC_U_XID, 1);
-}
-
-int gprs_llc_init(const char *cipher_plugin_path)
-{
- return gprs_cipher_load(cipher_plugin_path);
-}
diff --git a/openbsc/src/gprs/gprs_llc_parse.c b/openbsc/src/gprs/gprs_llc_parse.c
deleted file mode 100644
index a5a7a7122..000000000
--- a/openbsc/src/gprs/gprs_llc_parse.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/* GPRS LLC protocol implementation as per 3GPP TS 04.64 */
-
-/* (C) 2009-2010 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 <errno.h>
-#include <stdint.h>
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/gprs_sgsn.h>
-#include <openbsc/gprs_gmm.h>
-#include <openbsc/gprs_llc.h>
-#include <openbsc/crc24.h>
-
-static const struct value_string llc_cmd_strs[] = {
- { GPRS_LLC_NULL, "NULL" },
- { GPRS_LLC_RR, "RR" },
- { GPRS_LLC_ACK, "ACK" },
- { GPRS_LLC_RNR, "RNR" },
- { GPRS_LLC_SACK, "SACK" },
- { GPRS_LLC_DM, "DM" },
- { GPRS_LLC_DISC, "DISC" },
- { GPRS_LLC_UA, "UA" },
- { GPRS_LLC_SABM, "SABM" },
- { GPRS_LLC_FRMR, "FRMR" },
- { GPRS_LLC_XID, "XID" },
- { GPRS_LLC_UI, "UI" },
- { 0, NULL }
-};
-
-#define LLC_ALLOC_SIZE 16384
-#define UI_HDR_LEN 3
-#define N202 4
-#define CRC24_LENGTH 3
-
-int gprs_llc_fcs(uint8_t *data, unsigned int len)
-{
- uint32_t fcs_calc;
-
- fcs_calc = crc24_calc(INIT_CRC24, data, len);
- fcs_calc = ~fcs_calc;
- fcs_calc &= 0xffffff;
-
- return fcs_calc;
-}
-
-void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle)
-{
- const char *gea;
- uint32_t iov_ui = 0;
- if (lle) {
- gea = get_value_string(gprs_cipher_names, lle->llme->algo);
- iov_ui = lle->llme->iov_ui;
- } else
- gea = "GEA?";
- DEBUGP(DLLC, "LLC SAPI=%u %c %c %c %s IOV-UI=0x%06x FCS=0x%06x ",
- gph->sapi, gph->is_cmd ? 'C' : 'R', gph->ack_req ? 'A' : ' ',
- gph->is_encrypted ? 'E' : 'U',
- gea, iov_ui, gph->fcs);
-
- if (gph->cmd)
- DEBUGPC(DLLC, "CMD=%s ", get_value_string(llc_cmd_strs, gph->cmd));
-
- if (gph->data)
- DEBUGPC(DLLC, "DATA ");
-
- DEBUGPC(DLLC, "\n");
-}
-
-/* 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)
-{
- uint8_t *ctrl = llc_hdr+1;
-
- if (len <= CRC24_LENGTH)
- return -EIO;
-
- ghp->crc_length = len - CRC24_LENGTH;
-
- ghp->ack_req = 0;
-
- /* Section 5.5: FCS */
- ghp->fcs = *(llc_hdr + len - 3);
- ghp->fcs |= *(llc_hdr + len - 2) << 8;
- ghp->fcs |= *(llc_hdr + len - 1) << 16;
-
- /* Section 6.2.1: invalid PD field */
- if (llc_hdr[0] & 0x80)
- return -EIO;
-
- /* This only works for the MS->SGSN direction */
- if (llc_hdr[0] & 0x40)
- ghp->is_cmd = 0;
- else
- ghp->is_cmd = 1;
-
- ghp->sapi = llc_hdr[0] & 0xf;
-
- /* Section 6.2.3: check for reserved SAPI */
- switch (ghp->sapi) {
- case 0:
- case 4:
- case 6:
- case 0xa:
- case 0xc:
- case 0xd:
- case 0xf:
- return -EINVAL;
- }
-
- if ((ctrl[0] & 0x80) == 0) {
- /* I (Information transfer + Supervisory) format */
- uint8_t k;
-
- ghp->data = ctrl + 3;
-
- if (ctrl[0] & 0x40)
- ghp->ack_req = 1;
-
- ghp->seq_tx = (ctrl[0] & 0x1f) << 4;
- ghp->seq_tx |= (ctrl[1] >> 4);
-
- ghp->seq_rx = (ctrl[1] & 0x7) << 6;
- ghp->seq_rx |= (ctrl[2] >> 2);
-
- switch (ctrl[2] & 0x03) {
- case 0:
- ghp->cmd = GPRS_LLC_RR;
- break;
- case 1:
- ghp->cmd = GPRS_LLC_ACK;
- break;
- case 2:
- ghp->cmd = GPRS_LLC_RNR;
- break;
- case 3:
- ghp->cmd = GPRS_LLC_SACK;
- k = ctrl[3] & 0x1f;
- ghp->data += 1 + k;
- break;
- }
- ghp->data_len = (llc_hdr + len - 3) - ghp->data;
- } else if ((ctrl[0] & 0xc0) == 0x80) {
- /* S (Supervisory) format */
- ghp->data = NULL;
- ghp->data_len = 0;
-
- if (ctrl[0] & 0x20)
- ghp->ack_req = 1;
- ghp->seq_rx = (ctrl[0] & 0x7) << 6;
- ghp->seq_rx |= (ctrl[1] >> 2);
-
- switch (ctrl[1] & 0x03) {
- case 0:
- ghp->cmd = GPRS_LLC_RR;
- break;
- case 1:
- ghp->cmd = GPRS_LLC_ACK;
- break;
- case 2:
- ghp->cmd = GPRS_LLC_RNR;
- break;
- case 3:
- ghp->cmd = GPRS_LLC_SACK;
- break;
- }
- } else if ((ctrl[0] & 0xe0) == 0xc0) {
- /* UI (Unconfirmed Inforamtion) format */
- ghp->cmd = GPRS_LLC_UI;
- ghp->data = ctrl + 2;
- ghp->data_len = (llc_hdr + len - 3) - ghp->data;
-
- ghp->seq_tx = (ctrl[0] & 0x7) << 6;
- ghp->seq_tx |= (ctrl[1] >> 2);
- if (ctrl[1] & 0x02) {
- ghp->is_encrypted = 1;
- /* FIXME: encryption */
- }
- if (ctrl[1] & 0x01) {
- /* FCS over hdr + all inf fields */
- } else {
- /* FCS over hdr + N202 octets (4) */
- if (ghp->crc_length > UI_HDR_LEN + N202)
- ghp->crc_length = UI_HDR_LEN + N202;
- }
- } else {
- /* U (Unnumbered) format: 1 1 1 P/F M4 M3 M2 M1 */
- ghp->data = NULL;
- ghp->data_len = 0;
-
- switch (ctrl[0] & 0xf) {
- case GPRS_LLC_U_NULL_CMD:
- ghp->cmd = GPRS_LLC_NULL;
- break;
- case GPRS_LLC_U_DM_RESP:
- ghp->cmd = GPRS_LLC_DM;
- break;
- case GPRS_LLC_U_DISC_CMD:
- ghp->cmd = GPRS_LLC_DISC;
- break;
- case GPRS_LLC_U_UA_RESP:
- ghp->cmd = GPRS_LLC_UA;
- break;
- case GPRS_LLC_U_SABM_CMD:
- ghp->cmd = GPRS_LLC_SABM;
- break;
- case GPRS_LLC_U_FRMR_RESP:
- ghp->cmd = GPRS_LLC_FRMR;
- break;
- case GPRS_LLC_U_XID:
- ghp->cmd = GPRS_LLC_XID;
- ghp->data = ctrl + 1;
- ghp->data_len = (llc_hdr + len - 3) - ghp->data;
- break;
- default:
- return -EIO;
- }
- }
-
- /* FIXME: parse sack frame */
- if (ghp->cmd == GPRS_LLC_SACK) {
- LOGP(DLLC, LOGL_NOTICE, "Unsupported SACK frame\n");
- return -EIO;
- }
-
- return 0;
-}
diff --git a/openbsc/src/gprs/gprs_llc_vty.c b/openbsc/src/gprs/gprs_llc_vty.c
deleted file mode 100644
index bf34e9782..000000000
--- a/openbsc/src/gprs/gprs_llc_vty.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* VTY interface for our GPRS LLC implementation */
-
-/* (C) 2010 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 <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdint.h>
-#include <time.h>
-
-#include <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/rate_ctr.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-#include <openbsc/gprs_llc.h>
-
-#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),
- 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,
- lle->retrans_ctr, VTY_NEWLINE);
- vty_out(vty, " T200=%u, N200=%u, N201-U=%u, N201-I=%u, mD=%u, "
- "mU=%u, kD=%u, kU=%u%s", par->t200_201, par->n200,
- par->n201_u, par->n201_i, par->mD, par->mU, par->kD,
- par->kU, VTY_NEWLINE);
-}
-
-static uint8_t valid_sapis[] = { 1, 2, 3, 5, 7, 8, 9, 11 };
-
-static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme)
-{
- unsigned int i;
- struct timespec now_tp = {0};
- clock_gettime(CLOCK_MONOTONIC, &now_tp);
-
- vty_out(vty, "TLLI %08x (Old TLLI %08x) BVCI=%u NSEI=%u %s: "
- "IOV-UI=0x%06x CKSN=%d Age=%d: State %s%s", llme->tlli,
- llme->old_tlli, llme->bvci, llme->nsei,
- 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);
-
- for (i = 0; i < ARRAY_SIZE(valid_sapis); i++) {
- struct gprs_llc_lle *lle;
- uint8_t sapi = valid_sapis[i];
-
- if (sapi >= ARRAY_SIZE(llme->lle))
- continue;
-
- lle = &llme->lle[sapi];
- vty_dump_lle(vty, lle);
- }
-}
-
-
-DEFUN(show_llc, show_llc_cmd,
- "show llc",
- SHOW_STR "Display information about the LLC protocol")
-{
- struct gprs_llc_llme *llme;
-
- vty_out(vty, "State of LLC Entities%s", VTY_NEWLINE);
- llist_for_each_entry(llme, &gprs_llc_llmes, list) {
- vty_dump_llme(vty, llme);
- }
- return CMD_SUCCESS;
-}
-
-int gprs_llc_vty_init(void)
-{
- install_element_ve(&show_llc_cmd);
-
- return 0;
-}
diff --git a/openbsc/src/gprs/gprs_llc_xid.c b/openbsc/src/gprs/gprs_llc_xid.c
deleted file mode 100644
index fe631715a..000000000
--- a/openbsc/src/gprs/gprs_llc_xid.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <errno.h>
-
-#include <osmocom/core/utils.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/talloc.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gprs_llc.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/gprs_llc_xid.h>
-
-const struct value_string gprs_llc_xid_type_names[] = {
- { GPRS_LLC_XID_T_VERSION, "VERSION"},
- { GPRS_LLC_XID_T_IOV_UI, "IOV_UI"},
- { GPRS_LLC_XID_T_IOV_I, "IOV_I"},
- { GPRS_LLC_XID_T_T200, "T200"},
- { GPRS_LLC_XID_T_N200, "N200"},
- { GPRS_LLC_XID_T_N201_U, "N201_"},
- { GPRS_LLC_XID_T_N201_I, "N201_I"},
- { GPRS_LLC_XID_T_mD, "mD"},
- { GPRS_LLC_XID_T_mU, "mU"},
- { GPRS_LLC_XID_T_kD, "kD"},
- { GPRS_LLC_XID_T_kU, "kU"},
- { GPRS_LLC_XID_T_L3_PAR, "L3_PAR"},
- { GPRS_LLC_XID_T_RESET, "RESET"},
- { 0, NULL },
-};
-
-/* Parse XID parameter field */
-static int decode_xid_field(struct gprs_llc_xid_field *xid_field,
- const uint8_t *src, uint8_t src_len)
-{
- uint8_t xl;
- uint8_t type;
- uint8_t len;
- int src_counter = 0;
-
- /* Exit immediately if it is clear that no
- * parseable data is present */
- if (src_len < 1 || !src)
- return -EINVAL;
-
- /* Extract header info */
- xl = (*src >> 7) & 1;
- type = (*src >> 2) & 0x1F;
-
- /* Extract length field */
- len = (*src) & 0x3;
- src++;
- src_counter++;
- if (xl) {
- if (src_len < 2)
- return -EINVAL;
- len = (len << 6) & 0xC0;
- len |= ((*src) >> 2) & 0x3F;
- src++;
- src_counter++;
- }
-
- /* Fill out struct */
- xid_field->type = type;
- xid_field->data_len = len;
- if (len > 0) {
- if (src_len < src_counter + len)
- return -EINVAL;
- xid_field->data =
- talloc_memdup(xid_field,src,xid_field->data_len);
- } else
- xid_field->data = NULL;
-
- /* Return consumed length */
- return src_counter + len;
-}
-
-/* Encode XID parameter field */
-static int encode_xid_field(uint8_t *dst, int dst_maxlen,
- const struct gprs_llc_xid_field *xid_field)
-{
- int xl = 0;
-
- /* When the length does not fit into 2 bits,
- * we need extended length fields */
- if (xid_field->data_len > 3)
- xl = 1;
-
- /* Exit immediately if it is clear that no
- * encoding result can be stored */
- if (dst_maxlen < xid_field->data_len + 1 + xl)
- return -EINVAL;
-
- /* There are only 5 bits reserved for the type, exit on exceed */
- if (xid_field->type > 31)
- return -EINVAL;
-
- /* Encode header */
- memset(dst, 0, dst_maxlen);
- if (xl)
- dst[0] |= 0x80;
- dst[0] |= (((xid_field->type) & 0x1F) << 2);
-
- if (xl) {
- dst[0] |= (((xid_field->data_len) >> 6) & 0x03);
- dst[1] = ((xid_field->data_len) << 2) & 0xFC;
- } else
- dst[0] |= ((xid_field->data_len) & 0x03);
-
- /* Append payload data */
- if (xid_field->data && xid_field->data_len)
- memcpy(dst + 1 + xl, xid_field->data, xid_field->data_len);
-
- /* Return generated length */
- return xid_field->data_len + 1 + xl;
-}
-
-/* Transform a list with XID fields into a XID message (dst) */
-int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen,
- const struct llist_head *xid_fields)
-{
- struct gprs_llc_xid_field *xid_field;
- int rc;
- int byte_counter = 0;
-
- OSMO_ASSERT(xid_fields);
- OSMO_ASSERT(dst);
-
- llist_for_each_entry_reverse(xid_field, xid_fields, list) {
- /* Encode XID-Field */
- rc = encode_xid_field(dst, dst_maxlen, xid_field);
- if (rc < 0)
- return -EINVAL;
-
- /* Advance pointer and lower maxlen for the
- * next encoding round */
- dst += rc;
- byte_counter += rc;
- dst_maxlen -= rc;
- }
-
- /* Return generated length */
- return byte_counter;
-}
-
-/* Transform a XID message (dst) into a list of XID fields */
-struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src,
- int src_len)
-{
- struct gprs_llc_xid_field *xid_field;
- struct llist_head *xid_fields;
-
- int rc;
- int max_loops = src_len;
-
- OSMO_ASSERT(src);
-
- xid_fields = talloc_zero(ctx, struct llist_head);
- INIT_LLIST_HEAD(xid_fields);
-
- while (1) {
- /* Bail in case decode_xid_field() constantly returns zero */
- if (max_loops <= 0) {
- talloc_free(xid_fields);
- return NULL;
- }
-
- /* Decode XID field */
- xid_field = talloc_zero(xid_fields, struct gprs_llc_xid_field);
- rc = decode_xid_field(xid_field, src, src_len);
-
- /* Immediately stop on error */
- if (rc < 0) {
- talloc_free(xid_fields);
- return NULL;
- }
-
- /* Add parsed XID field to list */
- llist_add(&xid_field->list, xid_fields);
-
- /* Advance pointer and lower dst_len for the next
- * decoding round */
- src += rc;
- src_len -= rc;
-
- /* We are (scuccessfully) done when no further byes are left */
- if (src_len == 0)
- return xid_fields;
-
- max_loops--;
- }
-}
-
-/* Create a duplicate of an XID-Field */
-struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, const struct
- gprs_llc_xid_field
- *xid_field)
-{
- struct gprs_llc_xid_field *dup;
-
- OSMO_ASSERT(xid_field);
-
- /* Create a copy of the XID field in memory */
- dup = talloc_memdup(ctx, xid_field, sizeof(*xid_field));
- dup->data = talloc_memdup(ctx, xid_field->data, xid_field->data_len);
-
- /* Unlink duplicate from source list */
- INIT_LLIST_HEAD(&dup->list);
-
- return dup;
-}
-
-/* Copy an llist with xid fields */
-struct llist_head *gprs_llc_copy_xid(const void *ctx,
- const struct llist_head *xid_fields)
-{
- struct gprs_llc_xid_field *xid_field;
- struct llist_head *xid_fields_copy;
-
- OSMO_ASSERT(xid_fields);
-
- xid_fields_copy = talloc_zero(ctx, struct llist_head);
- INIT_LLIST_HEAD(xid_fields_copy);
-
- /* Create duplicates and add them to the target list */
- llist_for_each_entry(xid_field, xid_fields, list) {
- llist_add(&gprs_llc_dup_xid_field(ctx, xid_field)->list,
- xid_fields_copy);
- }
-
- return xid_fields_copy;
-}
-
-/* Dump a list with XID fields (Debug) */
-void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields,
- unsigned int logl)
-{
- struct gprs_llc_xid_field *xid_field;
-
- OSMO_ASSERT(xid_fields);
-
- llist_for_each_entry(xid_field, xid_fields, list) {
- if (xid_field->data_len) {
- OSMO_ASSERT(xid_field->data);
- LOGP(DLLC, logl,
- "XID: type %s, data_len=%d, data=%s\n",
- get_value_string(gprs_llc_xid_type_names,
- xid_field->type),
- xid_field->data_len,
- osmo_hexdump_nospc(xid_field->data,
- xid_field->data_len));
- } else {
- LOGP(DLLC, logl,
- "XID: type=%d, data_len=%d, data=NULL\n",
- xid_field->type, xid_field->data_len);
- }
- }
-}
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
deleted file mode 100644
index acaf78187..000000000
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ /dev/null
@@ -1,923 +0,0 @@
-/* GPRS SGSN 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/core/backtrace.h>
-#include <osmocom/gprs/gprs_ns.h>
-#include <osmocom/gprs/gprs_bssgp.h>
-#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
-#include <osmocom/gsm/apn.h>
-
-#include <openbsc/gprs_subscriber.h>
-#include <openbsc/debug.h>
-#include <openbsc/gprs_sgsn.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/gprs_gmm.h>
-#include <openbsc/gprs_utils.h>
-#include <openbsc/signal.h>
-#include "openbsc/gprs_llc.h"
-#include <openbsc/iu.h>
-
-#include <pdp.h>
-
-#include <time.h>
-
-#include <openssl/rand.h>
-
-#define GPRS_LLME_CHECK_TICK 30
-
-extern struct sgsn_instance *sgsn;
-
-LLIST_HEAD(sgsn_mm_ctxts);
-LLIST_HEAD(sgsn_ggsn_ctxts);
-LLIST_HEAD(sgsn_apn_ctxts);
-LLIST_HEAD(sgsn_pdp_ctxts);
-
-static const struct rate_ctr_desc mmctx_ctr_description[] = {
- { "sign.packets.in", "Signalling Messages ( In)" },
- { "sign.packets.out", "Signalling Messages (Out)" },
- { "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)" },
- { "pdp_ctx_act", "PDP Context Activations " },
- { "suspend", "SUSPEND Count " },
- { "paging.ps", "Paging Packet Switched " },
- { "paging.cs", "Paging Circuit Switched " },
- { "ra_update", "Routing Area Update " },
-};
-
-static const struct rate_ctr_group_desc mmctx_ctrg_desc = {
- .group_name_prefix = "sgsn.mmctx",
- .group_description = "SGSN MM Context Statistics",
- .num_ctr = ARRAY_SIZE(mmctx_ctr_description),
- .ctr_desc = mmctx_ctr_description,
- .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 sucessful received LLC bytes (encrypt & fcs correct)" },
- { "llc.dl_packets", "Count sucessful sent LLC packets before giving it to the bssgp layer" },
- { "llc.ul_packets", "Count sucessful 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_bsc_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) {
- if (ctx->ran_type == MM_CTX_T_UTRAN_Iu
- && uectx == ctx->iu.ue_ctx)
- return ctx;
- }
-
- return NULL;
-}
-
-/* look-up a SGSN MM context based on TLLI + RAI */
-struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
- const struct gprs_ra_id *raid)
-{
- struct sgsn_mm_ctx *ctx;
-
- llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
- if ((tlli == ctx->gb.tlli || tlli == ctx->gb.tlli_new) &&
- gprs_ra_id_equals(raid, &ctx->ra))
- return ctx;
- }
-
- return NULL;
-}
-
-struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
- const struct gprs_ra_id *raid)
-{
- struct sgsn_mm_ctx *ctx;
- int tlli_type;
-
- /* TODO: Also check the P_TMSI signature to be safe. That signature
- * should be different (at least with a sufficiently high probability)
- * after SGSN restarts and for multiple SGSN instances.
- */
-
- tlli_type = gprs_tlli_type(tlli);
- if (tlli_type != TLLI_FOREIGN && tlli_type != TLLI_LOCAL)
- return NULL;
-
- llist_for_each_entry(ctx, &sgsn_mm_ctxts, 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))
- return ctx;
- }
-
- return NULL;
-}
-
-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) {
- if (p_tmsi == ctx->p_tmsi ||
- (ctx->p_tmsi_old && ctx->p_tmsi_old == p_tmsi))
- return ctx;
- }
- return NULL;
-}
-
-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) {
- if (!strcmp(imsi, ctx->imsi))
- return ctx;
- }
- return NULL;
-
-}
-
-/* Allocate a new SGSN MM context for GERAN_Gb */
-struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
- const struct gprs_ra_id *raid)
-{
- struct sgsn_mm_ctx *ctx;
-
- ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx);
- if (!ctx)
- return NULL;
-
- memcpy(&ctx->ra, raid, sizeof(ctx->ra));
- ctx->ran_type = MM_CTX_T_GERAN_Gb;
- ctx->gb.tlli = tlli;
- ctx->gmm_state = GMM_DEREGISTERED;
- ctx->pmm_state = MM_IDLE;
- ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
- ctx->ciph_algo = sgsn->cfg.cipher;
- LOGMMCTXP(LOGL_DEBUG, ctx, "Allocated with %s cipher.\n",
- get_value_string(gprs_cipher_names, ctx->ciph_algo));
- ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
- if (!ctx->ctrg) {
- LOGMMCTXP(LOGL_ERROR, ctx, "Cannot allocate counter group\n");
- talloc_free(ctx);
- return NULL;
- }
- INIT_LLIST_HEAD(&ctx->pdp_list);
-
- llist_add(&ctx->list, &sgsn_mm_ctxts);
-
- return ctx;
-}
-
-/* Allocate a new SGSN MM context */
-struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
-{
- struct sgsn_mm_ctx *ctx;
-
- ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx);
- if (!ctx)
- return NULL;
-
- ctx->ran_type = MM_CTX_T_UTRAN_Iu;
- ctx->iu.ue_ctx = uectx;
- ctx->iu.new_key = 1;
- ctx->gmm_state = GMM_DEREGISTERED;
- ctx->pmm_state = PMM_DETACHED;
- ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
- ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0);
- if (!ctx->ctrg) {
- LOGMMCTXP(LOGL_ERROR, ctx, "Cannot allocate counter group\n");
- talloc_free(ctx);
- return NULL;
- }
-
- /* Need to get RAID from IU conn */
- ctx->ra = ctx->iu.ue_ctx->ra_id;
-
- INIT_LLIST_HEAD(&ctx->pdp_list);
-
- llist_add(&ctx->list, &sgsn_mm_ctxts);
-
- return ctx;
-}
-
-
-/* this is a hard _free_ function, it doesn't clean up the PDP contexts
- * in libgtp! */
-static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
-{
- struct sgsn_pdp_ctx *pdp, *pdp2;
-
- /* Unlink from global list of MM contexts */
- llist_del(&mm->list);
-
- /* Free all PDP contexts */
- llist_for_each_entry_safe(pdp, pdp2, &mm->pdp_list, list)
- sgsn_pdp_ctx_free(pdp);
-
- rate_ctr_group_free(mm->ctrg);
-
- talloc_free(mm);
-}
-
-void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
-{
- struct gprs_llc_llme *llme = NULL;
- uint32_t tlli = mm->gb.tlli;
- struct sgsn_pdp_ctx *pdp, *pdp2;
- struct sgsn_signal_data sig_data;
-
- if (mm->ran_type == MM_CTX_T_GERAN_Gb)
- llme = mm->gb.llme;
- else
- OSMO_ASSERT(mm->gb.llme == NULL);
-
- /* Forget about ongoing look-ups */
- if (mm->ggsn_lookup) {
- LOGMMCTXP(LOGL_NOTICE, mm,
- "Cleaning mmctx with on-going query.\n");
- mm->ggsn_lookup->mmctx = NULL;
- mm->ggsn_lookup = NULL;
- }
-
- /* delete all existing PDP contexts for this MS */
- llist_for_each_entry_safe(pdp, pdp2, &mm->pdp_list, list) {
- LOGMMCTXP(LOGL_NOTICE, mm,
- "Dropping PDP context for NSAPI=%u\n", pdp->nsapi);
- sgsn_pdp_ctx_terminate(pdp);
- }
-
- if (osmo_timer_pending(&mm->timer)) {
- LOGMMCTXP(LOGL_INFO, mm, "Cancelling MM timer %u\n", mm->T);
- osmo_timer_del(&mm->timer);
- }
-
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = mm;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_MM_FREE, &sig_data);
-
-
- /* Detach from subscriber which is possibly freed then */
- if (mm->subscr) {
- struct gprs_subscr *subscr = gprs_subscr_get(mm->subscr);
- gprs_subscr_cleanup(subscr);
- gprs_subscr_put(subscr);
- }
-
- sgsn_mm_ctx_free(mm);
- mm = NULL;
-
- if (llme) {
- /* TLLI unassignment, must be called after sgsn_mm_ctx_free */
- gprs_llgmm_assign(llme, tlli, 0xffffffff);
- }
-}
-
-
-/* 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)
-{
- struct sgsn_pdp_ctx *pdp;
-
- llist_for_each_entry(pdp, &mm->pdp_list, list) {
- if (pdp->nsapi == nsapi)
- return pdp;
- }
- return NULL;
-}
-
-/* look up PDP context by MM context and transaction ID */
-struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
- uint8_t tid)
-{
- struct sgsn_pdp_ctx *pdp;
-
- llist_for_each_entry(pdp, &mm->pdp_list, list) {
- if (pdp->ti == tid)
- return pdp;
- }
- 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,
- uint8_t nsapi)
-{
- struct sgsn_pdp_ctx *pdp;
-
- pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
- if (pdp)
- return NULL;
-
- pdp = talloc_zero(tall_bsc_ctx, struct sgsn_pdp_ctx);
- if (!pdp)
- return NULL;
-
- pdp->mm = mm;
- 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);
- 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 */
- 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 */
- llist_del(&pdp->list);
- pdp->mm = NULL;
-
- 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);
-
- rate_ctr_group_free(pdp->ctrg);
- if (pdp->mm)
- llist_del(&pdp->list);
- 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;
- }
-
- if (pdp->destroy_ggsn)
- sgsn_ggsn_ctx_free(pdp->ggsn);
- talloc_free(pdp);
-}
-
-/* GGSN contexts */
-
-struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
-{
- struct sgsn_ggsn_ctx *ggc;
-
- ggc = talloc_zero(tall_bsc_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;
- llist_add(&ggc->list, &sgsn_ggsn_ctxts);
-
- return ggc;
-}
-
-void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
-{
- 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_bsc_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;
- uint32_t ptmsi = 0xdeadbeef;
- int max_retries = 100;
-
-restart:
- if (RAND_bytes((uint8_t *) &ptmsi, sizeof(ptmsi)) != 1)
- goto failed;
-
- /* Enforce that the 2 MSB are set without loosing the distance between
- * identical values. Since rand() has no duplicate values within a
- * period (because the size of the state is the same like the size of
- * the random value), this leads to a distance of period/4 when the
- * distribution of the 2 MSB is uniform. This approach fails with a
- * probability of (3/4)^max_retries, only 1% of the approaches will
- * need more than 16 numbers (even distribution assumed).
- *
- * Alternatively, a freeze list could be used if another PRNG is used
- * or when this approach proves to be not sufficient.
- */
- if (ptmsi >= 0xC0000000) {
- if (!max_retries--)
- goto failed;
- goto restart;
- }
- ptmsi |= 0xC0000000;
-
- if (ptmsi == GSM_RESERVED_TMSI) {
- if (!max_retries--)
- goto failed;
- goto restart;
- }
-
- llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
- if (mm->p_tmsi == ptmsi) {
- if (!max_retries--)
- goto failed;
- goto restart;
- }
- }
-
- return ptmsi;
-
-failed:
- LOGP(DGPRS, LOGL_ERROR, "Failed to allocate a P-TMSI\n");
- return GSM_RESERVED_TMSI;
-}
-
-static void drop_one_pdp(struct sgsn_pdp_ctx *pdp)
-{
- if (pdp->mm->gmm_state == GMM_REGISTERED_NORMAL)
- gsm48_tx_gsm_deact_pdp_req(pdp, GSM_CAUSE_NET_FAIL);
- else {
- /* FIXME: GPRS paging in case MS is SUSPENDED */
- LOGPDPCTXP(LOGL_NOTICE, pdp, "Hard-dropping PDP ctx due to GGSN "
- "recovery\n");
- /* FIXME: how to tell this to libgtp? */
- sgsn_pdp_ctx_free(pdp);
- }
-}
-
-/* High-level function to be called in case a GGSN has disappeared or
- * otherwise lost state (recovery procedure) */
-int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn)
-{
- struct sgsn_mm_ctx *mm;
- int num = 0;
-
- llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
- struct sgsn_pdp_ctx *pdp;
- llist_for_each_entry(pdp, &mm->pdp_list, list) {
- if (pdp->ggsn == ggsn) {
- drop_one_pdp(pdp);
- num++;
- }
- }
- }
-
- return num;
-}
-
-void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
-{
- OSMO_ASSERT(mmctx != NULL);
- LOGMMCTXP(LOGL_INFO, mmctx, "Subscriber data update\n");
-
- sgsn_auth_update(mmctx);
-}
-
-static void insert_extra(struct tlv_parsed *tp,
- struct sgsn_subscriber_data *data,
- struct sgsn_subscriber_pdp_data *pdp)
-{
- tp->lv[OSMO_IE_GSM_SUB_QOS].len = pdp->qos_subscribed_len;
- tp->lv[OSMO_IE_GSM_SUB_QOS].val = pdp->qos_subscribed;
-
- /* Prefer PDP charging characteristics of per subscriber one */
- if (pdp->has_pdp_charg) {
- tp->lv[OSMO_IE_GSM_CHARG_CHAR].len = sizeof(pdp->pdp_charg);
- tp->lv[OSMO_IE_GSM_CHARG_CHAR].val = &pdp->pdp_charg[0];
- } else if (data->has_pdp_charg) {
- tp->lv[OSMO_IE_GSM_CHARG_CHAR].len = sizeof(data->pdp_charg);
- tp->lv[OSMO_IE_GSM_CHARG_CHAR].val = &data->pdp_charg[0];
- }
-}
-
-/**
- * The tlv_parsed tp parameter will be modified to insert a
- * OSMO_IE_GSM_SUB_QOS in case the data is available in the
- * PDP context handling.
- */
-struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
- struct tlv_parsed *tp,
- enum gsm48_gsm_cause *gsm_cause,
- char *out_apn_str)
-{
- char req_apn_str[GSM_APN_LENGTH] = {0};
- const struct apn_ctx *apn_ctx = NULL;
- const char *selected_apn_str = NULL;
- struct sgsn_subscriber_pdp_data *pdp;
- struct sgsn_ggsn_ctx *ggsn = NULL;
- int allow_any_apn = 0;
-
- out_apn_str[0] = '\0';
-
- if (TLVP_PRESENT(tp, GSM48_IE_GSM_APN)) {
- if (TLVP_LEN(tp, GSM48_IE_GSM_APN) >= GSM_APN_LENGTH - 1) {
- LOGMMCTXP(LOGL_ERROR, mmctx, "APN IE too long\n");
- *gsm_cause = GSM_CAUSE_INV_MAND_INFO;
- return NULL;
- }
-
- osmo_apn_to_str(req_apn_str,
- TLVP_VAL(tp, GSM48_IE_GSM_APN),
- TLVP_LEN(tp, GSM48_IE_GSM_APN));
-
- if (strcmp(req_apn_str, "*") == 0)
- req_apn_str[0] = 0;
- }
-
- if (mmctx->subscr == NULL)
- allow_any_apn = 1;
-
- if (strlen(req_apn_str) == 0 && !allow_any_apn) {
- /* No specific APN requested, check for an APN that is both
- * granted and configured */
-
- llist_for_each_entry(pdp, &mmctx->subscr->sgsn_data->pdp_list, list) {
- if (strcmp(pdp->apn_str, "*") == 0)
- {
- allow_any_apn = 1;
- selected_apn_str = "";
- insert_extra(tp, mmctx->subscr->sgsn_data, pdp);
- continue;
- }
- if (!llist_empty(&sgsn_apn_ctxts)) {
- apn_ctx = sgsn_apn_ctx_match(req_apn_str, mmctx->imsi);
- /* Not configured */
- if (apn_ctx == NULL)
- continue;
- }
- insert_extra(tp, mmctx->subscr->sgsn_data, pdp);
- selected_apn_str = pdp->apn_str;
- break;
- }
- } else if (!allow_any_apn) {
- /* Check whether the given APN is granted */
- llist_for_each_entry(pdp, &mmctx->subscr->sgsn_data->pdp_list, list) {
- if (strcmp(pdp->apn_str, "*") == 0) {
- insert_extra(tp, mmctx->subscr->sgsn_data, pdp);
- selected_apn_str = req_apn_str;
- allow_any_apn = 1;
- continue;
- }
- if (strcasecmp(pdp->apn_str, req_apn_str) == 0) {
- insert_extra(tp, mmctx->subscr->sgsn_data, pdp);
- selected_apn_str = req_apn_str;
- break;
- }
- }
- } else if (strlen(req_apn_str) != 0) {
- /* Any APN is allowed */
- selected_apn_str = req_apn_str;
- } else {
- /* Prefer the GGSN associated with the wildcard APN */
- selected_apn_str = "";
- }
-
- if (!allow_any_apn && selected_apn_str == NULL) {
- /* Access not granted */
- LOGMMCTXP(LOGL_NOTICE, mmctx,
- "The requested APN '%s' is not allowed\n",
- req_apn_str);
- *gsm_cause = GSM_CAUSE_REQ_SERV_OPT_NOTSUB;
- return NULL;
- }
-
- /* copy the selected apn_str */
- if (selected_apn_str)
- strcpy(out_apn_str, selected_apn_str);
- else
- out_apn_str[0] = '\0';
-
- if (apn_ctx == NULL && selected_apn_str)
- apn_ctx = sgsn_apn_ctx_match(selected_apn_str, mmctx->imsi);
-
- if (apn_ctx != NULL) {
- ggsn = apn_ctx->ggsn;
- } else if (llist_empty(&sgsn_apn_ctxts)) {
- /* No configuration -> use GGSN 0 */
- ggsn = sgsn_ggsn_ctx_by_id(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);
- } else {
- /* No matching configuration found */
- LOGMMCTXP(LOGL_NOTICE, mmctx,
- "The selected APN '%s' has not been configured\n",
- selected_apn_str);
- *gsm_cause = GSM_CAUSE_MISSING_APN;
- return NULL;
- }
-
- if (!ggsn) {
- LOGMMCTXP(LOGL_NOTICE, mmctx,
- "No static GGSN configured. Selected APN '%s'\n",
- selected_apn_str);
- return NULL;
- }
-
- LOGMMCTXP(LOGL_INFO, mmctx,
- "Found GGSN %d for APN '%s' (requested '%s')\n",
- ggsn->id, selected_apn_str ? selected_apn_str : "---",
- req_apn_str);
-
- 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 = 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);
-}
-
-void sgsn_inst_init()
-{
- 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/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c
deleted file mode 100644
index a18998f9e..000000000
--- a/openbsc/src/gprs/gprs_sndcp.c
+++ /dev/null
@@ -1,1258 +0,0 @@
-/* GPRS SNDCP protocol implementation as per 3GPP TS 04.65 */
-
-/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010 by On-Waves
- *
- * 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 <errno.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gprs/gprs_bssgp.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/gprs_llc.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/gprs_sndcp.h>
-#include <openbsc/gprs_llc_xid.h>
-#include <openbsc/gprs_sndcp_xid.h>
-#include <openbsc/gprs_sndcp_pcomp.h>
-#include <openbsc/gprs_sndcp_dcomp.h>
-#include <openbsc/gprs_sndcp_comp.h>
-
-#define DEBUG_IP_PACKETS 0 /* 0=Disabled, 1=Enabled */
-
-#if DEBUG_IP_PACKETS == 1
-/* Calculate TCP/IP checksum */
-static uint16_t calc_ip_csum(uint8_t *data, int len)
-{
- int i;
- uint32_t accumulator = 0;
- uint16_t *pointer = (uint16_t *) data;
-
- for (i = len; i > 1; i -= 2) {
- accumulator += *pointer;
- pointer++;
- }
-
- if (len % 2)
- accumulator += *pointer;
-
- accumulator = (accumulator & 0xffff) + ((accumulator >> 16) & 0xffff);
- accumulator += (accumulator >> 16) & 0xffff;
- return (~accumulator);
-}
-
-/* Calculate TCP/IP checksum */
-static uint16_t calc_tcpip_csum(const void *ctx, uint8_t *packet, int len)
-{
- uint8_t *buf;
- uint16_t csum;
-
- buf = talloc_zero_size(ctx, len);
- memset(buf, 0, len);
- memcpy(buf, packet + 12, 8);
- buf[9] = packet[9];
- buf[11] = (len - 20) & 0xFF;
- buf[10] = (len - 20) >> 8 & 0xFF;
- memcpy(buf + 12, packet + 20, len - 20);
- csum = calc_ip_csum(buf, len - 20 + 12);
- talloc_free(buf);
- return csum;
-}
-
-/* Show some ip packet details */
-static void debug_ip_packet(uint8_t *data, int len, int dir, char *info)
-{
- uint8_t tcp_flags;
- char flags_debugmsg[256];
- int len_short;
- static unsigned int packet_count = 0;
- static unsigned int tcp_csum_err_count = 0;
- static unsigned int ip_csum_err_count = 0;
-
- packet_count++;
-
- if (len > 80)
- len_short = 80;
- else
- len_short = len;
-
- if (dir)
- DEBUGP(DSNDCP, "%s: MS => SGSN: %s\n", info,
- osmo_hexdump_nospc(data, len_short));
- else
- DEBUGP(DSNDCP, "%s: MS <= SGSN: %s\n", info,
- osmo_hexdump_nospc(data, len_short));
-
- DEBUGP(DSNDCP, "%s: Length.: %d\n", info, len);
- DEBUGP(DSNDCP, "%s: NO.: %d\n", info, packet_count);
-
- if (len < 20) {
- DEBUGP(DSNDCP, "%s: Error: Short IP packet!\n", info);
- return;
- }
-
- if (calc_ip_csum(data, 20) != 0) {
- DEBUGP(DSNDCP, "%s: Bad IP-Header checksum!\n", info);
- ip_csum_err_count++;
- } else
- DEBUGP(DSNDCP, "%s: IP-Header checksum ok.\n", info);
-
- if (data[9] == 0x06) {
- if (len < 40) {
- DEBUGP(DSNDCP, "%s: Error: Short TCP packet!\n", info);
- return;
- }
-
- DEBUGP(DSNDCP, "%s: Protocol type: TCP\n", info);
- tcp_flags = data[33];
-
- if (calc_tcpip_csum(NULL, data, len) != 0) {
- DEBUGP(DSNDCP, "%s: Bad TCP checksum!\n", info);
- tcp_csum_err_count++;
- } else
- DEBUGP(DSNDCP, "%s: TCP checksum ok.\n", info);
-
- memset(flags_debugmsg, 0, sizeof(flags_debugmsg));
- if (tcp_flags & 1)
- strcat(flags_debugmsg, "FIN ");
- if (tcp_flags & 2)
- strcat(flags_debugmsg, "SYN ");
- if (tcp_flags & 4)
- strcat(flags_debugmsg, "RST ");
- if (tcp_flags & 8)
- strcat(flags_debugmsg, "PSH ");
- if (tcp_flags & 16)
- strcat(flags_debugmsg, "ACK ");
- if (tcp_flags & 32)
- strcat(flags_debugmsg, "URG ");
- DEBUGP(DSNDCP, "%s: FLAGS: %s\n", info, flags_debugmsg);
- } else if (data[9] == 0x11) {
- DEBUGP(DSNDCP, "%s: Protocol type: UDP\n", info);
- } else {
- DEBUGP(DSNDCP, "%s: Protocol type: (%02x)\n", info, data[9]);
- }
-
- DEBUGP(DSNDCP, "%s: IP-Header checksum errors: %d\n", info,
- ip_csum_err_count);
- DEBUGP(DSNDCP, "%s: TCP-Checksum errors: %d\n", info,
- tcp_csum_err_count);
-}
-#endif
-
-/* Chapter 7.2: SN-PDU Formats */
-struct sndcp_common_hdr {
- /* octet 1 */
- uint8_t nsapi:4;
- uint8_t more:1;
- uint8_t type:1;
- uint8_t first:1;
- uint8_t spare:1;
-} __attribute__((packed));
-
-/* PCOMP / DCOMP only exist in first fragment */
-struct sndcp_comp_hdr {
- /* octet 2 */
- uint8_t pcomp:4;
- uint8_t dcomp:4;
-} __attribute__((packed));
-
-struct sndcp_udata_hdr {
- /* octet 3 */
- uint8_t npdu_high:4;
- uint8_t seg_nr:4;
- /* octet 4 */
- uint8_t npdu_low;
-} __attribute__((packed));
-
-
-static void *tall_sndcp_ctx;
-
-/* A fragment queue entry, containing one framgent of a N-PDU */
-struct defrag_queue_entry {
- struct llist_head list;
- /* segment number of this fragment */
- uint32_t seg_nr;
- /* length of the data area of this fragment */
- uint32_t data_len;
- /* pointer to the data of this fragment */
- uint8_t *data;
-};
-
-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) {
- if (sgsn->cfg.pcomp_rfc1144.active || sgsn->cfg.pcomp_rfc1144.passive ||
- sgsn->cfg.dcomp_v42bis.active || sgsn->cfg.dcomp_v42bis.passive)
- return true;
- else
- return false;
-}
-
-/* Enqueue a fragment into the defragment queue */
-static int defrag_enqueue(struct gprs_sndcp_entity *sne, uint8_t seg_nr,
- uint8_t *data, uint32_t data_len)
-{
- struct defrag_queue_entry *dqe;
-
- dqe = talloc_zero(tall_sndcp_ctx, struct defrag_queue_entry);
- if (!dqe)
- return -ENOMEM;
- dqe->data = talloc_zero_size(dqe, data_len);
- if (!dqe->data) {
- talloc_free(dqe);
- return -ENOMEM;
- }
- dqe->seg_nr = seg_nr;
- dqe->data_len = data_len;
-
- llist_add(&dqe->list, &sne->defrag.frag_list);
-
- if (seg_nr > sne->defrag.highest_seg)
- sne->defrag.highest_seg = seg_nr;
-
- sne->defrag.seg_have |= (1 << seg_nr);
- sne->defrag.tot_len += data_len;
-
- memcpy(dqe->data, data, data_len);
-
- return 0;
-}
-
-/* return if we have all segments of this N-PDU */
-static int defrag_have_all_segments(struct gprs_sndcp_entity *sne)
-{
- uint32_t seg_needed = 0;
- unsigned int i;
-
- /* create a bitmask of needed segments */
- for (i = 0; i <= sne->defrag.highest_seg; i++)
- seg_needed |= (1 << i);
-
- if (seg_needed == sne->defrag.seg_have)
- return 1;
-
- return 0;
-}
-
-static struct defrag_queue_entry *defrag_get_seg(struct gprs_sndcp_entity *sne,
- uint32_t seg_nr)
-{
- struct defrag_queue_entry *dqe;
-
- llist_for_each_entry(dqe, &sne->defrag.frag_list, list) {
- if (dqe->seg_nr == seg_nr) {
- llist_del(&dqe->list);
- return dqe;
- }
- }
- return NULL;
-}
-
-/* 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;
- int rc;
- uint8_t *expnd = NULL;
-
- LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Defragment output PDU %u "
- "num_seg=%u tot_len=%u\n", sne->lle->llme->tlli, sne->nsapi,
- sne->defrag.npdu, sne->defrag.highest_seg, sne->defrag.tot_len);
- msg = msgb_alloc_headroom(sne->defrag.tot_len+256, 128, "SNDCP Defrag");
- if (!msg)
- return -ENOMEM;
-
- /* FIXME: message headers + identifiers */
-
- npdu = msg->data;
-
- for (seg_nr = 0; seg_nr <= sne->defrag.highest_seg; seg_nr++) {
- struct defrag_queue_entry *dqe;
- uint8_t *data;
-
- dqe = defrag_get_seg(sne, seg_nr);
- if (!dqe) {
- LOGP(DSNDCP, LOGL_ERROR, "Segment %u missing\n", seg_nr);
- msgb_free(msg);
- return -EIO;
- }
- /* actually append the segment to the N-PDU */
- data = msgb_put(msg, dqe->data_len);
- memcpy(data, dqe->data, dqe->data_len);
-
- /* release memory for the fragment queue entry */
- talloc_free(dqe);
- }
-
- npdu_len = sne->defrag.tot_len;
-
- /* FIXME: cancel timer */
-
- /* 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() */
-
- /* 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;
- }
-
- /* Modify npu length, expnd is handed directly handed
- * over to gsn_rx_sndcp_ud_ind(), see below */
- npdu_len = rc;
- } 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);
-
- if (any_pcomp_or_dcomp_active(sgsn))
- talloc_free(expnd);
-
- return rc;
-}
-
-static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg,
- uint8_t *hdr, unsigned int len)
-{
- struct sndcp_common_hdr *sch;
- struct sndcp_udata_hdr *suh;
- uint16_t npdu_num;
- uint8_t *data;
- int rc;
-
- sch = (struct sndcp_common_hdr *) hdr;
- if (sch->first) {
- suh = (struct sndcp_udata_hdr *) (hdr + 1 + sizeof(struct sndcp_common_hdr));
- } else
- suh = (struct sndcp_udata_hdr *) (hdr + sizeof(struct sndcp_common_hdr));
-
- data = (uint8_t *)suh + sizeof(struct sndcp_udata_hdr);
-
- npdu_num = (suh->npdu_high << 8) | suh->npdu_low;
-
- LOGP(DSNDCP, LOGL_DEBUG, "TLLI=0x%08x NSAPI=%u: Input PDU %u Segment %u "
- "Length %u %s %s\n", sne->lle->llme->tlli, sne->nsapi, npdu_num,
- suh->seg_nr, len, sch->first ? "F " : "", sch->more ? "M" : "");
-
- if (sch->first) {
- /* first segment of a new packet. Discard all leftover fragments of
- * previous packet */
- if (!llist_empty(&sne->defrag.frag_list)) {
- struct defrag_queue_entry *dqe, *dqe2;
- LOGP(DSNDCP, LOGL_INFO, "TLLI=0x%08x NSAPI=%u: Dropping "
- "SN-PDU %u due to insufficient segments (%04x)\n",
- sne->lle->llme->tlli, sne->nsapi, sne->defrag.npdu,
- sne->defrag.seg_have);
- llist_for_each_entry_safe(dqe, dqe2, &sne->defrag.frag_list, list) {
- llist_del(&dqe->list);
- talloc_free(dqe);
- }
- }
- /* store the currently de-fragmented PDU number */
- sne->defrag.npdu = npdu_num;
-
- /* Re-set fragmentation state */
- sne->defrag.no_more = sne->defrag.highest_seg = sne->defrag.seg_have = 0;
- sne->defrag.tot_len = 0;
- /* FIXME: (re)start timer */
- }
-
- if (sne->defrag.npdu != npdu_num) {
- LOGP(DSNDCP, LOGL_INFO, "Segment for different SN-PDU "
- "(%u != %u)\n", npdu_num, sne->defrag.npdu);
- /* FIXME */
- }
-
- /* FIXME: check if seg_nr already exists */
- /* make sure to subtract length of SNDCP header from 'len' */
- rc = defrag_enqueue(sne, suh->seg_nr, data, len - (data - hdr));
- if (rc < 0)
- return rc;
-
- if (!sch->more) {
- /* this is suppsed to be the last segment of the N-PDU, but it
- * might well be not the last to arrive */
- sne->defrag.no_more = 1;
- }
-
- if (sne->defrag.no_more) {
- /* we have already received the last segment before, let's check
- * if all the previous segments exist */
- if (defrag_have_all_segments(sne))
- return defrag_segments(sne);
- }
-
- return 0;
-}
-
-static struct gprs_sndcp_entity *gprs_sndcp_entity_by_lle(const struct gprs_llc_lle *lle,
- uint8_t nsapi)
-{
- struct gprs_sndcp_entity *sne;
-
- llist_for_each_entry(sne, &gprs_sndcp_entities, list) {
- if (sne->lle == lle && sne->nsapi == nsapi)
- return sne;
- }
- return NULL;
-}
-
-static struct gprs_sndcp_entity *gprs_sndcp_entity_alloc(struct gprs_llc_lle *lle,
- uint8_t nsapi)
-{
- struct gprs_sndcp_entity *sne;
-
- sne = talloc_zero(tall_sndcp_ctx, struct gprs_sndcp_entity);
- if (!sne)
- return NULL;
-
- sne->lle = lle;
- sne->nsapi = nsapi;
- sne->defrag.timer.data = sne;
- //sne->fqueue.timer.cb = FIXME;
- sne->rx_state = SNDCP_RX_S_FIRST;
- INIT_LLIST_HEAD(&sne->defrag.frag_list);
-
- llist_add(&sne->list, &gprs_sndcp_entities);
-
- return sne;
-}
-
-/* Entry point for the SNSM-ACTIVATE.indication */
-int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
-{
- LOGP(DSNDCP, LOGL_INFO, "SNSM-ACTIVATE.ind (lle=%p TLLI=%08x, "
- "SAPI=%u, NSAPI=%u)\n", lle, lle->llme->tlli, lle->sapi, nsapi);
-
- if (gprs_sndcp_entity_by_lle(lle, nsapi)) {
- LOGP(DSNDCP, LOGL_ERROR, "Trying to ACTIVATE "
- "already-existing entity (TLLI=%08x, NSAPI=%u)\n",
- lle->llme->tlli, nsapi);
- return -EEXIST;
- }
-
- if (!gprs_sndcp_entity_alloc(lle, nsapi)) {
- LOGP(DSNDCP, LOGL_ERROR, "Out of memory during ACTIVATE\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/* Entry point for the SNSM-DEACTIVATE.indication */
-int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi)
-{
- struct gprs_sndcp_entity *sne;
-
- LOGP(DSNDCP, LOGL_INFO, "SNSM-DEACTIVATE.ind (lle=%p, TLLI=%08x, "
- "SAPI=%u, NSAPI=%u)\n", lle, lle->llme->tlli, lle->sapi, nsapi);
-
- sne = gprs_sndcp_entity_by_lle(lle, nsapi);
- if (!sne) {
- LOGP(DSNDCP, LOGL_ERROR, "SNSM-DEACTIVATE.ind for non-"
- "existing TLLI=%08x SAPI=%u NSAPI=%u\n", lle->llme->tlli,
- lle->sapi, nsapi);
- return -ENOENT;
- }
- llist_del(&sne->list);
- /* frag queue entries are hierarchically allocated, so no need to
- * free them explicitly here */
- talloc_free(sne);
-
- return 0;
-}
-
-/* Fragmenter state */
-struct sndcp_frag_state {
- uint8_t frag_nr;
- struct msgb *msg; /* original message */
- uint8_t *next_byte; /* first byte of next fragment */
-
- struct gprs_sndcp_entity *sne;
- void *mmcontext;
-};
-
-/* returns '1' if there are more fragments to send, '0' if none */
-static int sndcp_send_ud_frag(struct sndcp_frag_state *fs,
- uint8_t pcomp, uint8_t dcomp)
-{
- struct gprs_sndcp_entity *sne = fs->sne;
- struct gprs_llc_lle *lle = sne->lle;
- struct sndcp_common_hdr *sch;
- struct sndcp_comp_hdr *scomph;
- struct sndcp_udata_hdr *suh;
- struct msgb *fmsg;
- unsigned int max_payload_len;
- unsigned int len;
- uint8_t *data;
- int rc, more;
-
- fmsg = msgb_alloc_headroom(fs->sne->lle->params.n201_u+256, 128,
- "SNDCP Frag");
- if (!fmsg) {
- msgb_free(fs->msg);
- return -ENOMEM;
- }
-
- /* make sure lower layers route the fragment like the original */
- msgb_tlli(fmsg) = msgb_tlli(fs->msg);
- msgb_bvci(fmsg) = msgb_bvci(fs->msg);
- msgb_nsei(fmsg) = msgb_nsei(fs->msg);
-
- /* prepend common SNDCP header */
- sch = (struct sndcp_common_hdr *) msgb_put(fmsg, sizeof(*sch));
- sch->nsapi = sne->nsapi;
- /* Set FIRST bit if we are the first fragment in a series */
- if (fs->frag_nr == 0)
- sch->first = 1;
- sch->type = 1;
-
- /* append the compression header for first fragment */
- if (sch->first) {
- scomph = (struct sndcp_comp_hdr *)
- msgb_put(fmsg, sizeof(*scomph));
- scomph->pcomp = pcomp;
- scomph->dcomp = dcomp;
- }
-
- /* append the user-data header */
- suh = (struct sndcp_udata_hdr *) msgb_put(fmsg, sizeof(*suh));
- suh->npdu_low = sne->tx_npdu_nr & 0xff;
- suh->npdu_high = (sne->tx_npdu_nr >> 8) & 0xf;
- suh->seg_nr = fs->frag_nr % 0xf;
-
- /* calculate remaining length to be sent */
- len = (fs->msg->data + fs->msg->len) - fs->next_byte;
- /* how much payload can we actually send via LLC? */
- max_payload_len = lle->params.n201_u - (sizeof(*sch) + sizeof(*suh));
- if (sch->first)
- max_payload_len -= sizeof(*scomph);
- /* check if we're exceeding the max */
- if (len > max_payload_len)
- len = max_payload_len;
-
- /* copy the actual fragment data into our fmsg */
- data = msgb_put(fmsg, len);
- memcpy(data, fs->next_byte, len);
-
- /* Increment fragment number and data pointer to next fragment */
- fs->frag_nr++;
- fs->next_byte += len;
-
- /* determine if we have more fragemnts to send */
- if ((fs->msg->data + fs->msg->len) <= fs->next_byte)
- more = 0;
- else
- more = 1;
-
- /* set the MORE bit of the SNDCP header accordingly */
- sch->more = more;
-
- rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext, true);
- /* abort in case of error, do not advance frag_nr / next_byte */
- if (rc < 0) {
- msgb_free(fs->msg);
- return rc;
- }
-
- if (!more) {
- /* we've sent all fragments */
- msgb_free(fs->msg);
- memset(fs, 0, sizeof(*fs));
- /* increment NPDU number for next frame */
- sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff;
- return 0;
- }
-
- /* default: more fragments to send */
- return 1;
-}
-
-/* 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,
- void *mmcontext)
-{
- struct gprs_sndcp_entity *sne;
- struct sndcp_common_hdr *sch;
- struct sndcp_comp_hdr *scomph;
- struct sndcp_udata_hdr *suh;
- struct sndcp_frag_state fs;
- uint8_t pcomp = 0;
- uint8_t dcomp = 0;
- int rc;
-
- /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
-
- /* Compress packet */
-#if DEBUG_IP_PACKETS == 1
- DEBUGP(DSNDCP, " \n");
- DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
- DEBUGP(DSNDCP, "===================================================\n");
- debug_ip_packet(msg->data, msg->len, 0, "sndcp_initdata_req()");
-#endif
- if (any_pcomp_or_dcomp_active(sgsn)) {
-
- /* Apply header compression */
- rc = gprs_sndcp_pcomp_compress(msg->data, msg->len, &pcomp,
- lle->llme->comp.proto, nsapi);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR,
- "TCP/IP Header compression failed!\n");
- return -EIO;
- }
-
- /* Fixup pointer locations and sizes in message buffer to match
- * the new, compressed buffer size */
- msgb_get(msg, msg->len);
- msgb_put(msg, rc);
-
- /* Apply data compression */
- rc = gprs_sndcp_dcomp_compress(msg->data, msg->len, &dcomp,
- lle->llme->comp.data, nsapi);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR, "Data compression failed!\n");
- return -EIO;
- }
-
- /* Fixup pointer locations and sizes in message buffer to match
- * the new, compressed buffer size */
- msgb_get(msg, msg->len);
- msgb_put(msg, rc);
- }
-#if DEBUG_IP_PACKETS == 1
- DEBUGP(DSNDCP, "===================================================\n");
- DEBUGP(DSNDCP, ":::::::::::::::::::::::::::::::::::::::::::::::::::\n");
- DEBUGP(DSNDCP, " \n");
-#endif
-
- sne = gprs_sndcp_entity_by_lle(lle, nsapi);
- if (!sne) {
- LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity\n");
- 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 -
- (sizeof(*sch) + sizeof(*suh) + sizeof(*scomph))) {
- /* initialize the fragmenter state */
- fs.msg = msg;
- fs.frag_nr = 0;
- fs.next_byte = msg->data;
- fs.sne = sne;
- fs.mmcontext = mmcontext;
-
- /* call function to generate and send fragments until all
- * of the N-PDU has been sent */
- while (1) {
- int rc = sndcp_send_ud_frag(&fs,pcomp,dcomp);
- if (rc == 0)
- return 0;
- if (rc < 0)
- return rc;
- }
- /* not reached */
- return 0;
- }
-
- /* this is the non-fragmenting case where we only build 1 SN-PDU */
-
- /* prepend the user-data header */
- suh = (struct sndcp_udata_hdr *) msgb_push(msg, sizeof(*suh));
- suh->npdu_low = sne->tx_npdu_nr & 0xff;
- suh->npdu_high = (sne->tx_npdu_nr >> 8) & 0xf;
- suh->seg_nr = 0;
- sne->tx_npdu_nr = (sne->tx_npdu_nr + 1) % 0xfff;
-
- scomph = (struct sndcp_comp_hdr *) msgb_push(msg, sizeof(*scomph));
- scomph->pcomp = pcomp;
- scomph->dcomp = dcomp;
-
- /* prepend common SNDCP header */
- sch = (struct sndcp_common_hdr *) msgb_push(msg, sizeof(*sch));
- sch->first = 1;
- sch->type = 1;
- sch->nsapi = nsapi;
-
- return gprs_llc_tx_ui(msg, lle->sapi, 0, mmcontext, true);
-}
-
-/* Section 5.1.2.17 LL-UNITDATA.ind */
-int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
- uint8_t *hdr, uint16_t len)
-{
- struct gprs_sndcp_entity *sne;
- struct sndcp_common_hdr *sch = (struct sndcp_common_hdr *)hdr;
- struct sndcp_comp_hdr *scomph = NULL;
- struct sndcp_udata_hdr *suh;
- uint8_t *npdu;
- uint16_t npdu_num __attribute__((unused));
- int npdu_len;
- int rc;
- uint8_t *expnd = NULL;
-
- sch = (struct sndcp_common_hdr *) hdr;
- if (sch->first) {
- scomph = (struct sndcp_comp_hdr *) (hdr + 1);
- suh = (struct sndcp_udata_hdr *) (hdr + 1 + sizeof(struct sndcp_common_hdr));
- } else
- suh = (struct sndcp_udata_hdr *) (hdr + sizeof(struct sndcp_common_hdr));
-
- if (sch->type == 0) {
- LOGP(DSNDCP, LOGL_ERROR, "SN-DATA PDU at unitdata_ind() function\n");
- return -EINVAL;
- }
-
- if (len < sizeof(*sch) + sizeof(*suh)) {
- LOGP(DSNDCP, LOGL_ERROR, "SN-UNITDATA PDU too short (%u)\n", len);
- return -EIO;
- }
-
- sne = gprs_sndcp_entity_by_lle(lle, sch->nsapi);
- if (!sne) {
- LOGP(DSNDCP, LOGL_ERROR, "Message for non-existing SNDCP Entity "
- "(lle=%p, TLLI=%08x, SAPI=%u, NSAPI=%u)\n", lle,
- lle->llme->tlli, lle->sapi, sch->nsapi);
- return -EIO;
- }
- /* FIXME: move this RA_ID up to the LLME or even higher */
- bssgp_parse_cell_id(&sne->ra_id, msgb_bcid(msg));
-
- if (scomph) {
- sne->defrag.pcomp = scomph->pcomp;
- sne->defrag.dcomp = scomph->dcomp;
- sne->defrag.proto = lle->llme->comp.proto;
- sne->defrag.data = lle->llme->comp.data;
- }
-
- /* any non-first segment is by definition something to defragment
- * as is any segment that tells us there are more segments */
- if (!sch->first || sch->more)
- return defrag_input(sne, msg, hdr, len);
-
- npdu_num = (suh->npdu_high << 8) | suh->npdu_low;
- npdu = (uint8_t *)suh + sizeof(*suh);
- npdu_len = (msg->data + msg->len) - npdu - 3; /* -3 'removes' the FCS */
-
- if (npdu_len <= 0) {
- 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() */
-
- /* 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;
- }
-
- /* Modify npu length, expnd is handed directly handed
- * over to gsn_rx_sndcp_ud_ind(), see below */
- npdu_len = rc;
- } 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);
-
- if (any_pcomp_or_dcomp_active(sgsn))
- talloc_free(expnd);
-
- return rc;
-}
-
-#if 0
-/* Section 5.1.2.1 LL-RESET.ind */
-static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se)
-{
- /* treat all outstanding SNDCP-LLC request type primitives as not sent */
- /* reset all SNDCP XID parameters to default values */
- LOGP(DSNDCP, LOGL_NOTICE, "not implemented.\n");
- return 0;
-}
-
-static int sndcp_ll_status_ind()
-{
- /* inform the SM sub-layer by means of SNSM-STATUS.req */
- LOGP(DSNDCP, LOGL_NOTICE, "not implemented.\n");
- return 0;
-}
-
-static struct sndcp_state_list {{
- uint32_t states;
- unsigned int type;
- int (*rout)(struct gprs_sndcp_entity *se, struct msgb *msg);
-} sndcp_state_list[] = {
- { ALL_STATES,
- LL_RESET_IND, sndcp_ll_reset_ind },
- { ALL_STATES,
- LL_ESTABLISH_IND, sndcp_ll_est_ind },
- { SBIT(SNDCP_S_EST_RQD),
- LL_ESTABLISH_RESP, sndcp_ll_est_ind },
- { SBIT(SNDCP_S_EST_RQD),
- LL_ESTABLISH_CONF, sndcp_ll_est_conf },
- { SBIT(SNDCP_S_
-};
-
-static int sndcp_rx_llc_prim()
-{
- case LL_ESTABLISH_REQ:
- case LL_RELEASE_REQ:
- case LL_XID_REQ:
- case LL_DATA_REQ:
- LL_UNITDATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
-
- switch (prim) {
- case LL_RESET_IND:
- case LL_ESTABLISH_IND:
- case LL_ESTABLISH_RESP:
- case LL_ESTABLISH_CONF:
- case LL_RELEASE_IND:
- case LL_RELEASE_CONF:
- case LL_XID_IND:
- case LL_XID_RESP:
- case LL_XID_CONF:
- case LL_DATA_IND:
- case LL_DATA_CONF:
- case LL_UNITDATA_IND:
- case LL_STATUS_IND:
- }
-}
-#endif
-
-/* Generate SNDCP-XID message */
-static int gprs_llc_gen_sndcp_xid(uint8_t *bytes, int bytes_len, uint8_t nsapi)
-{
- int entity = 0;
- LLIST_HEAD(comp_fields);
- struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params;
- struct gprs_sndcp_comp_field rfc1144_comp_field;
- struct gprs_sndcp_dcomp_v42bis_params v42bis_params;
- struct gprs_sndcp_comp_field v42bis_comp_field;
-
- memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field));
- memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field));
-
- /* Setup rfc1144 */
- if (sgsn->cfg.pcomp_rfc1144.active) {
- rfc1144_params.nsapi[0] = nsapi;
- rfc1144_params.nsapi_len = 1;
- rfc1144_params.s01 = sgsn->cfg.pcomp_rfc1144.s01;
- rfc1144_comp_field.p = 1;
- rfc1144_comp_field.entity = entity;
- rfc1144_comp_field.algo = RFC_1144;
- rfc1144_comp_field.comp[RFC1144_PCOMP1] = 1;
- rfc1144_comp_field.comp[RFC1144_PCOMP2] = 2;
- rfc1144_comp_field.comp_len = RFC1144_PCOMP_NUM;
- rfc1144_comp_field.rfc1144_params = &rfc1144_params;
- entity++;
- llist_add(&rfc1144_comp_field.list, &comp_fields);
- }
-
- /* Setup V.42bis */
- if (sgsn->cfg.dcomp_v42bis.active) {
- v42bis_params.nsapi[0] = nsapi;
- v42bis_params.nsapi_len = 1;
- v42bis_params.p0 = sgsn->cfg.dcomp_v42bis.p0;
- v42bis_params.p1 = sgsn->cfg.dcomp_v42bis.p1;
- v42bis_params.p2 = sgsn->cfg.dcomp_v42bis.p2;
- v42bis_comp_field.p = 1;
- v42bis_comp_field.entity = entity;
- v42bis_comp_field.algo = V42BIS;
- v42bis_comp_field.comp[V42BIS_DCOMP1] = 1;
- v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM;
- v42bis_comp_field.v42bis_params = &v42bis_params;
- entity++;
- llist_add(&v42bis_comp_field.list, &comp_fields);
- }
-
- /* Do not attempt to compile anything if there is no data in the list */
- if (llist_empty(&comp_fields))
- return 0;
-
- /* Compile bytestream */
- return gprs_sndcp_compile_xid(bytes, bytes_len, &comp_fields,
- DEFAULT_SNDCP_VERSION);
-}
-
-/* Set of SNDCP-XID bnegotiation (See also: TS 144 065,
- * Section 6.8 XID parameter negotiation) */
-int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi)
-{
- /* Note: The specification requires the SNDCP-User to set of an
- * SNDCP xid request. See also 3GPP TS 44.065, 6.8 XID parameter
- * negotiation, Figure 11: SNDCP XID negotiation procedure. In
- * our case the SNDCP-User is sgsn_libgtp.c, which calls
- * sndcp_sn_xid_req directly. */
-
- uint8_t l3params[1024];
- int xid_len;
- struct gprs_llc_xid_field xid_field_request;
-
- /* Wipe off all compression entities and their states to
- * get rid of possible leftovers from a previous session */
- gprs_sndcp_comp_free(lle->llme->comp.proto);
- gprs_sndcp_comp_free(lle->llme->comp.data);
- lle->llme->comp.proto = gprs_sndcp_comp_alloc(lle->llme);
- lle->llme->comp.data = gprs_sndcp_comp_alloc(lle->llme);
- talloc_free(lle->llme->xid);
- lle->llme->xid = NULL;
-
- /* Generate compression parameter bytestream */
- xid_len = gprs_llc_gen_sndcp_xid(l3params, sizeof(l3params), nsapi);
-
- /* Send XID with the SNDCP-XID bytetsream included */
- if (xid_len > 0) {
- xid_field_request.type = GPRS_LLC_XID_T_L3_PAR;
- xid_field_request.data = l3params;
- xid_field_request.data_len = xid_len;
- return gprs_ll_xid_req(lle, &xid_field_request);
- }
-
- /* When bytestream can not be generated, proceed without SNDCP-XID */
- return gprs_ll_xid_req(lle, NULL);
-
-}
-
-/* Handle header compression entites */
-static int handle_pcomp_entities(struct gprs_sndcp_comp_field *comp_field,
- struct gprs_llc_lle *lle)
-{
- /* Note: This functions also transforms the comp_field into its
- * echo form (strips comp values, resets propose bit etc...)
- * the processed comp_fields can then be sent back as XID-
- * Response without further modification. */
-
- /* Delete propose bit */
- comp_field->p = 0;
-
- /* Process proposed parameters */
- switch (comp_field->algo) {
- case RFC_1144:
- if (sgsn->cfg.pcomp_rfc1144.passive
- && comp_field->rfc1144_params->nsapi_len > 0) {
- DEBUGP(DSNDCP,
- "Accepting RFC1144 header compression...\n");
- gprs_sndcp_comp_add(lle->llme, lle->llme->comp.proto,
- comp_field);
- } else {
- DEBUGP(DSNDCP,
- "Rejecting RFC1144 header compression...\n");
- gprs_sndcp_comp_delete(lle->llme->comp.proto,
- comp_field->entity);
- comp_field->rfc1144_params->nsapi_len = 0;
- }
- break;
- case RFC_2507:
- /* RFC 2507 is not yet supported,
- * so we set applicable nsapis to zero */
- DEBUGP(DSNDCP, "Rejecting RFC2507 header compression...\n");
- comp_field->rfc2507_params->nsapi_len = 0;
- gprs_sndcp_comp_delete(lle->llme->comp.proto,
- comp_field->entity);
- break;
- case ROHC:
- /* ROHC is not yet supported,
- * so we set applicable nsapis to zero */
- DEBUGP(DSNDCP, "Rejecting ROHC header compression...\n");
- comp_field->rohc_params->nsapi_len = 0;
- gprs_sndcp_comp_delete(lle->llme->comp.proto,
- comp_field->entity);
- break;
- }
-
- return 0;
-}
-
-/* Hanle data compression entites */
-static int handle_dcomp_entities(struct gprs_sndcp_comp_field *comp_field,
- struct gprs_llc_lle *lle)
-{
- /* See note in handle_pcomp_entities() */
-
- /* Delete propose bit */
- comp_field->p = 0;
-
- /* Process proposed parameters */
- switch (comp_field->algo) {
- case V42BIS:
- if (sgsn->cfg.dcomp_v42bis.passive &&
- comp_field->v42bis_params->nsapi_len > 0) {
- DEBUGP(DSNDCP,
- "Accepting V.42bis data compression...\n");
- gprs_sndcp_comp_add(lle->llme, lle->llme->comp.data,
- comp_field);
- } else {
- LOGP(DSNDCP, LOGL_DEBUG,
- "Rejecting V.42bis data compression...\n");
- gprs_sndcp_comp_delete(lle->llme->comp.data,
- comp_field->entity);
- comp_field->v42bis_params->nsapi_len = 0;
- }
- break;
- case V44:
- /* V44 is not yet supported,
- * so we set applicable nsapis to zero */
- DEBUGP(DSNDCP, "Rejecting V.44 data compression...\n");
- comp_field->v44_params->nsapi_len = 0;
- gprs_sndcp_comp_delete(lle->llme->comp.data,
- comp_field->entity);
- break;
- }
-
- return 0;
-
-}
-
-/* Process SNDCP-XID indication
- * (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)
-{
- /* Note: This function computes the SNDCP-XID response that is sent
- * back to the ms when a ms originated XID is received. The
- * Input XID fields are directly processed and the result is directly
- * handed back. */
-
- int rc;
- int compclass;
- int version;
-
- struct llist_head *comp_fields;
- struct gprs_sndcp_comp_field *comp_field;
-
- OSMO_ASSERT(xid_field_indication);
- OSMO_ASSERT(xid_field_response);
- OSMO_ASSERT(lle);
-
- /* Parse SNDCP-CID XID-Field */
- comp_fields = gprs_sndcp_parse_xid(&version, lle->llme,
- xid_field_indication->data,
- xid_field_indication->data_len,
- NULL);
- if (!comp_fields)
- return -EINVAL;
-
- /* Handle compression entites */
- DEBUGP(DSNDCP, "SNDCP-XID-IND (ms):\n");
- gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG);
-
- llist_for_each_entry(comp_field, comp_fields, list) {
- compclass = gprs_sndcp_get_compression_class(comp_field);
- if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
- rc = handle_pcomp_entities(comp_field, lle);
- else if (compclass == SNDCP_XID_DATA_COMPRESSION)
- rc = handle_dcomp_entities(comp_field, lle);
- else {
- gprs_sndcp_comp_delete(lle->llme->comp.proto,
- comp_field->entity);
- gprs_sndcp_comp_delete(lle->llme->comp.data,
- comp_field->entity);
- rc = 0;
- }
-
- if (rc < 0) {
- talloc_free(comp_fields);
- return -EINVAL;
- }
- }
-
- DEBUGP(DSNDCP, "SNDCP-XID-RES (sgsn):\n");
- gprs_sndcp_dump_comp_fields(comp_fields, LOGL_DEBUG);
-
- /* Reserve some memory to store the modified SNDCP-XID bytes */
- xid_field_response->data =
- talloc_zero_size(lle->llme, xid_field_indication->data_len);
-
- /* Set Type flag for response */
- xid_field_response->type = GPRS_LLC_XID_T_L3_PAR;
-
- /* Compile modified SNDCP-XID bytes */
- rc = gprs_sndcp_compile_xid(xid_field_response->data,
- xid_field_indication->data_len,
- comp_fields, 0);
-
- if (rc > 0)
- xid_field_response->data_len = rc;
- else {
- talloc_free(xid_field_response->data);
- xid_field_response->data = NULL;
- xid_field_response->data_len = 0;
- return -EINVAL;
- }
-
- talloc_free(comp_fields);
-
- return 0;
-}
-
-/* Process SNDCP-XID indication
- * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */
-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)
-{
- /* Note: This function handles an incomming SNDCP-XID confirmiation.
- * Since the confirmation fields may lack important parameters we
- * will reconstruct these missing fields using the original request
- * we have sent. After that we will create (or delete) the
- * compression entites */
-
- struct llist_head *comp_fields_req;
- struct llist_head *comp_fields_conf;
- struct gprs_sndcp_comp_field *comp_field;
- int rc;
- int compclass;
-
- /* We need both, the confirmation that is sent back by the ms,
- * and the original request we have sent. If one of this is missing
- * we can not process the confirmation, the caller must check if
- * request and confirmation fields are available. */
- OSMO_ASSERT(xid_field_conf);
- OSMO_ASSERT(xid_field_request);
-
- /* Parse SNDCP-CID XID-Field */
- comp_fields_req = gprs_sndcp_parse_xid(NULL, lle->llme,
- xid_field_request->data,
- xid_field_request->data_len,
- NULL);
- if (!comp_fields_req)
- return -EINVAL;
-
- DEBUGP(DSNDCP, "SNDCP-XID-REQ (sgsn):\n");
- gprs_sndcp_dump_comp_fields(comp_fields_req, LOGL_DEBUG);
-
- /* Parse SNDCP-CID XID-Field */
- comp_fields_conf = gprs_sndcp_parse_xid(NULL, lle->llme,
- xid_field_conf->data,
- xid_field_conf->data_len,
- comp_fields_req);
- if (!comp_fields_conf)
- return -EINVAL;
-
- DEBUGP(DSNDCP, "SNDCP-XID-CONF (ms):\n");
- gprs_sndcp_dump_comp_fields(comp_fields_conf, LOGL_DEBUG);
-
- /* Handle compression entites */
- llist_for_each_entry(comp_field, comp_fields_conf, list) {
- compclass = gprs_sndcp_get_compression_class(comp_field);
- if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION)
- rc = handle_pcomp_entities(comp_field, lle);
- else if (compclass == SNDCP_XID_DATA_COMPRESSION)
- rc = handle_dcomp_entities(comp_field, lle);
- else {
- gprs_sndcp_comp_delete(lle->llme->comp.proto,
- comp_field->entity);
- gprs_sndcp_comp_delete(lle->llme->comp.data,
- comp_field->entity);
- rc = 0;
- }
-
- if (rc < 0) {
- talloc_free(comp_fields_req);
- talloc_free(comp_fields_conf);
- return -EINVAL;
- }
- }
-
- talloc_free(comp_fields_req);
- talloc_free(comp_fields_conf);
-
- return 0;
-}
diff --git a/openbsc/src/gprs/gprs_sndcp_comp.c b/openbsc/src/gprs/gprs_sndcp_comp.c
deleted file mode 100644
index a12c39aa6..000000000
--- a/openbsc/src/gprs/gprs_sndcp_comp.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/* GPRS SNDCP header compression entity management tools */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <math.h>
-#include <errno.h>
-#include <stdbool.h>
-
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gprs_sndcp_xid.h>
-#include <openbsc/gprs_sndcp_comp.h>
-#include <openbsc/gprs_sndcp_pcomp.h>
-#include <openbsc/gprs_sndcp_dcomp.h>
-
-/* Create a new compression entity from a XID-Field */
-static struct gprs_sndcp_comp *gprs_sndcp_comp_create(const void *ctx,
- const struct
- gprs_sndcp_comp_field
- *comp_field)
-{
- struct gprs_sndcp_comp *comp_entity;
- comp_entity = talloc_zero(ctx, struct gprs_sndcp_comp);
-
- /* Copy relevant information from the SNDCP-XID field */
- comp_entity->entity = comp_field->entity;
- comp_entity->comp_len = comp_field->comp_len;
- memcpy(comp_entity->comp, comp_field->comp, sizeof(comp_entity->comp));
-
- if (comp_field->rfc1144_params) {
- comp_entity->nsapi_len = comp_field->rfc1144_params->nsapi_len;
- memcpy(comp_entity->nsapi,
- comp_field->rfc1144_params->nsapi,
- sizeof(comp_entity->nsapi));
- } else if (comp_field->rfc2507_params) {
- comp_entity->nsapi_len = comp_field->rfc2507_params->nsapi_len;
- memcpy(comp_entity->nsapi,
- comp_field->rfc2507_params->nsapi,
- sizeof(comp_entity->nsapi));
- } else if (comp_field->rohc_params) {
- comp_entity->nsapi_len = comp_field->rohc_params->nsapi_len;
- memcpy(comp_entity->nsapi, comp_field->rohc_params->nsapi,
- sizeof(comp_entity->nsapi));
- } else if (comp_field->v42bis_params) {
- comp_entity->nsapi_len = comp_field->v42bis_params->nsapi_len;
- memcpy(comp_entity->nsapi,
- comp_field->v42bis_params->nsapi,
- sizeof(comp_entity->nsapi));
- } else if (comp_field->v44_params) {
- comp_entity->nsapi_len = comp_field->v44_params->nsapi_len;
- memcpy(comp_entity->nsapi,
- comp_field->v44_params->nsapi,
- sizeof(comp_entity->nsapi));
- } else {
- /* The caller is expected to check carefully if the all
- * data fields required for compression entity creation
- * are present. Otherwise we blow an assertion here */
- OSMO_ASSERT(false);
- }
- comp_entity->algo = comp_field->algo;
-
- /* Check if an NSAPI is selected, if not, it does not make sense
- * to create the compression entity, since the caller should
- * have checked the presence of the NSAPI, we blow an assertion
- * in case of missing NSAPIs */
- OSMO_ASSERT(comp_entity->nsapi_len > 0);
-
- /* Determine of which class our compression entity will be
- * (Protocol or Data compresson ?) */
- comp_entity->compclass = gprs_sndcp_get_compression_class(comp_field);
-
- OSMO_ASSERT(comp_entity->compclass != -1);
-
- /* Create an algorithm specific compression context */
- if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
- if (gprs_sndcp_pcomp_init(ctx, comp_entity, comp_field) != 0) {
- talloc_free(comp_entity);
- comp_entity = NULL;
- }
- } else {
- if (gprs_sndcp_dcomp_init(ctx, comp_entity, comp_field) != 0) {
- talloc_free(comp_entity);
- comp_entity = NULL;
- }
- }
-
- /* Bail on failure */
- if (comp_entity == NULL) {
- LOGP(DSNDCP, LOGL_ERROR,
- "Compression entity creation failed!\n");
- return NULL;
- }
-
- /* Display info message */
- if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
- LOGP(DSNDCP, LOGL_INFO,
- "New header compression entity (%d) created.\n",
- comp_entity->entity);
- } else {
- LOGP(DSNDCP, LOGL_INFO,
- "New data compression entity (%d) created.\n",
- comp_entity->entity);
- }
-
- return comp_entity;
-}
-
-/* Allocate a compression enitiy list */
-struct llist_head *gprs_sndcp_comp_alloc(const void *ctx)
-{
- struct llist_head *lh;
-
- lh = talloc_zero(ctx, struct llist_head);
- INIT_LLIST_HEAD(lh);
-
- return lh;
-}
-
-/* Free a compression entitiy list */
-void gprs_sndcp_comp_free(struct llist_head *comp_entities)
-{
- struct gprs_sndcp_comp *comp_entity;
-
- /* We expect the caller to take care of allocating a
- * compression entity list properly. Attempting to
- * free a non existing list clearly points out
- * a malfunction. */
- OSMO_ASSERT(comp_entities);
-
- llist_for_each_entry(comp_entity, comp_entities, list) {
- /* Free compression entity */
- if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
- LOGP(DSNDCP, LOGL_INFO,
- "Deleting header compression entity %d ...\n",
- comp_entity->entity);
- gprs_sndcp_pcomp_term(comp_entity);
- } else {
- LOGP(DSNDCP, LOGL_INFO,
- "Deleting data compression entity %d ...\n",
- comp_entity->entity);
- gprs_sndcp_dcomp_term(comp_entity);
- }
- }
-
- talloc_free(comp_entities);
-}
-
-/* Delete a compression entity */
-void gprs_sndcp_comp_delete(struct llist_head *comp_entities,
- unsigned int entity)
-{
- struct gprs_sndcp_comp *comp_entity;
- struct gprs_sndcp_comp *comp_entity_to_delete = NULL;
-
- OSMO_ASSERT(comp_entities);
-
- llist_for_each_entry(comp_entity, comp_entities, list) {
- if (comp_entity->entity == entity) {
- comp_entity_to_delete = comp_entity;
- break;
- }
- }
-
- if (!comp_entity_to_delete)
- return;
-
- if (comp_entity_to_delete->compclass == SNDCP_XID_PROTOCOL_COMPRESSION) {
- LOGP(DSNDCP, LOGL_INFO,
- "Deleting header compression entity %d ...\n",
- comp_entity_to_delete->entity);
- gprs_sndcp_pcomp_term(comp_entity_to_delete);
- } else {
- LOGP(DSNDCP, LOGL_INFO,
- "Deleting data compression entity %d ...\n",
- comp_entity_to_delete->entity);
- }
-
- /* Delete compression entity */
- llist_del(&comp_entity_to_delete->list);
- talloc_free(comp_entity_to_delete);
-}
-
-/* Create and Add a new compression entity
- * (returns a pointer to the compression entity that has just been created) */
-struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx,
- struct llist_head *comp_entities,
- const struct gprs_sndcp_comp_field
- *comp_field)
-{
- struct gprs_sndcp_comp *comp_entity;
-
- OSMO_ASSERT(comp_entities);
- OSMO_ASSERT(comp_field);
-
- /* Just to be sure, if the entity is already in
- * the list it will be deleted now */
- gprs_sndcp_comp_delete(comp_entities, comp_field->entity);
-
- /* Create and add a new entity to the list */
- comp_entity = gprs_sndcp_comp_create(ctx, comp_field);
-
- if (!comp_entity)
- return NULL;
-
- llist_add(&comp_entity->list, comp_entities);
- return comp_entity;
-}
-
-/* Find which compression entity handles the specified pcomp/dcomp */
-struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head
- *comp_entities, uint8_t comp)
-{
- struct gprs_sndcp_comp *comp_entity;
- int i;
-
- OSMO_ASSERT(comp_entities);
-
- llist_for_each_entry(comp_entity, comp_entities, list) {
- for (i = 0; i < comp_entity->comp_len; i++) {
- if (comp_entity->comp[i] == comp)
- return comp_entity;
- }
- }
-
- LOGP(DSNDCP, LOGL_ERROR,
- "Could not find a matching compression entity for given pcomp/dcomp value %d.\n",
- comp);
- return NULL;
-}
-
-/* Find which compression entity handles the specified nsapi */
-struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head
- *comp_entities, uint8_t nsapi)
-{
- struct gprs_sndcp_comp *comp_entity;
- int i;
-
- OSMO_ASSERT(comp_entities);
-
- llist_for_each_entry(comp_entity, comp_entities, list) {
- for (i = 0; i < comp_entity->nsapi_len; i++) {
- if (comp_entity->nsapi[i] == nsapi)
- return comp_entity;
- }
- }
-
- return NULL;
-}
-
-/* Find a comp_index for a given pcomp/dcomp value */
-uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity,
- uint8_t comp)
-{
- /* Note: This function returns a normalized version of the comp value,
- * which matches up with the position of the comp field. Since comp=0
- * is reserved for "no compression", the index value starts counting
- * at one. The return value is the PCOMPn/DCOMPn value one can find
- * in the Specification (see e.g. 3GPP TS 44.065, 6.5.3.2, Table 7) */
-
- int i;
- OSMO_ASSERT(comp_entity);
-
- /* A pcomp/dcomp value of zero is reserved for "no comproession",
- * So we just bail and return zero in this case */
- if (comp == 0)
- return 0;
-
- /* Look in the pcomp/dcomp list for the index */
- for (i = 0; i < comp_entity->comp_len; i++) {
- if (comp_entity->comp[i] == comp)
- return i + 1;
- }
-
- LOGP(DSNDCP, LOGL_ERROR,
- "Could not find a matching comp_index for given pcomp/dcomp value %d\n",
- comp);
- return 0;
-}
-
-/* Find a pcomp/dcomp value for a given comp_index */
-uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity,
- uint8_t comp_index)
-{
- OSMO_ASSERT(comp_entity);
-
- /* A comp_index of zero translates to zero right away. */
- if (comp_index == 0)
- return 0;
-
- if (comp_index > comp_entity->comp_len) {
- LOGP(DSNDCP, LOGL_ERROR,
- "Could not find a matching pcomp/dcomp value for given comp_index value %d.\n",
- comp_index);
- return 0;
- }
-
- /* Look in the pcomp/dcomp list for the comp_index, see
- * note in gprs_sndcp_comp_get_idx() */
- return comp_entity->comp[comp_index - 1];
-}
diff --git a/openbsc/src/gprs/gprs_sndcp_dcomp.c b/openbsc/src/gprs/gprs_sndcp_dcomp.c
deleted file mode 100644
index b0f95b486..000000000
--- a/openbsc/src/gprs/gprs_sndcp_dcomp.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/* GPRS SNDCP data compression handler */
-
-/* (C) 2016 by Sysmocom s.f.m.c. GmbH
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <math.h>
-#include <errno.h>
-#include <stdbool.h>
-
-#include <osmocom/core/utils.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/tlv.h>
-
-#include <openbsc/gprs_llc.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/gprs_sndcp_xid.h>
-#include <openbsc/v42bis.h>
-#include <openbsc/v42bis_private.h>
-#include <openbsc/debug.h>
-#include <openbsc/gprs_sndcp_comp.h>
-#include <openbsc/gprs_sndcp_dcomp.h>
-
-/* A struct to capture the output data of compressor and decompressor */
-struct v42bis_output_buffer {
- uint8_t *buf;
- uint8_t *buf_pointer;
- int len;
-};
-
-/* Handler to capture the output data from the compressor */
-void tx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len)
-{
- struct v42bis_output_buffer *output_buffer =
- (struct v42bis_output_buffer *)user_data;
- memcpy(output_buffer->buf_pointer, pkt, len);
- output_buffer->buf_pointer += len;
- output_buffer->len += len;
- return;
-}
-
-/* Handler to capture the output data from the decompressor */
-void rx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len)
-{
- struct v42bis_output_buffer *output_buffer =
- (struct v42bis_output_buffer *)user_data;
- memcpy(output_buffer->buf_pointer, buf, len);
- output_buffer->buf_pointer += len;
- output_buffer->len += len;
- return;
-}
-
-/* Initalize data compression */
-int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
- const struct gprs_sndcp_comp_field *comp_field)
-{
- /* Note: This function is automatically called from
- * gprs_sndcp_comp.c when a new data compression
- * entity is created by gprs_sndcp.c */
-
- OSMO_ASSERT(comp_entity);
- OSMO_ASSERT(comp_field);
-
- if (comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION
- && comp_entity->algo == V42BIS) {
- OSMO_ASSERT(comp_field->v42bis_params);
- comp_entity->state =
- v42bis_init(ctx, NULL, comp_field->v42bis_params->p0,
- comp_field->v42bis_params->p1,
- comp_field->v42bis_params->p2,
- &tx_v42bis_frame_handler, NULL,
- V42BIS_MAX_OUTPUT_LENGTH,
- &rx_v42bis_data_handler, NULL,
- V42BIS_MAX_OUTPUT_LENGTH);
- LOGP(DSNDCP, LOGL_INFO,
- "V.42bis data compression initalized.\n");
- return 0;
- }
-
- /* Just in case someone tries to initalize an unknown or unsupported
- * data compresson. Since everything is checked during the SNDCP
- * negotiation process, this should never happen! */
- OSMO_ASSERT(false);
-}
-
-/* Terminate data compression */
-void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity)
-{
- /* Note: This function is automatically called from
- * gprs_sndcp_comp.c when a data compression
- * entity is deleted by gprs_sndcp.c */
-
- OSMO_ASSERT(comp_entity);
-
- if (comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION
- && comp_entity->algo == V42BIS) {
- if (comp_entity->state) {
- v42bis_free((v42bis_state_t *) comp_entity->state);
- comp_entity->state = NULL;
- }
- LOGP(DSNDCP, LOGL_INFO,
- "V.42bis data compression terminated.\n");
- return;
- }
-
- /* Just in case someone tries to terminate an unknown or unsupported
- * data compresson. Since everything is checked during the SNDCP
- * negotiation process, this should never happen! */
- OSMO_ASSERT(false);
-}
-
-/* Perform a full reset of the V.42bis compression state */
-static void v42bis_reset(v42bis_state_t *comp)
-{
- /* This function performs a complete reset of the V.42bis compression
- * state by reinitalizing the state withe the previously negotiated
- * parameters. */
-
- int p0, p1, p2;
- p0 = comp->decompress.v42bis_parm_p0 | comp->compress.v42bis_parm_p0;
- p1 = comp->decompress.v42bis_parm_n2;
- p2 = comp->decompress.v42bis_parm_n7;
-
- DEBUGP(DSNDCP, "Resetting compression state: %p, p0=%d, p1=%d, p2=%d\n",
- comp, p0, p1, p2);
-
- v42bis_init(NULL, comp, p0, p1, p2, &tx_v42bis_frame_handler, NULL,
- V42BIS_MAX_OUTPUT_LENGTH, &rx_v42bis_data_handler, NULL,
- V42BIS_MAX_OUTPUT_LENGTH);
-}
-
-/* Compress a packet using V.42bis data compression */
-static int v42bis_compress_unitdata(uint8_t *pcomp_index, uint8_t *data,
- unsigned int len, v42bis_state_t *comp)
-{
- /* Note: This implementation may only be used to compress SN_UNITDATA
- * packets, since it resets the compression state for each NPDU. */
-
- uint8_t *data_o;
- int rc;
- int skip = 0;
- struct v42bis_output_buffer compressed_data;
-
- /* Don't bother with short packets */
- if (len < MIN_COMPR_PAYLOAD)
- skip = 1;
-
- /* Skip if compression is not enabled for TX direction */
- if (!comp->compress.v42bis_parm_p0)
- skip = 1;
-
- /* Skip compression */
- if (skip) {
- *pcomp_index = 0;
- return len;
- }
-
- /* Reset V.42bis compression state */
- v42bis_reset(comp);
-
- /* Run compressor */
- data_o = talloc_zero_size(comp, len * MAX_DATADECOMPR_FAC);
- compressed_data.buf = data_o;
- compressed_data.buf_pointer = data_o;
- compressed_data.len = 0;
- comp->compress.user_data = (&compressed_data);
- rc = v42bis_compress(comp, data, len);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR,
- "Data compression failed, skipping...\n");
- skip = 1;
- }
- rc = v42bis_compress_flush(comp);
- if (rc < 0) {
- LOGP(DSNDCP, LOGL_ERROR,
- "Data compression failed, skipping...\n");
- skip = 1;
- }
-
- /* The compressor might yield negative compression gain, in
- * this case, we just decide to send the packat as normal,
- * uncompressed payload => skip compresssion */
- if (compressed_data.len >= len) {
- LOGP(DSNDCP, LOGL_ERROR,
- "Data compression ineffective, skipping...\n");
- skip = 1;
- }
-
- /* Skip compression */
- if (skip) {
- *pcomp_index = 0;
- talloc_free(data_o);
- return len;
- }
-
- *pcomp_index = 1;
- memcpy(data, data_o, compressed_data.len);
- talloc_free(data_o);
-
- return compressed_data.len;
-}
-
-/* Expand a packet using V.42bis data compression */
-static int v42bis_expand_unitdata(uint8_t *data, unsigned int len,
- uint8_t pcomp_index, v42bis_state_t *comp)
-{
- /* Note: This implementation may only be used to compress SN_UNITDATA
- * packets, since it resets the compression state for each NPDU. */
-
- int rc;
- struct v42bis_output_buffer uncompressed_data;
- uint8_t *data_i;
-
- /* Skip when the packet is marked as uncompressed */
- if (pcomp_index == 0) {
- return len;
- }
-
- /* Reset V.42bis compression state */
- v42bis_reset(comp);
-
- /* Decompress packet */
- data_i = talloc_zero_size(comp, len);
- memcpy(data_i, data, len);
- uncompressed_data.buf = data;
- uncompressed_data.buf_pointer = data;
- uncompressed_data.len = 0;
- comp->decompress.user_data = (&uncompressed_data);
- rc = v42bis_decompress(comp, data_i, len);
- talloc_free(data_i);
- if (rc < 0)
- return -EINVAL;
- rc = v42bis_decompress_flush(comp);
- if (rc < 0)
- return -EINVAL;
-
- return uncompressed_data.len;
-}
-
-/* Expand packet */
-int gprs_sndcp_dcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp,
- const struct llist_head *comp_entities)
-{
- int rc;
- uint8_t pcomp_index = 0;
- struct gprs_sndcp_comp *comp_entity;
-
- OSMO_ASSERT(data);
- OSMO_ASSERT(comp_entities);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Data compression entity list: comp_entities=%p\n", comp_entities);
-
- LOGP(DSNDCP, LOGL_DEBUG, "Data compression mode: dcomp=%d\n", pcomp);
-
- /* Skip on pcomp=0 */
- if (pcomp == 0) {
- return len;
- }
-
- /* Find out which compression entity handles the data */
- comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp);
-
- /* Skip compression if no suitable compression entity can be found */
- if (!comp_entity) {
- return len;
- }
-
- /* Note: Only data compression entities may appear in
- * data compression context */
- OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION);
-
- /* Note: Currently V42BIS is the only compression method we
- * support, so the only allowed algorithm is V42BIS */
- OSMO_ASSERT(comp_entity->algo == V42BIS);
-
- /* Find pcomp_index */
- pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp);
-
- /* Run decompression algo */
- rc = v42bis_expand_unitdata(data, len, pcomp_index, comp_entity->state);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Data expansion done, old length=%d, new length=%d, entity=%p\n",
- len, rc, comp_entity);
-
- return rc;
-}
-
-/* Compress packet */
-int gprs_sndcp_dcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp,
- const struct llist_head *comp_entities,
- uint8_t nsapi)
-{
- int rc;
- uint8_t pcomp_index = 0;
- struct gprs_sndcp_comp *comp_entity;
-
- OSMO_ASSERT(data);
- OSMO_ASSERT(pcomp);
- OSMO_ASSERT(comp_entities);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Data compression entity list: comp_entities=%p\n", comp_entities);
-
- /* Find out which compression entity handles the data */
- comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi);
-
- /* Skip compression if no suitable compression entity can be found */
- if (!comp_entity) {
- *pcomp = 0;
- return len;
- }
-
- /* Note: Only data compression entities may appear in
- * data compression context */
- OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_DATA_COMPRESSION);
-
- /* Note: Currently V42BIS is the only compression method we
- * support, so the only allowed algorithm is V42BIS */
- OSMO_ASSERT(comp_entity->algo == V42BIS);
-
- /* Run compression algo */
- rc = v42bis_compress_unitdata(&pcomp_index, data, len,
- comp_entity->state);
-
- /* Find pcomp value */
- *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index);
-
- LOGP(DSNDCP, LOGL_DEBUG, "Data compression mode: dcomp=%d\n", *pcomp);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Data compression done, old length=%d, new length=%d, entity=%p\n",
- len, rc, comp_entity);
-
- return rc;
-}
diff --git a/openbsc/src/gprs/gprs_sndcp_pcomp.c b/openbsc/src/gprs/gprs_sndcp_pcomp.c
deleted file mode 100644
index a2236c3b1..000000000
--- a/openbsc/src/gprs/gprs_sndcp_pcomp.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/* GPRS SNDCP header compression handler */
-
-/* (C) 2016 by Sysmocom s.f.m.c. GmbH
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <math.h>
-#include <errno.h>
-#include <stdbool.h>
-
-#include <osmocom/core/utils.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/tlv.h>
-
-#include <openbsc/gprs_llc.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/gprs_sndcp_xid.h>
-#include <openbsc/slhc.h>
-#include <openbsc/debug.h>
-#include <openbsc/gprs_sndcp_comp.h>
-#include <openbsc/gprs_sndcp_pcomp.h>
-
-/* Initalize header compression */
-int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity,
- const struct gprs_sndcp_comp_field *comp_field)
-{
- /* Note: This function is automatically called from
- * gprs_sndcp_comp.c when a new header compression
- * entity is created by gprs_sndcp.c */
-
- OSMO_ASSERT(comp_entity);
- OSMO_ASSERT(comp_field);
-
- if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION
- && comp_entity->algo == RFC_1144) {
- OSMO_ASSERT(comp_field->rfc1144_params);
- comp_entity->state =
- slhc_init(ctx, comp_field->rfc1144_params->s01 + 1,
- comp_field->rfc1144_params->s01 + 1);
- LOGP(DSNDCP, LOGL_INFO,
- "RFC1144 header compression initalized.\n");
- return 0;
- }
-
- /* Just in case someone tries to initalize an unknown or unsupported
- * header compresson. Since everything is checked during the SNDCP
- * negotiation process, this should never happen! */
- OSMO_ASSERT(false);
-}
-
-/* Terminate header compression */
-void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity)
-{
- /* Note: This function is automatically called from
- * gprs_sndcp_comp.c when a header compression
- * entity is deleted by gprs_sndcp.c */
-
- OSMO_ASSERT(comp_entity);
-
- if (comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION
- && comp_entity->algo == RFC_1144) {
- if (comp_entity->state) {
- slhc_free((struct slcompress *)comp_entity->state);
- comp_entity->state = NULL;
- }
- LOGP(DSNDCP, LOGL_INFO,
- "RFC1144 header compression terminated.\n");
- return;
- }
-
- /* Just in case someone tries to terminate an unknown or unsupported
- * data compresson. Since everything is checked during the SNDCP
- * negotiation process, this should never happen! */
- OSMO_ASSERT(false);
-}
-
-/* Compress a packet using Van Jacobson RFC1144 header compression */
-static int rfc1144_compress(uint8_t *pcomp_index, uint8_t *data,
- unsigned int len, struct slcompress *comp)
-{
- uint8_t *comp_ptr;
- int compr_len;
- uint8_t *data_o;
-
- /* Create a working copy of the incoming data */
- data_o = talloc_zero_size(comp, len);
- memcpy(data_o, data, len);
-
- /* Run compressor */
- compr_len = slhc_compress(comp, data, len, data_o, &comp_ptr, 0);
-
- /* Generate pcomp_index */
- if (data_o[0] & SL_TYPE_COMPRESSED_TCP) {
- *pcomp_index = 2;
- data_o[0] &= ~SL_TYPE_COMPRESSED_TCP;
- memcpy(data, data_o, compr_len);
- } else if ((data_o[0] & SL_TYPE_UNCOMPRESSED_TCP) ==
- SL_TYPE_UNCOMPRESSED_TCP) {
- *pcomp_index = 1;
- data_o[0] &= 0x4F;
- memcpy(data, data_o, compr_len);
- } else
- *pcomp_index = 0;
-
- talloc_free(data_o);
- return compr_len;
-}
-
-/* Expand a packet using Van Jacobson RFC1144 header compression */
-static int rfc1144_expand(uint8_t *data, unsigned int len, uint8_t pcomp_index,
- struct slcompress *comp)
-{
- int data_decompressed_len;
- int type;
-
- /* Note: this function should never be called with pcomp_index=0,
- * since this condition is already filtered
- * out by gprs_sndcp_pcomp_expand() */
-
- /* Determine the data type by the PCOMP index */
- switch (pcomp_index) {
- case 0:
- type = SL_TYPE_IP;
- break;
- case 1:
- type = SL_TYPE_UNCOMPRESSED_TCP;
- break;
- case 2:
- type = SL_TYPE_COMPRESSED_TCP;
- break;
- default:
- LOGP(DSNDCP, LOGL_ERROR,
- "rfc1144_expand() Invalid pcomp_index value (%d) detected, assuming no compression!\n",
- pcomp_index);
- type = SL_TYPE_IP;
- break;
- }
-
- /* Restore the original version nibble on
- * marked uncompressed packets */
- if (type == SL_TYPE_UNCOMPRESSED_TCP) {
- /* Just in case the phone tags uncompressed tcp-data
- * (normally this is handled by pcomp so there is
- * no need for tagging the data) */
- data[0] &= 0x4F;
- data_decompressed_len = slhc_remember(comp, data, len);
- return data_decompressed_len;
- }
-
- /* Uncompress compressed packets */
- else if (type == SL_TYPE_COMPRESSED_TCP) {
- data_decompressed_len = slhc_uncompress(comp, data, len);
- return data_decompressed_len;
- }
-
- /* Regular or unknown packets will not be touched */
- return len;
-}
-
-/* Expand packet header */
-int gprs_sndcp_pcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp,
- const struct llist_head *comp_entities)
-{
- int rc;
- uint8_t pcomp_index = 0;
- struct gprs_sndcp_comp *comp_entity;
-
- OSMO_ASSERT(data);
- OSMO_ASSERT(comp_entities);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Header compression entity list: comp_entities=%p\n",
- comp_entities);
-
- LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", pcomp);
-
- /* Skip on pcomp=0 */
- if (pcomp == 0) {
- return len;
- }
-
- /* Find out which compression entity handles the data */
- comp_entity = gprs_sndcp_comp_by_comp(comp_entities, pcomp);
-
- /* Skip compression if no suitable compression entity can be found */
- if (!comp_entity) {
- return len;
- }
-
- /* Note: Only protocol compression entities may appear in
- * protocol compression context */
- OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION);
-
- /* Note: Currently RFC1144 is the only compression method we
- * support, so the only allowed algorithm is RFC1144 */
- OSMO_ASSERT(comp_entity->algo == RFC_1144);
-
- /* Find pcomp_index */
- pcomp_index = gprs_sndcp_comp_get_idx(comp_entity, pcomp);
-
- /* Run decompression algo */
- rc = rfc1144_expand(data, len, pcomp_index, comp_entity->state);
- slhc_i_status(comp_entity->state);
- slhc_o_status(comp_entity->state);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Header expansion done, old length=%d, new length=%d, entity=%p\n",
- len, rc, comp_entity);
-
- return rc;
-}
-
-/* Compress packet header */
-int gprs_sndcp_pcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp,
- const struct llist_head *comp_entities,
- uint8_t nsapi)
-{
- int rc;
- uint8_t pcomp_index = 0;
- struct gprs_sndcp_comp *comp_entity;
-
- OSMO_ASSERT(data);
- OSMO_ASSERT(pcomp);
- OSMO_ASSERT(comp_entities);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Header compression entity list: comp_entities=%p\n",
- comp_entities);
-
- /* Find out which compression entity handles the data */
- comp_entity = gprs_sndcp_comp_by_nsapi(comp_entities, nsapi);
-
- /* Skip compression if no suitable compression entity can be found */
- if (!comp_entity) {
- *pcomp = 0;
- return len;
- }
-
- /* Note: Only protocol compression entities may appear in
- * protocol compression context */
- OSMO_ASSERT(comp_entity->compclass == SNDCP_XID_PROTOCOL_COMPRESSION);
-
- /* Note: Currently RFC1144 is the only compression method we
- * support, so the only allowed algorithm is RFC1144 */
- OSMO_ASSERT(comp_entity->algo == RFC_1144);
-
- /* Run compression algo */
- rc = rfc1144_compress(&pcomp_index, data, len, comp_entity->state);
- slhc_i_status(comp_entity->state);
- slhc_o_status(comp_entity->state);
-
- /* Find pcomp value */
- *pcomp = gprs_sndcp_comp_get_comp(comp_entity, pcomp_index);
-
- LOGP(DSNDCP, LOGL_DEBUG, "Header compression mode: pcomp=%d\n", *pcomp);
-
- LOGP(DSNDCP, LOGL_DEBUG,
- "Header compression done, old length=%d, new length=%d, entity=%p\n",
- len, rc, comp_entity);
- return rc;
-}
diff --git a/openbsc/src/gprs/gprs_sndcp_vty.c b/openbsc/src/gprs/gprs_sndcp_vty.c
deleted file mode 100644
index 430881fc8..000000000
--- a/openbsc/src/gprs/gprs_sndcp_vty.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/* VTY interface for our GPRS SNDCP implementation */
-
-/* (C) 2010 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 <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdint.h>
-
-#include <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/rate_ctr.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-#include <openbsc/gprs_llc.h>
-#include <openbsc/gprs_sndcp.h>
-
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/command.h>
-
-static void vty_dump_sne(struct vty *vty, struct gprs_sndcp_entity *sne)
-{
- vty_out(vty, " TLLI %08x SAPI=%u NSAPI=%u:%s",
- sne->lle->llme->tlli, sne->lle->sapi, sne->nsapi, VTY_NEWLINE);
- vty_out(vty, " Defrag: npdu=%u highest_seg=%u seg_have=0x%08x tot_len=%u%s",
- sne->defrag.npdu, sne->defrag.highest_seg, sne->defrag.seg_have,
- sne->defrag.tot_len, VTY_NEWLINE);
-}
-
-
-DEFUN(show_sndcp, show_sndcp_cmd,
- "show sndcp",
- SHOW_STR "Display information about the SNDCP protocol")
-{
- struct gprs_sndcp_entity *sne;
-
- vty_out(vty, "State of SNDCP Entities%s", VTY_NEWLINE);
- llist_for_each_entry(sne, &gprs_sndcp_entities, list)
- vty_dump_sne(vty, sne);
-
- return CMD_SUCCESS;
-}
-
-int gprs_sndcp_vty_init(void)
-{
- install_element_ve(&show_sndcp_cmd);
-
- return 0;
-}
diff --git a/openbsc/src/gprs/gprs_sndcp_xid.c b/openbsc/src/gprs/gprs_sndcp_xid.c
deleted file mode 100644
index dfea5febc..000000000
--- a/openbsc/src/gprs/gprs_sndcp_xid.c
+++ /dev/null
@@ -1,1822 +0,0 @@
-/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- * All Rights Reserved
- *
- * Author: Philipp Maier
- *
- * 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 <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <math.h>
-#include <errno.h>
-
-#include <osmocom/core/utils.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/tlv.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gprs_llc.h>
-#include <openbsc/sgsn.h>
-#include <openbsc/gprs_sndcp_xid.h>
-
-/* When the propose bit in an SNDCP-XID compression field is set to zero,
- * the algorithm identifier is stripped. The algoritm parameters are specific
- * for each algorithms. The following struct is used to pass the information
- * about the referenced algorithm to the parser. */
-struct entity_algo_table {
- unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */
- unsigned int algo; /* see also: 6.5.1.1.4 and 6.6.1.1.4 */
- unsigned int compclass; /* Can be either SNDCP_XID_DATA_COMPRESSION or
- SNDCP_XID_PROTOCOL_COMPRESSION */
-};
-
-/* FUNCTIONS RELATED TO SNDCP-XID ENCODING */
-
-/* Encode applicable sapis (works the same in all three compression schemes) */
-static int encode_pcomp_applicable_sapis(uint8_t *dst,
- const uint8_t *nsapis,
- uint8_t nsapis_len)
-{
- /* NOTE: Buffer *dst needs offer at 2 bytes
- * of space to store the generation results */
-
- uint16_t blob;
- uint8_t nsapi;
- int i;
-
- /* Bail if number of possible nsapis exceeds valid range
- * (Only 11 nsapis possible for PDP-Contexts) */
- OSMO_ASSERT(nsapis_len <= 11);
-
- /* Encode applicable SAPIs */
- blob = 0;
- for (i = 0; i < nsapis_len; i++) {
- nsapi = nsapis[i];
- /* Only NSAPI 5 to 15 are applicable for user traffic (PDP-
- * contexts). Only for these NSAPIs SNDCP-XID parameters
- * can apply. See also 3GPP TS 44.065, 5.1 Service primitives */
- OSMO_ASSERT(nsapi >= 5 && nsapi <= 15);
- blob |= (1 << nsapi);
- }
-
- /* Store result */
- *dst = (blob >> 8) & 0xFF;
- dst++;
- *dst = blob & 0xFF;
-
- return 2;
-}
-
-/* Encode rfc1144 parameter field
- * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
-static int encode_pcomp_rfc1144_params(uint8_t *dst, unsigned int dst_maxlen,
- const struct
- gprs_sndcp_pcomp_rfc1144_params *params)
-{
- /* NOTE: Buffer *dst should offer at least 3 bytes
- * of space to store the generation results */
-
- int dst_counter = 0;
- int rc;
-
- OSMO_ASSERT(dst_maxlen >= 3);
-
- /* Zero out buffer */
- memset(dst, 0, dst_maxlen);
-
- /* Encode applicable SAPIs */
- rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
- params->nsapi_len);
- dst += rc;
- dst_counter += rc;
-
- /* Encode s01 (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
- OSMO_ASSERT(params->s01 >= 0);
- OSMO_ASSERT(params->s01 <= 255);
- *dst = params->s01;
- dst++;
- dst_counter++;
-
- /* Return generated length */
- return dst_counter;
-}
-
-/*
- * Encode rfc2507 parameter field
- * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6)
- */
-static int encode_pcomp_rfc2507_params(uint8_t *dst, unsigned int dst_maxlen,
- const struct
- gprs_sndcp_pcomp_rfc2507_params *params)
-{
- /* NOTE: Buffer *dst should offer at least 3 bytes
- * of space to store the generation results */
-
- int dst_counter = 0;
- int rc;
-
- OSMO_ASSERT(dst_maxlen >= 9);
-
- /* Zero out buffer */
- memset(dst, 0, dst_maxlen);
-
- /* Encode applicable SAPIs */
- rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
- params->nsapi_len);
- dst += rc;
- dst_counter += rc;
-
- /* Encode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- OSMO_ASSERT(params->f_max_period >= 1);
- OSMO_ASSERT(params->f_max_period <= 65535);
- *dst = (params->f_max_period >> 8) & 0xFF;
- dst++;
- dst_counter++;
- *dst = (params->f_max_period) & 0xFF;
- dst++;
- dst_counter++;
-
- /* Encode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- OSMO_ASSERT(params->f_max_time >= 1);
- OSMO_ASSERT(params->f_max_time <= 255);
- *dst = params->f_max_time;
- dst++;
- dst_counter++;
-
- /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- OSMO_ASSERT(params->max_header >= 60);
- OSMO_ASSERT(params->max_header <= 255);
- *dst = params->max_header;
- dst++;
- dst_counter++;
-
- /* Encode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- OSMO_ASSERT(params->tcp_space >= 3);
- OSMO_ASSERT(params->tcp_space <= 255);
- *dst = params->tcp_space;
- dst++;
- dst_counter++;
-
- /* Encode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- OSMO_ASSERT(params->non_tcp_space >= 3);
- OSMO_ASSERT(params->non_tcp_space <= 65535);
- *dst = (params->non_tcp_space >> 8) & 0xFF;
- dst++;
- dst_counter++;
- *dst = (params->non_tcp_space) & 0xFF;
- dst++;
- dst_counter++;
-
- /* Return generated length */
- return dst_counter;
-}
-
-/* Encode ROHC parameter field
- * (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
-static int encode_pcomp_rohc_params(uint8_t *dst, unsigned int dst_maxlen,
- const struct gprs_sndcp_pcomp_rohc_params
- *params)
-{
- /* NOTE: Buffer *dst should offer at least 36
- * (2 * 16 Profiles + 2 * 3 Parameter) bytes
- * of memory space to store generation results */
-
- int i;
- int dst_counter = 0;
- int rc;
-
- OSMO_ASSERT(dst_maxlen >= 38);
-
- /* Bail if number of ROHC profiles exceeds limit
- * (ROHC supports only a maximum of 16 different profiles) */
- OSMO_ASSERT(params->profile_len <= 16);
-
- /* Zero out buffer */
- memset(dst, 0, dst_maxlen);
-
- /* Encode applicable SAPIs */
- rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
- params->nsapi_len);
- dst += rc;
- dst_counter += rc;
-
- /* Encode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
- OSMO_ASSERT(params->max_cid >= 0);
- OSMO_ASSERT(params->max_cid <= 16383);
- *dst = (params->max_cid >> 8) & 0xFF;
- dst++;
- *dst = params->max_cid & 0xFF;
- dst++;
- dst_counter += 2;
-
- /* Encode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
- OSMO_ASSERT(params->max_header >= 60);
- OSMO_ASSERT(params->max_header <= 255);
- *dst = (params->max_header >> 8) & 0xFF;
- dst++;
- *dst = params->max_header & 0xFF;
- dst++;
- dst_counter += 2;
-
- /* Encode ROHC Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
- for (i = 0; i < params->profile_len; i++) {
- *dst = (params->profile[i] >> 8) & 0xFF;
- dst++;
- *dst = params->profile[i] & 0xFF;
- dst++;
- dst_counter += 2;
- }
-
- /* Return generated length */
- return dst_counter;
-}
-
-/* Encode V.42bis parameter field
- * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
-static int encode_dcomp_v42bis_params(uint8_t *dst, unsigned int dst_maxlen,
- const struct
- gprs_sndcp_dcomp_v42bis_params *params)
-{
- /* NOTE: Buffer *dst should offer at least 6 bytes
- * of space to store the generation results */
-
- int dst_counter = 0;
- int rc;
-
- OSMO_ASSERT(dst_maxlen >= 6);
-
- /* Zero out buffer */
- memset(dst, 0, dst_maxlen);
-
- /* Encode applicable SAPIs */
- rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
- params->nsapi_len);
- dst += rc;
- dst_counter += rc;
-
- /* Encode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
- OSMO_ASSERT(params->p0 >= 0);
- OSMO_ASSERT(params->p0 <= 3);
- *dst = params->p0 & 0x03;
- dst++;
- dst_counter++;
-
- /* Encode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
- OSMO_ASSERT(params->p1 >= 512);
- OSMO_ASSERT(params->p1 <= 65535);
- *dst = (params->p1 >> 8) & 0xFF;
- dst++;
- *dst = params->p1 & 0xFF;
- dst++;
- dst_counter += 2;
-
- /* Encode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
- OSMO_ASSERT(params->p2 >= 6);
- OSMO_ASSERT(params->p2 <= 250);
- *dst = params->p2;
- dst++;
- dst_counter++;
-
- /* Return generated length */
- return dst_counter;
-}
-
-/* Encode V44 parameter field
- * (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
-static int encode_dcomp_v44_params(uint8_t *dst, unsigned int dst_maxlen,
- const struct gprs_sndcp_dcomp_v44_params
- *params)
-{
- /* NOTE: Buffer *dst should offer at least 12 bytes
- * of space to store the generation results */
-
- int dst_counter = 0;
- int rc;
-
- OSMO_ASSERT(dst_maxlen >= 12);
-
- /* Zero out buffer */
- memset(dst, 0, dst_maxlen);
-
- /* Encode applicable SAPIs */
- rc = encode_pcomp_applicable_sapis(dst, params->nsapi,
- params->nsapi_len);
- dst += rc;
- dst_counter += rc;
-
- /* Encode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
- OSMO_ASSERT(params->c0 == 0x80 || params->c0 == 0xC0);
- *dst = params->c0 & 0xC0;
- dst++;
- dst_counter++;
-
- /* Encode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
- OSMO_ASSERT(params->p0 >= 0);
- OSMO_ASSERT(params->p0 <= 3);
- *dst = params->p0 & 0x03;
- dst++;
- dst_counter++;
-
- /* Encode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
- OSMO_ASSERT(params->p1t >= 256);
- OSMO_ASSERT(params->p1t <= 65535);
- *dst = (params->p1t >> 8) & 0xFF;
- dst++;
- *dst = params->p1t & 0xFF;
- dst++;
- dst_counter += 2;
-
- /* Encode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
- OSMO_ASSERT(params->p1r >= 256);
- OSMO_ASSERT(params->p1r <= 65535);
- *dst = (params->p1r >> 8) & 0xFF;
- dst++;
- *dst = params->p1r & 0xFF;
- dst++;
- dst_counter += 2;
-
- /* Encode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
- OSMO_ASSERT(params->p3t >= 0);
- OSMO_ASSERT(params->p3t <= 65535);
- OSMO_ASSERT(params->p3t >= 2 * params->p1t);
- *dst = (params->p3t >> 8) & 0xFF;
- dst++;
- *dst = params->p3t & 0xFF;
- dst++;
- dst_counter += 2;
-
- /* Encode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */
- OSMO_ASSERT(params->p3r >= 0);
- OSMO_ASSERT(params->p3r <= 65535);
- OSMO_ASSERT(params->p3r >= 2 * params->p1r);
- *dst = (params->p3r >> 8) & 0xFF;
- dst++;
- *dst = params->p3r & 0xFF;
- dst++;
- dst_counter += 2;
-
- /* Return generated length */
- return dst_counter;
-}
-
-/* Encode data or protocol control information compression field
- * (see also: 3GPP TS 44.065, 6.6.1.1, Figure 9 and
- * 3GPP TS 44.065, 6.5.1.1, Figure 7) */
-static int encode_comp_field(uint8_t *dst, unsigned int dst_maxlen,
- const struct gprs_sndcp_comp_field *comp_field)
-{
- int dst_counter = 0;
- int len;
- int expected_length;
- int i;
-
- uint8_t payload_bytes[256];
- int payload_bytes_len = -1;
-
- /* If possible, try do encode payload bytes first */
- if (comp_field->rfc1144_params) {
- payload_bytes_len =
- encode_pcomp_rfc1144_params(payload_bytes,
- sizeof(payload_bytes),
- comp_field->rfc1144_params);
- } else if (comp_field->rfc2507_params) {
- payload_bytes_len =
- encode_pcomp_rfc2507_params(payload_bytes,
- sizeof(payload_bytes),
- comp_field->rfc2507_params);
- } else if (comp_field->rohc_params) {
- payload_bytes_len =
- encode_pcomp_rohc_params(payload_bytes,
- sizeof(payload_bytes),
- comp_field->rohc_params);
- } else if (comp_field->v42bis_params) {
- payload_bytes_len =
- encode_dcomp_v42bis_params(payload_bytes,
- sizeof(payload_bytes),
- comp_field->v42bis_params);
- } else if (comp_field->v44_params) {
- payload_bytes_len =
- encode_dcomp_v44_params(payload_bytes,
- sizeof(payload_bytes),
- comp_field->v44_params);
- } else
- OSMO_ASSERT(false);
-
- /* Bail immediately if payload byte generation failed */
- OSMO_ASSERT(payload_bytes_len >= 0);
-
- /* Bail if comp_len is out of bounds */
- OSMO_ASSERT(comp_field->comp_len <= sizeof(comp_field->comp));
-
- /* Calculate length field of the data block */
- if (comp_field->p) {
- len =
- payload_bytes_len +
- ceil((double)(comp_field->comp_len) / 2.0);
- expected_length = len + 3;
- } else {
- len = payload_bytes_len;
- expected_length = len + 2;
- }
-
- /* Bail immediately if no sufficient memory space is supplied */
- OSMO_ASSERT(dst_maxlen >= expected_length);
-
- /* Check if the entity number is within bounds */
- OSMO_ASSERT(comp_field->entity <= 0x1f);
-
- /* Check if the algorithm number is within bounds */
- OSMO_ASSERT(comp_field->algo >= 0 || comp_field->algo <= 0x1f);
-
- /* Zero out buffer */
- memset(dst, 0, dst_maxlen);
-
- /* Encode Propose bit */
- if (comp_field->p)
- *dst |= (1 << 7);
-
- /* Encode entity number */
- *dst |= comp_field->entity & 0x1F;
- dst++;
- dst_counter++;
-
- /* Encode algorithm number */
- if (comp_field->p) {
- *dst |= comp_field->algo & 0x1F;
- dst++;
- dst_counter++;
- }
-
- /* Encode length field */
- *dst |= len & 0xFF;
- dst++;
- dst_counter++;
-
- /* Encode PCOMP/DCOMP values */
- if (comp_field->p) {
- for (i = 0; i < comp_field->comp_len; i++) {
- /* Check if submitted PCOMP/DCOMP
- values are within bounds */
- if (comp_field->comp[i] > 0x0F)
- return -EINVAL;
-
- if (i & 1) {
- *dst |= comp_field->comp[i] & 0x0F;
- dst++;
- dst_counter++;
- } else
- *dst |= (comp_field->comp[i] << 4) & 0xF0;
- }
-
- if (i & 1) {
- dst++;
- dst_counter++;
- }
- }
-
- /* Append payload bytes */
- memcpy(dst, payload_bytes, payload_bytes_len);
- dst_counter += payload_bytes_len;
-
- /* Return generated length */
- return dst_counter;
-}
-
-/* Find out to which compression class the specified comp-field belongs
- * (header compression or data compression?) */
-int gprs_sndcp_get_compression_class(const struct gprs_sndcp_comp_field
- *comp_field)
-{
- OSMO_ASSERT(comp_field);
-
- if (comp_field->rfc1144_params)
- return SNDCP_XID_PROTOCOL_COMPRESSION;
- else if (comp_field->rfc2507_params)
- return SNDCP_XID_PROTOCOL_COMPRESSION;
- else if (comp_field->rohc_params)
- return SNDCP_XID_PROTOCOL_COMPRESSION;
- else if (comp_field->v42bis_params)
- return SNDCP_XID_DATA_COMPRESSION;
- else if (comp_field->v44_params)
- return SNDCP_XID_DATA_COMPRESSION;
- else
- return -EINVAL;
-}
-
-/* Convert all compression fields to bytstreams */
-static int gprs_sndcp_pack_fields(const struct llist_head *comp_fields,
- uint8_t *dst,
- unsigned int dst_maxlen, int class)
-{
- struct gprs_sndcp_comp_field *comp_field;
- int byte_counter = 0;
- int rc;
-
- llist_for_each_entry_reverse(comp_field, comp_fields, list) {
- if (class == gprs_sndcp_get_compression_class(comp_field)) {
- rc = encode_comp_field(dst + byte_counter,
- dst_maxlen - byte_counter,
- comp_field);
-
- /* When input data is correct, there is
- * no reason for the encoder to fail! */
- OSMO_ASSERT(rc >= 0);
-
- byte_counter += rc;
- }
- }
-
- /* Return generated length */
- return byte_counter;
-}
-
-/* Transform a list with compression fields into an SNDCP-XID message (dst) */
-int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen,
- const struct llist_head *comp_fields, int version)
-{
- int rc;
- int byte_counter = 0;
- uint8_t comp_bytes[512];
- uint8_t xid_version_number[1];
-
- OSMO_ASSERT(comp_fields);
- OSMO_ASSERT(dst);
- OSMO_ASSERT(dst_maxlen >= 2 + sizeof(xid_version_number));
-
- /* Prepend header with version number */
- if (version >= 0) {
- xid_version_number[0] = (uint8_t) (version & 0xff);
- dst =
- tlv_put(dst, SNDCP_XID_VERSION_NUMBER,
- sizeof(xid_version_number), xid_version_number);
- byte_counter += (sizeof(xid_version_number) + 2);
- }
-
- /* Stop if there is no compression fields supplied */
- if (llist_empty(comp_fields))
- return byte_counter;
-
- /* Add data compression fields */
- rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes,
- sizeof(comp_bytes),
- SNDCP_XID_DATA_COMPRESSION);
- OSMO_ASSERT(rc >= 0);
-
- if (rc > 0) {
- dst = tlv_put(dst, SNDCP_XID_DATA_COMPRESSION, rc, comp_bytes);
- byte_counter += rc + 2;
- }
-
- /* Add header compression fields */
- rc = gprs_sndcp_pack_fields(comp_fields, comp_bytes,
- sizeof(comp_bytes),
- SNDCP_XID_PROTOCOL_COMPRESSION);
- OSMO_ASSERT(rc >= 0);
-
- if (rc > 0) {
- dst = tlv_put(dst, SNDCP_XID_PROTOCOL_COMPRESSION, rc,
- comp_bytes);
- byte_counter += rc + 2;
- }
-
- /* Return generated length */
- return byte_counter;
-}
-
-/* FUNCTIONS RELATED TO SNDCP-XID DECODING */
-
-/* Decode applicable sapis (works the same in all three compression schemes) */
-static int decode_pcomp_applicable_sapis(uint8_t *nsapis,
- uint8_t *nsapis_len,
- const uint8_t *src,
- unsigned int src_len)
-{
- uint16_t blob;
- int i;
- int nsapi_len = 0;
-
- /* Exit immediately if no result can be stored */
- if (!nsapis)
- return -EINVAL;
-
- /* Exit immediately if not enough input data is available */
- if (src_len < 2)
- return -EINVAL;
-
- /* Read bitmask */
- blob = *src;
- blob = (blob << 8) & 0xFF00;
- src++;
- blob |= (*src) & 0xFF;
- blob = (blob >> 5);
-
- /* Decode applicable SAPIs */
- for (i = 0; i < 15; i++) {
- if ((blob >> i) & 1) {
- nsapis[nsapi_len] = i + 5;
- nsapi_len++;
- }
- }
-
- /* Return consumed length */
- *nsapis_len = nsapi_len;
- return 2;
-}
-
-/* Decode 16 bit field */
-static int decode_pcomp_16_bit_field(int *value_int, uint16_t * value_uint16,
- const uint8_t *src,
- unsigned int src_len,
- int value_min, int value_max)
-{
- uint16_t blob;
-
- /* Reset values to zero (just to be sure) */
- if (value_int)
- *value_int = -1;
- if (value_uint16)
- *value_uint16 = 0;
-
- /* Exit if not enough src are available */
- if (src_len < 2)
- return -EINVAL;
-
- /* Decode bit value */
- blob = *src;
- blob = (blob << 8) & 0xFF00;
- src++;
- blob |= *src;
-
- /* Check if parsed value is within bounds */
- if (blob < value_min)
- return -EINVAL;
- if (blob > value_max)
- return -EINVAL;
-
- /* Hand back results to the caller */
- if (value_int)
- *value_int = blob;
- if (value_uint16)
- *value_uint16 = blob;
-
- /* Return consumed length */
- return 2;
-}
-
-/* Decode 8 bit field */
-static int decode_pcomp_8_bit_field(int *value_int, uint8_t *value_uint8,
- const uint8_t *src,
- unsigned int src_len,
- int value_min, int value_max)
-{
- uint8_t blob;
-
- /* Reset values to invalid (just to be sure) */
- if (value_int)
- *value_int = -1;
- if (value_uint8)
- *value_uint8 = 0;
-
- /* Exit if not enough src are available */
- if (src_len < 1)
- return -EINVAL;
-
- /* Decode bit value */
- blob = *src;
-
- /* Check if parsed value is within bounds */
- if (blob < value_min)
- return -EINVAL;
- if (blob > value_max)
- return -EINVAL;
-
- /* Hand back results to the caller */
- if (value_int)
- *value_int = blob;
- if (value_uint8)
- *value_uint8 = blob;
-
- /* Return consumed length */
- return 1;
-}
-
-/* Decode rfc1144 parameter field see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
-static int decode_pcomp_rfc1144_params(struct gprs_sndcp_pcomp_rfc1144_params
- *params, const uint8_t *src,
- unsigned int src_len)
-{
- int rc;
- int byte_counter = 0;
-
- /* Mark all optional parameters invalid by default */
- params->s01 = -1;
-
- /* Decode applicable SAPIs */
- rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
- src, src_len);
- if (rc > 0) {
- byte_counter += rc;
- src += rc;
- } else
- return byte_counter;
-
- /* Decode parameter S0 -1
- * (see also: 3GPP TS 44.065, 6.5.2.1, Table 5) */
- rc = decode_pcomp_8_bit_field(&params->s01, NULL, src,
- src_len - byte_counter, 0, 255);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Return consumed length */
- return byte_counter;
-}
-
-/* Decode rfc2507 parameter field
- * (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
-static int decode_pcomp_rfc2507_params(struct gprs_sndcp_pcomp_rfc2507_params
- *params, const uint8_t *src,
- unsigned int src_len)
-{
- int rc;
- int byte_counter = 0;
-
- /* Mark all optional parameters invalid by default */
- params->f_max_period = -1;
- params->f_max_time = -1;
- params->max_header = -1;
- params->tcp_space = -1;
- params->non_tcp_space = -1;
-
- /* Decode applicable SAPIs */
- rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
- src, src_len);
- if (rc > 0) {
- byte_counter += rc;
- src += rc;
- } else
- return byte_counter;
-
- /* Decode F_MAX_PERIOD (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- rc = decode_pcomp_16_bit_field(&params->f_max_period, NULL, src,
- src_len - byte_counter, 1, 65535);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Decode F_MAX_TIME (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- rc = decode_pcomp_8_bit_field(&params->f_max_time, NULL, src,
- src_len - byte_counter, 1, 255);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- rc = decode_pcomp_8_bit_field(&params->max_header, NULL, src,
- src_len - byte_counter, 60, 255);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Decode TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- rc = decode_pcomp_8_bit_field(&params->tcp_space, NULL, src,
- src_len - byte_counter, 3, 255);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Decode NON_TCP_SPACE (see also: 3GPP TS 44.065, 6.5.3.1, Table 6) */
- rc = decode_pcomp_16_bit_field(&params->non_tcp_space, NULL, src,
- src_len - byte_counter, 3, 65535);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Return consumed length */
- return byte_counter;
-}
-
-/* Decode ROHC parameter field (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
-static int decode_pcomp_rohc_params(struct gprs_sndcp_pcomp_rohc_params *params,
- const uint8_t *src, unsigned int src_len)
-{
- int rc;
- int byte_counter = 0;
- int i;
-
- /* Mark all optional parameters invalid by default */
- params->max_cid = -1;
- params->max_header = -1;
-
- /* Decode applicable SAPIs */
- rc = decode_pcomp_applicable_sapis(params->nsapi, &params->nsapi_len,
- src, src_len);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Decode MAX_CID (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
- rc = decode_pcomp_16_bit_field(&params->max_cid, NULL, src,
- src_len - byte_counter, 0, 16383);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Decode MAX_HEADER (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
- rc = decode_pcomp_16_bit_field(&params->max_header, NULL, src,
- src_len - byte_counter, 60, 255);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
-
- /* Decode Profiles (see also: 3GPP TS 44.065, 6.5.4.1, Table 10) */
- for (i = 0; i < 16; i++) {
- params->profile_len = 0;
- rc = decode_pcomp_16_bit_field(NULL, &params->profile[i], src,
- src_len - byte_counter, 0,
- 65535);
- if (rc <= 0)
- return byte_counter;
- byte_counter += rc;
- src += rc;
- params->profile_len = i + 1;
- }
-
- /* Return consumed length */
- return byte_counter;
-}
-
-/* Decode V.42bis parameter field
- * (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */
-sta