diff --git a/configure.ac b/configure.ac index e97198528..9b25ab8db 100644 --- a/configure.ac +++ b/configure.ac @@ -44,30 +44,11 @@ PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0) PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.9.5) PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0) -PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4) PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1) PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran) # TODO version? PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= 0.9.5) PKG_CHECK_MODULES(LIBOSMOLEGACYMGCP, libosmo-legacy-mgcp >= 0.0.1) -# Enabke/disable the NAT? -AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])], - [osmo_ac_build_nat="$enableval"],[osmo_ac_build_nat="no"]) -if test "$osmo_ac_build_nat" = "yes" ; then - PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.2) -fi -AM_CONDITIONAL(BUILD_NAT, test "x$osmo_ac_build_nat" = "xyes") -AC_SUBST(osmo_ac_build_nat) - -# Enable/disable the BSC? -AC_ARG_ENABLE([osmo-bsc], [AS_HELP_STRING([--enable-osmo-bsc], [Build the Osmo BSC])], - [osmo_ac_build_bsc="$enableval"],[osmo_ac_build_bsc="no"]) -if test "$osmo_ac_build_bsc" = "yes" ; then - PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.6) -fi -AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes") -AC_SUBST(osmo_ac_build_bsc) - # Enable/disable smpp support in the msc? AC_ARG_ENABLE([smpp], [AS_HELP_STRING([--enable-smpp], [Build the SMPP interface])], [osmo_ac_build_smpp="$enableval"],[osmo_ac_build_smpp="no"]) @@ -105,23 +86,6 @@ fi 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)) @@ -227,40 +191,15 @@ AC_OUTPUT( include/openbsc/Makefile include/Makefile src/Makefile - src/libtrau/Makefile - src/libbsc/Makefile src/libmsc/Makefile src/libvlr/Makefile src/libcommon/Makefile - src/libfilter/Makefile src/libcommon-cs/Makefile src/osmo-msc/Makefile - src/osmo-bsc/Makefile - src/osmo-bsc_nat/Makefile - src/ipaccess/Makefile src/utils/Makefile - src/gprs/Makefile tests/Makefile tests/atlocal - tests/gsm0408/Makefile - tests/channel/Makefile - tests/bsc/Makefile - tests/bsc-nat/Makefile - tests/bsc-nat-trie/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/xid/Makefile - tests/sndcp_xid/Makefile - tests/slhc/Makefile - tests/v42bis/Makefile - tests/nanobts_omlattr/Makefile tests/sms_queue/Makefile tests/msc_vlr/Makefile doc/Makefile 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 - -# 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-bs11-utils.install b/debian/osmocom-bs11-utils.install deleted file mode 100644 index 757a8542b..000000000 --- a/debian/osmocom-bs11-utils.install +++ /dev/null @@ -1,2 +0,0 @@ -/usr/bin/bs11_config -/usr/bin/isdnsync diff --git a/debian/osmocom-bsc-nat.init b/debian/osmocom-bsc-nat.init deleted file mode 100755 index 984a7ce0b..000000000 --- a/debian/osmocom-bsc-nat.init +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/sh -### BEGIN INIT INFO -# Provides: osmocom-bsc-nat -# Required-Start: $network $local_fs -# Required-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Osmocom GSM network-in-a-box -# Description: A minimal implementation of the GSM Base Station Controller, -# Mobile Switching Center, Home Location regster and all other -# components to run a self-contained GSM network. -### END INIT INFO - -# Author: Harald Welte - -# PATH should only include /usr/* if it runs after the mountnfs.sh script -PATH=/sbin:/usr/sbin:/bin:/usr/bin -NAME=osmo-bsc_nat # Introduce the short server's name here -DESC="Osmocom GSM BSC Multiplexer (NAT)" # Introduce a short description here -DAEMON=/usr/bin/osmo-bsc_nat # Introduce the server's location here -SCRIPTNAME=/etc/init.d/osmocom-bsc-nat -CONFIG_FILE=/etc/osmocom/osmocom-bsc-nat.cfg - -# Exit if the package is not installed -[ -x $DAEMON ] || exit 0 - -# Read configuration variable file if it is present -[ -r /etc/default/osmocom-bsc-nat ] && . /etc/default/osmocom-bsc-nat - -# 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-bsc-nat.install b/debian/osmocom-bsc-nat.install deleted file mode 100644 index b561a7e11..000000000 --- a/debian/osmocom-bsc-nat.install +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/osmo-bsc_nat diff --git a/debian/osmocom-bsc.examples b/debian/osmocom-bsc.examples deleted file mode 100644 index a95f12ba3..000000000 --- a/debian/osmocom-bsc.examples +++ /dev/null @@ -1 +0,0 @@ -openbsc/doc/examples/osmo-bsc_mgcp diff --git a/debian/osmocom-bsc.install b/debian/osmocom-bsc.install deleted file mode 100644 index ab9459ecc..000000000 --- a/debian/osmocom-bsc.install +++ /dev/null @@ -1,2 +0,0 @@ -/usr/bin/osmo-bsc_mgcp -/usr/bin/osmo-bsc 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 - -# 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-ipaccess-utils.install b/debian/osmocom-ipaccess-utils.install deleted file mode 100644 index de13c1896..000000000 --- a/debian/osmocom-ipaccess-utils.install +++ /dev/null @@ -1,3 +0,0 @@ -/usr/bin/ipaccess-config -/usr/bin/abisip-find -/usr/bin/ipaccess-proxy 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 - -# 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/doc/BS11-OML.txt b/doc/BS11-OML.txt deleted file mode 100644 index e5c3299c9..000000000 --- a/doc/BS11-OML.txt +++ /dev/null @@ -1,31 +0,0 @@ -The Siemens BS-11 supports the following additional GSM 12.21 OML operations: - - -CREATE OBJECT - -abis_om_fom_hdr.obj_class can be -A3: -A5: ALCO, BBSIG, CCLK, GPSU, LI, PA -A8: EnvaBTSE -A9: BPORT - -the abis_om_obj_inst.trx_nr field indicates the index of object, whereas the -abis_om_fom_hdr.bts_nr indicates the type of the object. - -enum abis_bs11_objtype { - BS11_OBJ_ALCO = 0x01, - BS11_OBJ_BBSIG = 0x02, /* obj_class: 0,1 */ - BS11_OBJ_TRX1 = 0x03, /* only DEACTIVATE TRX1 */ - BS11_OBJ_CCLK = 0x04, - BS11_OBJ_GPSU = 0x06, - BS11_OBJ_LI = 0x07, - BS11_OBJ_PA = 0x09, /* obj_class: 0, 1*/ -}; - -In case of CREATE ENVABTSE, the abis_om_obj_inst.trx_nr indicates the EnvaBTSEx -number. - -In case of A9 (CREAETE BPORT), the abis_om_obj_inst.bts_nr indicates which BPORT -shall be used. - - diff --git a/doc/channel_release.txt b/doc/channel_release.txt deleted file mode 100644 index c9cdfebca..000000000 --- a/doc/channel_release.txt +++ /dev/null @@ -1,95 +0,0 @@ - -GSM 04.08 7.1.7 / 9.1.7 RR CHANNEL RELESE - -RSL 08.58 3.4 / ? RLL Link Release Request - -RSL 08.58 4.6 / 8.4.5 DEACTivate SACCH - * Deactivate SACCH according to Channel Release Proc 04.08 - * to be sent after RR CHANNEL RELEASE is sent to MS - -RSL 08.58 4.7 / 8.4.14 RF CHANnel RELease - * tells the BTS to release a radio channel - * "when an activated radio channel is no longer needed" - * BTS responds with RF CHANnel RELease ACKnowledge - - -GSM 04.08 3.4.13: RR connection release procedure - -* network sends RR CHANNEL RELEASE to MS on the DCCH - * start T3109 - * deactivate SACCH -* MS disconnects main signalling link (by sending DISC) - * all other data links are disconnected by local end link release -* network receives DISC (BTS sends RLL REL IND to BSC) - * stop T3109 - * start T3111 -* when T3111 times out, the network can reuse the channls -* if T3109 times out, the network deactivates the channels - and can reuse them - * this probably means simply RF CHANnel RELease - - -== Implementation in OpenBSC == - -There are two possible reasons a gsm_subscriber_connection -will be released. One is a network failure, the other is -the completion of an operation/transaction. - -=== Failure === -The BSC API will call the gsm_04_08.c:gsm0408_clear_request callback -and the MSC part will release all transactions, operations and such -and the channels will be released as error case. - -=== Success === -Every time an 'operation' or 'transaction' is finished msc_release_connection -will be called and it will determine if the gsm_subscriber_connection can -be released. - -In case it can be released bsc_api.c:gsm0808_clear will be called -which will release all lchan's associated with the connection. For the -primary channel a SACH Deactivate will be send with the release -reason NORMAL RELEASE. - - -bsc_api.c:gsm0808_clear - * Release a channel used for handover - * Release the primary lchan with normal release, SACH deactivate - -chan_alloc.c:lchan_release(chan, sacch_deactivate, reason) - * Start the release procedure. It is working in steps with callbacks - coming from the abis_rsl.c code. - * Release all SAPI's > 0 as local end (The BTS should send a - REL_CONF a message) - * Send SACH Deactivate on SAPI=0 if required. - * Start T3109 (stop it when the main signalling link is disconnected) - or when the channel released. On timeout start the error handling. - * abis_rsl.c schedules the RSL_MT_RF_CHAN_REL once all SAPI's are - released and after T3111 has timed out or there is an error. - -RX of RELease INDication: - * Calls internal rsl_handle_release which might release the RF. - -RX of RELease CONFirmation: - * Calls internal rsl_handle_release which might release the RF. - -* RX of RF_CHAN_REL_ACK - * call lchan_free() - - -=== Integration with SMS === - -* RX of CP_ERROR or unimplemented MT - * trigger trans_free() which will msc_release_connection() - -* CP TC1* expired while waiting for CP-ACK - * trigger trans_free() which will msc_release_connection() - -* RX of RP_ERROR - * trigger trans_free() which will msc_release_connection() - -* TX of CP-ACK in MT DELIVER - * trigger trans_free() which will msc_release_connection() - -* RX of CP-ACK in MO SUBMIT - * trigger trans_free() which will msc_release_connection() - diff --git a/doc/examples/osmo-bsc/osmo-bsc.cfg b/doc/examples/osmo-bsc/osmo-bsc.cfg deleted file mode 100644 index 7c10e9dea..000000000 --- a/doc/examples/osmo-bsc/osmo-bsc.cfg +++ /dev/null @@ -1,101 +0,0 @@ -! -! OsmoBSC (0.9.14+gitr1+3d331c0062bb0c9694dbd4d1eab7adc58138c3ae) configuration saved from vty -!! -password foo -! -! -line vty - no login -! -e1_input - e1_line 0 driver ipa -network - network country code 1 - mobile network code 1 - short name OsmoBSC - long name OsmoBSC - auth policy closed - location updating reject cause 13 - encryption a5 0 - neci 1 - paging any use tch 0 - rrlp mode none - mm info 1 - handover 0 - handover window rxlev averaging 10 - handover window rxqual averaging 1 - handover window rxlev neighbor averaging 10 - handover power budget interval 6 - handover power budget hysteresis 3 - handover maximum distance 9999 - bts 0 - type nanobts - band DCS1800 - cell_identity 0 - location_area_code 1 - training_sequence_code 7 - base_station_id_code 63 - ms max power 15 - cell reselection hysteresis 4 - rxlev access min 0 - channel allocator ascending - rach tx integer 9 - rach max transmission 7 - dtx uplink force - dtx downlink - ip.access unit_id 0 0 - oml ip.access stream_id 255 line 0 - neighbor-list mode manual-si5 - neighbor-list add arfcn 100 - neighbor-list add arfcn 200 - si5 neighbor-list add arfcn 10 - si5 neighbor-list add arfcn 20 - gprs mode none - trx 0 - rf_locked 0 - arfcn 871 - nominal power 23 - max_power_red 20 - rsl e1 tei 0 - timeslot 0 - phys_chan_config CCCH+SDCCH4 - hopping enabled 0 - timeslot 1 - phys_chan_config TCH/F - hopping enabled 0 - timeslot 2 - phys_chan_config TCH/F - hopping enabled 0 - timeslot 3 - phys_chan_config TCH/F - hopping enabled 0 - timeslot 4 - phys_chan_config TCH/F - hopping enabled 0 - timeslot 5 - phys_chan_config TCH/F - hopping enabled 0 - timeslot 6 - phys_chan_config TCH/F - hopping enabled 0 - timeslot 7 - phys_chan_config TCH/F - hopping enabled 0 -cs7 instance 1 - point-code 3.0.0 - sccp-address bsc_local - point-code 3.0.0 - sccp-address msc_remote - point-code 1.0.0 -msc - bsc-addr bsc_local - msc-addr msc_remote - ip.access rtp-base 4000 - timeout-ping 20 - timeout-pong 5 - dest 192.168.100.11 6666 0 - access-list-name msc-list - no access-list-name -bsc - no access-list-name - access-list-name bsc-list diff --git a/doc/examples/osmo-bsc_mgcp/mgcp.cfg b/doc/examples/osmo-bsc_mgcp/mgcp.cfg deleted file mode 100644 index 3c43f1feb..000000000 --- a/doc/examples/osmo-bsc_mgcp/mgcp.cfg +++ /dev/null @@ -1,19 +0,0 @@ -! -! MGCP configuration hand edited -! ! -password foo -! -line vty - no login -! -mgcp - !local ip 10.23.24.2 - !bts ip 10.24.24.1 - !bind ip 10.23.24.1 - bind port 2427 - rtp base 4000 - rtp force-ptime 20 - sdp audio payload number 98 - sdp audio payload name AMR/8000 - number endpoints 31 - no rtcp-omit diff --git a/doc/examples/osmo-bsc_nat/black-list.cfg b/doc/examples/osmo-bsc_nat/black-list.cfg deleted file mode 100644 index d36179d37..000000000 --- a/doc/examples/osmo-bsc_nat/black-list.cfg +++ /dev/null @@ -1 +0,0 @@ -678012512671923:6:6: diff --git a/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg b/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg deleted file mode 100644 index e835e068a..000000000 --- a/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg +++ /dev/null @@ -1,66 +0,0 @@ -! -! OsmoBSCNAT (0.12.0.266-2daa9) configuration saved from vty -!! -! -log stderr - logging filter all 1 - logging color 1 - logging timestamp 0 - logging level all debug - logging level rll notice - logging level cc notice - logging level mm notice - logging level rr notice - logging level rsl notice - logging level nm info - logging level mncc notice - logging level pag notice - logging level meas notice - logging level sccp notice - logging level msc notice - logging level mgcp notice - logging level ho notice - logging level db notice - logging level ref notice - logging level gprs debug - logging level ns info - logging level bssgp debug - logging level llc debug - logging level sndcp debug - logging level nat notice - logging level ctrl notice - logging level smpp 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 -! -mgcp - bind ip 0.0.0.0 - bind port 2427 - rtp bts-base 4000 - rtp net-base 16000 - rtp ip-dscp 0 - no rtcp-omit - sdp audio-payload number 126 - sdp audio-payload name AMR/8000 - loop 0 - number endpoints 1 - call-agent ip 127.0.0.1 - rtp transcoder-base 0 - transcoder-remote-base 4000 -nat - msc ip 127.0.0.1 - msc port 5000 - timeout auth 2 - timeout ping 20 - timeout pong 5 - ip-dscp 0 - bscs-config-file bscs.cfg - access-list bla imsi-allow ^11$ diff --git a/doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg b/doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg deleted file mode 100644 index 15fd74a2b..000000000 --- a/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/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg b/doc/examples/osmo-gbproxy/osmo-gbproxy.cfg deleted file mode 100644 index 0c3917a3e..000000000 --- a/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/doc/examples/osmo-gtphub/gtphub-example.txt b/doc/examples/osmo-gtphub/gtphub-example.txt deleted file mode 100644 index 9c65f925f..000000000 --- a/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 - LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/ggsn -f -c ./ggsn.conf - -2. GTPHub: - - cd - path/to/openbsc/openbsc/src/gprs/osmo-gtphub -c gtphub.conf #-e 1 #for DEBUG level - -3. SGSN tests: - - sudo -s - cd - /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/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg b/doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg deleted file mode 100644 index 3913d2c3c..000000000 --- a/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/doc/examples/osmo-gtphub/osmo-gtphub.cfg b/doc/examples/osmo-gtphub/osmo-gtphub.cfg deleted file mode 100644 index 0dc415047..000000000 --- a/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/doc/examples/osmo-sgsn/osmo-sgsn.cfg b/doc/examples/osmo-sgsn/osmo-sgsn.cfg deleted file mode 100644 index 06f035f1b..000000000 --- a/doc/examples/osmo-sgsn/osmo-sgsn.cfg +++ /dev/null @@ -1,29 +0,0 @@ -! -! Osmocom SGSN configuration -! -! -line vty - no login -! -sgsn - gtp local-ip 127.0.0.1 - ggsn 0 remote-ip 127.0.0.2 - ggsn 0 gtp-version 1 - auth-policy remote - gsup remote-ip 127.0.0.1 - gsup remote-port 4222 -! -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/doc/oml-interface.txt b/doc/oml-interface.txt deleted file mode 100644 index 02bead77a..000000000 --- a/doc/oml-interface.txt +++ /dev/null @@ -1,22 +0,0 @@ -oml interface design notes - -problems: - -* there is no way how to tag a command sent to the BTS, with the response - having the same tag to identify the originator of the command -* therefore, we can have e.g. both the BSC and the OML interface send a - SET ATTRIBUTE message, where the responses would end up at the wrong - query. -* The BTS has 10s to ACK/NACK a command. We do not run any timers. - -the only possible solutions i can imagine: -* have some kind of exclusive locking, where the OML interface gets blocked - from the BSC and is exclusively assigned to the OML console until all commands - of the OML console have terminated. This can either be done explicitly - dynamically or on demand - -* use the OML interface synchronously, i.e. always wait for the response from - the BTS before - -* unilateral / unsolicited messages need to be broadcasted to both the BSC and - the OML console diff --git a/include/Makefile.am b/include/Makefile.am index 3234e6265..677eec3aa 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,8 +1,3 @@ SUBDIRS = \ openbsc \ $(NULL) - -noinst_HEADERS = \ - mISDNif.h \ - compat_af_isdn.h \ - $(NULL) diff --git a/include/compat_af_isdn.h b/include/compat_af_isdn.h deleted file mode 100644 index 56cbfb3f2..000000000 --- a/include/compat_af_isdn.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifdef MISDN_OLD_AF_COMPATIBILITY -#undef AF_ISDN -#undef PF_ISDN - -extern int AF_ISDN; -#define PF_ISDN AF_ISDN - -int AF_ISDN; - -#endif - -extern void init_af_isdn(void); - -#ifdef AF_COMPATIBILITY_FUNC -#ifdef MISDN_OLD_AF_COMPATIBILITY -void init_af_isdn(void) -{ - int s; - - /* test for new value */ - AF_ISDN = 34; - s = socket(AF_ISDN, SOCK_RAW, ISDN_P_BASE); - if (s >= 0) { - close(s); - return; - } - AF_ISDN = 27; - s = socket(AF_ISDN, SOCK_RAW, ISDN_P_BASE); - if (s >= 0) { - close(s); - return; - } -} -#else -void init_af_isdn(void) -{ -} -#endif -#endif diff --git a/include/mISDNif.h b/include/mISDNif.h deleted file mode 100644 index 8e065d24b..000000000 --- a/include/mISDNif.h +++ /dev/null @@ -1,387 +0,0 @@ -/* - * - * Author Karsten Keil - * - * Copyright 2008 by Karsten Keil - * - * This code 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 code 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. - * - */ - -#ifndef mISDNIF_H -#define mISDNIF_H - -#include -#ifdef linux -#include -#include -#include -#else -#include -#include -#include -#endif - -/* - * ABI Version 32 bit - * - * <8 bit> Major version - * - changed if any interface become backwards incompatible - * - * <8 bit> Minor version - * - changed if any interface is extended but backwards compatible - * - * <16 bit> Release number - * - should be incremented on every checkin - */ -#define MISDN_MAJOR_VERSION 1 -#define MISDN_MINOR_VERSION 1 -#define MISDN_RELEASE 20 - -/* primitives for information exchange - * generell format - * <16 bit 0 > - * <8 bit command> - * BIT 8 = 1 LAYER private - * BIT 7 = 1 answer - * BIT 6 = 1 DATA - * <8 bit target layer mask> - * - * Layer = 00 is reserved for general commands - Layer = 01 L2 -> HW - Layer = 02 HW -> L2 - Layer = 04 L3 -> L2 - Layer = 08 L2 -> L3 - * Layer = FF is reserved for broadcast commands - */ - -#define MISDN_CMDMASK 0xff00 -#define MISDN_LAYERMASK 0x00ff - -/* generell commands */ -#define OPEN_CHANNEL 0x0100 -#define CLOSE_CHANNEL 0x0200 -#define CONTROL_CHANNEL 0x0300 -#define CHECK_DATA 0x0400 - -/* layer 2 -> layer 1 */ -#define PH_ACTIVATE_REQ 0x0101 -#define PH_DEACTIVATE_REQ 0x0201 -#define PH_DATA_REQ 0x2001 -#define MPH_ACTIVATE_REQ 0x0501 -#define MPH_DEACTIVATE_REQ 0x0601 -#define MPH_INFORMATION_REQ 0x0701 -#define PH_CONTROL_REQ 0x0801 - -/* layer 1 -> layer 2 */ -#define PH_ACTIVATE_IND 0x0102 -#define PH_ACTIVATE_CNF 0x4102 -#define PH_DEACTIVATE_IND 0x0202 -#define PH_DEACTIVATE_CNF 0x4202 -#define PH_DATA_IND 0x2002 -#define PH_DATA_E_IND 0x3002 -#define MPH_ACTIVATE_IND 0x0502 -#define MPH_DEACTIVATE_IND 0x0602 -#define MPH_INFORMATION_IND 0x0702 -#define PH_DATA_CNF 0x6002 -#define PH_CONTROL_IND 0x0802 -#define PH_CONTROL_CNF 0x4802 - -/* layer 3 -> layer 2 */ -#define DL_ESTABLISH_REQ 0x1004 -#define DL_RELEASE_REQ 0x1104 -#define DL_DATA_REQ 0x3004 -#define DL_UNITDATA_REQ 0x3104 -#define DL_INFORMATION_REQ 0x0004 - -/* layer 2 -> layer 3 */ -#define DL_ESTABLISH_IND 0x1008 -#define DL_ESTABLISH_CNF 0x5008 -#define DL_RELEASE_IND 0x1108 -#define DL_RELEASE_CNF 0x5108 -#define DL_DATA_IND 0x3008 -#define DL_UNITDATA_IND 0x3108 -#define DL_INFORMATION_IND 0x0008 - -/* intern layer 2 managment */ -#define MDL_ASSIGN_REQ 0x1804 -#define MDL_ASSIGN_IND 0x1904 -#define MDL_REMOVE_REQ 0x1A04 -#define MDL_REMOVE_IND 0x1B04 -#define MDL_STATUS_UP_IND 0x1C04 -#define MDL_STATUS_DOWN_IND 0x1D04 -#define MDL_STATUS_UI_IND 0x1E04 -#define MDL_ERROR_IND 0x1F04 -#define MDL_ERROR_RSP 0x5F04 - -/* DL_INFORMATION_IND types */ -#define DL_INFO_L2_CONNECT 0x0001 -#define DL_INFO_L2_REMOVED 0x0002 - -/* PH_CONTROL types */ -/* TOUCH TONE IS 0x20XX XX "0"..."9", "A","B","C","D","*","#" */ -#define DTMF_TONE_VAL 0x2000 -#define DTMF_TONE_MASK 0x007F -#define DTMF_TONE_START 0x2100 -#define DTMF_TONE_STOP 0x2200 -#define DTMF_HFC_COEF 0x4000 -#define DSP_CONF_JOIN 0x2403 -#define DSP_CONF_SPLIT 0x2404 -#define DSP_RECEIVE_OFF 0x2405 -#define DSP_RECEIVE_ON 0x2406 -#define DSP_ECHO_ON 0x2407 -#define DSP_ECHO_OFF 0x2408 -#define DSP_MIX_ON 0x2409 -#define DSP_MIX_OFF 0x240a -#define DSP_DELAY 0x240b -#define DSP_JITTER 0x240c -#define DSP_TXDATA_ON 0x240d -#define DSP_TXDATA_OFF 0x240e -#define DSP_TX_DEJITTER 0x240f -#define DSP_TX_DEJ_OFF 0x2410 -#define DSP_TONE_PATT_ON 0x2411 -#define DSP_TONE_PATT_OFF 0x2412 -#define DSP_VOL_CHANGE_TX 0x2413 -#define DSP_VOL_CHANGE_RX 0x2414 -#define DSP_BF_ENABLE_KEY 0x2415 -#define DSP_BF_DISABLE 0x2416 -#define DSP_BF_ACCEPT 0x2416 -#define DSP_BF_REJECT 0x2417 -#define DSP_PIPELINE_CFG 0x2418 -#define HFC_VOL_CHANGE_TX 0x2601 -#define HFC_VOL_CHANGE_RX 0x2602 -#define HFC_SPL_LOOP_ON 0x2603 -#define HFC_SPL_LOOP_OFF 0x2604 - -/* DSP_TONE_PATT_ON parameter */ -#define TONE_OFF 0x0000 -#define TONE_GERMAN_DIALTONE 0x0001 -#define TONE_GERMAN_OLDDIALTONE 0x0002 -#define TONE_AMERICAN_DIALTONE 0x0003 -#define TONE_GERMAN_DIALPBX 0x0004 -#define TONE_GERMAN_OLDDIALPBX 0x0005 -#define TONE_AMERICAN_DIALPBX 0x0006 -#define TONE_GERMAN_RINGING 0x0007 -#define TONE_GERMAN_OLDRINGING 0x0008 -#define TONE_AMERICAN_RINGPBX 0x000b -#define TONE_GERMAN_RINGPBX 0x000c -#define TONE_GERMAN_OLDRINGPBX 0x000d -#define TONE_AMERICAN_RINGING 0x000e -#define TONE_GERMAN_BUSY 0x000f -#define TONE_GERMAN_OLDBUSY 0x0010 -#define TONE_AMERICAN_BUSY 0x0011 -#define TONE_GERMAN_HANGUP 0x0012 -#define TONE_GERMAN_OLDHANGUP 0x0013 -#define TONE_AMERICAN_HANGUP 0x0014 -#define TONE_SPECIAL_INFO 0x0015 -#define TONE_GERMAN_GASSENBESETZT 0x0016 -#define TONE_GERMAN_AUFSCHALTTON 0x0016 - -/* MPH_INFORMATION_IND */ -#define L1_SIGNAL_LOS_OFF 0x0010 -#define L1_SIGNAL_LOS_ON 0x0011 -#define L1_SIGNAL_AIS_OFF 0x0012 -#define L1_SIGNAL_AIS_ON 0x0013 -#define L1_SIGNAL_RDI_OFF 0x0014 -#define L1_SIGNAL_RDI_ON 0x0015 -#define L1_SIGNAL_SLIP_RX 0x0020 -#define L1_SIGNAL_SLIP_TX 0x0021 - -/* - * protocol ids - * D channel 1-31 - * B channel 33 - 63 - */ - -#define ISDN_P_NONE 0 -#define ISDN_P_BASE 0 -#define ISDN_P_TE_S0 0x01 -#define ISDN_P_NT_S0 0x02 -#define ISDN_P_TE_E1 0x03 -#define ISDN_P_NT_E1 0x04 -#define ISDN_P_TE_UP0 0x05 -#define ISDN_P_NT_UP0 0x06 - -#define IS_ISDN_P_TE(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_TE_E1) || \ - (p == ISDN_P_TE_UP0) || (p == ISDN_P_LAPD_TE)) -#define IS_ISDN_P_NT(p) ((p == ISDN_P_NT_S0) || (p == ISDN_P_NT_E1) || \ - (p == ISDN_P_NT_UP0) || (p == ISDN_P_LAPD_NT)) -#define IS_ISDN_P_S0(p) ((p == ISDN_P_TE_S0) || (p == ISDN_P_NT_S0)) -#define IS_ISDN_P_E1(p) ((p == ISDN_P_TE_E1) || (p == ISDN_P_NT_E1)) -#define IS_ISDN_P_UP0(p) ((p == ISDN_P_TE_UP0) || (p == ISDN_P_NT_UP0)) - - -#define ISDN_P_LAPD_TE 0x10 -#define ISDN_P_LAPD_NT 0x11 - -#define ISDN_P_B_MASK 0x1f -#define ISDN_P_B_START 0x20 - -#define ISDN_P_B_RAW 0x21 -#define ISDN_P_B_HDLC 0x22 -#define ISDN_P_B_X75SLP 0x23 -#define ISDN_P_B_L2DTMF 0x24 -#define ISDN_P_B_L2DSP 0x25 -#define ISDN_P_B_L2DSPHDLC 0x26 - -#define OPTION_L2_PMX 1 -#define OPTION_L2_PTP 2 -#define OPTION_L2_FIXEDTEI 3 -#define OPTION_L2_CLEANUP 4 - -/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ -#define MISDN_MAX_IDLEN 20 - -struct mISDNhead { - unsigned int prim; - unsigned int id; -} __attribute__((packed)); - -#define MISDN_HEADER_LEN sizeof(struct mISDNhead) -#define MAX_DATA_SIZE 2048 -#define MAX_DATA_MEM (MAX_DATA_SIZE + MISDN_HEADER_LEN) -#define MAX_DFRAME_LEN 260 - -#define MISDN_ID_ADDR_MASK 0xFFFF -#define MISDN_ID_TEI_MASK 0xFF00 -#define MISDN_ID_SAPI_MASK 0x00FF -#define MISDN_ID_TEI_ANY 0x7F00 - -#define MISDN_ID_ANY 0xFFFF -#define MISDN_ID_NONE 0xFFFE - -#define GROUP_TEI 127 -#define TEI_SAPI 63 -#define CTRL_SAPI 0 - -#define MISDN_MAX_CHANNEL 127 -#define MISDN_CHMAP_SIZE ((MISDN_MAX_CHANNEL + 1) >> 3) - -#define SOL_MISDN 0 - -struct sockaddr_mISDN { - sa_family_t family; - unsigned char dev; - unsigned char channel; - unsigned char sapi; - unsigned char tei; -}; - -struct mISDNversion { - unsigned char major; - unsigned char minor; - unsigned short release; -}; - -#define MAX_DEVICE_ID 63 - -struct mISDN_devinfo { - u_int id; - u_int Dprotocols; - u_int Bprotocols; - u_int protocol; - u_char channelmap[MISDN_CHMAP_SIZE]; - u_int nrbchan; - char name[MISDN_MAX_IDLEN]; -}; - -struct mISDN_devrename { - u_int id; - char name[MISDN_MAX_IDLEN]; -}; - -struct ph_info_ch { - int32_t protocol; - int64_t Flags; -}; - -struct ph_info_dch { - struct ph_info_ch ch; - int16_t state; - int16_t num_bch; -}; - -struct ph_info { - struct ph_info_dch dch; - struct ph_info_ch bch[]; -}; - -/* timer device ioctl */ -#define IMADDTIMER _IOR('I', 64, int) -#define IMDELTIMER _IOR('I', 65, int) -/* socket ioctls */ -#define IMGETVERSION _IOR('I', 66, int) -#define IMGETCOUNT _IOR('I', 67, int) -#define IMGETDEVINFO _IOR('I', 68, int) -#define IMCTRLREQ _IOR('I', 69, int) -#define IMCLEAR_L2 _IOR('I', 70, int) -#define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename) - -static inline int -test_channelmap(u_int nr, u_char *map) -{ - if (nr <= MISDN_MAX_CHANNEL) - return map[nr >> 3] & (1 << (nr & 7)); - else - return 0; -} - -static inline void -set_channelmap(u_int nr, u_char *map) -{ - map[nr >> 3] |= (1 << (nr & 7)); -} - -static inline void -clear_channelmap(u_int nr, u_char *map) -{ - map[nr >> 3] &= ~(1 << (nr & 7)); -} - -/* CONTROL_CHANNEL parameters */ -#define MISDN_CTRL_GETOP 0x0000 -#define MISDN_CTRL_LOOP 0x0001 -#define MISDN_CTRL_CONNECT 0x0002 -#define MISDN_CTRL_DISCONNECT 0x0004 -#define MISDN_CTRL_PCMCONNECT 0x0010 -#define MISDN_CTRL_PCMDISCONNECT 0x0020 -#define MISDN_CTRL_SETPEER 0x0040 -#define MISDN_CTRL_UNSETPEER 0x0080 -#define MISDN_CTRL_RX_OFF 0x0100 -#define MISDN_CTRL_FILL_EMPTY 0x0200 -#define MISDN_CTRL_GETPEER 0x0400 -#define MISDN_CTRL_HW_FEATURES_OP 0x2000 -#define MISDN_CTRL_HW_FEATURES 0x2001 -#define MISDN_CTRL_HFC_OP 0x4000 -#define MISDN_CTRL_HFC_PCM_CONN 0x4001 -#define MISDN_CTRL_HFC_PCM_DISC 0x4002 -#define MISDN_CTRL_HFC_CONF_JOIN 0x4003 -#define MISDN_CTRL_HFC_CONF_SPLIT 0x4004 -#define MISDN_CTRL_HFC_RECEIVE_OFF 0x4005 -#define MISDN_CTRL_HFC_RECEIVE_ON 0x4006 -#define MISDN_CTRL_HFC_ECHOCAN_ON 0x4007 -#define MISDN_CTRL_HFC_ECHOCAN_OFF 0x4008 - - -/* socket options */ -#define MISDN_TIME_STAMP 0x0001 - -struct mISDN_ctrl_req { - int op; - int channel; - int p1; - int p2; -}; - -/* muxer options */ -#define MISDN_OPT_ALL 1 -#define MISDN_OPT_TEIMGR 2 - -#endif /* mISDNIF_H */ diff --git a/include/openbsc/Makefile.am b/include/openbsc/Makefile.am index c1cb6a3fb..6e7aa384b 100644 --- a/include/openbsc/Makefile.am +++ b/include/openbsc/Makefile.am @@ -8,11 +8,7 @@ noinst_HEADERS = \ auth.h \ bsc_msc.h \ bsc_msg_filter.h \ - bsc_nat.h \ - bsc_nat_callstats.h \ - bsc_nat_sccp.h \ bsc_rll.h \ - bsc_subscriber.h \ bss.h \ bts_ipaccess_nanobts_omlattr.h \ chan_alloc.h \ @@ -24,19 +20,6 @@ noinst_HEADERS = \ 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 \ @@ -45,7 +28,6 @@ noinst_HEADERS = \ gsm_data_shared.h \ gsm_subscriber.h \ gsup_client.h \ - gtphub.h \ handover.h \ handover_decision.h \ ipaccess.h \ @@ -58,7 +40,6 @@ noinst_HEADERS = \ mncc.h \ mncc_int.h \ msc_ifaces.h \ - nat_rewrite_trie.h \ network_listen.h \ oap_client.h \ openbscdefines.h \ @@ -71,13 +52,10 @@ noinst_HEADERS = \ bsc_msc_data.h \ osmux.h \ paging.h \ - pcu_if.h \ - pcuif_proto.h \ rest_octets.h \ rrlp.h \ rs232.h \ rtp_proxy.h \ - sgsn.h \ signal.h \ silent_call.h \ slhc.h \ @@ -91,8 +69,6 @@ noinst_HEADERS = \ ussd.h \ vlr.h \ vty.h \ - v42bis.h \ - v42bis_private.h \ $(NULL) openbsc_HEADERS = \ diff --git a/include/openbsc/bsc_nat.h b/include/openbsc/bsc_nat.h deleted file mode 100644 index 452daf2ab..000000000 --- a/include/openbsc/bsc_nat.h +++ /dev/null @@ -1,462 +0,0 @@ -/* - * (C) 2010-2012 by Holger Hans Peter Freyther - * (C) 2010-2012 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 . - * - */ - -#ifndef BSC_NAT_H -#define BSC_NAT_H - -#include - -#include "bsc_msg_filter.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define DIR_BSC 1 -#define DIR_MSC 2 - -#define PAGIN_GROUP_UNASSIGNED -1 - -struct sccp_source_reference; -struct nat_sccp_connection; -struct bsc_nat_parsed; -struct bsc_nat; -struct bsc_nat_ussd_con; -struct nat_rewrite_rule; - -/* - * Is this terminated to the MSC, to the local machine (release - * handling for IMSI filtering) or to a USSD provider? - */ -enum { - NAT_CON_END_MSC, - NAT_CON_END_LOCAL, - NAT_CON_END_USSD, -}; - -/* - * Pending command entry - */ -struct bsc_cmd_list { - struct llist_head list_entry; - - struct osmo_timer_list timeout; - - /* The NATed ID used on the bsc_con*/ - int nat_id; - - /* The control connection from which the command originated */ - struct ctrl_connection *ccon; - - /* The command from the control connection */ - struct ctrl_cmd *cmd; -}; - -/* - * Per BSC data structure - */ -struct bsc_connection { - struct llist_head list_entry; - - /* do we know anything about this BSC? */ - int authenticated; - uint8_t last_rand[16]; - - /* the fd we use to communicate */ - struct osmo_wqueue write_queue; - - /* incoming message buffer */ - struct msgb *pending_msg; - - /* the BSS associated */ - struct bsc_config *cfg; - - /* a timeout node */ - struct osmo_timer_list id_timeout; - - /* pong timeout */ - struct osmo_timer_list ping_timeout; - struct osmo_timer_list pong_timeout; - - /* mgcp related code */ - char *_endpoint_status; - int number_multiplexes; - int max_endpoints; - int last_endpoint; - int next_transaction; - uint32_t pending_dlcx_count; - struct llist_head pending_dlcx; - - /* track the pending commands for this BSC */ - struct llist_head cmd_pending; - int last_id; - - /* a back pointer */ - struct bsc_nat *nat; -}; - -/** - * Stats per BSC - */ -struct bsc_config_stats { - struct rate_ctr_group *ctrg; -}; - -enum bsc_cfg_ctr { - BCFG_CTR_SCCP_CONN, - BCFG_CTR_SCCP_CALLS, - BCFG_CTR_NET_RECONN, - BCFG_CTR_DROPPED_SCCP, - BCFG_CTR_DROPPED_CALLS, - BCFG_CTR_REJECTED_CR, - BCFG_CTR_REJECTED_MSG, - BCFG_CTR_ILL_PACKET, - BCFG_CTR_CON_TYPE_LU, - BCFG_CTR_CON_CMSERV_RQ, - BCFG_CTR_CON_PAG_RESP, - BCFG_CTR_CON_SSA, - BCFG_CTR_CON_OTHER, -}; - -/** - * One BSC entry in the config - */ -struct bsc_config { - struct llist_head entry; - - uint8_t key[16]; - uint8_t key_present; - char *token; - int nr; - - char *description; - - /* imsi white and blacklist */ - char *acc_lst_name; - - int forbid_paging; - int paging_group; - - /* audio handling */ - int max_endpoints; - - /* used internally for reload handling */ - bool remove; - bool token_updated; - - /* backpointer */ - struct bsc_nat *nat; - - struct bsc_config_stats stats; - - struct llist_head lac_list; - - /* Osmux is enabled/disabled per BSC */ - int osmux; -}; - -struct bsc_lac_entry { - struct llist_head entry; - uint16_t lac; -}; - -struct bsc_nat_paging_group { - struct llist_head entry; - - /* list of lac entries */ - struct llist_head lists; - int nr; -}; - -/** - * BSCs point of view of endpoints - */ -struct bsc_endpoint { - /* the operation that is carried out */ - int transaction_state; - /* the pending transaction id */ - char *transaction_id; - /* the bsc we are talking to */ - struct bsc_connection *bsc; -}; - -/** - * Statistic for the nat. - */ -struct bsc_nat_statistics { - struct { - struct osmo_counter *conn; - struct osmo_counter *calls; - } sccp; - - struct { - struct osmo_counter *reconn; - struct osmo_counter *auth_fail; - } bsc; - - struct { - struct osmo_counter *reconn; - } msc; - - struct { - struct osmo_counter *reconn; - } ussd; -}; - -/** - * the structure of the "nat" network - */ -struct bsc_nat { - /* active SCCP connections that need patching */ - struct llist_head sccp_connections; - - /* active BSC connections that need patching */ - struct llist_head bsc_connections; - - /* access lists */ - struct llist_head access_lists; - - /* paging groups */ - struct llist_head paging_groups; - - /* known BSC's */ - struct llist_head bsc_configs; - int num_bsc; - int bsc_ip_dscp; - - /* MGCP config */ - struct mgcp_config *mgcp_cfg; - uint8_t mgcp_msg[4096]; - int mgcp_length; - int mgcp_ipa; - int sdp_ensure_amr_mode_set; - - /* msc things */ - struct llist_head dests; - struct bsc_msc_dest *main_dest; - struct bsc_msc_connection *msc_con; - char *token; - - /* timeouts */ - int auth_timeout; - int ping_timeout; - int pong_timeout; - - struct bsc_endpoint *bsc_endpoints; - - /* path to file with BSC config */ - char *include_file; - char *include_base; - char *resolved_path; - - /* filter */ - char *acc_lst_name; - - /* Barring of subscribers with a rb tree */ - struct rb_root imsi_black_list; - char *imsi_black_list_fn; - - /* number rewriting */ - char *num_rewr_name; - struct llist_head num_rewr; - char *num_rewr_post_name; - struct llist_head num_rewr_post; - - char *smsc_rewr_name; - struct llist_head smsc_rewr; - char *tpdest_match_name; - struct llist_head tpdest_match; - char *sms_clear_tp_srr_name; - struct llist_head sms_clear_tp_srr; - char *sms_num_rewr_name; - struct llist_head sms_num_rewr; - - /* more rewriting */ - char *num_rewr_trie_name; - struct nat_rewrite *num_rewr_trie; - - /* USSD messages we want to match */ - char *ussd_lst_name; - char *ussd_query; - regex_t ussd_query_re; - char *ussd_token; - char *ussd_local; - struct osmo_fd ussd_listen; - struct bsc_nat_ussd_con *ussd_con; - - /* for maintainenance */ - int blocked; - - /* statistics */ - struct bsc_nat_statistics stats; - - /* control interface */ - struct ctrl_handle *ctrl; -}; - -struct bsc_nat_ussd_con { - struct osmo_wqueue queue; - struct bsc_nat *nat; - int authorized; - - struct msgb *pending_msg; - - struct osmo_timer_list auth_timeout; -}; - -/* create and init the structures */ -struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, - unsigned int number); -struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num); -struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len); -void bsc_config_free(struct bsc_config *); -void bsc_config_add_lac(struct bsc_config *cfg, int lac); -void bsc_config_del_lac(struct bsc_config *cfg, int lac); -int bsc_config_handles_lac(struct bsc_config *cfg, int lac); - -struct bsc_nat *bsc_nat_alloc(void); -struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat); -void bsc_nat_set_msc_ip(struct bsc_nat *bsc, const char *ip); - -void sccp_connection_destroy(struct nat_sccp_connection *); -void bsc_close_connection(struct bsc_connection *); - -const char *bsc_con_type_to_string(int type); - -/** - * parse the given message into the above structure - */ -struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg); - -/** - * filter based on IP Access header in both directions - */ -int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *parsed); -int bsc_nat_vty_init(struct bsc_nat *nat); -int bsc_nat_find_paging(struct msgb *msg, const uint8_t **,int *len); - -/** - * SCCP patching and handling - */ -struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed); -int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed); -void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed); -struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *); -struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_connection *); -struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *, struct sccp_source_reference *); - -/** - * MGCP/Audio handling - */ -int bsc_mgcp_nr_multiplexes(int max_endpoints); -int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length); -int bsc_mgcp_assign_patch(struct nat_sccp_connection *, struct msgb *msg); -void bsc_mgcp_init(struct nat_sccp_connection *); -void bsc_mgcp_dlcx(struct nat_sccp_connection *); -void bsc_mgcp_free_endpoints(struct bsc_nat *nat); -int bsc_mgcp_nat_init(struct bsc_nat *nat); - -struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number); -struct msgb *bsc_mgcp_rewrite(char *input, int length, int endp, const char *ip, - int port, int osmux, int *first_payload_type, int mode_set); -void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg); - -void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc); -int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]); -uint32_t bsc_mgcp_extract_ci(const char *resp); - - -int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id); -int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int id); -int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg); -int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg); - -int bsc_nat_msc_is_connected(struct bsc_nat *nat); - -int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn); - -struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, struct msgb *msg, uint32_t *len); - -/** USSD filtering */ -int bsc_ussd_init(struct bsc_nat *nat); -int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, struct msgb *msg); -int bsc_ussd_close_connections(struct bsc_nat *nat); - -struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *, const char *imsi); - -/** paging group handling */ -struct bsc_nat_paging_group *bsc_nat_paging_group_num(struct bsc_nat *nat, int group); -struct bsc_nat_paging_group *bsc_nat_paging_group_create(struct bsc_nat *nat, int group); -void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *); -void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *grp, int lac); -void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *grp, int lac); - -/** - * Number rewriting support below - */ -struct bsc_nat_num_rewr_entry { - struct llist_head list; - - regex_t msisdn_reg; - regex_t num_reg; - - char *replace; - uint8_t is_prefix_lookup; -}; - -void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const struct osmo_config_list *); - -void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg); -void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg); - -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, - const char *bind_addr, int port); -void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending); -int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg); - -int bsc_nat_extract_lac(struct bsc_connection *bsc, struct nat_sccp_connection *con, - struct bsc_nat_parsed *parsed, struct msgb *msg); - -int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, - struct bsc_nat_parsed *, int *con_type, char **imsi, - struct bsc_filter_reject_cause *cause); -int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, - struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct bsc_filter_reject_cause *cause); - -/** - * CTRL interface helper - */ -void bsc_nat_inform_reject(struct bsc_connection *bsc, const char *imsi); - -/* - * Use for testing - */ -void bsc_nat_free(struct bsc_nat *nat); - -#endif diff --git a/include/openbsc/bsc_nat_callstats.h b/include/openbsc/bsc_nat_callstats.h deleted file mode 100644 index 64f9bfc0a..000000000 --- a/include/openbsc/bsc_nat_callstats.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) 2010-2012 by Holger Hans Peter Freyther - * (C) 2010-2012 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 . - * - */ - -#ifndef BSC_NAT_CALLSTATS_H -#define BSC_NAT_CALLSTATS_H - -#include - -#include - -struct bsc_nat_call_stats { - struct llist_head entry; - - struct sccp_source_reference remote_ref; - struct sccp_source_reference src_ref; /* as seen by the MSC */ - - /* mgcp options */ - uint32_t ci; - int bts_rtp_port; - int net_rtp_port; - struct in_addr bts_addr; - struct in_addr net_addr; - - - /* as witnessed by the NAT */ - uint32_t net_ps; - uint32_t net_os; - uint32_t bts_pr; - uint32_t bts_or; - uint32_t bts_expected; - uint32_t bts_jitter; - int bts_loss; - - uint32_t trans_id; - int msc_endpoint; -}; - -#endif diff --git a/include/openbsc/bsc_nat_sccp.h b/include/openbsc/bsc_nat_sccp.h deleted file mode 100644 index 082466408..000000000 --- a/include/openbsc/bsc_nat_sccp.h +++ /dev/null @@ -1,105 +0,0 @@ -/* NAT utilities using SCCP types */ -/* - * (C) 2010 by Holger Hans Peter Freyther - * (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 . - * - */ - -#ifndef BSC_NAT_SCCP_H -#define BSC_NAT_SCCP_H - -#include "bsc_msg_filter.h" - -#include - -/* - * For the NAT we will need to analyze and later patch - * the received message. This would require us to parse - * the IPA and SCCP header twice. Instead of doing this - * we will have one analyze structure and have the patching - * and filter operate on the same structure. - */ -struct bsc_nat_parsed { - /* ip access prototype */ - int ipa_proto; - - /* source local reference */ - struct sccp_source_reference *src_local_ref; - - /* destination local reference */ - struct sccp_source_reference *dest_local_ref; - - /* original value */ - struct sccp_source_reference original_dest_ref; - - /* called ssn number */ - int called_ssn; - - /* calling ssn number */ - int calling_ssn; - - /* sccp message type */ - int sccp_type; - - /* bssap type, e.g. 0 for BSS Management */ - int bssap; - - /* the gsm0808 message type */ - int gsm_type; -}; - -/* - * Per SCCP source local reference patch table. It needs to - * be updated on new SCCP connections, connection confirm and reject, - * and on the loss of the BSC connection. - */ -struct nat_sccp_connection { - struct llist_head list_entry; - - struct bsc_connection *bsc; - struct bsc_msc_connection *msc_con; - - struct sccp_source_reference real_ref; - struct sccp_source_reference patched_ref; - struct sccp_source_reference remote_ref; - int has_remote_ref; - - /* status */ - int con_local; - int authorized; - - struct bsc_filter_state filter_state; - - uint16_t lac; - uint16_t ci; - - /* remember which Transactions we run over the bypass */ - char ussd_ti[8]; - - /* - * audio handling. Remember if we have ever send a CRCX, - * remember the endpoint used by the MSC and BSC. - */ - int msc_endp; - int bsc_endp; - - /* timeout handling */ - struct timespec creation_time; -}; - - -#endif diff --git a/include/openbsc/bsc_subscriber.h b/include/openbsc/bsc_subscriber.h deleted file mode 100644 index 324734f9a..000000000 --- a/include/openbsc/bsc_subscriber.h +++ /dev/null @@ -1,43 +0,0 @@ -/* GSM subscriber details for use in BSC land */ - -#pragma once - -#include - -#include -#include - -struct log_target; - -struct bsc_subscr { - struct llist_head entry; - int use_count; - - char imsi[GSM23003_IMSI_MAX_DIGITS+1]; - uint32_t tmsi; - uint16_t lac; -}; - -const char *bsc_subscr_name(struct bsc_subscr *bsub); - -struct bsc_subscr *bsc_subscr_find_or_create_by_imsi(struct llist_head *list, - const char *imsi); -struct bsc_subscr *bsc_subscr_find_or_create_by_tmsi(struct llist_head *list, - uint32_t tmsi); - -struct bsc_subscr *bsc_subscr_find_by_imsi(struct llist_head *list, - const char *imsi); -struct bsc_subscr *bsc_subscr_find_by_tmsi(struct llist_head *list, - uint32_t tmsi); - -void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi); - -struct bsc_subscr *_bsc_subscr_get(struct bsc_subscr *bsub, - const char *file, int line); -struct bsc_subscr *_bsc_subscr_put(struct bsc_subscr *bsub, - const char *file, int line); -#define bsc_subscr_get(bsub) _bsc_subscr_get(bsub, __BASE_FILE__, __LINE__) -#define bsc_subscr_put(bsub) _bsc_subscr_put(bsub, __BASE_FILE__, __LINE__) - -void log_set_filter_bsc_subscr(struct log_target *target, - struct bsc_subscr *bsub); diff --git a/include/openbsc/gb_proxy.h b/include/openbsc/gb_proxy.h deleted file mode 100644 index e10894fc3..000000000 --- a/include/openbsc/gb_proxy.h +++ /dev/null @@ -1,288 +0,0 @@ -#ifndef _GB_PROXY_H -#define _GB_PROXY_H - - -#include - -#include -#include - -#include -#include - -#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/include/openbsc/gprs_gb_parse.h b/include/openbsc/gprs_gb_parse.h deleted file mode 100644 index 246839286..000000000 --- a/include/openbsc/gprs_gb_parse.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include - -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/include/openbsc/gprs_gmm.h b/include/openbsc/gprs_gmm.h deleted file mode 100644 index c38e49f0d..000000000 --- a/include/openbsc/gprs_gmm.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _GPRS_GMM_H -#define _GPRS_GMM_H - -#include -#include - -#include - -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); - -#endif /* _GPRS_GMM_H */ diff --git a/include/openbsc/gprs_llc.h b/include/openbsc/gprs_llc.h deleted file mode 100644 index 8bc226781..000000000 --- a/include/openbsc/gprs_llc.h +++ /dev/null @@ -1,284 +0,0 @@ -#ifndef _GPRS_LLC_H -#define _GPRS_LLC_H - -#include -#include -#include -#include - -/* 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/include/openbsc/gprs_llc_xid.h b/include/openbsc/gprs_llc_xid.h deleted file mode 100644 index d340d40b7..000000000 --- a/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 - * 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 . - */ - -#pragma once - -#include -#include - -/* 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/include/openbsc/gprs_sgsn.h b/include/openbsc/gprs_sgsn.h deleted file mode 100644 index 57995e018..000000000 --- a/include/openbsc/gprs_sgsn.h +++ /dev/null @@ -1,478 +0,0 @@ -#ifndef _GPRS_SGSN_H -#define _GPRS_SGSN_H - -#include -#include - -#include - -#include - -#include -#include - -#include - -#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 ranap_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 ranap_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/include/openbsc/gprs_sndcp.h b/include/openbsc/gprs_sndcp.h deleted file mode 100644 index d970240e4..000000000 --- a/include/openbsc/gprs_sndcp.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef _INT_SNDCP_H -#define _INT_SNDCP_H - -#include -#include - -/* 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/include/openbsc/gprs_sndcp_comp.h b/include/openbsc/gprs_sndcp_comp.h deleted file mode 100644 index 87ab6382a..000000000 --- a/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 - * 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 . - */ - -#pragma once - -#include -#include -#include - -/* 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/include/openbsc/gprs_sndcp_dcomp.h b/include/openbsc/gprs_sndcp_dcomp.h deleted file mode 100644 index a76b4a4b3..000000000 --- a/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 - * 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 . - */ - -#pragma once - -#include -#include -#include - -/* 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/include/openbsc/gprs_sndcp_pcomp.h b/include/openbsc/gprs_sndcp_pcomp.h deleted file mode 100644 index 4e15b9be2..000000000 --- a/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 - * 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 . - */ - -#pragma once - -#include -#include -#include - -/* 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/include/openbsc/gprs_sndcp_xid.h b/include/openbsc/gprs_sndcp_xid.h deleted file mode 100644 index e64bc5237..000000000 --- a/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 - * 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 . - */ - -#pragma once - -#include -#include - -#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/include/openbsc/gprs_subscriber.h b/include/openbsc/gprs_subscriber.h deleted file mode 100644 index be78febff..000000000 --- a/include/openbsc/gprs_subscriber.h +++ /dev/null @@ -1,31 +0,0 @@ -/* GPRS subscriber details for use in SGSN land */ -#pragma once - -#include - -#include -#include - -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/include/openbsc/gprs_utils.h b/include/openbsc/gprs_utils.h deleted file mode 100644 index 574f5c50c..000000000 --- a/include/openbsc/gprs_utils.h +++ /dev/null @@ -1,44 +0,0 @@ -/* GPRS utility functions */ - -/* (C) 2010 by Harald Welte - * (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 . - * - */ -#pragma once - -#include -#include - -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/include/openbsc/nat_rewrite_trie.h b/include/openbsc/nat_rewrite_trie.h deleted file mode 100644 index 0571099c6..000000000 --- a/include/openbsc/nat_rewrite_trie.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * (C) 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 . - * - */ -#ifndef NAT_REWRITE_FILE_H -#define NAT_REWRITE_FILE_H - -#include - -struct vty; - -struct nat_rewrite_rule { - /* For digits 0-9 and + */ - struct nat_rewrite_rule *rules[11]; - - char empty; - char prefix[14]; - char rewrite[6]; -}; - -struct nat_rewrite { - struct nat_rewrite_rule rule; - size_t prefixes; -}; - - -struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename); -struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *, const char *prefix); -void nat_rewrite_dump(struct nat_rewrite *rewr); -void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewr); - -#endif diff --git a/include/openbsc/paging.h b/include/openbsc/paging.h index 7dd8500ac..049da1402 100644 --- a/include/openbsc/paging.h +++ b/include/openbsc/paging.h @@ -27,7 +27,6 @@ #include #include -#include /** * A pending paging request diff --git a/include/openbsc/pcu_if.h b/include/openbsc/pcu_if.h deleted file mode 100644 index 1f398b4aa..000000000 --- a/include/openbsc/pcu_if.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _PCU_IF_H -#define _PCU_IF_H - -#include - -extern int pcu_direct; - -struct pcu_sock_state { - struct gsm_network *net; - struct osmo_fd listen_bfd; /* fd for listen socket */ - struct osmo_fd conn_bfd; /* fd for connection to lcr */ - struct llist_head upqueue; /* queue for sending messages */ -}; - -/* PCU relevant information has changed; Inform PCU (if connected) */ -void pcu_info_update(struct gsm_bts *bts); - -/* Forward rach indication to PCU */ -int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn, - uint8_t is_11bit, enum ph_burst_type burst_type); - -/* Confirm the sending of an immediate assignment to the pcu */ -int pcu_tx_imm_ass_sent(struct gsm_bts *bts, uint32_t tlli); - - -/* Confirm the sending of an immediate assignment to the pcu */ -int pcu_tx_imm_ass_sent(struct gsm_bts *bts, uint32_t tlli); - -/* Open connection to PCU */ -int pcu_sock_init(const char *path, struct gsm_bts *bts); - -/* Close connection to PCU */ -void pcu_sock_exit(struct gsm_bts *bts); - -#endif /* _PCU_IF_H */ diff --git a/include/openbsc/pcuif_proto.h b/include/openbsc/pcuif_proto.h deleted file mode 100644 index eb28d66bc..000000000 --- a/include/openbsc/pcuif_proto.h +++ /dev/null @@ -1,176 +0,0 @@ -#ifndef _PCUIF_PROTO_H -#define _PCUIF_PROTO_H - -#define PCU_IF_VERSION 0x08 - -/* msg_type */ -#define PCU_IF_MSG_DATA_REQ 0x00 /* send data to given channel */ -#define PCU_IF_MSG_DATA_CNF 0x01 /* confirm (e.g. transmission on PCH) */ -#define PCU_IF_MSG_DATA_IND 0x02 /* receive data from given channel */ -#define PCU_IF_MSG_DATA_CNF_DT 0x11 /* confirm (with direct tlli) */ -#define PCU_IF_MSG_RTS_REQ 0x10 /* ready to send request */ -#define PCU_IF_MSG_RACH_IND 0x22 /* receive RACH */ -#define PCU_IF_MSG_INFO_IND 0x32 /* retrieve BTS info */ -#define PCU_IF_MSG_ACT_REQ 0x40 /* activate/deactivate PDCH */ -#define PCU_IF_MSG_TIME_IND 0x52 /* GSM time indication */ -#define PCU_IF_MSG_PAG_REQ 0x60 /* paging request */ - -/* sapi */ -#define PCU_IF_SAPI_RACH 0x01 /* channel request on CCCH */ -#define PCU_IF_SAPI_AGCH 0x02 /* assignment on AGCH */ -#define PCU_IF_SAPI_PCH 0x03 /* paging/assignment on PCH */ -#define PCU_IF_SAPI_BCCH 0x04 /* SI on BCCH */ -#define PCU_IF_SAPI_PDTCH 0x05 /* packet data/control/ccch block */ -#define PCU_IF_SAPI_PRACH 0x06 /* packet random access channel */ -#define PCU_IF_SAPI_PTCCH 0x07 /* packet TA control channel */ -#define PCU_IF_SAPI_AGCH_DT 0x08 /* assignment on AGCH but with additional TLLI */ - -/* flags */ -#define PCU_IF_FLAG_ACTIVE (1 << 0)/* BTS is active */ -#define PCU_IF_FLAG_SYSMO (1 << 1)/* access PDCH of sysmoBTS directly */ -#define PCU_IF_FLAG_CS1 (1 << 16) -#define PCU_IF_FLAG_CS2 (1 << 17) -#define PCU_IF_FLAG_CS3 (1 << 18) -#define PCU_IF_FLAG_CS4 (1 << 19) -#define PCU_IF_FLAG_MCS1 (1 << 20) -#define PCU_IF_FLAG_MCS2 (1 << 21) -#define PCU_IF_FLAG_MCS3 (1 << 22) -#define PCU_IF_FLAG_MCS4 (1 << 23) -#define PCU_IF_FLAG_MCS5 (1 << 24) -#define PCU_IF_FLAG_MCS6 (1 << 25) -#define PCU_IF_FLAG_MCS7 (1 << 26) -#define PCU_IF_FLAG_MCS8 (1 << 27) -#define PCU_IF_FLAG_MCS9 (1 << 28) - -struct gsm_pcu_if_data { - uint8_t sapi; - uint8_t len; - uint8_t data[162]; - uint32_t fn; - uint16_t arfcn; - uint8_t trx_nr; - uint8_t ts_nr; - uint8_t block_nr; - int8_t rssi; - uint16_t ber10k; /*!< \brief BER in units of 0.01% */ - int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */ - int16_t lqual_cb; /* !< \brief Link quality in centiBel */ -} __attribute__ ((packed)); - -/* data confirmation with direct tlli (instead of raw mac block with tlli) */ -struct gsm_pcu_if_data_cnf_dt { - uint8_t sapi; - uint32_t tlli; - uint32_t fn; - uint16_t arfcn; - uint8_t trx_nr; - uint8_t ts_nr; - uint8_t block_nr; - int8_t rssi; - uint16_t ber10k; /*!< \brief BER in units of 0.01% */ - int16_t ta_offs_qbits; /* !< \brief Burst TA Offset in quarter bits */ - int16_t lqual_cb; /* !< \brief Link quality in centiBel */ -} __attribute__ ((packed)); - -struct gsm_pcu_if_rts_req { - uint8_t sapi; - uint8_t spare[3]; - uint32_t fn; - uint16_t arfcn; - uint8_t trx_nr; - uint8_t ts_nr; - uint8_t block_nr; -} __attribute__ ((packed)); - -struct gsm_pcu_if_rach_ind { - uint8_t sapi; - uint16_t ra; - int16_t qta; - uint32_t fn; - uint16_t arfcn; - uint8_t is_11bit; - uint8_t burst_type; -} __attribute__ ((packed)); - -struct gsm_pcu_if_info_trx { - uint16_t arfcn; - uint8_t pdch_mask; /* PDCH channels per TS */ - uint8_t spare; - uint8_t tsc[8]; /* TSC per channel */ - uint32_t hlayer1; -} __attribute__ ((packed)); - -struct gsm_pcu_if_info_ind { - uint32_t version; - uint32_t flags; - struct gsm_pcu_if_info_trx trx[8]; /* TRX infos per BTS */ - uint8_t bsic; - /* RAI */ - uint16_t mcc, mnc, lac, rac; - /* NSE */ - uint16_t nsei; - uint8_t nse_timer[7]; - uint8_t cell_timer[11]; - /* cell */ - uint16_t cell_id; - uint16_t repeat_time; - uint8_t repeat_count; - uint16_t bvci; - uint8_t t3142; - uint8_t t3169; - uint8_t t3191; - uint8_t t3193_10ms; - uint8_t t3195; - uint8_t n3101; - uint8_t n3103; - uint8_t n3105; - uint8_t cv_countdown; - uint16_t dl_tbf_ext; - uint16_t ul_tbf_ext; - uint8_t initial_cs; - uint8_t initial_mcs; - /* NSVC */ - uint16_t nsvci[2]; - uint16_t local_port[2]; - uint16_t remote_port[2]; - uint32_t remote_ip[2]; -} __attribute__ ((packed)); - -struct gsm_pcu_if_act_req { - uint8_t activate; - uint8_t trx_nr; - uint8_t ts_nr; - uint8_t spare; -} __attribute__ ((packed)); - -struct gsm_pcu_if_time_ind { - uint32_t fn; -} __attribute__ ((packed)); - -struct gsm_pcu_if_pag_req { - uint8_t sapi; - uint8_t chan_needed; - uint8_t identity_lv[9]; -} __attribute__ ((packed)); - -struct gsm_pcu_if { - /* context based information */ - uint8_t msg_type; /* message type */ - uint8_t bts_nr; /* bts number */ - uint8_t spare[2]; - - union { - struct gsm_pcu_if_data data_req; - struct gsm_pcu_if_data data_cnf; - struct gsm_pcu_if_data_cnf_dt data_cnf_dt; - struct gsm_pcu_if_data data_ind; - struct gsm_pcu_if_rts_req rts_req; - struct gsm_pcu_if_rach_ind rach_ind; - struct gsm_pcu_if_info_ind info_ind; - struct gsm_pcu_if_act_req act_req; - struct gsm_pcu_if_time_ind time_ind; - struct gsm_pcu_if_pag_req pag_req; - } u; -} __attribute__ ((packed)); - -#endif /* _PCUIF_PROTO_H */ diff --git a/include/openbsc/sgsn.h b/include/openbsc/sgsn.h deleted file mode 100644 index f371dc695..000000000 --- a/include/openbsc/sgsn.h +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef _SGSN_H -#define _SGSN_H - - -#include -#include -#include -#include -#include -#include - -#include - -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 { - int rab_assign_addr_enc; - } iu; -}; - -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(struct sgsn_config *cfg); -int sgsn_parse_config(const char *config_file); - -/* 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/include/openbsc/v42bis.h b/include/openbsc/v42bis.h deleted file mode 100644 index 607a58e51..000000000 --- a/include/openbsc/v42bis.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42bis.h - * - * Written by Steve Underwood - * - * 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 - -#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/include/openbsc/v42bis_private.h b/include/openbsc/v42bis_private.h deleted file mode 100644 index daa5ea315..000000000 --- a/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 - * - * 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/osmoappdesc.py b/osmoappdesc.py index 22210d5bf..b72c93e71 100644 --- a/osmoappdesc.py +++ b/osmoappdesc.py @@ -28,25 +28,14 @@ nitb_e1_configs = [ app_configs = { - "osmo-bsc": ["doc/examples/osmo-bsc/osmo-bsc.cfg"], - "nat": ["doc/examples/osmo-bsc_nat/osmo-bsc_nat.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"], "msc": ["doc/examples/osmo-msc/osmo-msc.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"), - (4246, "src/gprs/osmo-gbproxy", "OsmoGbProxy", "gbproxy"), - (4245, "src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn"), - (4254, "src/osmo-msc/osmo-msc", "OsmoMSC", "msc"), - (4253, "src/gprs/osmo-gtphub", "OsmoGTPhub", "gtphub") +apps = [(4254, "src/osmo-msc/osmo-msc", "OsmoMSC", "msc"), ] vty_command = ["./src/osmo-msc/osmo-msc", "-c", "doc/examples/osmo-msc/osmo-msc.cfg"] -vty_app = apps[4] # reference apps[] entry for osmo-msc +vty_app = apps[0] # reference apps[] entry for osmo-msc diff --git a/src/Makefile.am b/src/Makefile.am index 70e53ac3e..b03ee8c93 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,10 +23,7 @@ AM_LDFLAGS = \ SUBDIRS = \ libcommon \ libvlr \ - libbsc \ libmsc \ - libtrau \ - libfilter \ libcommon-cs \ $(NULL) @@ -34,19 +31,4 @@ SUBDIRS = \ SUBDIRS += \ osmo-msc \ utils \ - ipaccess \ - gprs \ $(NULL) - -# Conditional Programs -if BUILD_NAT -SUBDIRS += \ - osmo-bsc_nat \ - $(NULL) -endif - -if BUILD_BSC -SUBDIRS += \ - osmo-bsc \ - $(NULL) -endif diff --git a/src/gprs/.gitignore b/src/gprs/.gitignore deleted file mode 100644 index 7cfefbac2..000000000 --- a/src/gprs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gsn_restart -osmo_*.cfg* diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am deleted file mode 100644 index 39a4c12a7..000000000 --- a/src/gprs/Makefile.am +++ /dev/null @@ -1,133 +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) \ - $(LIBOSMOSIGTRAN_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 += \ - $(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) \ - $(LIBOSMOSIGTRAN_LIBS) \ - -lrt \ - $(NULL) diff --git a/src/gprs/crc24.c b/src/gprs/crc24.c deleted file mode 100644 index 1a420ed66..000000000 --- a/src/gprs/crc24.c +++ /dev/null @@ -1,67 +0,0 @@ -/* GPRS LLC CRC-24 Implementation */ - -/* (C) 2008-2009 by Harald Welte - * - * 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 . - * - */ - -#include - -/* 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/src/gprs/gb_proxy.c b/src/gprs/gb_proxy.c deleted file mode 100644 index cd38d23bf..000000000 --- a/src/gprs/gb_proxy.c +++ /dev/null @@ -1,1438 +0,0 @@ -/* NS-over-IP proxy */ - -/* (C) 2010 by Harald Welte - * (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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -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/src/gprs/gb_proxy_main.c b/src/gprs/gb_proxy_main.c deleted file mode 100644 index caff27f6f..000000000 --- a/src/gprs/gb_proxy_main.c +++ /dev/null @@ -1,317 +0,0 @@ -/* NS-over-IP proxy */ - -/* (C) 2010 by Harald Welte - * (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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../../bscconfig.h" - -#define _GNU_SOURCE -#include - -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 \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/src/gprs/gb_proxy_patch.c b/src/gprs/gb_proxy_patch.c deleted file mode 100644 index 210fb2b96..000000000 --- a/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 . - * - */ - -#include - -#include -#include - -#include -#include - -#include -#include -#include - -/* 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/src/gprs/gb_proxy_peer.c b/src/gprs/gb_proxy_peer.c deleted file mode 100644 index 890968717..000000000 --- a/src/gprs/gb_proxy_peer.c +++ /dev/null @@ -1,222 +0,0 @@ -/* Gb proxy peer handling */ - -/* (C) 2010 by Harald Welte - * (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 . - * - */ - -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -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/src/gprs/gb_proxy_tlli.c b/src/gprs/gb_proxy_tlli.c deleted file mode 100644 index 3b3b976a5..000000000 --- a/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 . - * - */ - -#include - -#include - -#include -#include - -#include - -#include - -#include -#include - -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/src/gprs/gb_proxy_vty.c b/src/gprs/gb_proxy_vty.c deleted file mode 100644 index 86d65a8e3..000000000 --- a/src/gprs/gb_proxy_vty.c +++ /dev/null @@ -1,853 +0,0 @@ -/* - * (C) 2010 by Harald Welte - * (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 . - * - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -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/src/gprs/gprs_gb_parse.c b/src/gprs/gprs_gb_parse.c deleted file mode 100644 index d5a122bda..000000000 --- a/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 . - * - */ - -#include -#include - -#include - -#include - -#include - -#include - -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/src/gprs/gprs_gmm.c b/src/gprs/gprs_gmm.c deleted file mode 100644 index 032137f0b..000000000 --- a/src/gprs/gprs_gmm.c +++ /dev/null @@ -1,2937 +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 - * (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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "bscconfig.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef BUILD_IU -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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 ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data) -{ - struct sgsn_mm_ctx *mm; - int rc = -1; - - mm = sgsn_mm_ctx_by_ue_ctx(ctx); - -#define REQUIRE_MM \ - if (!mm) { \ - LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %d\n", type); \ - return rc; \ - } - - switch (type) { - case RANAP_IU_EVENT_RAB_ASSIGN: - REQUIRE_MM - rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data); - break; - case RANAP_IU_EVENT_IU_RELEASE: - /* fall thru */ - case RANAP_IU_EVENT_LINK_INVALIDATED: - /* Clean up ranap_ue_conn_ctx here */ - if (mm) - LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi); - else - LOGMMCTXP(LOGL_INFO, mm, "IU release for UE conn 0x%x\n", - ctx->conn_id); - if (mm && mm->pmm_state == PMM_CONNECTED) - mmctx_set_pmm_state(mm, PMM_IDLE); - rc = 0; - break; - case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE: - REQUIRE_MM - /* 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 ranap_iu_tx(msg, GPRS_SAPI_GMM); -#endif - } - -#ifdef BUILD_IU - /* In Iu mode, msg->dst contains the ranap_ue_conn_ctx pointer, in Gb mode - * dst is empty. */ - /* FIXME: have a more explicit indicator for Iu messages */ - if (msg->dst) - return ranap_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; - if (mm->ran_type == MM_CTX_T_UTRAN_Iu - && mm->iu.ue_ctx) { -#ifdef BUILD_IU - mm->iu.ue_ctx->rab_assign_addr_enc = - sgsn->cfg.iu.rab_assign_addr_enc; -#endif - } -} - -/* 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 -/* Send RAB activation requests for all PDP contexts */ -void activate_pdp_rabs(struct sgsn_mm_ctx *ctx) -{ - struct sgsn_pdp_ctx *pdp; - if (ctx->ran_type != MM_CTX_T_UTRAN_Iu) - return; - llist_for_each_entry(pdp, &ctx->pdp_list, list) { - iu_rab_act_ps(pdp->nsapi, pdp); - } -} -#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 = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, 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 ranap_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 { -#ifdef BUILD_IU - ra_id = ((struct ranap_ue_conn_ctx*)msg->dst)->ra_id; -#else - LOGMMCTXP(LOGL_ERROR, ctx, "Cannot handle Iu Attach Request, built without Iu support\n"); - return -ENOTSUP; -#endif - } - - /* 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; - - /* 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 ranap_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) -{ - struct msgb *msg; - struct sgsn_mm_ctx *mm = pdp->mm; - struct ranap_ue_conn_ctx *uectx; - uint32_t ggsn_ip; - bool use_x213_nsap; - - uectx = mm->iu.ue_ctx; - use_x213_nsap = (uectx->rab_assign_addr_enc == RANAP_NSAP_ADDR_ENC_X213); - - /* 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 ranap_iu_rab_act(uectx, msg); -} -#endif diff --git a/src/gprs/gprs_llc.c b/src/gprs/gprs_llc.c deleted file mode 100644 index 2be663f98..000000000 --- a/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 - * - * 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 . - * - */ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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/src/gprs/gprs_llc_parse.c b/src/gprs/gprs_llc_parse.c deleted file mode 100644 index a5a7a7122..000000000 --- a/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 - * - * 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 . - * - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -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/src/gprs/gprs_llc_vty.c b/src/gprs/gprs_llc_vty.c deleted file mode 100644 index bf34e9782..000000000 --- a/src/gprs/gprs_llc_vty.c +++ /dev/null @@ -1,116 +0,0 @@ -/* VTY interface for our GPRS LLC implementation */ - -/* (C) 2010 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -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/src/gprs/gprs_llc_xid.c b/src/gprs/gprs_llc_xid.c deleted file mode 100644 index fe631715a..000000000 --- a/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 - * 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 . - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -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/src/gprs/gprs_sgsn.c b/src/gprs/gprs_sgsn.c deleted file mode 100644 index de79afb1a..000000000 --- a/src/gprs/gprs_sgsn.c +++ /dev/null @@ -1,933 +0,0 @@ -/* GPRS SGSN functionality */ - -/* (C) 2009 by Harald Welte - * - * 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 . - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "openbsc/gprs_llc.h" - -#include - -#include - -#include - -#include "../../bscconfig.h" - -#if BUILD_IU -#include -#endif - -#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) -{ -#if BUILD_IU - 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.ue_ctx->rab_assign_addr_enc = sgsn->cfg.iu.rab_assign_addr_enc; - 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; -#else - return NULL; -#endif -} - - -/* 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/src/gprs/gprs_sndcp.c b/src/gprs/gprs_sndcp.c deleted file mode 100644 index a18998f9e..000000000 --- a/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 - * (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 . - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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/src/gprs/gprs_sndcp_comp.c b/src/gprs/gprs_sndcp_comp.c deleted file mode 100644 index a12c39aa6..000000000 --- a/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 - * 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 . - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -/* 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/src/gprs/gprs_sndcp_dcomp.c b/src/gprs/gprs_sndcp_dcomp.c deleted file mode 100644 index b0f95b486..000000000 --- a/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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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/src/gprs/gprs_sndcp_pcomp.c b/src/gprs/gprs_sndcp_pcomp.c deleted file mode 100644 index a2236c3b1..000000000 --- a/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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* 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/src/gprs/gprs_sndcp_vty.c b/src/gprs/gprs_sndcp_vty.c deleted file mode 100644 index 430881fc8..000000000 --- a/src/gprs/gprs_sndcp_vty.c +++ /dev/null @@ -1,71 +0,0 @@ -/* VTY interface for our GPRS SNDCP implementation */ - -/* (C) 2010 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -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/src/gprs/gprs_sndcp_xid.c b/src/gprs/gprs_sndcp_xid.c deleted file mode 100644 index dfea5febc..000000000 --- a/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 - * 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 . - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* 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, ¶ms->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(¶ms->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, ¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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(¶ms->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, ¶ms->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(¶ms->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(¶ms->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, ¶ms->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) */ -static int decode_dcomp_v42bis_params(struct gprs_sndcp_dcomp_v42bis_params - *params, const uint8_t *src, - unsigned int src_len) -{ - int rc; - int byte_counter = 0; - - /* Mark all optional parameters invalid by default */ - params->p0 = -1; - params->p1 = -1; - params->p2 = -1; - - /* Decode applicable SAPIs */ - rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, - src, src_len); - if (rc > 0) { - byte_counter += rc; - src += rc; - } else - return byte_counter; - - /* Decode P0 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ - rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, - src_len - byte_counter, 0, 3); - if (rc <= 0) - return byte_counter; - byte_counter += rc; - src += rc; - - /* Decode P1 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ - rc = decode_pcomp_16_bit_field(¶ms->p1, NULL, src, - src_len - byte_counter, 512, 65535); - if (rc <= 0) - return byte_counter; - byte_counter += rc; - src += rc; - - /* Decode P2 (see also: 3GPP TS 44.065, 6.6.2.1, Table 7a) */ - rc = decode_pcomp_8_bit_field(¶ms->p2, NULL, src, - src_len - byte_counter, 6, 250); - if (rc <= 0) - return byte_counter; - byte_counter += rc; - src += rc; - - /* Return consumed length */ - return byte_counter; -} - -/* Decode V44 parameter field (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ -static int decode_dcomp_v44_params(struct gprs_sndcp_dcomp_v44_params *params, - const uint8_t *src, unsigned int src_len) -{ - int rc; - int byte_counter = 0; - - /* Mark all optional parameters invalid by default */ - params->c0 = -1; - params->p0 = -1; - params->p1t = -1; - params->p1r = -1; - params->p3t = -1; - params->p3r = -1; - - /* Decode applicable SAPIs */ - rc = decode_pcomp_applicable_sapis(params->nsapi, ¶ms->nsapi_len, - src, src_len); - if (rc > 0) { - byte_counter += rc; - src += rc; - } else - return byte_counter; - - /* Decode C0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ - rc = decode_pcomp_8_bit_field(¶ms->c0, NULL, src, - src_len - byte_counter, 0, 255); - if (rc <= 0) - return byte_counter; - if ((params->c0 != 0x80) && (params->c0 != 0xC0)) - return -EINVAL; - byte_counter += rc; - src += rc; - - /* Decode P0 (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ - rc = decode_pcomp_8_bit_field(¶ms->p0, NULL, src, - src_len - byte_counter, 0, 3); - if (rc <= 0) - return byte_counter; - byte_counter += rc; - src += rc; - - /* Decode P1T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ - rc = decode_pcomp_16_bit_field(¶ms->p1t, NULL, src, - src_len - byte_counter, 265, 65535); - if (rc <= 0) - return byte_counter; - byte_counter += rc; - src += rc; - - /* Decode P1R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ - rc = decode_pcomp_16_bit_field(¶ms->p1r, NULL, src, - src_len - byte_counter, 265, 65535); - if (rc <= 0) - return byte_counter; - byte_counter += rc; - src += rc; - - /* Decode P3T (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ - rc = decode_pcomp_16_bit_field(¶ms->p3t, NULL, src, - src_len - byte_counter, 265, 65535); - if (rc <= 0) - return byte_counter; - if (params->p3t < 2 * params->p1t) - return -EINVAL; - byte_counter += rc; - src += rc; - - /* Decode P3R (see also: 3GPP TS 44.065, 6.6.3.1, Table 7c) */ - rc = decode_pcomp_16_bit_field(¶ms->p3r, NULL, src, - src_len - byte_counter, 265, 65535); - if (rc <= 0) - return byte_counter; - if (params->p3r < 2 * params->p1r) - return -EINVAL; - byte_counter += rc; - src += rc; - - /* Return consumed length */ - return byte_counter; -} - -/* Lookup algorithm identfier by entity ID */ -static int lookup_algorithm_identifier(int entity, const struct - entity_algo_table - *lt, unsigned int lt_len, int compclass) -{ - int i; - - if (!lt) - return -1; - - for (i = 0; i < lt_len; i++) { - if ((lt[i].entity == entity) - && (lt[i].compclass == compclass)) - return lt[i].algo; - } - - return -1; -} - -/* Helper function for decode_comp_field(), decodes - * numeric pcomp/dcomp values */ -static int decode_comp_values(struct gprs_sndcp_comp_field *comp_field, - const uint8_t *src, int compclass) -{ - int src_counter = 0; - int i; - - if (comp_field->p) { - /* Determine the number of expected PCOMP/DCOMP values */ - if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { - /* For protocol compression */ - switch (comp_field->algo) { - case RFC_1144: - comp_field->comp_len = RFC1144_PCOMP_NUM; - break; - case RFC_2507: - comp_field->comp_len = RFC2507_PCOMP_NUM; - break; - case ROHC: - comp_field->comp_len = ROHC_PCOMP_NUM; - break; - - /* Exit if the algorithem type encodes - something unknown / unspecified */ - default: - return -EINVAL; - } - } else { - /* For data compression */ - switch (comp_field->algo) { - case V42BIS: - comp_field->comp_len = V42BIS_DCOMP_NUM; - break; - case V44: - comp_field->comp_len = V44_DCOMP_NUM; - break; - - /* Exit if the algorithem type encodes - something unknown / unspecified */ - default: - return -EINVAL; - } - } - - for (i = 0; i < comp_field->comp_len; i++) { - if (i & 1) { - comp_field->comp[i] = (*src) & 0x0F; - src++; - src_counter++; - } else - comp_field->comp[i] = ((*src) >> 4) & 0x0F; - } - - if (i & 1) { - src++; - src_counter++; - } - } - - return src_counter; -} - -/* Helper function for decode_comp_field(), decodes the parameters - * which are protocol compression specific */ -static int decode_pcomp_params(struct gprs_sndcp_comp_field *comp_field, - const uint8_t *src, int src_len) -{ - int rc; - - switch (comp_field->algo) { - case RFC_1144: - comp_field->rfc1144_params = talloc_zero(comp_field, struct - gprs_sndcp_pcomp_rfc1144_params); - rc = decode_pcomp_rfc1144_params(comp_field->rfc1144_params, - src, src_len); - if (rc < 0) - talloc_free(comp_field->rfc1144_params); - break; - case RFC_2507: - comp_field->rfc2507_params = talloc_zero(comp_field, struct - gprs_sndcp_pcomp_rfc2507_params); - rc = decode_pcomp_rfc2507_params(comp_field->rfc2507_params, - src, src_len); - if (rc < 0) - talloc_free(comp_field->rfc1144_params); - break; - case ROHC: - comp_field->rohc_params = talloc_zero(comp_field, struct - gprs_sndcp_pcomp_rohc_params); - rc = decode_pcomp_rohc_params(comp_field->rohc_params, src, - src_len); - if (rc < 0) - talloc_free(comp_field->rohc_params); - break; - - /* If no suitable decoder is detected, - leave the remaining bytes undecoded */ - default: - rc = src_len; - } - - if (rc < 0) { - comp_field->rfc1144_params = NULL; - comp_field->rfc2507_params = NULL; - comp_field->rohc_params = NULL; - } - - return rc; -} - -/* Helper function for decode_comp_field(), decodes the parameters - * which are data compression specific */ -static int decode_dcomp_params(struct gprs_sndcp_comp_field *comp_field, - const uint8_t *src, int src_len) -{ - int rc; - - switch (comp_field->algo) { - case V42BIS: - comp_field->v42bis_params = talloc_zero(comp_field, struct - gprs_sndcp_dcomp_v42bis_params); - rc = decode_dcomp_v42bis_params(comp_field->v42bis_params, src, - src_len); - if (rc < 0) - talloc_free(comp_field->v42bis_params); - break; - case V44: - comp_field->v44_params = talloc_zero(comp_field, struct - gprs_sndcp_dcomp_v44_params); - rc = decode_dcomp_v44_params(comp_field->v44_params, src, - src_len); - if (rc < 0) - talloc_free(comp_field->v44_params); - break; - - /* If no suitable decoder is detected, - * leave the remaining bytes undecoded */ - default: - rc = src_len; - } - - if (rc < 0) { - comp_field->v42bis_params = NULL; - comp_field->v44_params = NULL; - } - - return rc; -} - -/* Decode 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 decode_comp_field(struct gprs_sndcp_comp_field *comp_field, - const uint8_t *src, unsigned int src_len, - const struct entity_algo_table *lt, - unsigned int lt_len, int compclass) -{ - int src_counter = 0; - unsigned int len; - int rc; - - OSMO_ASSERT(comp_field); - - /* Exit immediately if it is clear that no - parseable data is present */ - if (src_len < 1 || !src) - return -EINVAL; - - /* Zero out target struct */ - memset(comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); - - /* Decode Propose bit and Entity number */ - if ((*src) & 0x80) - comp_field->p = 1; - comp_field->entity = (*src) & 0x1F; - src_counter++; - src++; - - /* Decode algorithm number (if present) */ - if (comp_field->p) { - comp_field->algo = (*src) & 0x1F; - src_counter++; - src++; - } - /* Alternatively take the information from the lookup table */ - else - comp_field->algo = - lookup_algorithm_identifier(comp_field->entity, lt, - lt_len, compclass); - - /* Decode length field */ - len = *src; - src_counter++; - src++; - - /* Decode PCOMP/DCOMP values */ - rc = decode_comp_values(comp_field, src, compclass); - if (rc < 0) - return -EINVAL; - src_counter += rc; - src += rc; - len -= rc; - - /* Decode algorithm specific payload data */ - if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) - rc = decode_pcomp_params(comp_field, src, len); - else if (compclass == SNDCP_XID_DATA_COMPRESSION) - rc = decode_dcomp_params(comp_field, src, len); - else - return -EINVAL; - - if (rc >= 0) - src_counter += rc; - else - return -EINVAL; - - /* Return consumed length */ - return src_counter; -} - -/* Helper function for gprs_sndcp_decode_xid() to decode XID blocks */ -static int decode_xid_block(struct llist_head *comp_fields, uint8_t tag, - uint16_t tag_len, const uint8_t *val, - const struct entity_algo_table *lt, - unsigned int lt_len) -{ - struct gprs_sndcp_comp_field *comp_field; - int byte_counter = 0; - int comp_field_count = 0; - int rc; - - byte_counter = 0; - do { - /* Bail if more than the maximum number of - comp_fields is generated */ - if (comp_field_count > MAX_ENTITIES * 2) { - return -EINVAL; - } - - /* Parse and add comp_field */ - comp_field = - talloc_zero(comp_fields, struct gprs_sndcp_comp_field); - - rc = decode_comp_field(comp_field, val + byte_counter, - tag_len - byte_counter, lt, lt_len, tag); - - if (rc < 0) { - talloc_free(comp_field); - return -EINVAL; - } - - byte_counter += rc; - llist_add(&comp_field->list, comp_fields); - comp_field_count++; - } - while (tag_len - byte_counter > 0); - - return byte_counter; -} - -/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ -static int gprs_sndcp_decode_xid(int *version, struct llist_head *comp_fields, - const uint8_t *src, unsigned int src_len, - const struct entity_algo_table *lt, - unsigned int lt_len) -{ - int src_pos = 0; - uint8_t tag; - uint16_t tag_len; - const uint8_t *val; - int byte_counter = 0; - int rc; - int tlv_count = 0; - - /* Preset version value as invalid */ - if (version) - *version = -1; - - /* Valid TLV-Tag and types */ - static const struct tlv_definition sndcp_xid_def = { - .def = { - [SNDCP_XID_VERSION_NUMBER] = {TLV_TYPE_TLV,}, - [SNDCP_XID_DATA_COMPRESSION] = {TLV_TYPE_TLV,}, - [SNDCP_XID_PROTOCOL_COMPRESSION] = {TLV_TYPE_TLV,}, - }, - }; - - /* Parse TLV-Encoded SNDCP-XID message and defer payload - to the apporpiate sub-parser functions */ - while (1) { - - /* Bail if an the maximum number of TLV fields - * have been parsed */ - if (tlv_count >= 3) { - talloc_free(comp_fields); - return -EINVAL; - } - - /* Parse TLV field */ - rc = tlv_parse_one(&tag, &tag_len, &val, &sndcp_xid_def, - src + src_pos, src_len - src_pos); - if (rc > 0) - src_pos += rc; - else { - talloc_free(comp_fields); - return -EINVAL; - } - - /* Decode sndcp xid version number */ - if (version && tag == SNDCP_XID_VERSION_NUMBER) - *version = val[0]; - - /* Decode compression parameters */ - if ((tag == SNDCP_XID_PROTOCOL_COMPRESSION) - || (tag == SNDCP_XID_DATA_COMPRESSION)) { - rc = decode_xid_block(comp_fields, tag, tag_len, val, - lt, lt_len); - - if (rc < 0) { - talloc_free(comp_fields); - return -EINVAL; - } else - byte_counter += rc; - } - - /* Stop when no further TLV elements can be expected */ - if (src_len - src_pos <= 2) - break; - - tlv_count++; - } - - return 0; -} - -/* Fill up lookutable from a list with comression entitiy fields */ -static int gprs_sndcp_fill_table(struct - entity_algo_table *lt, - unsigned int lt_len, - const struct llist_head *comp_fields) -{ - struct gprs_sndcp_comp_field *comp_field; - int i = 0; - int rc; - - if (!comp_fields) - return -EINVAL; - if (!lt) - return -EINVAL; - - memset(lt, 0, sizeof(*lt)); - - llist_for_each_entry(comp_field, comp_fields, list) { - if (comp_field->algo >= 0) { - lt[i].entity = comp_field->entity; - lt[i].algo = comp_field->algo; - rc = gprs_sndcp_get_compression_class(comp_field); - - if (rc < 0) { - memset(lt, 0, sizeof(*lt)); - return -EINVAL; - } - - lt[i].compclass = rc; - i++; - } - } - - return i; -} - -/* Complete comp field params - * (if a param (dst) is not valid, it will be copied from source (src) */ -static int complete_comp_field_params(struct gprs_sndcp_comp_field - *comp_field_dst, const struct - gprs_sndcp_comp_field *comp_field_src) -{ - if (comp_field_dst->algo < 0) - return -EINVAL; - - if (comp_field_dst->rfc1144_params && comp_field_src->rfc1144_params) { - if (comp_field_dst->rfc1144_params->s01 < 0) { - comp_field_dst->rfc1144_params->s01 = - comp_field_src->rfc1144_params->s01; - } - return 0; - } - - if (comp_field_dst->rfc2507_params && comp_field_src->rfc2507_params) { - - if (comp_field_dst->rfc2507_params->f_max_period < 0) { - comp_field_dst->rfc2507_params->f_max_period = - comp_field_src->rfc2507_params->f_max_period; - } - if (comp_field_dst->rfc2507_params->f_max_time < 0) { - comp_field_dst->rfc2507_params->f_max_time = - comp_field_src->rfc2507_params->f_max_time; - } - if (comp_field_dst->rfc2507_params->max_header < 0) { - comp_field_dst->rfc2507_params->max_header = - comp_field_src->rfc2507_params->max_header; - } - if (comp_field_dst->rfc2507_params->tcp_space < 0) { - comp_field_dst->rfc2507_params->tcp_space = - comp_field_src->rfc2507_params->tcp_space; - } - if (comp_field_dst->rfc2507_params->non_tcp_space < 0) { - comp_field_dst->rfc2507_params->non_tcp_space = - comp_field_src->rfc2507_params->non_tcp_space; - } - return 0; - } - - if (comp_field_dst->rohc_params && comp_field_src->rohc_params) { - if (comp_field_dst->rohc_params->max_cid < 0) { - comp_field_dst->rohc_params->max_cid = - comp_field_src->rohc_params->max_cid; - } - if (comp_field_dst->rohc_params->max_header < 0) { - comp_field_dst->rohc_params->max_header = - comp_field_src->rohc_params->max_header; - } - if (comp_field_dst->rohc_params->profile_len > 0) { - memcpy(comp_field_dst->rohc_params->profile, - comp_field_src->rohc_params->profile, - sizeof(comp_field_dst->rohc_params->profile)); - comp_field_dst->rohc_params->profile_len = - comp_field_src->rohc_params->profile_len; - } - - return 0; - } - - if (comp_field_dst->v42bis_params && comp_field_src->v42bis_params) { - if (comp_field_dst->v42bis_params->p0 < 0) { - comp_field_dst->v42bis_params->p0 = - comp_field_src->v42bis_params->p0; - } - if (comp_field_dst->v42bis_params->p1 < 0) { - comp_field_dst->v42bis_params->p1 = - comp_field_src->v42bis_params->p1; - } - if (comp_field_dst->v42bis_params->p2 < 0) { - comp_field_dst->v42bis_params->p2 = - comp_field_src->v42bis_params->p2; - } - return 0; - } - - if (comp_field_dst->v44_params && comp_field_src->v44_params) { - if (comp_field_dst->v44_params->c0 < 0) { - comp_field_dst->v44_params->c0 = - comp_field_src->v44_params->c0; - } - if (comp_field_dst->v44_params->p0 < 0) { - comp_field_dst->v44_params->p0 = - comp_field_src->v44_params->p0; - } - if (comp_field_dst->v44_params->p1t < 0) { - comp_field_dst->v44_params->p1t = - comp_field_src->v44_params->p1t; - } - if (comp_field_dst->v44_params->p1r < 0) { - comp_field_dst->v44_params->p1r = - comp_field_src->v44_params->p1r; - } - if (comp_field_dst->v44_params->p3t < 0) { - comp_field_dst->v44_params->p3t = - comp_field_src->v44_params->p3t; - } - if (comp_field_dst->v44_params->p3r < 0) { - comp_field_dst->v44_params->p3r = - comp_field_src->v44_params->p3r; - } - return 0; - } - - /* There should be at least exist one param set - * in the destination struct, otherwise something - * must be wrong! */ - return -EINVAL; -} - -/* Complete missing parameters in a comp_field */ -static int gprs_sndcp_complete_comp_field(struct gprs_sndcp_comp_field - *comp_field, const struct llist_head - *comp_fields) -{ - struct gprs_sndcp_comp_field *comp_field_src; - int rc = 0; - - llist_for_each_entry(comp_field_src, comp_fields, list) { - if (comp_field_src->entity == comp_field->entity) { - - /* Complete header fields */ - if (comp_field_src->comp_len > 0) { - memcpy(comp_field->comp, - comp_field_src->comp, - sizeof(comp_field_src->comp)); - comp_field->comp_len = comp_field_src->comp_len; - } - - /* Complete parameter fields */ - rc = complete_comp_field_params(comp_field, - comp_field_src); - } - } - - return rc; -} - -/* Complete missing parameters of all comp_field in a list */ -static int gprs_sndcp_complete_comp_fields(struct llist_head - *comp_fields_incomplete, - const struct llist_head *comp_fields) -{ - struct gprs_sndcp_comp_field *comp_field_incomplete; - int rc; - - llist_for_each_entry(comp_field_incomplete, comp_fields_incomplete, - list) { - - rc = gprs_sndcp_complete_comp_field(comp_field_incomplete, - comp_fields); - if (rc < 0) - return -EINVAL; - - } - - return 0; -} - -/* 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) -{ - int rc; - int lt_len; - struct llist_head *comp_fields; - struct entity_algo_table lt[MAX_ENTITIES * 2]; - - /* In case of a zero length field, just exit */ - if (src_len == 0) - return NULL; - - /* We should go any further if we have a field length greater - * zero and a null pointer as buffer! */ - OSMO_ASSERT(src); - - comp_fields = talloc_zero(ctx, struct llist_head); - INIT_LLIST_HEAD(comp_fields); - - if (comp_fields_req) { - /* Generate lookup table */ - lt_len = - gprs_sndcp_fill_table(lt, MAX_ENTITIES * 2, - comp_fields_req); - if (lt_len < 0) { - talloc_free(comp_fields); - return NULL; - } - - /* Parse SNDCP-CID XID-Field */ - rc = gprs_sndcp_decode_xid(version, comp_fields, src, src_len, - lt, lt_len); - if (rc < 0) { - talloc_free(comp_fields); - return NULL; - } - - rc = gprs_sndcp_complete_comp_fields(comp_fields, - comp_fields_req); - if (rc < 0) { - talloc_free(comp_fields); - return NULL; - } - - } else { - /* Parse SNDCP-CID XID-Field */ - rc = gprs_sndcp_decode_xid(version, comp_fields, src, src_len, - NULL, 0); - if (rc < 0) { - talloc_free(comp_fields); - return NULL; - } - } - - return comp_fields; -} - -/* Helper for gprs_sndcp_dump_comp_fields(), - * dumps protocol compression parameters */ -static void dump_pcomp_params(const struct gprs_sndcp_comp_field - *comp_field, unsigned int logl) -{ - int i; - - switch (comp_field->algo) { - case RFC_1144: - if (comp_field->rfc1144_params == NULL) { - LOGP(DSNDCP, logl, - " gprs_sndcp_pcomp_rfc1144_params=NULL\n"); - break; - } - LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc1144_params {\n"); - LOGP(DSNDCP, logl, - " nsapi_len=%d;\n", - comp_field->rfc1144_params->nsapi_len); - if (comp_field->rfc1144_params->nsapi_len == 0) - LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); - for (i = 0; i < comp_field->rfc1144_params->nsapi_len; i++) { - LOGP(DSNDCP, logl, - " nsapi[%d]=%d;\n", i, - comp_field->rfc1144_params->nsapi[i]); - } - LOGP(DSNDCP, logl, " s01=%d;\n", - comp_field->rfc1144_params->s01); - LOGP(DSNDCP, logl, " }\n"); - break; - case RFC_2507: - if (comp_field->rfc2507_params == NULL) { - LOGP(DSNDCP, logl, - " gprs_sndcp_pcomp_rfc2507_params=NULL\n"); - break; - } - LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rfc2507_params {\n"); - LOGP(DSNDCP, logl, - " nsapi_len=%d;\n", - comp_field->rfc2507_params->nsapi_len); - if (comp_field->rfc2507_params->nsapi_len == 0) - LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); - for (i = 0; i < comp_field->rfc2507_params->nsapi_len; i++) { - LOGP(DSNDCP, logl, - " nsapi[%d]=%d;\n", i, - comp_field->rfc2507_params->nsapi[i]); - } - LOGP(DSNDCP, logl, - " f_max_period=%d;\n", - comp_field->rfc2507_params->f_max_period); - LOGP(DSNDCP, logl, - " f_max_time=%d;\n", - comp_field->rfc2507_params->f_max_time); - LOGP(DSNDCP, logl, - " max_header=%d;\n", - comp_field->rfc2507_params->max_header); - LOGP(DSNDCP, logl, - " tcp_space=%d;\n", - comp_field->rfc2507_params->tcp_space); - LOGP(DSNDCP, logl, - " non_tcp_space=%d;\n", - comp_field->rfc2507_params->non_tcp_space); - LOGP(DSNDCP, logl, " }\n"); - break; - case ROHC: - if (comp_field->rohc_params == NULL) { - LOGP(DSNDCP, logl, - " gprs_sndcp_pcomp_rohc_params=NULL\n"); - break; - } - LOGP(DSNDCP, logl, " gprs_sndcp_pcomp_rohc_params {\n"); - LOGP(DSNDCP, logl, - " nsapi_len=%d;\n", - comp_field->rohc_params->nsapi_len); - if (comp_field->rohc_params->nsapi_len == 0) - LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); - for (i = 0; i < comp_field->rohc_params->nsapi_len; i++) { - LOGP(DSNDCP, logl, - " nsapi[%d]=%d;\n", i, - comp_field->rohc_params->nsapi[i]); - } - LOGP(DSNDCP, logl, - " max_cid=%d;\n", comp_field->rohc_params->max_cid); - LOGP(DSNDCP, logl, - " max_header=%d;\n", - comp_field->rohc_params->max_header); - LOGP(DSNDCP, logl, - " profile_len=%d;\n", - comp_field->rohc_params->profile_len); - if (comp_field->rohc_params->profile_len == 0) - LOGP(DSNDCP, logl, " profile[] = NULL;\n"); - for (i = 0; i < comp_field->rohc_params->profile_len; i++) - LOGP(DSNDCP, logl, - " profile[%d]=%04x;\n", - i, comp_field->rohc_params->profile[i]); - LOGP(DSNDCP, logl, " }\n"); - break; - } - -} - -/* Helper for gprs_sndcp_dump_comp_fields(), - * data protocol compression parameters */ -static void dump_dcomp_params(const struct gprs_sndcp_comp_field - *comp_field, unsigned int logl) -{ - int i; - - switch (comp_field->algo) { - case V42BIS: - if (comp_field->v42bis_params == NULL) { - LOGP(DSNDCP, logl, - " gprs_sndcp_dcomp_v42bis_params=NULL\n"); - break; - } - LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v42bis_params {\n"); - LOGP(DSNDCP, logl, - " nsapi_len=%d;\n", - comp_field->v42bis_params->nsapi_len); - if (comp_field->v42bis_params->nsapi_len == 0) - LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); - for (i = 0; i < comp_field->v42bis_params->nsapi_len; i++) - LOGP(DSNDCP, logl, - " nsapi[%d]=%d;\n", i, - comp_field->v42bis_params->nsapi[i]); - LOGP(DSNDCP, logl, " p0=%d;\n", - comp_field->v42bis_params->p0); - LOGP(DSNDCP, logl, " p1=%d;\n", - comp_field->v42bis_params->p1); - LOGP(DSNDCP, logl, " p2=%d;\n", - comp_field->v42bis_params->p2); - LOGP(DSNDCP, logl, " }\n"); - break; - case V44: - if (comp_field->v44_params == NULL) { - LOGP(DSNDCP, logl, - " gprs_sndcp_dcomp_v44_params=NULL\n"); - break; - } - LOGP(DSNDCP, logl, " gprs_sndcp_dcomp_v44_params {\n"); - LOGP(DSNDCP, logl, - " nsapi_len=%d;\n", - comp_field->v44_params->nsapi_len); - if (comp_field->v44_params->nsapi_len == 0) - LOGP(DSNDCP, logl, " nsapi[] = NULL;\n"); - for (i = 0; i < comp_field->v44_params->nsapi_len; i++) { - LOGP(DSNDCP, logl, - " nsapi[%d]=%d;\n", i, - comp_field->v44_params->nsapi[i]); - } - LOGP(DSNDCP, logl, " c0=%d;\n", - comp_field->v44_params->c0); - LOGP(DSNDCP, logl, " p0=%d;\n", - comp_field->v44_params->p0); - LOGP(DSNDCP, logl, " p1t=%d;\n", - comp_field->v44_params->p1t); - LOGP(DSNDCP, logl, " p1r=%d;\n", - comp_field->v44_params->p1r); - LOGP(DSNDCP, logl, " p3t=%d;\n", - comp_field->v44_params->p3t); - LOGP(DSNDCP, logl, " p3r=%d;\n", - comp_field->v44_params->p3r); - LOGP(DSNDCP, logl, " }\n"); - break; - } -} - -/* Dump a list with SNDCP-XID fields (Debug) */ -void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, - unsigned int logl) -{ - struct gprs_sndcp_comp_field *comp_field; - int i; - int compclass; - - OSMO_ASSERT(comp_fields); - - llist_for_each_entry(comp_field, comp_fields, list) { - LOGP(DSNDCP, logl, "SNDCP-XID:\n"); - LOGP(DSNDCP, logl, "struct gprs_sndcp_comp_field {\n"); - LOGP(DSNDCP, logl, " entity=%d;\n", comp_field->entity); - LOGP(DSNDCP, logl, " algo=%d;\n", comp_field->algo); - LOGP(DSNDCP, logl, " comp_len=%d;\n", comp_field->comp_len); - if (comp_field->comp_len == 0) - LOGP(DSNDCP, logl, " comp[] = NULL;\n"); - for (i = 0; i < comp_field->comp_len; i++) { - LOGP(DSNDCP, logl, " comp[%d]=%d;\n", i, - comp_field->comp[i]); - } - - compclass = gprs_sndcp_get_compression_class(comp_field); - - if (compclass == SNDCP_XID_PROTOCOL_COMPRESSION) { - dump_pcomp_params(comp_field, logl); - } else if (compclass == SNDCP_XID_DATA_COMPRESSION) { - dump_dcomp_params(comp_field, logl); - } - - LOGP(DSNDCP, logl, "}\n"); - } - -} diff --git a/src/gprs/gprs_subscriber.c b/src/gprs/gprs_subscriber.c deleted file mode 100644 index 94297d0d6..000000000 --- a/src/gprs/gprs_subscriber.c +++ /dev/null @@ -1,937 +0,0 @@ -/* MS subscriber data handling */ - -/* (C) 2014 by sysmocom s.f.m.c. GmbH - * (C) 2015 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#define SGSN_SUBSCR_MAX_RETRIES 3 -#define SGSN_SUBSCR_RETRY_INTERVAL 10 - -#define LOGGSUPP(level, gsup, fmt, args...) \ - LOGP(DGPRS, level, "GSUP(%s) " fmt, \ - (gsup)->imsi, \ - ## args) - -extern void *tall_bsc_ctx; - -LLIST_HEAD(_gprs_subscribers); -struct llist_head * const gprs_subscribers = &_gprs_subscribers; - -static int gsup_read_cb(struct gsup_client *gsupc, struct msgb *msg); - -/* TODO: Some functions are specific to the SGSN, but this file is more general - * (it has gprs_* name). Either move these functions elsewhere, split them and - * move a part, or replace the gprs_ prefix by sgsn_. The applies to - * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message. - */ - -int gprs_subscr_init(struct sgsn_instance *sgi) -{ - const char *addr_str; - - if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr) - return 0; - - addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr); - - sgi->gsup_client = gsup_client_create( - "SGSN", - addr_str, sgi->cfg.gsup_server_port, - &gsup_read_cb, - &sgi->cfg.oap); - - if (!sgi->gsup_client) - return -1; - - return 1; -} - -static int gsup_read_cb(struct gsup_client *gsupc, struct msgb *msg) -{ - int rc; - - rc = gprs_subscr_rx_gsup_message(msg); - msgb_free(msg); - if (rc < 0) - return -1; - - return rc; -} - -int gprs_subscr_purge(struct gprs_subscr *subscr); - -static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx) -{ - struct sgsn_subscriber_data *sdata; - int idx; - - sdata = talloc_zero(ctx, struct sgsn_subscriber_data); - - sdata->error_cause = SGSN_ERROR_CAUSE_NONE; - - for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++) - sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL; - - INIT_LLIST_HEAD(&sdata->pdp_list); - - return sdata; -} - -struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc( - struct sgsn_subscriber_data *sdata) -{ - struct sgsn_subscriber_pdp_data* pdata; - - pdata = talloc_zero(sdata, struct sgsn_subscriber_pdp_data); - - llist_add_tail(&pdata->list, &sdata->pdp_list); - - return pdata; -} - -struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi) -{ - struct gprs_subscr *gsub; - - if (!imsi || !*imsi) - return NULL; - - llist_for_each_entry(gsub, gprs_subscribers, entry) { - if (!strcmp(gsub->imsi, imsi)) - return gprs_subscr_get(gsub); - } - return NULL; -} - -static struct gprs_subscr *gprs_subscr_alloc(void) -{ - struct gprs_subscr *gsub; - gsub = talloc_zero(tall_bsc_ctx, struct gprs_subscr); - if (!gsub) - return NULL; - llist_add_tail(&gsub->entry, gprs_subscribers); - gsub->use_count = 1; - gsub->tmsi = GSM_RESERVED_TMSI; - return gsub; -} - -struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi) -{ - struct gprs_subscr *gsub; - - gsub = gprs_subscr_get_by_imsi(imsi); - if (!gsub) { - gsub = gprs_subscr_alloc(); - if (!gsub) - return NULL; - osmo_strlcpy(gsub->imsi, imsi, sizeof(gsub->imsi)); - } - - if (!gsub->sgsn_data) - gsub->sgsn_data = sgsn_subscriber_data_alloc(gsub); - return gsub; -} - -void gprs_subscr_cleanup(struct gprs_subscr *subscr) -{ - if (subscr->sgsn_data->mm) { - gprs_subscr_put(subscr->sgsn_data->mm->subscr); - subscr->sgsn_data->mm->subscr = NULL; - subscr->sgsn_data->mm = NULL; - } - - if (subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) { - gprs_subscr_purge(subscr); - subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE; - } -} - -void gprs_subscr_cancel(struct gprs_subscr *subscr) -{ - subscr->authorized = 0; - subscr->flags |= GPRS_SUBSCRIBER_CANCELLED; - subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE; - - gprs_subscr_update(subscr); - gprs_subscr_cleanup(subscr); -} - -static int gprs_subscr_tx_gsup_message(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - struct msgb *msg = gsup_client_msgb_alloc(); - - if (strlen(gsup_msg->imsi) == 0 && subscr) - osmo_strlcpy(gsup_msg->imsi, subscr->imsi, - sizeof(gsup_msg->imsi)); - gsup_msg->cn_domain = OSMO_GSUP_CN_DOMAIN_PS; - osmo_gsup_encode(msg, gsup_msg); - - LOGGSUBSCRP(LOGL_INFO, subscr, - "Sending GSUP, will send: %s\n", msgb_hexdump(msg)); - - if (!sgsn->gsup_client) { - msgb_free(msg); - return -ENOTSUP; - } - - return gsup_client_send(sgsn->gsup_client, msg); -} - -static int gprs_subscr_tx_gsup_error_reply(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_orig, - enum gsm48_gmm_cause cause) -{ - struct osmo_gsup_message gsup_reply = {0}; - - osmo_strlcpy(gsup_reply.imsi, gsup_orig->imsi, - sizeof(gsup_reply.imsi)); - gsup_reply.cause = cause; - gsup_reply.message_type = - OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type); - - return gprs_subscr_tx_gsup_message(subscr, &gsup_reply); -} - -static int gprs_subscr_handle_gsup_auth_res(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - unsigned idx; - struct sgsn_subscriber_data *sdata = subscr->sgsn_data; - - LOGGSUBSCRP(LOGL_INFO, subscr, - "Got SendAuthenticationInfoResult, num_auth_vectors = %zu\n", - gsup_msg->num_auth_vectors); - - if (gsup_msg->num_auth_vectors > 0) { - memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets)); - - for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++) - sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL; - } - - for (idx = 0; idx < gsup_msg->num_auth_vectors; idx++) { - size_t key_seq = idx; - LOGGSUBSCRP(LOGL_DEBUG, subscr, - "Adding auth tuple, cksn = %zu\n", key_seq); - if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) { - LOGGSUBSCRP(LOGL_NOTICE, subscr, - "Skipping auth triplet with invalid cksn %zu\n", - key_seq); - continue; - } - sdata->auth_triplets[key_seq].vec = gsup_msg->auth_vectors[idx]; - sdata->auth_triplets[key_seq].key_seq = key_seq; - } - - sdata->auth_triplets_updated = 1; - sdata->error_cause = SGSN_ERROR_CAUSE_NONE; - - gprs_subscr_update_auth_info(subscr); - - return 0; -} - -static int gprs_subscr_pdp_data_clear(struct gprs_subscr *subscr) -{ - struct sgsn_subscriber_pdp_data *pdp, *pdp2; - int count = 0; - - llist_for_each_entry_safe(pdp, pdp2, &subscr->sgsn_data->pdp_list, list) { - llist_del(&pdp->list); - talloc_free(pdp); - count += 1; - } - - return count; -} - -static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id( - struct gprs_subscr *subscr, unsigned context_id) -{ - struct sgsn_subscriber_pdp_data *pdp; - - llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) { - if (pdp->context_id == context_id) - return pdp; - } - - return NULL; -} - - -static void gprs_subscr_gsup_insert_data(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - struct sgsn_subscriber_data *sdata = subscr->sgsn_data; - unsigned idx; - int rc; - - if (gsup_msg->msisdn_enc) { - if (gsup_msg->msisdn_enc_len > sizeof(sdata->msisdn)) { - LOGP(DGPRS, LOGL_ERROR, "MSISDN too long (%zu)\n", - gsup_msg->msisdn_enc_len); - sdata->msisdn_len = 0; - } else { - memcpy(sdata->msisdn, gsup_msg->msisdn_enc, - gsup_msg->msisdn_enc_len); - sdata->msisdn_len = gsup_msg->msisdn_enc_len; - } - } - - if (gsup_msg->hlr_enc) { - if (gsup_msg->hlr_enc_len > sizeof(sdata->hlr)) { - LOGP(DGPRS, LOGL_ERROR, "HLR-Number too long (%zu)\n", - gsup_msg->hlr_enc_len); - sdata->hlr_len = 0; - } else { - memcpy(sdata->hlr, gsup_msg->hlr_enc, - gsup_msg->hlr_enc_len); - sdata->hlr_len = gsup_msg->hlr_enc_len; - } - } - - if (gsup_msg->pdp_charg_enc && gsup_msg->pdp_charg_enc_len >= sizeof(sdata->pdp_charg)) { - memcpy(&sdata->pdp_charg, gsup_msg->pdp_charg_enc, sizeof(sdata->pdp_charg)); - sdata->has_pdp_charg = 1; - } else { - sdata->has_pdp_charg = 0; - } - - if (gsup_msg->pdp_info_compl) { - rc = gprs_subscr_pdp_data_clear(subscr); - if (rc > 0) - LOGP(DGPRS, LOGL_INFO, "Cleared existing PDP info\n"); - } - - for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) { - struct osmo_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx]; - size_t ctx_id = pdp_info->context_id; - struct sgsn_subscriber_pdp_data *pdp_data; - - if (pdp_info->apn_enc_len >= sizeof(pdp_data->apn_str)-1) { - LOGGSUBSCRP(LOGL_ERROR, subscr, - "APN too long, context id = %zu, APN = %s\n", - ctx_id, osmo_hexdump(pdp_info->apn_enc, - pdp_info->apn_enc_len)); - continue; - } - - if (pdp_info->qos_enc_len > sizeof(pdp_data->qos_subscribed)) { - LOGGSUBSCRP(LOGL_ERROR, subscr, - "QoS info too long (%zu)\n", - pdp_info->qos_enc_len); - continue; - } - - LOGGSUBSCRP(LOGL_INFO, subscr, - "Will set PDP info, context id = %zu, APN = %s\n", - ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len)); - - /* Set PDP info [ctx_id] */ - pdp_data = gprs_subscr_pdp_data_get_by_id(subscr, ctx_id); - if (!pdp_data) { - pdp_data = sgsn_subscriber_pdp_data_alloc(subscr->sgsn_data); - pdp_data->context_id = ctx_id; - } - - OSMO_ASSERT(pdp_data != NULL); - pdp_data->pdp_type = pdp_info->pdp_type; - osmo_apn_to_str(pdp_data->apn_str, - pdp_info->apn_enc, pdp_info->apn_enc_len); - memcpy(pdp_data->qos_subscribed, pdp_info->qos_enc, pdp_info->qos_enc_len); - pdp_data->qos_subscribed_len = pdp_info->qos_enc_len; - - if (pdp_info->pdp_charg_enc && pdp_info->pdp_charg_enc_len >= sizeof(pdp_data->pdp_charg)) { - memcpy(&pdp_data->pdp_charg, pdp_info->pdp_charg_enc, sizeof(pdp_data->pdp_charg)); - pdp_data->has_pdp_charg = 1; - } else { - pdp_data->has_pdp_charg = 0; - } - } -} - -static int gprs_subscr_handle_gsup_upd_loc_res(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - /* contrary to MAP, we allow piggy-backing subscriber data onto - * the UPDATE LOCATION RESULT, and don't mandate the use of a - * separate nested INSERT SUBSCRIBER DATA transaction */ - gprs_subscr_gsup_insert_data(subscr, gsup_msg); - - subscr->authorized = 1; - subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; - - subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE; - - gprs_subscr_update(subscr); - return 0; -} - -static int gprs_subscr_handle_gsup_dsd_req(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - struct osmo_gsup_message gsup_reply = {0}; - - if (gsup_msg->cn_domain != OSMO_GSUP_CN_DOMAIN_PS) { - LOGGSUBSCRP(LOGL_ERROR, subscr, - "Rx GSUP message %s not supported for CS\n", - osmo_gsup_message_type_name(gsup_msg->message_type)); - gsup_reply.cause = GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL; - gsup_reply.message_type = OSMO_GSUP_MSGT_DELETE_DATA_ERROR; - } else { - gsm0408_gprs_access_cancelled(subscr->sgsn_data->mm, - GMM_CAUSE_GPRS_NOTALLOWED); - gsup_reply.message_type = OSMO_GSUP_MSGT_DELETE_DATA_RESULT; - } - - return gprs_subscr_tx_gsup_message(subscr, &gsup_reply); -} - -static int gprs_subscr_handle_gsup_isd_req(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - struct osmo_gsup_message gsup_reply = {0}; - - gprs_subscr_gsup_insert_data(subscr, gsup_msg); - - subscr->authorized = 1; - subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; - subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE; - gprs_subscr_update(subscr); - - gsup_reply.message_type = OSMO_GSUP_MSGT_INSERT_DATA_RESULT; - return gprs_subscr_tx_gsup_message(subscr, &gsup_reply); -} - -static int check_cause(int cause) -{ - switch (cause) { - case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME: - case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN: - return EACCES; - - case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION: - return EHOSTUNREACH; - - case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC: - default: - return EINVAL; - } -} - -static int gprs_subscr_handle_gsup_auth_err(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - unsigned idx; - struct sgsn_subscriber_data *sdata = subscr->sgsn_data; - int cause_err; - - cause_err = check_cause(gsup_msg->cause); - - LOGGSUBSCRP(LOGL_DEBUG, subscr, - "Send authentication info has failed with cause %d, " - "handled as: %s\n", - gsup_msg->cause, strerror(cause_err)); - - switch (cause_err) { - case EACCES: - LOGGSUBSCRP(LOGL_NOTICE, subscr, - "GPRS send auth info req failed, access denied, " - "GMM cause = '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - /* Clear auth tuples */ - memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets)); - for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++) - sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL; - - subscr->authorized = 0; - sdata->error_cause = gsup_msg->cause; - gprs_subscr_update_auth_info(subscr); - break; - - case EHOSTUNREACH: - LOGGSUBSCRP(LOGL_NOTICE, subscr, - "GPRS send auth info req failed, GMM cause = '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - - sdata->error_cause = gsup_msg->cause; - gprs_subscr_update_auth_info(subscr); - break; - - default: - case EINVAL: - LOGGSUBSCRP(LOGL_ERROR, subscr, - "GSUP protocol remote error, GMM cause = '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - break; - } - - return -gsup_msg->cause; -} - -static int gprs_subscr_handle_gsup_upd_loc_err(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - int cause_err; - - cause_err = check_cause(gsup_msg->cause); - - LOGGSUBSCRP(LOGL_DEBUG, subscr, - "Update location has failed with cause %d, handled as: %s\n", - gsup_msg->cause, strerror(cause_err)); - - switch (cause_err) { - case EACCES: - LOGGSUBSCRP(LOGL_NOTICE, subscr, - "GPRS update location failed, access denied, " - "GMM cause = '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - - subscr->authorized = 0; - subscr->sgsn_data->error_cause = gsup_msg->cause; - gprs_subscr_update_auth_info(subscr); - break; - - case EHOSTUNREACH: - LOGGSUBSCRP(LOGL_NOTICE, subscr, - "GPRS update location failed, GMM cause = '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - - subscr->sgsn_data->error_cause = gsup_msg->cause; - gprs_subscr_update_auth_info(subscr); - break; - - default: - case EINVAL: - LOGGSUBSCRP(LOGL_ERROR, subscr, - "GSUP protocol remote error, GMM cause = '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - break; - } - - return -gsup_msg->cause; -} - -static int gprs_subscr_handle_gsup_purge_no_subscr( - struct osmo_gsup_message *gsup_msg) -{ - if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) { - LOGGSUPP(LOGL_NOTICE, gsup_msg, - "Purge MS has failed with cause '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - return -gsup_msg->cause; - } - - LOGGSUPP(LOGL_INFO, gsup_msg, "Completing purge MS\n"); - return 0; -} - -static int gprs_subscr_handle_gsup_purge_res(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n"); - - /* Force silent cancellation */ - subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; - gprs_subscr_cancel(subscr); - - return 0; -} - -static int gprs_subscr_handle_gsup_purge_err(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - LOGGSUBSCRP(LOGL_NOTICE, subscr, - "Purge MS has failed with cause '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - - /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that - * the subscriber data is not removed if the request has failed. On the - * other hand, keeping the subscriber data in either error case - * (subscriber unknown, syntactical message error, connection error) - * doesn't seem to give any advantage, since the data will be restored - * on the next Attach Request anyway. - * This approach ensures, that the subscriber record will not stick if - * an error happens. - */ - - /* TODO: Check whether this behaviour is acceptable and either just - * remove this TODO-notice or change the implementation to not delete - * the subscriber data (eventually resetting the ENABLE_PURGE flag and - * restarting the expiry timer based on the cause). - * - * Subscriber Unknown: cancel subscr - * Temporary network problems: do nothing (handled by timer based retry) - * Message problems (syntax, nyi, ...): cancel subscr (retry won't help) - */ - - gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg); - - return -gsup_msg->cause; -} - -static int gprs_subscr_handle_loc_cancel_req(struct gprs_subscr *subscr, - struct osmo_gsup_message *gsup_msg) -{ - struct osmo_gsup_message gsup_reply = {0}; - int is_update_procedure = !gsup_msg->cancel_type || - gsup_msg->cancel_type == OSMO_GSUP_CANCEL_TYPE_UPDATE; - - LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n", - is_update_procedure ? - "update procedure" : "subscription withdraw"); - - gsup_reply.message_type = OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT; - gprs_subscr_tx_gsup_message(subscr, &gsup_reply); - - if (is_update_procedure) - subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; - else - /* Since a withdraw cause is not specified, just abort the - * current attachment. The following re-attachment should then - * be rejected with a proper cause value. - */ - subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED; - - gprs_subscr_cancel(subscr); - - return 0; -} - -static int gprs_subscr_handle_unknown_imsi(struct osmo_gsup_message *gsup_msg) -{ - if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) { - gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg, - GMM_CAUSE_IMSI_UNKNOWN); - LOGP(DGPRS, LOGL_NOTICE, - "Unknown IMSI %s, discarding GSUP request " - "of type 0x%02x\n", - gsup_msg->imsi, gsup_msg->message_type); - } else if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) { - LOGP(DGPRS, LOGL_NOTICE, - "Unknown IMSI %s, discarding GSUP error " - "of type 0x%02x, cause '%s' (%d)\n", - gsup_msg->imsi, gsup_msg->message_type, - get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), - gsup_msg->cause); - } else { - LOGP(DGPRS, LOGL_NOTICE, - "Unknown IMSI %s, discarding GSUP response " - "of type 0x%02x\n", - gsup_msg->imsi, gsup_msg->message_type); - } - - return -GMM_CAUSE_IMSI_UNKNOWN; -} - -int gprs_subscr_rx_gsup_message(struct msgb *msg) -{ - uint8_t *data = msgb_l2(msg); - size_t data_len = msgb_l2len(msg); - int rc = 0; - - struct osmo_gsup_message gsup_msg = {0}; - struct gprs_subscr *subscr; - - rc = osmo_gsup_decode(data, data_len, &gsup_msg); - if (rc < 0) { - LOGP(DGPRS, LOGL_ERROR, - "decoding GSUP message fails with error '%s' (%d)\n", - get_value_string(gsm48_gmm_cause_names, -rc), -rc); - return rc; - } - - if (!gsup_msg.imsi[0]) { - LOGP(DGPRS, LOGL_ERROR, "Missing IMSI in GSUP message\n"); - - if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type)) - gprs_subscr_tx_gsup_error_reply(NULL, &gsup_msg, - GMM_CAUSE_INV_MAND_INFO); - return -GMM_CAUSE_INV_MAND_INFO; - } - - if (!gsup_msg.cause && OSMO_GSUP_IS_MSGT_ERROR(gsup_msg.message_type)) - gsup_msg.cause = GMM_CAUSE_NET_FAIL; - - subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi); - - if (!subscr) { - switch (gsup_msg.message_type) { - case OSMO_GSUP_MSGT_PURGE_MS_RESULT: - case OSMO_GSUP_MSGT_PURGE_MS_ERROR: - return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg); - default: - return gprs_subscr_handle_unknown_imsi(&gsup_msg); - } - } - - LOGGSUBSCRP(LOGL_INFO, subscr, - "Received GSUP message %s\n", - osmo_gsup_message_type_name(gsup_msg.message_type)); - - switch (gsup_msg.message_type) { - case OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST: - rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT: - rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR: - rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: - rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR: - rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_PURGE_MS_ERROR: - rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_PURGE_MS_RESULT: - rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST: - rc = gprs_subscr_handle_gsup_isd_req(subscr, &gsup_msg); - break; - - case OSMO_GSUP_MSGT_DELETE_DATA_REQUEST: - rc = gprs_subscr_handle_gsup_dsd_req(subscr, &gsup_msg); - break; - - default: - LOGGSUBSCRP(LOGL_ERROR, subscr, - "Rx GSUP message %s not valid at SGSN\n", - osmo_gsup_message_type_name(gsup_msg.message_type)); - if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type)) - gprs_subscr_tx_gsup_error_reply( - subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL); - rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL; - break; - }; - - gprs_subscr_put(subscr); - - return rc; -} - -int gprs_subscr_purge(struct gprs_subscr *subscr) -{ - struct sgsn_subscriber_data *sdata = subscr->sgsn_data; - struct osmo_gsup_message gsup_msg = {0}; - - LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n"); - - gsup_msg.message_type = OSMO_GSUP_MSGT_PURGE_MS_REQUEST; - - /* Provide the HLR number in case it is known */ - gsup_msg.hlr_enc_len = sdata->hlr_len; - gsup_msg.hlr_enc = sdata->hlr; - - return gprs_subscr_tx_gsup_message(subscr, &gsup_msg); -} - -static int gprs_subscr_query_auth_info(struct gprs_subscr *subscr, - const uint8_t *auts, - const uint8_t *auts_rand) -{ - struct osmo_gsup_message gsup_msg = {0}; - - /* Make sure we have a complete resync or clearly no resync. */ - OSMO_ASSERT((auts != NULL) == (auts_rand != NULL)); - - LOGGSUBSCRP(LOGL_INFO, subscr, "requesting auth info%s\n", - auts ? " with AUTS (UMTS Resynch)" : ""); - - gsup_msg.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST; - gsup_msg.auts = auts; - gsup_msg.rand = auts_rand; - return gprs_subscr_tx_gsup_message(subscr, &gsup_msg); -} - -int gprs_subscr_location_update(struct gprs_subscr *subscr) -{ - struct osmo_gsup_message gsup_msg = {0}; - - LOGGSUBSCRP(LOGL_INFO, subscr, - "subscriber data is not available\n"); - - gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST; - return gprs_subscr_tx_gsup_message(subscr, &gsup_msg); -} - -void gprs_subscr_update(struct gprs_subscr *subscr) -{ - LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n"); - - subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING; - subscr->flags &= ~GPRS_SUBSCRIBER_FIRST_CONTACT; - - if (subscr->sgsn_data->mm) - sgsn_update_subscriber_data(subscr->sgsn_data->mm); -} - -void gprs_subscr_update_auth_info(struct gprs_subscr *subscr) -{ - LOGGSUBSCRP(LOGL_DEBUG, subscr, - "Updating subscriber authentication info\n"); - - subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING; - subscr->flags &= ~GPRS_SUBSCRIBER_FIRST_CONTACT; - - if (subscr->sgsn_data->mm) - sgsn_update_subscriber_data(subscr->sgsn_data->mm); -} - -struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx) -{ - struct gprs_subscr *subscr = NULL; - - if (mmctx->subscr) - return gprs_subscr_get(mmctx->subscr); - - if (mmctx->imsi[0]) - subscr = gprs_subscr_get_by_imsi(mmctx->imsi); - - if (!subscr) { - subscr = gprs_subscr_get_or_create(mmctx->imsi); - subscr->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT; - subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE; - } - - osmo_strlcpy(subscr->imei, mmctx->imei, sizeof(subscr->imei)); - - if (subscr->lac != mmctx->ra.lac) - subscr->lac = mmctx->ra.lac; - - subscr->sgsn_data->mm = mmctx; - mmctx->subscr = gprs_subscr_get(subscr); - - return subscr; -} - -int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx) -{ - struct gprs_subscr *subscr = NULL; - int rc; - - LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n"); - - subscr = gprs_subscr_get_or_create_by_mmctx(mmctx); - - subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING; - - rc = gprs_subscr_location_update(subscr); - gprs_subscr_put(subscr); - return rc; -} - -/*! \brief Send Update Auth Info request via GSUP, with or without resync. - * \param[in] mmctx MM context to request authentication tuples for. - * \param[in] auts 14 octet AUTS token for UMTS resync, or NULL. - * \param[in] auts_rand 16 octet Random token for UMTS resync, or NULL. - * In case of normal Authentication Info request, both \a auts and \a auts_rand - * must be NULL. For resync, both must be non-NULL. - */ -int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, - const uint8_t *auts, - const uint8_t *auts_rand) -{ - struct gprs_subscr *subscr = NULL; - int rc; - - LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n"); - - subscr = gprs_subscr_get_or_create_by_mmctx(mmctx); - - subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING; - - rc = gprs_subscr_query_auth_info(subscr, auts, auts_rand); - gprs_subscr_put(subscr); - return rc; -} - -static void gprs_subscr_free(struct gprs_subscr *gsub) -{ - llist_del(&gsub->entry); - talloc_free(gsub); -} - -struct gprs_subscr *_gprs_subscr_get(struct gprs_subscr *gsub, - const char *file, int line) -{ - OSMO_ASSERT(gsub->use_count < INT_MAX); - gsub->use_count++; - LOGPSRC(DREF, LOGL_DEBUG, file, line, - "subscr %s usage increases to: %d\n", - gsub->imsi, gsub->use_count); - return gsub; -} - -struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub, - const char *file, int line) -{ - gsub->use_count--; - LOGPSRC(DREF, gsub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR, - file, line, - "subscr %s usage decreases to: %d%s\n", - gsub->imsi, gsub->use_count, - gsub->keep_in_ram? ", keep-in-ram flag is set" : ""); - if (gsub->use_count > 0) - return gsub; - if (gsub->keep_in_ram) - return gsub; - gprs_subscr_free(gsub); - return NULL; -} diff --git a/src/gprs/gprs_utils.c b/src/gprs/gprs_utils.c deleted file mode 100644 index 91a09d2db..000000000 --- a/src/gprs/gprs_utils.c +++ /dev/null @@ -1,246 +0,0 @@ -/* GPRS utility functions */ - -/* (C) 2010 by Harald Welte - * (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 . - * - */ -#include - -#include -#include - -#include -#include -#include - -#include - -/* FIXME: this needs to go to libosmocore/msgb.c */ -struct msgb *gprs_msgb_copy(const struct msgb *msg, const char *name) -{ - struct libgb_msgb_cb *old_cb, *new_cb; - struct msgb *new_msg; - - new_msg = msgb_alloc(msg->data_len, name); - if (!new_msg) - return NULL; - - /* copy data */ - memcpy(new_msg->_data, msg->_data, new_msg->data_len); - - /* copy header */ - new_msg->len = msg->len; - new_msg->data += msg->data - msg->_data; - new_msg->head += msg->head - msg->_data; - new_msg->tail += msg->tail - msg->_data; - - if (msg->l1h) - new_msg->l1h = new_msg->_data + (msg->l1h - msg->_data); - if (msg->l2h) - new_msg->l2h = new_msg->_data + (msg->l2h - msg->_data); - if (msg->l3h) - new_msg->l3h = new_msg->_data + (msg->l3h - msg->_data); - if (msg->l4h) - new_msg->l4h = new_msg->_data + (msg->l4h - msg->_data); - - /* copy GB specific data */ - old_cb = LIBGB_MSGB_CB(msg); - new_cb = LIBGB_MSGB_CB(new_msg); - - if (old_cb->bssgph) - new_cb->bssgph = new_msg->_data + (old_cb->bssgph - msg->_data); - if (old_cb->llch) - new_cb->llch = new_msg->_data + (old_cb->llch - msg->_data); - - /* bssgp_cell_id is a pointer into the old msgb, so we need to make - * it a pointer into the new msgb */ - if (old_cb->bssgp_cell_id) - new_cb->bssgp_cell_id = new_msg->_data + - (old_cb->bssgp_cell_id - msg->_data); - new_cb->nsei = old_cb->nsei; - new_cb->bvci = old_cb->bvci; - new_cb->tlli = old_cb->tlli; - - return new_msg; -} - -/* TODO: Move this to libosmocore/msgb.c */ -int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area, - size_t old_size, size_t new_size) -{ - int rc; - uint8_t *rest = area + old_size; - int rest_len = msg->len - old_size - (area - msg->data); - int delta_size = (int)new_size - (int)old_size; - - if (delta_size == 0) - return 0; - - if (delta_size > 0) { - rc = msgb_trim(msg, msg->len + delta_size); - if (rc < 0) - return rc; - } - - memmove(area + new_size, area + old_size, rest_len); - - if (msg->l1h >= rest) - msg->l1h += delta_size; - if (msg->l2h >= rest) - msg->l2h += delta_size; - if (msg->l3h >= rest) - msg->l3h += delta_size; - if (msg->l4h >= rest) - msg->l4h += delta_size; - - if (delta_size < 0) - msgb_trim(msg, msg->len + delta_size); - - return 0; -} - -int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str) -{ - uint8_t *last_len_field; - int len; - - /* Can we even write the length field to the output? */ - if (max_len == 0) - return -1; - - /* Remember where we need to put the length once we know it */ - last_len_field = apn_enc; - len = 1; - apn_enc += 1; - - while (str[0]) { - if (len >= max_len) - return -1; - - if (str[0] == '.') { - *last_len_field = (apn_enc - last_len_field) - 1; - last_len_field = apn_enc; - } else { - *apn_enc = str[0]; - } - apn_enc += 1; - str += 1; - len += 1; - } - - *last_len_field = (apn_enc - last_len_field) - 1; - - return len; -} - -/* GSM 04.08, 10.5.7.3 GPRS Timer */ -int gprs_tmr_to_secs(uint8_t tmr) -{ - switch (tmr & GPRS_TMR_UNIT_MASK) { - case GPRS_TMR_2SECONDS: - return 2 * (tmr & GPRS_TMR_FACT_MASK); - default: - case GPRS_TMR_MINUTE: - return 60 * (tmr & GPRS_TMR_FACT_MASK); - case GPRS_TMR_6MINUTE: - return 360 * (tmr & GPRS_TMR_FACT_MASK); - case GPRS_TMR_DEACTIVATED: - return -1; - } -} - -/* This functions returns a tmr value such that - * - f is monotonic - * - f(s) <= s - * - f(s) == s if a tmr exists with s = gprs_tmr_to_secs(tmr) - * - the best possible resolution is used - * where - * f(s) = gprs_tmr_to_secs(gprs_secs_to_tmr_floor(s)) - */ -uint8_t gprs_secs_to_tmr_floor(int secs) -{ - if (secs < 0) - return GPRS_TMR_DEACTIVATED; - if (secs < 2 * 32) - return GPRS_TMR_2SECONDS | (secs / 2); - if (secs < 60 * 2) - /* Ensure monotonicity */ - return GPRS_TMR_2SECONDS | GPRS_TMR_FACT_MASK; - if (secs < 60 * 32) - return GPRS_TMR_MINUTE | (secs / 60); - if (secs < 360 * 6) - /* Ensure monotonicity */ - return GPRS_TMR_MINUTE | GPRS_TMR_FACT_MASK; - if (secs < 360 * 32) - return GPRS_TMR_6MINUTE | (secs / 360); - - return GPRS_TMR_6MINUTE | GPRS_TMR_FACT_MASK; -} - -/* GSM 04.08, 10.5.1.4 */ -int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len) -{ - if (value_len != GSM48_TMSI_LEN) - return 0; - - if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_TMSI) - return 0; - - return 1; -} - -/* GSM 04.08, 10.5.1.4 */ -int gprs_is_mi_imsi(const uint8_t *value, size_t value_len) -{ - if (value_len == 0) - return 0; - - if (!value || (value[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) - return 0; - - return 1; -} - -int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi) -{ - uint32_t tmsi_be; - - if (!gprs_is_mi_tmsi(value, value_len)) - return 0; - - memcpy(&tmsi_be, value + 1, sizeof(tmsi_be)); - - *tmsi = ntohl(tmsi_be); - return 1; -} - -void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi) -{ - uint32_t tmsi_be; - - memcpy(&tmsi_be, value, sizeof(tmsi_be)); - - *tmsi = ntohl(tmsi_be); -} - -int gprs_ra_id_equals(const struct gprs_ra_id *id1, - const struct gprs_ra_id *id2) -{ - return (id1->mcc == id2->mcc && id1->mnc == id2->mnc && - id1->lac == id2->lac && id1->rac == id2->rac); -} diff --git a/src/gprs/gtphub.c b/src/gprs/gtphub.c deleted file mode 100644 index 0a8e375ab..000000000 --- a/src/gprs/gtphub.c +++ /dev/null @@ -1,2937 +0,0 @@ -/* GTP Hub Implementation */ - -/* (C) 2015 by sysmocom s.f.m.c. GmbH - * 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 . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - - -static const int GTPH_GC_TICK_SECONDS = 1; - -void *osmo_gtphub_ctx; - -/* Convenience makro, note: only within this C file. */ -#define LOG(level, fmt, args...) \ - LOGP(DGTPHUB, level, fmt, ##args) - -#define ZERO_STRUCT(struct_pointer) memset(struct_pointer, '\0', \ - sizeof(*(struct_pointer))) - -/* TODO move this to osmocom/core/select.h ? */ -typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what); - -/* TODO move this to osmocom/core/linuxlist.h ? */ -#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next) -#define llist_first(head, type, entry) \ - llist_entry(__llist_first(head), type, entry) - -#define __llist_last(head) (((head)->next == (head)) ? NULL : (head)->prev) -#define llist_last(head, type, entry) \ - llist_entry(__llist_last(head), type, entry) - -/* TODO move GTP header stuff to openggsn/gtp/ ? See gtp_decaps*() */ - -enum gtp_rc { - GTP_RC_UNKNOWN = 0, - GTP_RC_TINY = 1, /* no IEs (like ping/pong) */ - GTP_RC_PDU_C = 2, /* a real packet with IEs */ - GTP_RC_PDU_U = 3, /* a real packet with User data */ - - GTP_RC_TOOSHORT = -1, - GTP_RC_UNSUPPORTED_VERSION = -2, - GTP_RC_INVALID_IE = -3, -}; - -struct gtp_packet_desc { - union gtp_packet *data; - int data_len; - int header_len; - int version; - uint8_t type; - uint16_t seq; - uint32_t header_tei_rx; - uint32_t header_tei; - int rc; /* enum gtp_rc */ - unsigned int plane_idx; - unsigned int side_idx; - struct gtphub_tunnel *tun; - time_t timestamp; - union gtpie_member *ie[GTPIE_SIZE]; -}; - -struct pending_delete { - struct llist_head entry; - struct expiring_item expiry_entry; - - struct gtphub_tunnel *tun; - uint8_t teardown_ind; - uint8_t nsapi; -}; - - -/* counters */ - -enum gtphub_counters_io { - GTPH_CTR_PKTS_IN = 0, - GTPH_CTR_PKTS_OUT, - GTPH_CTR_BYTES_IN, - GTPH_CTR_BYTES_OUT -}; - -static const struct rate_ctr_desc gtphub_counters_io_desc[] = { - { "packets.in", "Packets ( In)" }, - { "packets.out", "Packets (Out)" }, - { "bytes.in", "Bytes ( In)" }, - { "bytes.out", "Bytes (Out)" }, -}; - -static const struct rate_ctr_group_desc gtphub_ctrg_io_desc = { - .group_name_prefix = "gtphub.bind", - .group_description = "I/O Statistics", - .num_ctr = ARRAY_SIZE(gtphub_counters_io_desc), - .ctr_desc = gtphub_counters_io_desc, - .class_id = OSMO_STATS_CLASS_GLOBAL, -}; - - -/* support */ - -static const char *gtp_type_str(uint8_t type) -{ - switch (type) { - case 1: - return " (Echo Request)"; - case 2: - return " (Echo Response)"; - case 16: - return " (Create PDP Ctx Request)"; - case 17: - return " (Create PDP Ctx Response)"; - case 18: - return " (Update PDP Ctx Request)"; - case 19: - return " (Update PDP Ctx Response)"; - case 20: - return " (Delete PDP Ctx Request)"; - case 21: - return " (Delete PDP Ctx Response)"; - case 255: - return " (User Data)"; - default: - return ""; - } -} - -void gsn_addr_copy(struct gsn_addr *gsna, const struct gsn_addr *src) -{ - *gsna = *src; -} - -int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port, - const struct osmo_sockaddr *sa) -{ - char addr_str[256]; - char port_str[6]; - - if (osmo_sockaddr_to_strs(addr_str, sizeof(addr_str), - port_str, sizeof(port_str), - sa, (NI_NUMERICHOST | NI_NUMERICSERV)) - != 0) { - return -1; - } - - if (port) - *port = atoi(port_str); - - return gsn_addr_from_str(gsna, addr_str); -} - -int gsn_addr_from_str(struct gsn_addr *gsna, const char *numeric_addr_str) -{ - if ((!gsna) || (!numeric_addr_str)) - return -1; - - int af = AF_INET; - gsna->len = 4; - const char *pos = numeric_addr_str; - for (; *pos; pos++) { - if (*pos == ':') { - af = AF_INET6; - gsna->len = 16; - break; - } - } - - int rc = inet_pton(af, numeric_addr_str, gsna->buf); - if (rc != 1) { - LOG(LOGL_ERROR, "Cannot resolve numeric address: '%s'\n", - numeric_addr_str); - return -1; - } - return 0; -} - -const char *gsn_addr_to_str(const struct gsn_addr *gsna) -{ - static char buf[INET6_ADDRSTRLEN + 1]; - return gsn_addr_to_strb(gsna, buf, sizeof(buf)); -} - -const char *gsn_addr_to_strb(const struct gsn_addr *gsna, - char *strbuf, - int strbuf_len) -{ - int af; - switch (gsna->len) { - case 4: - af = AF_INET; - break; - case 16: - af = AF_INET6; - break; - default: - return NULL; - } - - const char *r = inet_ntop(af, gsna->buf, strbuf, strbuf_len); - if (!r) { - LOG(LOGL_ERROR, "Cannot convert gsn_addr to string:" - " %s: len=%d, buf=%s\n", - strerror(errno), - (int)gsna->len, - osmo_hexdump(gsna->buf, sizeof(gsna->buf))); - } - return r; -} - -int gsn_addr_same(const struct gsn_addr *a, const struct gsn_addr *b) -{ - if (a == b) - return 1; - if ((!a) || (!b)) - return 0; - if (a->len != b->len) - return 0; - return (memcmp(a->buf, b->buf, a->len) == 0)? 1 : 0; -} - -static int gsn_addr_get(struct gsn_addr *gsna, const struct gtp_packet_desc *p, - int idx) -{ - if (p->rc != GTP_RC_PDU_C) - return -1; - - unsigned int len; - /* gtpie.h fails to declare gtpie_gettlv()'s first arg as const. */ - if (gtpie_gettlv((union gtpie_member**)p->ie, GTPIE_GSN_ADDR, idx, - &len, gsna->buf, sizeof(gsna->buf)) - != 0) - return -1; - gsna->len = len; - return 0; -} - -static int gsn_addr_put(const struct gsn_addr *gsna, struct gtp_packet_desc *p, - int idx) -{ - if (p->rc != GTP_RC_PDU_C) - return -1; - - int ie_idx; - ie_idx = gtpie_getie(p->ie, GTPIE_GSN_ADDR, idx); - - if (ie_idx < 0) - return -1; - - struct gtpie_tlv *ie = &p->ie[ie_idx]->tlv; - int ie_l = ntoh16(ie->l); - if (ie_l != gsna->len) { - LOG(LOGL_ERROR, "Not implemented:" - " replace an IE address of different size:" - " replace %d with %d\n", (int)ie_l, (int)gsna->len); - return -1; - } - - memcpy(ie->v, gsna->buf, (int)ie_l); - return 0; -} - -/* Validate GTP version 0 data; analogous to validate_gtp1_header(), see there. - */ -void validate_gtp0_header(struct gtp_packet_desc *p) -{ - const struct gtp0_header *pheader = &(p->data->gtp0.h); - p->rc = GTP_RC_UNKNOWN; - p->header_len = 0; - - OSMO_ASSERT(p->data_len >= 1); - OSMO_ASSERT(p->version == 0); - - if (p->data_len < GTP0_HEADER_SIZE) { - LOG(LOGL_ERROR, "GTP0 packet too short: %d\n", p->data_len); - p->rc = GTP_RC_TOOSHORT; - return; - } - - p->type = ntoh8(pheader->type); - p->seq = ntoh16(pheader->seq); - p->header_tei_rx = 0; /* TODO */ - p->header_tei = p->header_tei_rx; - - if (p->data_len == GTP0_HEADER_SIZE) { - p->rc = GTP_RC_TINY; - p->header_len = GTP0_HEADER_SIZE; - return; - } - - /* Check packet length field versus length of packet */ - if (p->data_len != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) { - LOG(LOGL_ERROR, "GTP packet length field (%d + %d) does not" - " match actual length (%d)\n", - GTP0_HEADER_SIZE, (int)ntoh16(pheader->length), - p->data_len); - p->rc = GTP_RC_TOOSHORT; - return; - } - - LOG(LOGL_DEBUG, "GTP v0 TID = %" PRIu64 "\n", pheader->tid); - p->header_len = GTP0_HEADER_SIZE; - p->rc = GTP_RC_PDU_C; -} - -/* Validate GTP version 1 data, and update p->rc with the result, as well as - * p->header_len in case of a valid header. */ -void validate_gtp1_header(struct gtp_packet_desc *p) -{ - const struct gtp1_header_long *pheader = &(p->data->gtp1l.h); - p->rc = GTP_RC_UNKNOWN; - p->header_len = 0; - - OSMO_ASSERT(p->data_len >= 1); - OSMO_ASSERT(p->version == 1); - - if ((p->data_len < GTP1_HEADER_SIZE_LONG) - && (p->data_len != GTP1_HEADER_SIZE_SHORT)){ - LOG(LOGL_ERROR, "GTP packet too short: %d\n", p->data_len); - p->rc = GTP_RC_TOOSHORT; - return; - } - - p->type = ntoh8(pheader->type); - p->header_tei_rx = ntoh32(pheader->tei); - p->header_tei = p->header_tei_rx; - p->seq = ntoh16(pheader->seq); - - LOG(LOGL_DEBUG, "| GTPv1\n"); - LOG(LOGL_DEBUG, "| type = %" PRIu8 " 0x%02" PRIx8 "\n", p->type, p->type); - LOG(LOGL_DEBUG, "| length = %" PRIu16 " 0x%04" PRIx16 "\n", ntoh16(pheader->length), ntoh16(pheader->length)); - LOG(LOGL_DEBUG, "| TEI = %" PRIu32 " 0x%08" PRIx32 "\n", p->header_tei_rx, p->header_tei_rx); - LOG(LOGL_DEBUG, "| seq = %" PRIu16 " 0x%04" PRIx16 "\n", p->seq, p->seq); - LOG(LOGL_DEBUG, "| npdu = %" PRIu8 " 0x%02" PRIx8 "\n", pheader->npdu, pheader->npdu); - LOG(LOGL_DEBUG, "| next = %" PRIu8 " 0x%02" PRIx8 "\n", pheader->next, pheader->next); - - if (p->data_len <= GTP1_HEADER_SIZE_LONG) { - p->rc = GTP_RC_TINY; - p->header_len = GTP1_HEADER_SIZE_SHORT; - return; - } - - /* Check packet length field versus length of packet */ - int announced_len = ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT; - if (p->data_len != announced_len) { - LOG(LOGL_ERROR, "GTP packet length field (%d + %d) does not" - " match actual length (%d)\n", - GTP1_HEADER_SIZE_SHORT, (int)ntoh16(pheader->length), - p->data_len); - p->rc = GTP_RC_TOOSHORT; - return; - } - - p->rc = GTP_RC_PDU_C; - p->header_len = GTP1_HEADER_SIZE_LONG; -} - -/* Examine whether p->data of size p->data_len has a valid GTP header. Set - * p->version, p->rc and p->header_len. On error, p->rc <= 0 (see enum - * gtp_rc). p->data must point at a buffer with p->data_len set. */ -void validate_gtp_header(struct gtp_packet_desc *p) -{ - p->rc = GTP_RC_UNKNOWN; - - /* Need at least 1 byte in order to check version */ - if (p->data_len < 1) { - LOG(LOGL_ERROR, "Discarding packet - too small: %d\n", - p->data_len); - p->rc = GTP_RC_TOOSHORT; - return; - } - - p->version = p->data->flags >> 5; - - switch (p->version) { - case 0: - validate_gtp0_header(p); - break; - case 1: - validate_gtp1_header(p); - break; - default: - LOG(LOGL_ERROR, "Unsupported GTP version: %d\n", p->version); - p->rc = GTP_RC_UNSUPPORTED_VERSION; - break; - } -} - - -/* Return the value of the i'th IMSI IEI by copying to *imsi. - * The first IEI is reached by passing i = 0. - * imsi must point at allocated space of (at least) 8 bytes. - * Return 1 on success, or 0 if not found. */ -static int get_ie_imsi(union gtpie_member *ie[], int i, uint8_t *imsi) -{ - return gtpie_gettv0(ie, GTPIE_IMSI, i, imsi, 8) == 0; -} - -/* Analogous to get_ie_imsi(). nsapi must point at a single uint8_t. */ -static int get_ie_nsapi(union gtpie_member *ie[], int i, uint8_t *nsapi) -{ - return gtpie_gettv1(ie, GTPIE_NSAPI, i, nsapi) == 0; -} - -static char imsi_digit_to_char(uint8_t nibble) -{ - nibble &= 0x0f; - if (nibble > 9) - return (nibble == 0x0f) ? '\0' : '?'; - return '0' + nibble; -} - -/* Return a human readable IMSI string, in a static buffer. - * imsi must point at 8 octets of IMSI IE encoded IMSI data. */ -static int imsi_to_str(uint8_t *imsi, const char **imsi_str) -{ - static char str[17]; - int i; - - for (i = 0; i < 8; i++) { - char c; - c = imsi_digit_to_char(imsi[i]); - if (c == '?') - return -1; - str[2*i] = c; - - c = imsi_digit_to_char(imsi[i] >> 4); - if (c == '?') - return -1; - str[2*i + 1] = c; - } - str[16] = '\0'; - *imsi_str = str; - return 1; -} - -/* Return 0 if not present, 1 if present and decoded successfully, -1 if - * present but cannot be decoded. */ -static int get_ie_imsi_str(union gtpie_member *ie[], int i, - const char **imsi_str) -{ - uint8_t imsi_buf[8]; - if (!get_ie_imsi(ie, i, imsi_buf)) - return 0; - return imsi_to_str(imsi_buf, imsi_str); -} - -/* Return 0 if not present, 1 if present and decoded successfully, -1 if - * present but cannot be decoded. */ -static int get_ie_apn_str(union gtpie_member *ie[], const char **apn_str) -{ - static char apn_buf[GSM_APN_LENGTH]; - unsigned int len; - if (gtpie_gettlv(ie, GTPIE_APN, 0, - &len, apn_buf, sizeof(apn_buf)) != 0) - return 0; - - if (len < 2) { - LOG(LOGL_ERROR, "APN IE: invalid length: %d\n", - (int)len); - return -1; - } - - if (len > (sizeof(apn_buf) - 1)) - len = sizeof(apn_buf) - 1; - apn_buf[len] = '\0'; - - *apn_str = osmo_apn_to_str(apn_buf, (uint8_t*)apn_buf, len); - if (!(*apn_str)) { - LOG(LOGL_ERROR, "APN IE: present but cannot be decoded: %s\n", - osmo_hexdump((uint8_t*)apn_buf, len)); - return -1; - } - return 1; -} - - -/* Validate header, and index information elements. Write decoded packet - * information to *res. res->data will point at the given data buffer. On - * error, p->rc is set <= 0 (see enum gtp_rc). */ -static void gtp_decode(const uint8_t *data, int data_len, - unsigned int from_side_idx, - unsigned int from_plane_idx, - struct gtp_packet_desc *res, - time_t now) -{ - ZERO_STRUCT(res); - res->data = (union gtp_packet*)data; - res->data_len = data_len; - res->side_idx = from_side_idx; - res->plane_idx = from_plane_idx; - res->timestamp = now; - - validate_gtp_header(res); - - if (res->rc <= 0) - return; - - LOG(LOGL_DEBUG, "Valid GTP header (v%d)\n", res->version); - - if (from_plane_idx == GTPH_PLANE_USER) { - res->rc = GTP_RC_PDU_U; - return; - } - - if (res->rc != GTP_RC_PDU_C) { - LOG(LOGL_DEBUG, "no IEs in this GTP packet\n"); - return; - } - - if (gtpie_decaps(res->ie, res->version, - (void*)(data + res->header_len), - res->data_len - res->header_len) != 0) { - res->rc = GTP_RC_INVALID_IE; - LOG(LOGL_ERROR, "INVALID: cannot decode IEs." - " Dropping GTP packet%s.\n", - gtp_type_str(res->type) - ); - return; - } - -#if 1 - /* TODO if () - (waiting for a commit from jerlbeck) */ - int i; - - for (i = 0; i < 10; i++) { - const char *imsi; - if (get_ie_imsi_str(res->ie, i, &imsi) < 1) - break; - LOG(LOGL_DEBUG, "| IMSI %s\n", imsi); - } - - for (i = 0; i < 10; i++) { - uint8_t nsapi; - if (!get_ie_nsapi(res->ie, i, &nsapi)) - break; - LOG(LOGL_DEBUG, "| NSAPI %d\n", (int)nsapi); - } - - for (i = 0; i < 2; i++) { - struct gsn_addr addr; - if (gsn_addr_get(&addr, res, i) == 0) - LOG(LOGL_DEBUG, "| addr %s\n", gsn_addr_to_str(&addr)); - } - - for (i = 0; i < 10; i++) { - uint32_t tei; - if (gtpie_gettv4(res->ie, GTPIE_TEI_DI, i, &tei) != 0) - break; - LOG(LOGL_DEBUG, "| TEI DI (USER) %" PRIu32 " 0x%08" PRIx32 "\n", - tei, tei); - } - - for (i = 0; i < 10; i++) { - uint32_t tei; - if (gtpie_gettv4(res->ie, GTPIE_TEI_C, i, &tei) != 0) - break; - LOG(LOGL_DEBUG, "| TEI (CTRL) %" PRIu32 " 0x%08" PRIx32 "\n", - tei, tei); - } -#endif -} - - -/* expiry */ - -void expiry_init(struct expiry *exq, int expiry_in_seconds) -{ - ZERO_STRUCT(exq); - exq->expiry_in_seconds = expiry_in_seconds; - INIT_LLIST_HEAD(&exq->items); -} - -void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now) -{ - item->expiry = now + exq->expiry_in_seconds; - - OSMO_ASSERT(llist_empty(&exq->items) - || (item->expiry - >= llist_last(&exq->items, struct expiring_item, entry)->expiry)); - - /* Add/move to the tail to always sort by expiry, ascending. */ - llist_del(&item->entry); - llist_add_tail(&item->entry, &exq->items); -} - -int expiry_tick(struct expiry *exq, time_t now) -{ - int expired = 0; - struct expiring_item *m, *n; - llist_for_each_entry_safe(m, n, &exq->items, entry) { - if (m->expiry <= now) { - expiring_item_del(m); - expired ++; - } else { - /* The items are added sorted by expiry. So when we hit - * an unexpired entry, only more unexpired ones will - * follow. */ - break; - } - } - return expired; -} - -void expiry_clear(struct expiry *exq) -{ - struct expiring_item *m, *n; - llist_for_each_entry_safe(m, n, &exq->items, entry) { - expiring_item_del(m); - } -} - -void expiring_item_init(struct expiring_item *item) -{ - ZERO_STRUCT(item); - INIT_LLIST_HEAD(&item->entry); -} - -void expiring_item_del(struct expiring_item *item) -{ - OSMO_ASSERT(item); - llist_del(&item->entry); - INIT_LLIST_HEAD(&item->entry); - if (item->del_cb) { - /* avoid loops */ - del_cb_t del_cb = item->del_cb; - item->del_cb = 0; - (del_cb)(item); - } -} - - -/* nr_map, nr_pool */ - -void nr_pool_init(struct nr_pool *pool, nr_t nr_min, nr_t nr_max) -{ - *pool = (struct nr_pool){ - .nr_min = nr_min, - .nr_max = nr_max, - .last_nr = nr_max - }; -} - -nr_t nr_pool_next(struct nr_pool *pool) -{ - if (pool->last_nr >= pool->nr_max) - pool->last_nr = pool->nr_min; - else - pool->last_nr ++; - - return pool->last_nr; -} - -void nr_map_init(struct nr_map *map, struct nr_pool *pool, - struct expiry *exq) -{ - ZERO_STRUCT(map); - map->pool = pool; - map->add_items_to_expiry = exq; - INIT_LLIST_HEAD(&map->mappings); -} - -void nr_mapping_init(struct nr_mapping *m) -{ - ZERO_STRUCT(m); - INIT_LLIST_HEAD(&m->entry); - expiring_item_init(&m->expiry_entry); -} - -void nr_map_add(struct nr_map *map, struct nr_mapping *mapping, time_t now) -{ - /* Generate a mapped number */ - mapping->repl = nr_pool_next(map->pool); - - /* Add to the tail to always yield a list sorted by expiry, in - * ascending order. */ - llist_add_tail(&mapping->entry, &map->mappings); - nr_map_refresh(map, mapping, now); -} - -void nr_map_refresh(struct nr_map *map, struct nr_mapping *mapping, time_t now) -{ - if (!map->add_items_to_expiry) - return; - expiry_add(map->add_items_to_expiry, - &mapping->expiry_entry, - now); -} - -void nr_map_clear(struct nr_map *map) -{ - struct nr_mapping *m; - struct nr_mapping *n; - llist_for_each_entry_safe(m, n, &map->mappings, entry) { - nr_mapping_del(m); - } -} - -int nr_map_empty(const struct nr_map *map) -{ - return llist_empty(&map->mappings); -} - -struct nr_mapping *nr_map_get(const struct nr_map *map, - void *origin, nr_t nr_orig) -{ - struct nr_mapping *mapping; - llist_for_each_entry(mapping, &map->mappings, entry) { - if ((mapping->origin == origin) - && (mapping->orig == nr_orig)) - return mapping; - } - /* Not found. */ - return NULL; -} - -struct nr_mapping *nr_map_get_inv(const struct nr_map *map, nr_t nr_repl) -{ - struct nr_mapping *mapping; - llist_for_each_entry(mapping, &map->mappings, entry) { - if (mapping->repl == nr_repl) { - return mapping; - } - } - /* Not found. */ - return NULL; -} - -void nr_mapping_del(struct nr_mapping *mapping) -{ - OSMO_ASSERT(mapping); - llist_del(&mapping->entry); - INIT_LLIST_HEAD(&mapping->entry); - expiring_item_del(&mapping->expiry_entry); -} - - -/* gtphub */ - -const char* const gtphub_plane_idx_names[GTPH_PLANE_N] = { - "CTRL", - "USER", -}; - -const uint16_t gtphub_plane_idx_default_port[GTPH_PLANE_N] = { - 2123, - 2152, -}; - -const char* const gtphub_side_idx_names[GTPH_SIDE_N] = { - "SGSN", - "GGSN", -}; - -time_t gtphub_now(void) -{ - struct timespec now_tp; - OSMO_ASSERT(clock_gettime(CLOCK_MONOTONIC, &now_tp) >= 0); - return now_tp.tv_sec; -} - -/* Remove a gtphub_peer from its list and free it. */ -static void gtphub_peer_del(struct gtphub_peer *peer) -{ - OSMO_ASSERT(llist_empty(&peer->addresses)); - nr_map_clear(&peer->seq_map); - llist_del(&peer->entry); - talloc_free(peer); -} - -static void gtphub_peer_addr_del(struct gtphub_peer_addr *pa) -{ - OSMO_ASSERT(llist_empty(&pa->ports)); - llist_del(&pa->entry); - talloc_free(pa); -} - -static void gtphub_peer_port_del(struct gtphub_peer_port *pp) -{ - OSMO_ASSERT(pp->ref_count == 0); - llist_del(&pp->entry); - rate_ctr_group_free(pp->counters_io); - talloc_free(pp); -} - -/* From the information in the gtp_packet_desc, return the address of a GGSN. - * Return -1 on error. */ -static int gtphub_resolve_ggsn(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port **pp); - -/* See gtphub_ext.c (wrapped by unit test) */ -struct gtphub_peer_port *gtphub_resolve_ggsn_addr(struct gtphub *hub, - const char *imsi_str, - const char *apn_ni_str); -int gtphub_ares_init(struct gtphub *hub); - -static void gtphub_zero(struct gtphub *hub) -{ - ZERO_STRUCT(hub); - INIT_LLIST_HEAD(&hub->ggsn_lookups); - INIT_LLIST_HEAD(&hub->resolved_ggsns); -} - -static int gtphub_sock_init(struct osmo_fd *ofd, - const struct gtphub_cfg_addr *addr, - osmo_fd_cb_t cb, - void *data, - int ofd_id) -{ - if (!addr->addr_str) { - LOG(LOGL_FATAL, "Cannot bind: empty address.\n"); - return -1; - } - if (!addr->port) { - LOG(LOGL_FATAL, "Cannot bind: zero port not permitted.\n"); - return -1; - } - - ofd->when = BSC_FD_READ; - ofd->cb = cb; - ofd->data = data; - ofd->priv_nr = ofd_id; - - int rc; - rc = osmo_sock_init_ofd(ofd, - AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, - addr->addr_str, addr->port, - OSMO_SOCK_F_BIND); - if (rc < 1) { - LOG(LOGL_FATAL, "Cannot bind to %s port %d (rc %d)\n", - addr->addr_str, (int)addr->port, rc); - return -1; - } - - return 0; -} - -static void gtphub_sock_close(struct osmo_fd *ofd) -{ - close(ofd->fd); - osmo_fd_unregister(ofd); - ofd->cb = NULL; -} - -static void gtphub_bind_init(struct gtphub_bind *b) -{ - ZERO_STRUCT(b); - - INIT_LLIST_HEAD(&b->peers); - - b->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, - >phub_ctrg_io_desc, 0); - OSMO_ASSERT(b->counters_io); -} - -static int gtphub_bind_start(struct gtphub_bind *b, - const struct gtphub_cfg_bind *cfg, - osmo_fd_cb_t cb, void *cb_data, - unsigned int ofd_id) -{ - LOG(LOGL_DEBUG, "Starting bind %s\n", b->label); - if (gsn_addr_from_str(&b->local_addr, cfg->bind.addr_str) != 0) { - LOG(LOGL_FATAL, "Invalid bind address for %s: %s\n", - b->label, cfg->bind.addr_str); - return -1; - } - if (gtphub_sock_init(&b->ofd, &cfg->bind, cb, cb_data, ofd_id) != 0) { - LOG(LOGL_FATAL, "Cannot bind for %s: %s\n", - b->label, cfg->bind.addr_str); - return -1; - } - b->local_port = cfg->bind.port; - return 0; -} - -static void gtphub_bind_free(struct gtphub_bind *b) -{ - OSMO_ASSERT(llist_empty(&b->peers)); - rate_ctr_group_free(b->counters_io); -} - -static void gtphub_bind_stop(struct gtphub_bind *b) { - gtphub_sock_close(&b->ofd); - gtphub_bind_free(b); -} - -/* Recv datagram from from->fd, write sender's address to *from_addr. - * Return the number of bytes read, zero on error. */ -static int gtphub_read(const struct osmo_fd *from, - struct osmo_sockaddr *from_addr, - uint8_t *buf, size_t buf_len) -{ - OSMO_ASSERT(from_addr); - - /* recvfrom requires the available length set in *from_addr_len. */ - from_addr->l = sizeof(from_addr->a); - errno = 0; - ssize_t received = recvfrom(from->fd, buf, buf_len, 0, - (struct sockaddr*)&from_addr->a, - &from_addr->l); - /* TODO use recvmsg and get a MSG_TRUNC flag to make sure the message - * is not truncated. Then maybe reduce buf's size. */ - - if (received <= 0) { - LOG((errno == EAGAIN? LOGL_DEBUG : LOGL_ERROR), - "error: %s\n", strerror(errno)); - return 0; - } - - LOG(LOGL_DEBUG, "Received %d bytes from %s: %s%s\n", - (int)received, osmo_sockaddr_to_str(from_addr), - osmo_hexdump(buf, received > 1000? 1000 : received), - received > 1000 ? "..." : ""); - - return received; -} - -static inline void gtphub_port_ref_count_inc(struct gtphub_peer_port *pp) -{ - OSMO_ASSERT(pp); - OSMO_ASSERT(pp->ref_count < UINT_MAX); - pp->ref_count++; -} - -static inline void gtphub_port_ref_count_dec(struct gtphub_peer_port *pp) -{ - OSMO_ASSERT(pp); - OSMO_ASSERT(pp->ref_count > 0); - pp->ref_count--; -} - -static inline void set_seq(struct gtp_packet_desc *p, uint16_t seq) -{ - OSMO_ASSERT(p->version == 1); - p->data->gtp1l.h.seq = hton16(seq); - p->seq = seq; -} - -static inline void set_tei(struct gtp_packet_desc *p, uint32_t tei) -{ - OSMO_ASSERT(p->version == 1); - p->data->gtp1l.h.tei = hton32(tei); - p->header_tei = tei; -} - -static void gtphub_mapping_del_cb(struct expiring_item *expi); - -static struct nr_mapping *gtphub_mapping_new() -{ - struct nr_mapping *nrm; - nrm = talloc_zero(osmo_gtphub_ctx, struct nr_mapping); - OSMO_ASSERT(nrm); - - nr_mapping_init(nrm); - nrm->expiry_entry.del_cb = gtphub_mapping_del_cb; - return nrm; -} - - -#define APPEND(args...) \ - l = snprintf(pos, left, args); \ - pos += l; \ - left -= l - -static const char *gtphub_tunnel_side_str(struct gtphub_tunnel *tun, - int side_idx) -{ - static char buf[256]; - char *pos = buf; - int left = sizeof(buf); - int l; - - struct gtphub_tunnel_endpoint *c, *u; - c = &tun->endpoint[side_idx][GTPH_PLANE_CTRL]; - u = &tun->endpoint[side_idx][GTPH_PLANE_USER]; - - /* print both only if they differ. */ - if (!c->peer) { - APPEND("(uninitialized)"); - } else { - APPEND("%s", gsn_addr_to_str(&c->peer->peer_addr->addr)); - } - - if (!u->peer) { - if (c->peer) { - APPEND("/(uninitialized)"); - } - } else if ((!c->peer) - || (!gsn_addr_same(&u->peer->peer_addr->addr, - &c->peer->peer_addr->addr))) { - APPEND("/%s", gsn_addr_to_str(&u->peer->peer_addr->addr)); - } - - APPEND(" (TEI C=%x U=%x)", - c->tei_orig, - u->tei_orig); - return buf; -} - -const char *gtphub_tunnel_str(struct gtphub_tunnel *tun) -{ - static char buf[512]; - char *pos = buf; - int left = sizeof(buf); - int l; - - if (!tun) - return "null-tunnel"; - - APPEND("TEI=%x: ", tun->tei_repl); - APPEND("%s", gtphub_tunnel_side_str(tun, GTPH_SIDE_SGSN)); - APPEND(" <-> %s", gtphub_tunnel_side_str(tun, GTPH_SIDE_GGSN)); - - return buf; -} - -#undef APPEND - -void gtphub_tunnel_endpoint_set_peer(struct gtphub_tunnel_endpoint *te, - struct gtphub_peer_port *pp) -{ - if (te->peer) - gtphub_port_ref_count_dec(te->peer); - te->peer = pp; - if (te->peer) - gtphub_port_ref_count_inc(te->peer); -} - -int gtphub_tunnel_complete(struct gtphub_tunnel *tun) -{ - if (!tun) - return 0; - if (!tun->tei_repl) - return 0; - int side_idx; - int plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - struct gtphub_tunnel_endpoint *te = - &tun->endpoint[side_idx][plane_idx]; - if (!(te->peer && te->tei_orig)) - return 0; - } - return 1; -} - -static void gtphub_tunnel_del_cb(struct expiring_item *expi) -{ - struct gtphub_tunnel *tun = container_of(expi, - struct gtphub_tunnel, - expiry_entry); - LOG(LOGL_DEBUG, "expired: %s\n", gtphub_tunnel_str(tun)); - - llist_del(&tun->entry); - INIT_LLIST_HEAD(&tun->entry); /* mark unused */ - - expi->del_cb = 0; /* avoid recursion loops */ - expiring_item_del(&tun->expiry_entry); /* usually already done, but make sure. */ - - int side_idx; - int plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - struct gtphub_tunnel_endpoint *te = &tun->endpoint[side_idx][plane_idx]; - - /* clear ref count */ - gtphub_tunnel_endpoint_set_peer(te, NULL); - - rate_ctr_group_free(te->counters_io); - } - - talloc_free(tun); -} - -static struct gtphub_tunnel *gtphub_tunnel_new() -{ - struct gtphub_tunnel *tun; - tun = talloc_zero(osmo_gtphub_ctx, struct gtphub_tunnel); - OSMO_ASSERT(tun); - - INIT_LLIST_HEAD(&tun->entry); - expiring_item_init(&tun->expiry_entry); - - int side_idx, plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - struct gtphub_tunnel_endpoint *te = &tun->endpoint[side_idx][plane_idx]; - te->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, - >phub_ctrg_io_desc, - 0); - OSMO_ASSERT(te->counters_io); - } - - tun->expiry_entry.del_cb = gtphub_tunnel_del_cb; - return tun; -} - -static const char *gtphub_peer_strb(struct gtphub_peer *peer, char *buf, - int buflen) -{ - if (llist_empty(&peer->addresses)) - return "(addressless)"; - - struct gtphub_peer_addr *a = llist_first(&peer->addresses, - struct gtphub_peer_addr, - entry); - return gsn_addr_to_strb(&a->addr, buf, buflen); -} - -static const char *gtphub_port_strb(struct gtphub_peer_port *port, char *buf, - int buflen) -{ - if (!port) - return "(null port)"; - - snprintf(buf, buflen, "%s port %d", - gsn_addr_to_str(&port->peer_addr->addr), - (int)port->port); - return buf; -} - -const char *gtphub_peer_str(struct gtphub_peer *peer) -{ - static char buf[256]; - return gtphub_peer_strb(peer, buf, sizeof(buf)); -} - -const char *gtphub_port_str(struct gtphub_peer_port *port) -{ - static char buf[256]; - return gtphub_port_strb(port, buf, sizeof(buf)); -} - -static const char *gtphub_port_str2(struct gtphub_peer_port *port) -{ - static char buf[256]; - return gtphub_port_strb(port, buf, sizeof(buf)); -} - -static void gtphub_mapping_del_cb(struct expiring_item *expi) -{ - expi->del_cb = 0; /* avoid recursion loops */ - expiring_item_del(expi); /* usually already done, but make sure. */ - - struct nr_mapping *nrm = container_of(expi, - struct nr_mapping, - expiry_entry); - llist_del(&nrm->entry); - INIT_LLIST_HEAD(&nrm->entry); /* mark unused */ - - /* Just for log */ - struct gtphub_peer_port *from = nrm->origin; - OSMO_ASSERT(from); - LOG(LOGL_DEBUG, "expired: %d: nr mapping from %s: %u->%u\n", - (int)nrm->expiry_entry.expiry, - gtphub_port_str(from), - (unsigned int)nrm->orig, (unsigned int)nrm->repl); - - gtphub_port_ref_count_dec(from); - - talloc_free(nrm); -} - -static struct nr_mapping *gtphub_mapping_have(struct nr_map *map, - struct gtphub_peer_port *from, - nr_t orig_nr, - time_t now) -{ - struct nr_mapping *nrm; - - nrm = nr_map_get(map, from, orig_nr); - - if (!nrm) { - nrm = gtphub_mapping_new(); - nrm->orig = orig_nr; - nrm->origin = from; - nr_map_add(map, nrm, now); - gtphub_port_ref_count_inc(from); - LOG(LOGL_DEBUG, "peer %s: sequence map %d --> %d\n", - gtphub_port_str(from), - (int)(nrm->orig), (int)(nrm->repl)); - } else { - nr_map_refresh(map, nrm, now); - } - - OSMO_ASSERT(nrm); - return nrm; -} - -static void gtphub_map_seq(struct gtp_packet_desc *p, - struct gtphub_peer_port *from_port, - struct gtphub_peer_port *to_port) -{ - /* Store a mapping in to_peer's map, so when we later receive a GTP - * packet back from to_peer, the seq nr can be unmapped back to its - * origin (from_peer here). */ - struct nr_mapping *nrm; - nrm = gtphub_mapping_have(&to_port->peer_addr->peer->seq_map, - from_port, p->seq, p->timestamp); - - /* Change the GTP packet to yield the new, mapped seq nr */ - set_seq(p, nrm->repl); -} - -static struct gtphub_peer_port *gtphub_unmap_seq(struct gtp_packet_desc *p, - struct gtphub_peer_port *responding_port) -{ - OSMO_ASSERT(p->version == 1); - struct nr_mapping *nrm = - nr_map_get_inv(&responding_port->peer_addr->peer->seq_map, - p->seq); - if (!nrm) - return NULL; - LOG(LOGL_DEBUG, "peer %p: sequence unmap %d <-- %d\n", - nrm->origin, (int)(nrm->orig), (int)(nrm->repl)); - set_seq(p, nrm->orig); - return nrm->origin; -} - -static int gtphub_check_mapped_tei(struct gtphub_tunnel *new_tun, - struct gtphub_tunnel *iterated_tun, - uint32_t *tei_min, - uint32_t *tei_max) -{ - if (!new_tun->tei_repl || !iterated_tun->tei_repl) - return 1; - - *tei_min = (*tei_min < iterated_tun->tei_repl)? *tei_min : iterated_tun->tei_repl; - *tei_max = (*tei_max > iterated_tun->tei_repl)? *tei_max : iterated_tun->tei_repl; - - if (new_tun->tei_repl != iterated_tun->tei_repl) - return 1; - - /* new_tun->tei_repl is already taken. Try to find one out of the known - * range. */ - LOG(LOGL_DEBUG, "TEI replacement %d already taken.\n", new_tun->tei_repl); - - if ((*tei_max) < 0xffffffff) { - (*tei_max)++; - new_tun->tei_repl = *tei_max; - LOG(LOGL_DEBUG, "Using TEI %d instead.\n", new_tun->tei_repl); - return 1; - } else if ((*tei_min) > 1) { - (*tei_min)--; - new_tun->tei_repl = *tei_min; - LOG(LOGL_DEBUG, "Using TEI %d instead.\n", new_tun->tei_repl); - return 1; - } - - /* None seems to be available. */ - return 0; -} - -static int gtphub_check_reused_teis(struct gtphub *hub, - struct gtphub_tunnel *new_tun) -{ - uint32_t tei_min = 0xffffffff; - uint32_t tei_max = 0; - int side_idx; - int plane_idx; - struct gtphub_tunnel_endpoint *te; - struct gtphub_tunnel_endpoint *te2; - - struct gtphub_tunnel *tun, *ntun; - - llist_for_each_entry_safe(tun, ntun, &hub->tunnels, entry) { - if (tun == new_tun) - continue; - - /* Check whether the GSN sent a TEI that it is reusing from a - * previous tunnel. */ - int tun_continue = 0; - for_each_side(side_idx) { - for_each_plane(plane_idx) { - te = &tun->endpoint[side_idx][plane_idx]; - te2 = &new_tun->endpoint[side_idx][plane_idx]; - if ((te->tei_orig == 0) - || (te->tei_orig != te2->tei_orig) - || (!te->peer) - || (!te2->peer) - || !gsn_addr_same(&te->peer->peer_addr->addr, - &te2->peer->peer_addr->addr)) - continue; - - /* The peer is reusing a TEI that I believe to - * be part of another tunnel. The other tunnel - * must be stale, then. */ - LOG(LOGL_NOTICE, - "Expiring tunnel due to reused TEI:" - " %s peer %s sent %s TEI %x," - " previously used by tunnel %s...\n", - gtphub_side_idx_names[side_idx], - gtphub_port_str(te->peer), - gtphub_plane_idx_names[plane_idx], - te->tei_orig, - gtphub_tunnel_str(tun)); - LOG(LOGL_NOTICE, "...while establishing tunnel %s\n", - gtphub_tunnel_str(new_tun)); - - expiring_item_del(&tun->expiry_entry); - /* continue to find more matches. There shouldn't be - * any, but let's make sure. However, tun is deleted, - * so we need to skip to the next tunnel. */ - tun_continue = 1; - break; - } - if (tun_continue) - break; - } - if (tun_continue) - continue; - - /* Check whether the mapped TEI is already used by another - * tunnel. */ - if (!gtphub_check_mapped_tei(new_tun, tun, &tei_min, &tei_max)) { - LOG(LOGL_ERROR, - "No mapped TEI is readily available." - " Searching for holes between occupied" - " TEIs not implemented."); - return 0; - } - - } - - return 1; -} - -static void gtphub_tunnel_refresh(struct gtphub *hub, - struct gtphub_tunnel *tun, - time_t now) -{ - expiry_add(&hub->expire_slowly, - &tun->expiry_entry, - now); -} - -static struct gtphub_tunnel_endpoint *gtphub_unmap_tei(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from, - struct gtphub_tunnel **unmapped_from_tun) -{ - OSMO_ASSERT(from); - int other_side = other_side_idx(p->side_idx); - - struct gtphub_tunnel *tun; - llist_for_each_entry(tun, &hub->tunnels, entry) { - struct gtphub_tunnel_endpoint *te_from = - &tun->endpoint[p->side_idx][p->plane_idx]; - struct gtphub_tunnel_endpoint *te_to = - &tun->endpoint[other_side][p->plane_idx]; - if ((tun->tei_repl == p->header_tei_rx) - && te_from->peer - && gsn_addr_same(&te_from->peer->peer_addr->addr, - &from->peer_addr->addr)) { - gtphub_tunnel_refresh(hub, tun, p->timestamp); - if (unmapped_from_tun) - *unmapped_from_tun = tun; - return te_to; - } - } - - if (unmapped_from_tun) - *unmapped_from_tun = NULL; - return NULL; -} - -static void gtphub_map_restart_counter(struct gtphub *hub, - struct gtp_packet_desc *p) -{ - if (p->rc != GTP_RC_PDU_C) - return; - - int ie_idx; - ie_idx = gtpie_getie(p->ie, GTPIE_RECOVERY, 0); - if (ie_idx < 0) - return; - - /* Always send gtphub's own restart counter */ - p->ie[ie_idx]->tv1.v = hton8(hub->restart_counter); -} - -static int gtphub_unmap_header_tei(struct gtphub_peer_port **to_port_p, - struct gtphub_tunnel **unmapped_from_tun, - struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from_port) -{ - OSMO_ASSERT(p->version == 1); - *to_port_p = NULL; - if (unmapped_from_tun) - *unmapped_from_tun = NULL; - - /* If the header's TEI is zero, no PDP context has been established - * yet. If nonzero, a mapping should actually already exist for this - * TEI, since it must have been announced in a PDP context creation. */ - if (!p->header_tei_rx) - return 0; - - /* to_peer has previously announced a TEI, which was stored and - * mapped in a tunnel struct. */ - struct gtphub_tunnel_endpoint *to; - to = gtphub_unmap_tei(hub, p, from_port, unmapped_from_tun); - if (!to) { - LOG(LOGL_ERROR, "Received unknown TEI %" PRIx32 " from %s\n", - p->header_tei_rx, gtphub_port_str(from_port)); - return -1; - } - - if (unmapped_from_tun) { - OSMO_ASSERT(*unmapped_from_tun); - LOG(LOGL_DEBUG, "Unmapped TEI coming from: %s\n", - gtphub_tunnel_str(*unmapped_from_tun)); - } - - uint32_t unmapped_tei = to->tei_orig; - set_tei(p, unmapped_tei); - - /* May be NULL for an invalidated tunnel. */ - *to_port_p = to->peer; - - return 0; -} - -static int gtphub_handle_create_pdp_ctx(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from_ctrl, - struct gtphub_peer_port *to_ctrl) -{ - int plane_idx; - - osmo_static_assert((GTPH_PLANE_CTRL == 0) && (GTPH_PLANE_USER == 1), - plane_nrs_match_GSN_addr_IE_indices); - - struct gtphub_tunnel *tun = p->tun; - - if (p->type == GTP_CREATE_PDP_REQ) { - if (p->side_idx != GTPH_SIDE_SGSN) { - LOG(LOGL_ERROR, "Wrong side: Create PDP Context" - " Request from the GGSN side: %s", - gtphub_port_str(from_ctrl)); - return -1; - } - - if (tun) { - LOG(LOGL_ERROR, "Not implemented: Received" - " Create PDP Context Request for an already" - " established tunnel:" - " from %s, tunnel %s\n", - gtphub_port_str(from_ctrl), - gtphub_tunnel_str(p->tun)); - return -1; - } - - /* A new tunnel. */ - p->tun = tun = gtphub_tunnel_new(); - - /* Create TEI mapping */ - tun->tei_repl = nr_pool_next(&hub->tei_pool); - - llist_add(&tun->entry, &hub->tunnels); - gtphub_tunnel_refresh(hub, tun, p->timestamp); - /* The endpoint peers on this side (SGSN) will be set from IEs - * below. Also set the GGSN Ctrl endpoint, for logging. */ - gtphub_tunnel_endpoint_set_peer(&tun->endpoint[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL], - to_ctrl); - } else if (p->type == GTP_CREATE_PDP_RSP) { - if (p->side_idx != GTPH_SIDE_GGSN) { - LOG(LOGL_ERROR, "Wrong side: Create PDP Context" - " Response from the SGSN side: %s", - gtphub_port_str(from_ctrl)); - return -1; - } - - /* The tunnel should already have been resolved from the header - * TEI and be available in tun (== p->tun). Just fill in the - * GSN Addresses below.*/ - OSMO_ASSERT(tun); - OSMO_ASSERT(tun->tei_repl == p->header_tei_rx); - OSMO_ASSERT(to_ctrl); - } - - uint8_t ie_type[] = { GTPIE_TEI_C, GTPIE_TEI_DI }; - int ie_mandatory = (p->type == GTP_CREATE_PDP_REQ); - unsigned int side_idx = p->side_idx; - - for (plane_idx = 0; plane_idx < 2; plane_idx++) { - int rc; - struct gsn_addr use_addr; - uint16_t use_port; - uint32_t tei_from_ie; - int ie_idx; - - /* Fetch GSN Address and TEI from IEs. As ensured by above - * static asserts, plane_idx corresponds to the GSN Address IE - * index (the first one = 0 = ctrl, second one = 1 = user). */ - rc = gsn_addr_get(&use_addr, p, plane_idx); - if (rc) { - LOG(LOGL_ERROR, "Cannot read %s GSN Address IE\n", - gtphub_plane_idx_names[plane_idx]); - return -1; - } - LOG(LOGL_DEBUG, "Read %s GSN addr %s (%d)\n", - gtphub_plane_idx_names[plane_idx], - gsn_addr_to_str(&use_addr), - use_addr.len); - - ie_idx = gtpie_getie(p->ie, ie_type[plane_idx], 0); - if (ie_idx < 0) { - if (ie_mandatory) { - LOG(LOGL_ERROR, - "Create PDP Context message invalid:" - " missing IE %d\n", - (int)ie_type[plane_idx]); - return -1; - } - tei_from_ie = 0; - } - else - tei_from_ie = ntoh32(p->ie[ie_idx]->tv4.v); - - /* Make sure an entry for this peer address with default port - * exists. - * - * Exception: if sgsn_use_sender is set, instead use the - * sender's address and port for Ctrl -- the User port is not - * known until the first User packet arrives. - * - * Note: doing this here is just an optimization, because - * gtphub_handle_buf() has code to replace the tunnel - * endpoints' addresses with the sender (needed for User - * plane). We could just ignore sgsn_use_sender here. But if we - * set up a default port here and replace it in - * gtphub_handle_buf(), we'd be creating a peer port just to - * expire it right away. */ - if (hub->sgsn_use_sender && (side_idx == GTPH_SIDE_SGSN)) { - gsn_addr_from_sockaddr(&use_addr, &use_port, &from_ctrl->sa); - } else { - use_port = gtphub_plane_idx_default_port[plane_idx]; - - } - - struct gtphub_peer_port *peer_from_ie; - peer_from_ie = gtphub_port_have(hub, - &hub->to_gsns[side_idx][plane_idx], - &use_addr, use_port); - - gtphub_tunnel_endpoint_set_peer(&tun->endpoint[side_idx][plane_idx], - peer_from_ie); - - if (!tei_from_ie && - !tun->endpoint[side_idx][plane_idx].tei_orig) { - LOG(LOGL_ERROR, - "Create PDP Context message omits %s TEI, but" - " no TEI has been announced for this tunnel: %s\n", - gtphub_plane_idx_names[plane_idx], - gtphub_tunnel_str(tun)); - return -1; - } - - if (tei_from_ie) { - /* Replace TEI in GTP packet IE */ - tun->endpoint[side_idx][plane_idx].tei_orig = tei_from_ie; - p->ie[ie_idx]->tv4.v = hton32(tun->tei_repl); - - if (!gtphub_check_reused_teis(hub, tun)) { - /* It's highly unlikely that all TEIs are - * taken. But the code looking for an unused - * TEI is, at the time of writing this comment, - * not able to find gaps in the TEI space. To - * explicitly alert the user of this problem, - * rather abort than carry on. */ - LOG(LOGL_FATAL, "TEI range exhausted. Cannot create TEI mapping, aborting.\n"); - abort(); - } - } - - /* Replace the GSN address to reflect gtphub. */ - rc = gsn_addr_put(&hub->to_gsns[other_side_idx(side_idx)][plane_idx].local_addr, - p, plane_idx); - if (rc) { - LOG(LOGL_ERROR, "Cannot write %s GSN Address IE\n", - gtphub_plane_idx_names[plane_idx]); - return -1; - } - } - - if (p->type == GTP_CREATE_PDP_REQ) { - LOG(LOGL_DEBUG, "New tunnel, first half: %s\n", - gtphub_tunnel_str(tun)); - } else if (p->type == GTP_CREATE_PDP_RSP) { - LOG(LOGL_DEBUG, "New tunnel: %s\n", - gtphub_tunnel_str(tun)); - } - - return 0; -} - -static void pending_delete_del_cb(struct expiring_item *expi) -{ - struct pending_delete *pd; - pd = container_of(expi, struct pending_delete, expiry_entry); - - llist_del(&pd->entry); - INIT_LLIST_HEAD(&pd->entry); - - pd->expiry_entry.del_cb = 0; - expiring_item_del(&pd->expiry_entry); - - talloc_free(pd); -} - -static struct pending_delete *pending_delete_new(void) -{ - struct pending_delete *pd = talloc_zero(osmo_gtphub_ctx, struct pending_delete); - INIT_LLIST_HEAD(&pd->entry); - expiring_item_init(&pd->expiry_entry); - pd->expiry_entry.del_cb = pending_delete_del_cb; - return pd; -} - -static int gtphub_handle_delete_pdp_ctx(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from_ctrl, - struct gtphub_peer_port *to_ctrl) -{ - struct gtphub_tunnel *known_tun = p->tun; - - if (p->type == GTP_DELETE_PDP_REQ) { - if (!known_tun) { - LOG(LOGL_ERROR, "Cannot find tunnel for Delete PDP Context Request.\n"); - return -1; - } - - /* Store the Delete Request until a successful Response is seen. */ - uint8_t teardown_ind; - uint8_t nsapi; - - if (gtpie_gettv1(p->ie, GTPIE_TEARDOWN, 0, &teardown_ind) != 0) { - LOG(LOGL_ERROR, "Missing Teardown Ind IE in Delete PDP Context Request.\n"); - return -1; - } - - if (gtpie_gettv1(p->ie, GTPIE_NSAPI, 0, &nsapi) != 0) { - LOG(LOGL_ERROR, "Missing NSAPI IE in Delete PDP Context Request.\n"); - return -1; - } - - struct pending_delete *pd = NULL; - - struct pending_delete *pdi = NULL; - llist_for_each_entry(pdi, &hub->pending_deletes, entry) { - if ((pdi->tun == known_tun) - && (pdi->teardown_ind == teardown_ind) - && (pdi->nsapi == nsapi)) { - pd = pdi; - break; - } - } - - if (!pd) { - pd = pending_delete_new(); - pd->tun = known_tun; - pd->teardown_ind = teardown_ind; - pd->nsapi = nsapi; - - LOG(LOGL_DEBUG, "Tunnel delete pending: %s\n", - gtphub_tunnel_str(known_tun)); - llist_add(&pd->entry, &hub->pending_deletes); - } - - /* Add or refresh timeout. */ - expiry_add(&hub->expire_quickly, &pd->expiry_entry, p->timestamp); - - /* If a pending_delete should expire before the response to - * indicate success comes in, the responding peer will have the - * tunnel deactivated, while the requesting peer gets no reply - * and keeps the tunnel. The hope is that the requesting peer - * will try again and get a useful response. */ - } else if (p->type == GTP_DELETE_PDP_RSP) { - /* Find the Delete Request for this Response. */ - struct pending_delete *pd = NULL; - - struct pending_delete *pdi; - llist_for_each_entry(pdi, &hub->pending_deletes, entry) { - if (known_tun == pdi->tun) { - pd = pdi; - break; - } - } - - if (!pd) { - LOG(LOGL_ERROR, "Delete PDP Context Response:" - " Cannot find matching request."); - /* If we delete the tunnel now, anyone can send a - * Delete response to kill tunnels at will. */ - return -1; - } - - /* TODO handle teardown_ind and nsapi */ - - expiring_item_del(&pd->expiry_entry); - - uint8_t cause; - if (gtpie_gettv1(p->ie, GTPIE_CAUSE, 0, &cause) != 0) { - LOG(LOGL_ERROR, "Delete PDP Context Response:" - " Missing Cause IE."); - /* If we delete the tunnel now, at least one of the - * peers may still think it is active. */ - return -1; - } - - if (cause != GTPCAUSE_ACC_REQ) { - LOG(LOGL_NOTICE, - "Delete PDP Context Response indicates failure;" - "for %s\n", - gtphub_tunnel_str(known_tun)); - return -1; - } - - LOG(LOGL_DEBUG, "Delete PDP Context: removing tunnel %s\n", - gtphub_tunnel_str(known_tun)); - p->tun = NULL; - expiring_item_del(&known_tun->expiry_entry); - } - - return 0; -} - -static int gtphub_handle_update_pdp_ctx(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from_ctrl, - struct gtphub_peer_port *to_ctrl) -{ - /* TODO */ - return 0; -} - -/* Read GSN address IEs from p, and make sure these peer addresses exist in - * bind[plane_idx] with default ports, in their respective planes (both Ctrl - * and User). Map TEIs announced in IEs, and write mapped TEIs in-place into - * the packet p. */ -static int gtphub_handle_pdp_ctx(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from_ctrl, - struct gtphub_peer_port *to_ctrl) -{ - OSMO_ASSERT(p->plane_idx == GTPH_PLANE_CTRL); - - switch (p->type) { - case GTP_CREATE_PDP_REQ: - case GTP_CREATE_PDP_RSP: - return gtphub_handle_create_pdp_ctx(hub, p, - from_ctrl, to_ctrl); - - case GTP_DELETE_PDP_REQ: - case GTP_DELETE_PDP_RSP: - return gtphub_handle_delete_pdp_ctx(hub, p, - from_ctrl, to_ctrl); - - case GTP_UPDATE_PDP_REQ: - case GTP_UPDATE_PDP_RSP: - return gtphub_handle_update_pdp_ctx(hub, p, - from_ctrl, to_ctrl); - - default: - /* Nothing to do for this message type. */ - return 0; - } - -} - -static int gtphub_send_del_pdp_ctx(struct gtphub *hub, - struct gtphub_tunnel *tun, - int to_side) -{ - static uint8_t del_ctx_msg[16] = { - 0x32, /* GTP v1 flags */ - GTP_DELETE_PDP_REQ, - 0x00, 0x08, /* Length in network byte order */ - 0x00, 0x00, 0x00, 0x00, /* TEI to be replaced */ - 0, 0, /* Seq, to be replaced */ - 0, 0, /* no extensions */ - 0x13, 0xff, /* 19: Teardown ind = 1 */ - 0x14, 0 /* 20: NSAPI = 0 */ - }; - - uint32_t *tei = (uint32_t*)&del_ctx_msg[4]; - uint16_t *seq = (uint16_t*)&del_ctx_msg[8]; - - struct gtphub_tunnel_endpoint *te = - &tun->endpoint[to_side][GTPH_PLANE_CTRL]; - - if (! te->peer) - return 0; - - *tei = hton32(te->tei_orig); - *seq = hton16(nr_pool_next(&te->peer->peer_addr->peer->seq_pool)); - - struct gtphub_bind *to_bind = &hub->to_gsns[to_side][GTPH_PLANE_CTRL]; - int rc = gtphub_write(&to_bind->ofd, &te->peer->sa, - del_ctx_msg, sizeof(del_ctx_msg)); - if (rc != 0) { - LOG(LOGL_ERROR, - "Failed to send out-of-band Delete PDP Context Request to %s\n", - gtphub_port_str(te->peer)); - } - return rc; -} - -/* Tell all peers on the other end of tunnels that PDP contexts are void. */ -static void gtphub_restarted(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *pp) -{ - LOG(LOGL_NOTICE, "Peer has restarted: %s\n", - gtphub_port_str(pp)); - - int deleted_count = 0; - struct gtphub_tunnel *tun; - llist_for_each_entry(tun, &hub->tunnels, entry) { - int side_idx; - for_each_side(side_idx) { - struct gtphub_tunnel_endpoint *te = &tun->endpoint[side_idx][GTPH_PLANE_CTRL]; - struct gtphub_tunnel_endpoint *te2 = &tun->endpoint[other_side_idx(side_idx)][GTPH_PLANE_CTRL]; - if ((!te->peer) - || (!te2->tei_orig) - || (pp->peer_addr->peer != te->peer->peer_addr->peer)) - continue; - - LOG(LOGL_DEBUG, "Deleting tunnel due to peer restart: %s\n", - gtphub_tunnel_str(tun)); - deleted_count ++; - - /* Send a Delete PDP Context Request to the - * peer on the other side, remember the pending - * delete and wait for the response to delete - * the tunnel. Clear this side of the tunnel to - * make sure it isn't used. - * - * Should the delete message send fail, or if no - * response is received, this tunnel will expire. If - * its TEIs come up in a new PDP Context Request, it - * will be removed. If messages for this tunnel should - * come in (from the not restarted side), they will be - * dropped because the tunnel is rendered unusable. */ - gtphub_send_del_pdp_ctx(hub, tun, other_side_idx(side_idx)); - - gtphub_tunnel_endpoint_set_peer(&tun->endpoint[side_idx][GTPH_PLANE_CTRL], - NULL); - gtphub_tunnel_endpoint_set_peer(&tun->endpoint[side_idx][GTPH_PLANE_USER], - NULL); - } - } - - if (deleted_count) - LOG(LOGL_NOTICE, "Deleting %d tunnels due to restart of: %s\n", - deleted_count, - gtphub_port_str(pp)); -} - -static int get_restart_count(struct gtp_packet_desc *p) -{ - int ie_idx; - ie_idx = gtpie_getie(p->ie, GTPIE_RECOVERY, 0); - if (ie_idx < 0) - return -1; - return ntoh8(p->ie[ie_idx]->tv1.v); -} - -static void gtphub_check_restart_counter(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from) -{ - /* If the peer is sending a Recovery IE (7.7.11) with a restart counter - * that doesn't match the peer's previously sent restart counter, clear - * that peer and cancel PDP contexts. */ - - int restart = get_restart_count(p); - - if ((restart < 0) || (restart > 255)) - return; - - if ((from->last_restart_count >= 0) && (from->last_restart_count <= 255)) { - if (from->last_restart_count != restart) { - gtphub_restarted(hub, p, from); - } - } - - from->last_restart_count = restart; -} - -static int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what) -{ - unsigned int plane_idx = from_sgsns_ofd->priv_nr; - OSMO_ASSERT(plane_idx < GTPH_PLANE_N); - LOG(LOGL_DEBUG, "=== reading from SGSN (%s)\n", - gtphub_plane_idx_names[plane_idx]); - - if (!(what & BSC_FD_READ)) - return 0; - - struct gtphub *hub = from_sgsns_ofd->data; - - static uint8_t buf[4096]; - struct osmo_sockaddr from_addr; - struct osmo_sockaddr to_addr; - struct osmo_fd *to_ofd; - int len; - uint8_t *reply_buf; - - len = gtphub_read(from_sgsns_ofd, &from_addr, buf, sizeof(buf)); - if (len < 1) - return 0; - - len = gtphub_handle_buf(hub, GTPH_SIDE_SGSN, plane_idx, &from_addr, - buf, len, gtphub_now(), - &reply_buf, &to_ofd, &to_addr); - if (len < 1) - return 0; - - return gtphub_write(to_ofd, &to_addr, reply_buf, len); -} - -static int from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what) -{ - unsigned int plane_idx = from_ggsns_ofd->priv_nr; - OSMO_ASSERT(plane_idx < GTPH_PLANE_N); - LOG(LOGL_DEBUG, "=== reading from GGSN (%s)\n", - gtphub_plane_idx_names[plane_idx]); - if (!(what & BSC_FD_READ)) - return 0; - - struct gtphub *hub = from_ggsns_ofd->data; - - static uint8_t buf[4096]; - struct osmo_sockaddr from_addr; - struct osmo_sockaddr to_addr; - struct osmo_fd *to_ofd; - int len; - uint8_t *reply_buf; - - len = gtphub_read(from_ggsns_ofd, &from_addr, buf, sizeof(buf)); - if (len < 1) - return 0; - - len = gtphub_handle_buf(hub, GTPH_SIDE_GGSN, plane_idx, &from_addr, - buf, len, gtphub_now(), - &reply_buf, &to_ofd, &to_addr); - if (len < 1) - return 0; - - return gtphub_write(to_ofd, &to_addr, reply_buf, len); -} - -static int gtphub_unmap(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port *from, - struct gtphub_peer_port *to_proxy, - struct gtphub_peer_port **final_unmapped, - struct gtphub_peer_port **unmapped_from_seq) -{ - /* Always (try to) unmap sequence and TEI numbers, which need to be - * replaced in the packet. Either way, give precedence to the proxy, if - * configured. */ - - if (unmapped_from_seq) - *unmapped_from_seq = NULL; - if (final_unmapped) - *final_unmapped = NULL; - p->tun = NULL; - - struct gtphub_peer_port *from_seq = NULL; - struct gtphub_peer_port *from_tei = NULL; - struct gtphub_peer_port *unmapped = NULL; - - from_seq = gtphub_unmap_seq(p, from); - - if (gtphub_unmap_header_tei(&from_tei, &p->tun, hub, p, from) < 0) - return -1; - - struct gtphub_peer *from_peer = from->peer_addr->peer; - if (from_seq && from_tei && (from_seq != from_tei)) { - LOG(LOGL_DEBUG, - "Seq unmap and TEI unmap yield two different peers." - " Using seq unmap." - " (from %s %s: seq %d yields %s, tei %u yields %s)\n", - gtphub_plane_idx_names[p->plane_idx], - gtphub_peer_str(from_peer), - (int)p->seq, - gtphub_port_str(from_seq), - (unsigned int)p->header_tei_rx, - gtphub_port_str2(from_tei) - ); - } - unmapped = (from_seq? from_seq : from_tei); - - if (unmapped && to_proxy && (unmapped != to_proxy)) { - LOG(LOGL_NOTICE, - "Unmap yields a different peer than the configured proxy." - " Using proxy." - " unmapped: %s proxy: %s\n", - gtphub_port_str(unmapped), - gtphub_port_str2(to_proxy) - ); - } - unmapped = (to_proxy? to_proxy : unmapped); - - if (!unmapped) { - /* Return no error, but returned pointers are all NULL. */ - return 0; - } - - if (unmapped_from_seq) - *unmapped_from_seq = from_seq; - if (final_unmapped) - *final_unmapped = unmapped; - return 0; -} - -static int gsn_addr_to_sockaddr(struct gsn_addr *src, - uint16_t port, - struct osmo_sockaddr *dst) -{ - return osmo_sockaddr_init_udp(dst, gsn_addr_to_str(src), port); -} - -/* If p is an Echo request, replace p's data with the matching response and - * return 1. If p is no Echo request, return 0, or -1 if an invalid packet is - * detected. */ -static int gtphub_handle_echo_req(struct gtphub *hub, struct gtp_packet_desc *p, - uint8_t **reply_buf) -{ - if (p->type != GTP_ECHO_REQ) - return 0; - - static uint8_t echo_response_data[14] = { - 0x32, /* GTP v1 flags */ - GTP_ECHO_RSP, - 0x00, 14 - 8, /* Length in network byte order */ - 0x00, 0x00, 0x00, 0x00, /* Zero TEI */ - 0, 0, /* Seq, to be replaced */ - 0, 0, /* no extensions */ - 0x0e, /* Recovery IE */ - 0 /* Restart counter, to be replaced */ - }; - uint16_t *seq = (uint16_t*)&echo_response_data[8]; - uint8_t *recovery = &echo_response_data[13]; - - *seq = hton16(p->seq); - *recovery = hub->restart_counter; - - *reply_buf = echo_response_data; - - return sizeof(echo_response_data); -} - -struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind, - const struct osmo_sockaddr *addr); - -/* Parse buffer as GTP packet, replace elements in-place and return the ofd and - * address to forward to. Return a pointer to the osmo_fd, but copy the - * sockaddr to *to_addr. The reason for this is that the sockaddr may expire at - * any moment, while the osmo_fd is guaranteed to persist. Return the number of - * bytes to forward, 0 or less on failure. */ -int gtphub_handle_buf(struct gtphub *hub, - unsigned int side_idx, - unsigned int plane_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_bind *from_bind = &hub->to_gsns[side_idx][plane_idx]; - struct gtphub_bind *to_bind = &hub->to_gsns[other_side_idx(side_idx)][plane_idx]; - - rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_IN], - received); - - struct gtp_packet_desc p; - gtp_decode(buf, received, side_idx, plane_idx, &p, now); - - LOG(LOGL_DEBUG, "%s rx %s from %s %s%s\n", - (side_idx == GTPH_SIDE_GGSN)? "<-" : "->", - gtphub_plane_idx_names[plane_idx], - gtphub_side_idx_names[side_idx], - osmo_sockaddr_to_str(from_addr), - gtp_type_str(p.type)); - - if (p.rc <= 0) { - LOG(LOGL_ERROR, "INVALID: dropping GTP packet%s from %s %s %s\n", - gtp_type_str(p.type), - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx], - osmo_sockaddr_to_str(from_addr)); - return -1; - } - - rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_IN]); - - int reply_len; - reply_len = gtphub_handle_echo_req(hub, &p, reply_buf); - if (reply_len > 0) { - /* It was an echo. Nothing left to do. */ - osmo_sockaddr_copy(to_addr, from_addr); - *to_ofd = &from_bind->ofd; - - rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]); - rate_ctr_add(&from_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT], - reply_len); - LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n", - (side_idx == GTPH_SIDE_GGSN)? "-->" : "<--", - gtphub_side_idx_names[side_idx], - (int)reply_len, osmo_sockaddr_to_str(to_addr)); - return reply_len; - } - if (reply_len < 0) - return -1; - - *to_ofd = &to_bind->ofd; - - /* If a proxy is configured, check that it's indeed that proxy talking - * to us. A proxy is a forced 1:1 connection, e.g. to another gtphub, - * so no-one else is allowed to talk to us from that side. */ - struct gtphub_peer_port *from_peer = hub->proxy[side_idx][plane_idx]; - if (from_peer) { - if (osmo_sockaddr_cmp(&from_peer->sa, from_addr) != 0) { - LOG(LOGL_ERROR, - "Rejecting: %s proxy configured, but GTP packet" - " received on %s bind is from another sender:" - " proxy: %s sender: %s\n", - gtphub_side_idx_names[side_idx], - gtphub_side_idx_names[side_idx], - gtphub_port_str(from_peer), - osmo_sockaddr_to_str(from_addr)); - return -1; - } - } - - if (!from_peer) { - /* Find or create a peer with a matching address. The sender's - * port may in fact differ. */ - from_peer = gtphub_known_addr_have_port(from_bind, from_addr); - } - - /* If any PDP context has been created, we already have an entry for - * this GSN. If we don't have an entry, a GGSN has nothing to tell us - * about, while an SGSN may initiate a PDP context. */ - if (!from_peer) { - if (side_idx == GTPH_SIDE_GGSN) { - LOG(LOGL_ERROR, "Dropping packet%s: unknown GGSN peer: %s\n", - gtp_type_str(p.type), - osmo_sockaddr_to_str(from_addr)); - return -1; - } else { - /* SGSN */ - /* A new peer. If this is on the Ctrl plane, an SGSN - * may make first contact without being known yet, so - * create the peer struct for the current sender. */ - if (plane_idx != GTPH_PLANE_CTRL) { - LOG(LOGL_ERROR, - "Dropping packet%s: User plane peer was not" - "announced by PDP Context: %s\n", - gtp_type_str(p.type), - osmo_sockaddr_to_str(from_addr)); - return -1; - } - - struct gsn_addr from_gsna; - uint16_t from_port; - if (gsn_addr_from_sockaddr(&from_gsna, &from_port, from_addr) != 0) - return -1; - - from_peer = gtphub_port_have(hub, from_bind, &from_gsna, from_port); - } - } - - if (!from_peer) { - /* This could theoretically happen for invalid address data or - * somesuch. */ - LOG(LOGL_ERROR, "Dropping packet%s: invalid %s peer: %s\n", - gtp_type_str(p.type), - gtphub_side_idx_names[side_idx], - osmo_sockaddr_to_str(from_addr)); - return -1; - } - - rate_ctr_add(&from_peer->counters_io->ctr[GTPH_CTR_BYTES_IN], - received); - rate_ctr_inc(&from_peer->counters_io->ctr[GTPH_CTR_PKTS_IN]); - - LOG(LOGL_DEBUG, "from %s peer: %s\n", gtphub_side_idx_names[side_idx], - gtphub_port_str(from_peer)); - - gtphub_check_restart_counter(hub, &p, from_peer); - gtphub_map_restart_counter(hub, &p); - - struct gtphub_peer_port *to_peer_from_seq; - struct gtphub_peer_port *to_peer; - if (gtphub_unmap(hub, &p, from_peer, - hub->proxy[other_side_idx(side_idx)][plane_idx], - &to_peer, &to_peer_from_seq) - != 0) { - return -1; - } - - if (p.tun) { - struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[p.side_idx][p.plane_idx]; - rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_IN], - received); - rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_IN]); - } - - if ((!to_peer) && (side_idx == GTPH_SIDE_SGSN)) { - if (gtphub_resolve_ggsn(hub, &p, &to_peer) < 0) - return -1; - } - - if (!to_peer && p.tun && p.type == GTP_DELETE_PDP_RSP) { - /* It's a delete confirmation for a tunnel that is partly - * invalid, probably marked unsuable due to a restarted peer. - * Remove the tunnel and be happy without forwarding. */ - expiring_item_del(&p.tun->expiry_entry); - p.tun = NULL; - return 0; - } - - if (!to_peer) { - LOG(LOGL_ERROR, "No %s to send to. Dropping packet%s" - " (type=%" PRIu8 ", header-TEI=%" PRIx32 ", seq=%" PRIx16 ").\n", - gtphub_side_idx_names[other_side_idx(side_idx)], - gtp_type_str(p.type), - p.type, p.header_tei_rx, p.seq - ); - return -1; - } - - if (plane_idx == GTPH_PLANE_CTRL) { - /* This may be a Create PDP Context response. If it is, there - * are other addresses in the GTP message to set up apart from - * the sender. */ - if (gtphub_handle_pdp_ctx(hub, &p, from_peer, to_peer) - != 0) - return -1; - } - - /* Either to_peer was resolved from an existing tunnel, - * or a PDP Ctx and thus a tunnel has just been created, - * or the tunnel has been deleted due to this message. */ - OSMO_ASSERT(p.tun || (p.type == GTP_DELETE_PDP_RSP)); - - /* If the GGSN is replying to an SGSN request, the sequence nr has - * already been unmapped above (to_peer_from_seq != NULL), and we need not - * create a new mapping. */ - if (!to_peer_from_seq) - gtphub_map_seq(&p, from_peer, to_peer); - - osmo_sockaddr_copy(to_addr, &to_peer->sa); - - *reply_buf = (uint8_t*)p.data; - - if (received) { - rate_ctr_inc(&to_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]); - rate_ctr_add(&to_bind->counters_io->ctr[GTPH_CTR_BYTES_OUT], - received); - - rate_ctr_inc(&to_peer->counters_io->ctr[GTPH_CTR_PKTS_OUT]); - rate_ctr_add(&to_peer->counters_io->ctr[GTPH_CTR_BYTES_OUT], - received); - } - - if (p.tun) { - struct gtphub_tunnel_endpoint *te = &p.tun->endpoint[other_side_idx(p.side_idx)][p.plane_idx]; - rate_ctr_inc(&te->counters_io->ctr[GTPH_CTR_PKTS_OUT]); - rate_ctr_add(&te->counters_io->ctr[GTPH_CTR_BYTES_OUT], - received); - } - - LOG(LOGL_DEBUG, "%s Forward to %s:" - " header-TEI %" PRIx32", seq %" PRIx16", %d bytes to %s\n", - (side_idx == GTPH_SIDE_SGSN)? "-->" : "<--", - gtphub_side_idx_names[other_side_idx(side_idx)], - p.header_tei, p.seq, - (int)received, osmo_sockaddr_to_str(to_addr)); - return received; -} - -static void resolved_gssn_del_cb(struct expiring_item *expi) -{ - struct gtphub_resolved_ggsn *ggsn; - ggsn = container_of(expi, struct gtphub_resolved_ggsn, expiry_entry); - - gtphub_port_ref_count_dec(ggsn->peer); - llist_del(&ggsn->entry); - - ggsn->expiry_entry.del_cb = 0; - expiring_item_del(&ggsn->expiry_entry); - - talloc_free(ggsn); -} - -void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str, - struct gsn_addr *resolved_addr, - time_t now) -{ - struct gtphub_peer_port *pp; - struct gtphub_resolved_ggsn *ggsn; - - LOG(LOGL_DEBUG, "Resolved GGSN callback: %s %s\n", - apn_oi_str, osmo_hexdump((unsigned char*)resolved_addr, - sizeof(*resolved_addr))); - - pp = gtphub_port_have(hub, &hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL], - resolved_addr, 2123); - if (!pp) { - LOG(LOGL_ERROR, "Internal: Cannot create/find peer '%s'\n", - gsn_addr_to_str(resolved_addr)); - return; - } - - ggsn = talloc_zero(osmo_gtphub_ctx, struct gtphub_resolved_ggsn); - OSMO_ASSERT(ggsn); - INIT_LLIST_HEAD(&ggsn->entry); - expiring_item_init(&ggsn->expiry_entry); - - ggsn->peer = pp; - gtphub_port_ref_count_inc(pp); - - osmo_strlcpy(ggsn->apn_oi_str, apn_oi_str, sizeof(ggsn->apn_oi_str)); - - ggsn->expiry_entry.del_cb = resolved_gssn_del_cb; - expiry_add(&hub->expire_slowly, &ggsn->expiry_entry, now); - - llist_add(&ggsn->entry, &hub->resolved_ggsns); -} - -static int gtphub_gc_peer_port(struct gtphub_peer_port *pp) -{ - return pp->ref_count == 0; -} - -static int gtphub_gc_peer_addr(struct gtphub_peer_addr *pa) -{ - struct gtphub_peer_port *pp, *npp; - llist_for_each_entry_safe(pp, npp, &pa->ports, entry) { - if (gtphub_gc_peer_port(pp)) { - LOG(LOGL_DEBUG, "expired: peer %s\n", - gtphub_port_str(pp)); - gtphub_peer_port_del(pp); - } - } - return llist_empty(&pa->ports); -} - -static int gtphub_gc_peer(struct gtphub_peer *p) -{ - struct gtphub_peer_addr *pa, *npa; - llist_for_each_entry_safe(pa, npa, &p->addresses, entry) { - if (gtphub_gc_peer_addr(pa)) { - gtphub_peer_addr_del(pa); - } - } - - /* Note that there's a ref_count in each gtphub_peer_port instance - * listed within p->addresses, referenced by TEI mappings from - * hub->tei_map. As long as those don't expire, this peer will stay. */ - - return llist_empty(&p->addresses) - && nr_map_empty(&p->seq_map); -} - -static void gtphub_gc_bind(struct gtphub_bind *b) -{ - struct gtphub_peer *p, *n; - llist_for_each_entry_safe(p, n, &b->peers, entry) { - if (gtphub_gc_peer(p)) { - gtphub_peer_del(p); - } - } -} - -void gtphub_gc(struct gtphub *hub, time_t now) -{ - int expired; - expired = expiry_tick(&hub->expire_quickly, now); - expired += expiry_tick(&hub->expire_slowly, now); - - /* ... */ - - if (expired) { - int s, p; - for_each_side_and_plane(s, p) { - gtphub_gc_bind(&hub->to_gsns[s][p]); - } - } -} - -static void gtphub_gc_cb(void *data) -{ - struct gtphub *hub = data; - gtphub_gc(hub, gtphub_now()); - osmo_timer_schedule(&hub->gc_timer, GTPH_GC_TICK_SECONDS, 0); -} - -static void gtphub_gc_start(struct gtphub *hub) -{ - osmo_timer_setup(&hub->gc_timer, gtphub_gc_cb, hub); - osmo_timer_schedule(&hub->gc_timer, GTPH_GC_TICK_SECONDS, 0); -} - -/* called by unit tests */ -void gtphub_init(struct gtphub *hub) -{ - gtphub_zero(hub); - - INIT_LLIST_HEAD(&hub->tunnels); - INIT_LLIST_HEAD(&hub->pending_deletes); - - expiry_init(&hub->expire_quickly, GTPH_EXPIRE_QUICKLY_SECS); - expiry_init(&hub->expire_slowly, GTPH_EXPIRE_SLOWLY_MINUTES * 60); - - nr_pool_init(&hub->tei_pool, 1, 0xffffffff); - - int side_idx; - int plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - gtphub_bind_init(&hub->to_gsns[side_idx][plane_idx]); - } - - hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].label = "SGSN Ctrl"; - hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].label = "GGSN Ctrl"; - hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].label = "SGSN User"; - hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].label = "GGSN User"; -} - -/* For the test suite, this is kept separate from gtphub_stop(), which also - * closes sockets. The test suite avoids using sockets and would cause - * segfaults when trying to close uninitialized ofds. */ -void gtphub_free(struct gtphub *hub) -{ - /* By expiring all mappings, a garbage collection should free - * everything else. A gtphub_bind_free() will assert that everything is - * indeed empty. */ - expiry_clear(&hub->expire_quickly); - expiry_clear(&hub->expire_slowly); - - int side_idx; - int plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - gtphub_gc_bind(&hub->to_gsns[side_idx][plane_idx]); - gtphub_bind_free(&hub->to_gsns[side_idx][plane_idx]); - } -} - -void gtphub_stop(struct gtphub *hub) -{ - int side_idx; - int plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - gtphub_bind_stop(&hub->to_gsns[side_idx][plane_idx]); - } - gtphub_free(hub); -} - -static int gtphub_make_proxy(struct gtphub *hub, - struct gtphub_peer_port **pp, - struct gtphub_bind *bind, - const struct gtphub_cfg_addr *addr) -{ - if (!addr->addr_str) - return 0; - - struct gsn_addr gsna; - if (gsn_addr_from_str(&gsna, addr->addr_str) != 0) - return -1; - - *pp = gtphub_port_have(hub, bind, &gsna, addr->port); - - /* This is *the* proxy. Make sure it is never expired. */ - gtphub_port_ref_count_inc(*pp); - return 0; -} - -int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg, - uint8_t restart_counter) -{ - gtphub_init(hub); - - hub->restart_counter = restart_counter; - hub->sgsn_use_sender = cfg->sgsn_use_sender? 1 : 0; - - /* If a Ctrl plane proxy is configured, ares will never be used. */ - if (!cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str) { - if (gtphub_ares_init(hub) != 0) { - LOG(LOGL_FATAL, "Failed to initialize ares\n"); - return -1; - } - } - - int side_idx; - int plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - int rc; - rc = gtphub_bind_start(&hub->to_gsns[side_idx][plane_idx], - &cfg->to_gsns[side_idx][plane_idx], - (side_idx == GTPH_SIDE_SGSN) - ? from_sgsns_read_cb - : from_ggsns_read_cb, - hub, plane_idx); - if (rc) { - LOG(LOGL_FATAL, "Failed to bind for %ss (%s)\n", - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx]); - return rc; - } - } - - for_each_side_and_plane(side_idx, plane_idx) { - if (gtphub_make_proxy(hub, - &hub->proxy[side_idx][plane_idx], - &hub->to_gsns[side_idx][plane_idx], - &cfg->proxy[side_idx][plane_idx]) - != 0) { - LOG(LOGL_FATAL, "Cannot configure %s proxy" - " %s port %d.\n", - gtphub_side_idx_names[side_idx], - cfg->proxy[side_idx][plane_idx].addr_str, - (int)cfg->proxy[side_idx][plane_idx].port); - return -1; - } - } - - for_each_side_and_plane(side_idx, plane_idx) { - if (hub->proxy[side_idx][plane_idx]) - LOG(LOGL_NOTICE, "Using %s %s proxy %s\n", - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx], - gtphub_port_str(hub->proxy[side_idx][plane_idx])); - } - - if (hub->sgsn_use_sender) - LOG(LOGL_NOTICE, "Using sender address and port for SGSN instead of GSN Addr IE and default ports.\n"); - - gtphub_gc_start(hub); - return 0; -} - -static struct gtphub_peer_addr *gtphub_peer_find_addr(const struct gtphub_peer *peer, - const struct gsn_addr *addr) -{ - struct gtphub_peer_addr *a; - llist_for_each_entry(a, &peer->addresses, entry) { - if (gsn_addr_same(&a->addr, addr)) - return a; - } - return NULL; -} - -static struct gtphub_peer_port *gtphub_addr_find_port(const struct gtphub_peer_addr *a, - uint16_t port) -{ - OSMO_ASSERT(port); - struct gtphub_peer_port *pp; - llist_for_each_entry(pp, &a->ports, entry) { - if (pp->port == port) - return pp; - } - return NULL; -} - -static struct gtphub_peer_addr *gtphub_addr_find(const struct gtphub_bind *bind, - const struct gsn_addr *addr) -{ - struct gtphub_peer *peer; - llist_for_each_entry(peer, &bind->peers, entry) { - struct gtphub_peer_addr *a = gtphub_peer_find_addr(peer, addr); - if (a) - return a; - } - return NULL; -} - -static struct gtphub_peer_port *gtphub_port_find(const struct gtphub_bind *bind, - const struct gsn_addr *addr, - uint16_t port) -{ - struct gtphub_peer_addr *a = gtphub_addr_find(bind, addr); - if (!a) - return NULL; - return gtphub_addr_find_port(a, port); -} - -struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind, - const struct osmo_sockaddr *addr) -{ - struct gsn_addr gsna; - uint16_t port; - gsn_addr_from_sockaddr(&gsna, &port, addr); - return gtphub_port_find(bind, &gsna, port); -} - -static struct gtphub_peer *gtphub_peer_new(struct gtphub *hub, - struct gtphub_bind *bind) -{ - struct gtphub_peer *peer = talloc_zero(osmo_gtphub_ctx, - struct gtphub_peer); - OSMO_ASSERT(peer); - - INIT_LLIST_HEAD(&peer->addresses); - - nr_pool_init(&peer->seq_pool, 0, 0xffff); - nr_map_init(&peer->seq_map, &peer->seq_pool, &hub->expire_quickly); - - /* TODO use something random to pick the initial sequence nr. - 0x6d31 produces the ASCII character sequence 'm1', currently used in - gtphub_nc_test.sh. */ - peer->seq_pool.last_nr = 0x6d31 - 1; - - llist_add(&peer->entry, &bind->peers); - return peer; -} - -static struct gtphub_peer_addr *gtphub_peer_add_addr(struct gtphub_peer *peer, - const struct gsn_addr *addr) -{ - struct gtphub_peer_addr *a; - a = talloc_zero(osmo_gtphub_ctx, struct gtphub_peer_addr); - OSMO_ASSERT(a); - a->peer = peer; - gsn_addr_copy(&a->addr, addr); - INIT_LLIST_HEAD(&a->ports); - llist_add(&a->entry, &peer->addresses); - - return a; -} - -static struct gtphub_peer_addr *gtphub_addr_have(struct gtphub *hub, - struct gtphub_bind *bind, - const struct gsn_addr *addr) -{ - struct gtphub_peer_addr *a = gtphub_addr_find(bind, addr); - if (a) - return a; - - /* If we haven't found an address, that means we need to create an - * entirely new peer for the new address. More addresses may be added - * to this peer later, but not via this function. */ - struct gtphub_peer *peer = gtphub_peer_new(hub, bind); - - a = gtphub_peer_add_addr(peer, addr); - - LOG(LOGL_DEBUG, "New peer address: %s %s\n", - bind->label, - gsn_addr_to_str(&a->addr)); - - return a; -} - -static struct gtphub_peer_port *gtphub_addr_add_port(struct gtphub_peer_addr *a, - uint16_t port) -{ - struct gtphub_peer_port *pp; - - pp = talloc_zero(osmo_gtphub_ctx, struct gtphub_peer_port); - OSMO_ASSERT(pp); - pp->peer_addr = a; - pp->port = port; - pp->last_restart_count = -1; - - if (gsn_addr_to_sockaddr(&a->addr, port, &pp->sa) != 0) { - talloc_free(pp); - return NULL; - } - - pp->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, - >phub_ctrg_io_desc, 0); - if (!pp->counters_io) { - talloc_free(pp); - return NULL; - } - - llist_add(&pp->entry, &a->ports); - - LOG(LOGL_DEBUG, "New peer port: %s port %d\n", - gsn_addr_to_str(&a->addr), - (int)port); - - return pp; -} - -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_addr *a = gtphub_addr_have(hub, bind, addr); - - struct gtphub_peer_port *pp = gtphub_addr_find_port(a, port); - if (pp) - return pp; - - return gtphub_addr_add_port(a, port); -} - -/* Find a GGSN peer with a matching address. If the address is known but the - * port not, create a new port for that peer address. */ -struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind, - const struct osmo_sockaddr *addr) -{ - struct gtphub_peer_addr *pa; - struct gtphub_peer_port *pp; - - struct gsn_addr gsna; - uint16_t port; - gsn_addr_from_sockaddr(&gsna, &port, addr); - - pa = gtphub_addr_find(bind, &gsna); - if (!pa) - return NULL; - - pp = gtphub_addr_find_port(pa, port); - - if (!pp) - pp = gtphub_addr_add_port(pa, port); - - return pp; -} - - -/* Return 0 if the message in p is not applicable for GGSN resolution, -1 if - * resolution should be possible but failed, and 1 if resolution was - * successful. *pp will be set to NULL if <1 is returned. */ -static int gtphub_resolve_ggsn(struct gtphub *hub, - struct gtp_packet_desc *p, - struct gtphub_peer_port **pp) -{ - *pp = NULL; - - /* TODO determine from message type whether IEs should be present? */ - - int rc; - const char *imsi_str; - rc = get_ie_imsi_str(p->ie, 0, &imsi_str); - if (rc < 1) - return rc; - OSMO_ASSERT(imsi_str); - - const char *apn_str; - rc = get_ie_apn_str(p->ie, &apn_str); - if (rc < 1) - return rc; - OSMO_ASSERT(apn_str); - - *pp = gtphub_resolve_ggsn_addr(hub, imsi_str, apn_str); - return (*pp)? 1 : -1; -} - - -/* TODO move to osmocom/core/socket.c ? */ -/* use this in osmo_sock_init() to remove dup. */ -/* Internal: call getaddrinfo for osmo_sockaddr_init(). The caller is required - to call freeaddrinfo(*result), iff zero is returned. */ -static int _osmo_getaddrinfo(struct addrinfo **result, - uint16_t family, uint16_t type, uint8_t proto, - const char *host, uint16_t port) -{ - struct addrinfo hints; - char portbuf[16]; - - sprintf(portbuf, "%u", port); - memset(&hints, '\0', sizeof(struct addrinfo)); - hints.ai_family = family; - if (type == SOCK_RAW) { - /* Workaround for glibc, that returns EAI_SERVICE (-8) if - * SOCK_RAW and IPPROTO_GRE is used. - */ - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - } else { - hints.ai_socktype = type; - hints.ai_protocol = proto; - } - - return getaddrinfo(host, portbuf, &hints, result); -} - -/* TODO move to osmocom/core/socket.c ? */ -int osmo_sockaddr_init(struct osmo_sockaddr *addr, - uint16_t family, uint16_t type, uint8_t proto, - const char *host, uint16_t port) -{ - struct addrinfo *res; - int rc; - rc = _osmo_getaddrinfo(&res, family, type, proto, host, port); - - if (rc != 0) { - LOG(LOGL_ERROR, "getaddrinfo returned error %d\n", (int)rc); - return -EINVAL; - } - - OSMO_ASSERT(res->ai_addrlen <= sizeof(addr->a)); - memcpy(&addr->a, res->ai_addr, res->ai_addrlen); - addr->l = res->ai_addrlen; - freeaddrinfo(res); - - return 0; -} - -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) -{ - int rc; - - if ((addr->l < 1) || (addr->l > sizeof(addr->a))) { - LOGP(DGTPHUB, LOGL_ERROR, "Invalid address size: %d\n", addr->l); - return -1; - } - - if (addr->l > sizeof(addr->a)) { - LOGP(DGTPHUB, LOGL_ERROR, "Invalid address: too long: %d\n", - addr->l); - return -1; - } - - rc = getnameinfo((struct sockaddr*)&addr->a, addr->l, - addr_str, addr_str_len, - port_str, port_str_len, - flags); - - if (rc) - LOGP(DGTPHUB, LOGL_ERROR, "Invalid address: %s: %s\n", - gai_strerror(rc), osmo_hexdump((uint8_t*)&addr->a, - addr->l)); - - return rc; -} - -const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr, - char *buf, size_t buf_len) -{ - const int portbuf_len = 6; - OSMO_ASSERT(buf_len > portbuf_len); - char *portbuf = buf + buf_len - portbuf_len; - buf_len -= portbuf_len; - if (osmo_sockaddr_to_strs(buf, buf_len, - portbuf, portbuf_len, - addr, - NI_NUMERICHOST | NI_NUMERICSERV)) - return NULL; - - char *pos = buf + strnlen(buf, buf_len-1); - size_t len = buf_len - (pos - buf); - - snprintf(pos, len, " port %s", portbuf); - buf[buf_len-1] = '\0'; - - return buf; -} - -const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr) -{ - static char buf[256]; - const char *result = osmo_sockaddr_to_strb(addr, buf, sizeof(buf)); - if (! result) - return "(invalid)"; - return result; -} - -int osmo_sockaddr_cmp(const struct osmo_sockaddr *a, - const struct osmo_sockaddr *b) -{ - if (a == b) - return 0; - if (!a) - return -1; - if (!b) - return 1; - if (a->l != b->l) { - /* Lengths are not the same, but determine the order. Will - * anyone ever sort a list by osmo_sockaddr though...? */ - int cmp = memcmp(&a->a, &b->a, (a->l < b->l)? a->l : b->l); - if (cmp == 0) { - if (a->l < b->l) - return -1; - else - return 1; - } - return cmp; - } - return memcmp(&a->a, &b->a, a->l); -} - -void osmo_sockaddr_copy(struct osmo_sockaddr *dst, - const struct osmo_sockaddr *src) -{ - OSMO_ASSERT(src->l <= sizeof(dst->a)); - memcpy(&dst->a, &src->a, src->l); - dst->l = src->l; -} diff --git a/src/gprs/gtphub_ares.c b/src/gprs/gtphub_ares.c deleted file mode 100644 index afeeda657..000000000 --- a/src/gprs/gtphub_ares.c +++ /dev/null @@ -1,220 +0,0 @@ -/* GTP Hub Implementation */ - -/* (C) 2015 by sysmocom s.f.m.c. GmbH - * All Rights Reserved - * - * gtphub_ares.c. - * - * This file is kept separate so that these functions can be wrapped for - * gtphub_test.c. When a function and its callers are in the same compilational - * unit, the wrappability may be optimized away. - * - * 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 . - */ - -#include -#include - -#include -#include - -#include -#include - -/* TODO split GRX ares from sgsn into a separate struct and allow use without - * globals. */ -#include -extern struct sgsn_instance *sgsn; - -struct sgsn_instance sgsn_inst = { 0 }; -struct sgsn_instance *sgsn = &sgsn_inst; - -extern void *osmo_gtphub_ctx; - -int gtphub_ares_init(struct gtphub *hub) -{ - return sgsn_ares_init(sgsn); -} - -struct ggsn_lookup { - struct llist_head entry; - struct expiring_item expiry_entry; - - struct gtphub *hub; - - char imsi_str[GSM23003_IMSI_MAX_DIGITS+1]; - char apn_ni_str[GSM_APN_LENGTH]; - char apn_oi_str[GSM_APN_LENGTH]; - int have_3dig_mnc; -}; - -static int start_ares_query(struct ggsn_lookup *lookup); - -static void ggsn_lookup_cb(void *arg, int status, int timeouts, - struct hostent *hostent) -{ - struct ggsn_lookup *lookup = arg; - LOGP(DGTPHUB, LOGL_NOTICE, "ggsn_lookup_cb(%p / %p)", lookup, - &lookup->expiry_entry); - - if (status != ARES_SUCCESS) { - LOGP(DGTPHUB, LOGL_ERROR, "DNS query failed.\n"); - - /* Need to try with three digits now */ - if (!lookup->have_3dig_mnc) { - lookup->have_3dig_mnc = 1; - if (start_ares_query(lookup) == 0) - return; - } - - LOGP(DGTPHUB, LOGL_ERROR, "Failed to resolve GGSN. (%p)\n", - lookup); - goto remove_from_queue; - } - - struct gsn_addr resolved_addr; - if (hostent->h_length > sizeof(resolved_addr.buf)) { - LOGP(DGTPHUB, LOGL_ERROR, "Addr size too large: %d > %d\n", - (int)hostent->h_length, (int)sizeof(resolved_addr.buf)); - goto remove_from_queue; - } - - /* Get the first addr from the list */ - char *addr0 = hostent->h_addr_list[0]; - if (!addr0) { - LOGP(DGTPHUB, LOGL_ERROR, "No host address.\n"); - goto remove_from_queue; - } - - memcpy(resolved_addr.buf, addr0, hostent->h_length); - resolved_addr.len = hostent->h_length; - - LOGP(DGTPHUB, LOGL_NOTICE, "resolved addr %s\n", - osmo_hexdump((unsigned char*)&resolved_addr, - sizeof(resolved_addr))); - - gtphub_resolved_ggsn(lookup->hub, lookup->apn_oi_str, &resolved_addr, - gtphub_now()); - -remove_from_queue: - LOGP(DGTPHUB, LOGL_ERROR, "Removing GGSN lookup. (%p / %p)\n", lookup, - &lookup->expiry_entry); - expiring_item_del(&lookup->expiry_entry); -} - -static void make_addr_str(struct ggsn_lookup *lookup) -{ - char *apn_oi_str; - apn_oi_str = osmo_apn_qualify_from_imsi(lookup->imsi_str, - lookup->apn_ni_str, - lookup->have_3dig_mnc); - osmo_strlcpy(lookup->apn_oi_str, apn_oi_str, - sizeof(lookup->apn_oi_str)); -} - -static int start_ares_query(struct ggsn_lookup *lookup) -{ - LOGP(DGTPHUB, LOGL_DEBUG, "Going to query %s (%p / %p)\n", - lookup->apn_oi_str, lookup, &lookup->expiry_entry); - - int rc = sgsn_ares_query(sgsn, lookup->apn_oi_str, ggsn_lookup_cb, - lookup); - if (rc != 0) - LOGP(DGTPHUB, LOGL_ERROR, "Failed to start ares query.\n"); - return rc; -} - -static void ggsn_lookup_del_cb(struct expiring_item *expi) -{ - struct ggsn_lookup *lookup; - lookup = container_of(expi, struct ggsn_lookup, expiry_entry); - - LOGP(DGTPHUB, LOGL_NOTICE, "ggsn_lookup_del_cb(%p / %p)\n", lookup, - expi); - - lookup->expiry_entry.del_cb = 0; - expiring_item_del(expi); - - llist_del(&lookup->entry); - talloc_free(lookup); -} - -struct gtphub_peer_port *gtphub_resolve_ggsn_addr(struct gtphub *hub, - const char *imsi_str, - const char *apn_ni_str) -{ - OSMO_ASSERT(imsi_str); - OSMO_ASSERT(apn_ni_str); - - struct ggsn_lookup *lookup = talloc_zero(osmo_gtphub_ctx, - struct ggsn_lookup); - OSMO_ASSERT(lookup); - - LOGP(DGTPHUB, LOGL_DEBUG, "Request to resolve IMSI" - " '%s' with APN-NI '%s' (%p / %p)\n", - imsi_str, apn_ni_str, lookup, &lookup->expiry_entry); - - expiring_item_init(&lookup->expiry_entry); - lookup->hub = hub; - - osmo_strlcpy(lookup->imsi_str, imsi_str, sizeof(lookup->imsi_str)); - osmo_strlcpy(lookup->apn_ni_str, apn_ni_str, - sizeof(lookup->apn_ni_str)); - - make_addr_str(lookup); - - struct ggsn_lookup *active; - llist_for_each_entry(active, &hub->ggsn_lookups, entry) { - if (strncmp(active->apn_oi_str, lookup->apn_oi_str, - sizeof(lookup->apn_oi_str)) == 0) { - LOGP(DGTPHUB, LOGL_DEBUG, - "Query already pending for %s\n", - lookup->apn_oi_str); - /* A query already pending. Just tip our hat. */ - return NULL; - } - } - - struct gtphub_resolved_ggsn *resolved; - llist_for_each_entry(resolved, &hub->resolved_ggsns, entry) { - if (strncmp(resolved->apn_oi_str, lookup->apn_oi_str, - sizeof(lookup->apn_oi_str)) == 0) { - LOGP(DGTPHUB, LOGL_DEBUG, - "GGSN resolved from cache: %s -> %s\n", - lookup->apn_oi_str, - gtphub_port_str(resolved->peer)); - return resolved->peer; - } - } - - /* Kick off a resolution, but so far return nothing. The hope is that - * the peer will resend the request (a couple of times), and by then - * the GGSN will be resolved. */ - LOGP(DGTPHUB, LOGL_DEBUG, - "Sending out DNS query for %s..." - " (Returning failure, hoping for a retry once resolution" - " has concluded)\n", - lookup->apn_oi_str); - - llist_add(&lookup->entry, &hub->ggsn_lookups); - - lookup->expiry_entry.del_cb = ggsn_lookup_del_cb; - expiry_add(&hub->expire_quickly, &lookup->expiry_entry, gtphub_now()); - - start_ares_query(lookup); - - return NULL; -} diff --git a/src/gprs/gtphub_main.c b/src/gprs/gtphub_main.c deleted file mode 100644 index 2b87d19ef..000000000 --- a/src/gprs/gtphub_main.c +++ /dev/null @@ -1,359 +0,0 @@ -/* GTP Hub main program */ - -/* (C) 2015 by sysmocom s.f.m.c. GmbH - * 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 . - */ - -#include -#include -#include -#include -#include -#include - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "../../bscconfig.h" - -extern void *osmo_gtphub_ctx; - - -const char *gtphub_copyright = - "Copyright (C) 2015 sysmocom s.f.m.c GmbH \r\n" - "License AGPLv3+: GNU AGPL version 2 or later \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 struct log_info_cat gtphub_categories[] = { - [DGTPHUB] = { - .name = "DGTPHUB", - .description = "GTP Hub", - .color = "\033[1;33m", - .enabled = 1, - .loglevel = LOGL_INFO, - }, -}; - -int gtphub_log_filter_fn(const struct log_context *ctx, - struct log_target *tar) -{ - return 0; -} - -static const struct log_info gtphub_log_info = { - .filter_fn = gtphub_log_filter_fn, - .cat = gtphub_categories, - .num_cat = ARRAY_SIZE(gtphub_categories), -}; - -void log_cfg(struct gtphub_cfg *cfg) -{ - int side_idx, plane_idx; - for_each_side_and_plane(side_idx, plane_idx) { - struct gtphub_cfg_addr *a; - a = &cfg->to_gsns[side_idx][plane_idx].bind; - LOGP(DGTPHUB, LOGL_NOTICE, - "to-%ss bind, %s: %s port %d\n", - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx], - a->addr_str, a->port); - } -} - -static void signal_handler(int signal) -{ - fprintf(stdout, "signal %d 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: - case SIGUSR2: - talloc_report_full(osmo_gtphub_ctx, stderr); - break; - default: - break; - } -} - -extern int bsc_vty_go_parent(struct vty *vty); - -static struct vty_app_info vty_info = { - .name = "OsmoGTPhub", - .version = PACKAGE_VERSION, - .go_parent_cb = bsc_vty_go_parent, - .is_config_node = bsc_vty_is_config_node, -}; - -struct cmdline_cfg { - const char *config_file; - const char *restart_counter_file; - int daemonize; -}; - -static uint8_t next_restart_count(const char *path) -{ - int umask_was = umask(022); - - uint8_t counter = 0; - - FILE *f = fopen(path, "r"); - if (f) { - int rc = fscanf(f, "%hhu", &counter); - - if (rc != 1) - goto failed_to_read; - - char c; - while (fread(&c, 1, 1, f) > 0) { - switch (c) { - case ' ': - case '\t': - case '\n': - case '\r': - break; - default: - goto failed_to_read; - } - } - fclose(f); - } - - counter ++; - - f = fopen(path, "w"); - if (!f) - goto failed_to_write; - if (fprintf(f, "%" PRIu8 "\n", counter) < 2) - goto failed_to_write; - if (fclose(f)) { - f = NULL; - goto failed_to_write; - } - - umask(umask_was); - - LOGP(DGTPHUB, LOGL_NOTICE, "Restarted with counter %hhu\n", counter); - return counter; - -failed_to_read: - fclose(f); - umask(umask_was); - LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be parsed:" - " %s\n", path); - exit(1); - -failed_to_write: - if (f) - fclose(f); - umask(umask_was); - LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be written:" - " %s\n", path); - exit(1); -} - -static void print_help(struct cmdline_cfg *ccfg) -{ - printf("gtphub commandline options\n"); - printf(" -h,--help This text.\n"); - printf(" -D,--daemonize Fork the process into a background daemon.\n"); - printf(" -d,--debug Enable Debugging for this category.\n"); - printf(" Pass '-d list' to get a category listing.\n"); - printf(" -s,--disable-color\n"); - printf(" -c,--config-file The config file to use [%s].\n", - ccfg->config_file); - printf(" -e,--log-level Set a global log level.\n"); - printf(" -r,--restart-file File for counting restarts [%s].\n", - ccfg->restart_counter_file); -} - -static void list_categories(void) -{ - printf("Avaliable debug categories:\n"); - int i; - for (i = 0; i < gtphub_log_info.num_cat; ++i) { - if (!gtphub_log_info.cat[i].name) - continue; - - printf("%s\n", gtphub_log_info.cat[i].name); - } -} - -static void handle_options(struct cmdline_cfg *ccfg, 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'}, - {"log-level", 1, 0, 'e'}, - {"restart-file", 1, 0, 'r'}, - {NULL, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "hd:Dc:sTe:r:", - long_options, &option_index); - if (c == -1) { - if (optind < argc) { - LOGP(DGTPHUB, LOGL_FATAL, - "Excess commandline arguments ('%s').\n", - argv[optind]); - exit(2); - } - break; - } - - switch (c) { - case 'h': - //print_usage(); - print_help(ccfg); - exit(0); - case 's': - log_set_use_color(osmo_stderr_target, 0); - break; - case 'd': - if (strcmp("list", optarg) == 0) { - list_categories(); - exit(0); - } else - log_parse_category_mask(osmo_stderr_target, optarg); - break; - case 'D': - ccfg->daemonize = 1; - break; - case 'c': - ccfg->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 'r': - ccfg->restart_counter_file = optarg; - break; - default: - LOGP(DGTPHUB, LOGL_FATAL, "Invalid command line argument, abort.\n"); - exit(1); - break; - } - } -} - -int main(int argc, char **argv) -{ - int rc; - - struct cmdline_cfg _ccfg; - struct cmdline_cfg *ccfg = &_ccfg; - memset(ccfg, '\0', sizeof(*ccfg)); - ccfg->config_file = "./gtphub.conf"; - ccfg->restart_counter_file = "./gtphub_restart_count"; - - struct gtphub_cfg _cfg; - struct gtphub_cfg *cfg = &_cfg; - memset(cfg, '\0', sizeof(*cfg)); - - struct gtphub _hub; - struct gtphub *hub = &_hub; - - osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub"); - msgb_talloc_ctx_init(osmo_gtphub_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(>phub_log_info); - - vty_info.copyright = gtphub_copyright; - vty_init(&vty_info); - logging_vty_add_cmds(NULL); - gtphub_vty_init(hub, cfg); - - rate_ctr_init(osmo_gtphub_ctx); - - handle_options(ccfg, argc, argv); - - rc = gtphub_cfg_read(cfg, ccfg->config_file); - if (rc < 0) { - LOGP(DGTPHUB, LOGL_FATAL, "Cannot parse config file '%s'\n", - ccfg->config_file); - exit(2); - } - - /* start telnet after reading config for vty_get_bind_addr() */ - rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(), - OSMO_VTY_PORT_GTPHUB); - if (rc < 0) - exit(1); - - if (gtphub_start(hub, cfg, - next_restart_count(ccfg->restart_counter_file)) - != 0) - return -1; - - log_cfg(cfg); - - if (ccfg->daemonize) { - rc = osmo_daemonize(); - if (rc < 0) { - LOGP(DGTPHUB, LOGL_FATAL, "Error during daemonize"); - exit(1); - } - } - - while (1) { - rc = osmo_select_main(0); - if (rc < 0) - exit(3); - } - - /* not reached */ - exit(0); -} diff --git a/src/gprs/gtphub_sock.c b/src/gprs/gtphub_sock.c deleted file mode 100644 index 60bebaaeb..000000000 --- a/src/gprs/gtphub_sock.c +++ /dev/null @@ -1,60 +0,0 @@ -/* GTP Hub Implementation */ - -/* (C) 2015 by sysmocom s.f.m.c. GmbH - * All Rights Reserved - * - * gtphub_sock.c. - * - * This file is kept separate so that these functions can be wrapped for - * gtphub_test.c. When a function and its callers are in the same compilational - * unit, the wrappability may be optimized away. - * - * 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 . - */ - -#include -#include - -/* Convenience makro, note: only within this C file. */ -#define LOG(level, fmt, args...) \ - LOGP(DGTPHUB, level, fmt, ##args) - -int gtphub_write(const struct osmo_fd *to, - const struct osmo_sockaddr *to_addr, - const uint8_t *buf, size_t buf_len) -{ - errno = 0; - ssize_t sent = sendto(to->fd, buf, buf_len, 0, - (struct sockaddr*)&to_addr->a, to_addr->l); - LOG(LOGL_DEBUG, "to %s\n", osmo_sockaddr_to_str(to_addr)); - - if (sent == -1) { - LOG(LOGL_ERROR, "error: %s\n", strerror(errno)); - return -EINVAL; - } - - if (sent != buf_len) - LOG(LOGL_ERROR, "sent(%d) != data_len(%d)\n", - (int)sent, (int)buf_len); - else - LOG(LOGL_DEBUG, "Sent %d: %s%s\n", - (int)sent, - osmo_hexdump(buf, sent > 1000? 1000 : sent), - sent > 1000 ? "..." : ""); - - return 0; -} - diff --git a/src/gprs/gtphub_vty.c b/src/gprs/gtphub_vty.c deleted file mode 100644 index a30ad2a54..000000000 --- a/src/gprs/gtphub_vty.c +++ /dev/null @@ -1,613 +0,0 @@ -/* (C) 2015 by sysmocom s.f.m.c. GmbH - * 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 . - * - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/* TODO split GRX ares from sgsn into a separate struct and allow use without - * globals. */ -#include -extern struct sgsn_instance *sgsn; - -static struct gtphub *g_hub = 0; -static struct gtphub_cfg *g_cfg = 0; - -static struct cmd_node gtphub_node = { - GTPHUB_NODE, - "%s(config-gtphub)# ", - 1, -}; - -#define GTPH_DEFAULT_CONTROL_PORT 2123 -#define GTPH_DEFAULT_USER_PORT 2152 - -static void write_addrs(struct vty *vty, const char *name, - struct gtphub_cfg_addr *c, struct gtphub_cfg_addr *u) -{ - if ((c->port == GTPH_DEFAULT_CONTROL_PORT) - && (u->port == GTPH_DEFAULT_USER_PORT) - && (strcmp(c->addr_str, u->addr_str) == 0)) { - /* Default port numbers and same IP address: write "short" - * variant. */ - vty_out(vty, " %s %s%s", - name, - c->addr_str, - VTY_NEWLINE); - return; - } - - vty_out(vty, " %s ctrl %s %d user %s %d%s", - name, - c->addr_str, (int)c->port, - u->addr_str, (int)u->port, - VTY_NEWLINE); - - struct ares_addr_node *server; - for (server = sgsn->ares_servers; server; server = server->next) - vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE); -} - -static int config_write_gtphub(struct vty *vty) -{ - vty_out(vty, "gtphub%s", VTY_NEWLINE); - - write_addrs(vty, "bind-to-sgsns", - &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind, - &g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind); - - write_addrs(vty, "bind-to-ggsns", - &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind, - &g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind); - - if (g_cfg->sgsn_use_sender) { - vty_out(vty, "sgsn-use-sender%s", VTY_NEWLINE); - } - - if (g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str) { - write_addrs(vty, "sgsn-proxy", - &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL], - &g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER]); - } - - if (g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str) { - write_addrs(vty, "ggsn-proxy", - &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL], - &g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER]); - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_gtphub, cfg_gtphub_cmd, - "gtphub", - "Configure the GTP hub\n") -{ - vty->node = GTPHUB_NODE; - return CMD_SUCCESS; -} - -#define BIND_ARGS "ctrl ADDR <0-65535> user ADDR <0-65535>" -#define BIND_DOCS \ - "Set GTP-C bind\n" \ - "GTP-C local IP address (v4 or v6)\n" \ - "GTP-C local port\n" \ - "Set GTP-U bind\n" \ - "GTP-U local IP address (v4 or v6)\n" \ - "GTP-U local port\n" - - -DEFUN(cfg_gtphub_bind_to_sgsns_short, cfg_gtphub_bind_to_sgsns_short_cmd, - "bind-to-sgsns ADDR", - "GTP Hub Parameters\n" - "Set the local bind address to listen for SGSNs, for both GTP-C and GTP-U\n" - "Local IP address (v4 or v6)\n" - ) -{ - int i; - for_each_plane(i) - g_cfg->to_gsns[GTPH_SIDE_SGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT; - g_cfg->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT; - return CMD_SUCCESS; -} - -DEFUN(cfg_gtphub_bind_to_ggsns_short, cfg_gtphub_bind_to_ggsns_short_cmd, - "bind-to-ggsns ADDR", - "GTP Hub Parameters\n" - "Set the local bind address to listen for GGSNs, for both GTP-C and GTP-U\n" - "Local IP address (v4 or v6)\n" - ) -{ - int i; - for_each_plane(i) - g_cfg->to_gsns[GTPH_SIDE_GGSN][i].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].bind.port = GTPH_DEFAULT_CONTROL_PORT; - g_cfg->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].bind.port = GTPH_DEFAULT_USER_PORT; - return CMD_SUCCESS; -} - - -static int handle_binds(struct gtphub_cfg_bind *b, const char **argv) -{ - b[GTPH_PLANE_CTRL].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - b[GTPH_PLANE_CTRL].bind.port = atoi(argv[1]); - b[GTPH_PLANE_USER].bind.addr_str = talloc_strdup(tall_vty_ctx, argv[2]); - b[GTPH_PLANE_USER].bind.port = atoi(argv[3]); - return CMD_SUCCESS; -} - -DEFUN(cfg_gtphub_bind_to_sgsns, cfg_gtphub_bind_to_sgsns_cmd, - "bind-to-sgsns " BIND_ARGS, - "GTP Hub Parameters\n" - "Set the local bind addresses and ports to listen for SGSNs\n" - BIND_DOCS - ) -{ - return handle_binds(g_cfg->to_gsns[GTPH_SIDE_SGSN], argv); -} - -DEFUN(cfg_gtphub_bind_to_ggsns, cfg_gtphub_bind_to_ggsns_cmd, - "bind-to-ggsns " BIND_ARGS, - "GTP Hub Parameters\n" - "Set the local bind addresses and ports to listen for GGSNs\n" - BIND_DOCS - ) -{ - return handle_binds(g_cfg->to_gsns[GTPH_SIDE_GGSN], argv); -} - -DEFUN(cfg_gtphub_ggsn_proxy_short, cfg_gtphub_ggsn_proxy_short_cmd, - "ggsn-proxy ADDR", - "GTP Hub Parameters\n" - "Redirect all GGSN bound traffic to default ports on this address (another gtphub)\n" - "Remote IP address (v4 or v6)\n" - ) -{ - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT; - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT; - return CMD_SUCCESS; -} - -DEFUN(cfg_gtphub_ggsn_proxy, cfg_gtphub_ggsn_proxy_cmd, - "ggsn-proxy " BIND_ARGS, - "GTP Hub Parameters\n" - "Redirect all GGSN bound traffic to these addresses and ports (another gtphub)\n" - BIND_DOCS - ) -{ - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]); - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]); - g_cfg->proxy[GTPH_SIDE_GGSN][GTPH_PLANE_USER].port = atoi(argv[3]); - return CMD_SUCCESS; -} - -DEFUN(cfg_gtphub_sgsn_proxy_short, cfg_gtphub_sgsn_proxy_short_cmd, - "sgsn-proxy ADDR", - "GTP Hub Parameters\n" - "Redirect all SGSN bound traffic to default ports on this address (another gtphub)\n" - "Remote IP address (v4 or v6)\n" - ) -{ - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = GTPH_DEFAULT_CONTROL_PORT; - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = GTPH_DEFAULT_USER_PORT; - return CMD_SUCCESS; -} - -DEFUN(cfg_gtphub_sgsn_proxy, cfg_gtphub_sgsn_proxy_cmd, - "sgsn-proxy " BIND_ARGS, - "GTP Hub Parameters\n" - "Redirect all SGSN bound traffic to these addresses and ports (another gtphub)\n" - BIND_DOCS - ) -{ - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].addr_str = talloc_strdup(tall_vty_ctx, argv[0]); - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].port = atoi(argv[1]); - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].addr_str = talloc_strdup(tall_vty_ctx, argv[2]); - g_cfg->proxy[GTPH_SIDE_SGSN][GTPH_PLANE_USER].port = atoi(argv[3]); - return CMD_SUCCESS; -} - - -#define SGSN_USE_SENDER_STR \ - "Ignore SGSN's Address IEs, use sender address and port (useful over NAT)\n" - -DEFUN(cfg_gtphub_sgsn_use_sender, - cfg_gtphub_sgsn_use_sender_cmd, - "sgsn-use-sender", - SGSN_USE_SENDER_STR) -{ - g_cfg->sgsn_use_sender = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_gtphub_no_sgsn_use_sender, - cfg_gtphub_no_sgsn_use_sender_cmd, - "no sgsn-use-sender", - NO_STR SGSN_USE_SENDER_STR) -{ - g_cfg->sgsn_use_sender = 0; - return CMD_SUCCESS; -} - - -/* Copied from sgsn_vty.h */ -DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd, - "grx-dns-add A.B.C.D", - "Add DNS server\nIPv4 address\n") -{ - struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node); - node->family = AF_INET; - inet_aton(argv[0], &node->addr.addr4); - - node->next = sgsn->ares_servers; - sgsn->ares_servers = node; - return CMD_SUCCESS; -} - - -static void show_bind_stats_all(struct vty *vty) -{ - int plane_idx; - for_each_plane(plane_idx) { - vty_out(vty, "- %s Plane:%s", - gtphub_plane_idx_names[plane_idx], VTY_NEWLINE); - - int side_idx; - for_each_side(side_idx) { - struct gtphub_bind *b = &g_hub->to_gsns[side_idx][plane_idx]; - vty_out(vty, " - local addr to/from %ss: %s port %d%s", - gtphub_side_idx_names[side_idx], - gsn_addr_to_str(&b->local_addr), (int)b->local_port, - VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", b->counters_io); - } - } -} - -static void show_tunnel_stats(struct vty *vty, struct gtphub_tunnel *tun) -{ - int plane_idx; - for_each_plane(plane_idx) { - vty_out(vty, "- %s Plane:%s", - gtphub_plane_idx_names[plane_idx], VTY_NEWLINE); - - int side_idx; - for_each_side(side_idx) { - struct gtphub_tunnel_endpoint *te = &tun->endpoint[side_idx][plane_idx]; - vty_out(vty, " - to/from %s:%s", - gtphub_side_idx_names[side_idx], - VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", te->counters_io); - } - } -} - -static void show_peer_summary(struct vty *vty, const char *prefix, - int side_idx, int plane_idx, - struct gtphub_peer *p, int with_io_stats) -{ - struct gtphub_peer_addr *pa; - int p2l = strlen(prefix) + 4 + 1; - char prefix2[p2l]; - memset(prefix2, ' ', p2l - 1); - prefix2[p2l - 1] = '\0'; - - if (with_io_stats) { - llist_for_each_entry(pa, &p->addresses, entry) { - vty_out(vty, "%s- %s %s %s%s", prefix, - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx], - gsn_addr_to_str(&pa->addr), - VTY_NEWLINE); - - - struct gtphub_peer_port *pp; - llist_for_each_entry(pp, &pa->ports, entry) { - vty_out(vty, "%s Port %" PRIu16 "%s", prefix, pp->port, VTY_NEWLINE); - vty_out_rate_ctr_group(vty, prefix2, pp->counters_io); - } - } - } else { - llist_for_each_entry(pa, &p->addresses, entry) { - vty_out(vty, "%s- %s %s %s", prefix, - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx], - gsn_addr_to_str(&pa->addr)); - struct gtphub_peer_port *pp; - llist_for_each_entry(pp, &pa->ports, entry) { - vty_out(vty, ":%" PRIu16, pp->port); - } - vty_out(vty, VTY_NEWLINE); - } - } -} - -static void show_peers_summary(struct vty *vty) -{ - int side_idx; - int plane_idx; - - int count[GTPH_SIDE_N][GTPH_PLANE_N] = {{0}}; - - for_each_side(side_idx) { - for_each_plane(plane_idx) { - struct gtphub_peer *p; - llist_for_each_entry(p, &g_hub->to_gsns[side_idx][plane_idx].peers, entry) { - count[side_idx][plane_idx] ++; - } - } - } - - vty_out(vty, "Peers Count:%s", VTY_NEWLINE); - for_each_side_and_plane(side_idx, plane_idx) { - vty_out(vty, " %s %s peers: %d%s", - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx], - count[side_idx][plane_idx], - VTY_NEWLINE); - } -} - -static void show_peers_all(struct vty *vty, int with_io_stats) -{ - int side_idx; - int plane_idx; - - int count[GTPH_SIDE_N][GTPH_PLANE_N] = {{0}}; - - vty_out(vty, "All Peers%s%s", - with_io_stats? " with I/O stats" : "", - VTY_NEWLINE); - for_each_side(side_idx) { - vty_out(vty, "- %s%s", gtphub_side_idx_names[side_idx], VTY_NEWLINE); - for_each_plane(plane_idx) { - struct gtphub_peer *p; - llist_for_each_entry(p, &g_hub->to_gsns[side_idx][plane_idx].peers, entry) { - count[side_idx][plane_idx] ++; - show_peer_summary(vty, " ", side_idx, plane_idx, p, with_io_stats); - } - } - } - for_each_side_and_plane(side_idx, plane_idx) { - vty_out(vty, "%s %s peers: %d%s", - gtphub_side_idx_names[side_idx], - gtphub_plane_idx_names[plane_idx], - count[side_idx][plane_idx], - VTY_NEWLINE); - } -} - - -static void show_tunnels_summary(struct vty *vty) -{ - time_t now = gtphub_now(); - - const int w = 36; - int max_expiry = g_hub->expire_slowly.expiry_in_seconds; - float seconds_per_step = ((float)max_expiry) / w; - - /* Print TEI mapping expiry in an ASCII histogram, like: - TEI map summary - Legend: '_'=0 '.'<=1% ':'<=2% '|'<=10% '#'>10% (10.0 m/step) - CTRL: 30 mappings, valid for 360m[# :. | . : . ]1m - USER: 30 mappings, valid for 360m[# :. | . : . ]1m - 4 TEI mappings in total, last expiry in 359.4 min - */ - vty_out(vty, - "Tunnels summary%s" - " Legend: ' '=0 '.'<=1%% ':'<=2%% '|'<=10%% '#'>10%% (%.1f m/step)%s", - VTY_NEWLINE, - seconds_per_step / 60., - VTY_NEWLINE); - - int last_expiry = 0; - - unsigned int count = 0; - - int histogram[w]; - memset(histogram, 0, sizeof(histogram)); - - struct gtphub_tunnel *t; - llist_for_each_entry(t, &g_hub->tunnels, entry) { - count ++; - int expiry = t->expiry_entry.expiry - now; - last_expiry = (last_expiry > expiry) ? last_expiry : expiry; - - int hi = ((float)expiry) / seconds_per_step; - if (hi < 0) - hi = 0; - if (hi > (w - 1)) - hi = w - 1; - histogram[hi] ++; - } - - vty_out(vty, - " %u tunnels, valid for %dm[", - count, max_expiry / 60); - - int i; - for (i = w - 1; i >= 0; i--) { - char c; - int val = histogram[i]; - int percent = 100. * val / count; - if (!val) - c = ' '; - else if (percent <= 1) - c = '.'; - else if (percent <= 2) - c = ':'; - else if (percent <= 10) - c = '|'; - else c = '#'; - vty_out(vty, "%c", c); - } - vty_out(vty, "]1m%s", VTY_NEWLINE); - - vty_out(vty, " last expiry in %.1f min%s", - ((float)last_expiry) / 60., - VTY_NEWLINE); -} - -static void show_tunnels_all(struct vty *vty, int with_io_stats) -{ - time_t now = gtphub_now(); - - vty_out(vty, "All tunnels%s:%s" - "Legend: TEI=: SGSN <-> GGSN (expiry in minutes), with each:%s" - " [/] (TEI C= U=)%s", - with_io_stats? "with I/O stats" : "", - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); - - unsigned int count = 0; - unsigned int incomplete = 0; - struct gtphub_tunnel *tun; - llist_for_each_entry(tun, &g_hub->tunnels, entry) { - vty_out(vty, - "%s (expiry in %dm)%s", - gtphub_tunnel_str(tun), - (int)((tun->expiry_entry.expiry - now) / 60), - VTY_NEWLINE); - count ++; - if (!gtphub_tunnel_complete(tun)) - incomplete ++; - if (with_io_stats) - show_tunnel_stats(vty, tun); - } - vty_out(vty, "Total: %u tunnels (of which %u incomplete)%s", - count, incomplete, VTY_NEWLINE); -} - -#define SHOW_GTPHUB_STRS SHOW_STR "Show info on running GTP hub\n" -#define SHOW_GTPHUB_PEERS_STRS SHOW_GTPHUB_STRS "Active peers\n" -#define SHOW_GTPHUB_TUNS_STRS SHOW_GTPHUB_STRS "Active tunnels\n" - -DEFUN(show_gtphub_peers_summary, show_gtphub_peers_summary_cmd, "show gtphub peers summary", - SHOW_GTPHUB_PEERS_STRS "Summary of all peers\n") -{ - show_peers_summary(vty); - return CMD_SUCCESS; -} - -DEFUN(show_gtphub_peers_list, show_gtphub_peers_list_cmd, "show gtphub peers list", - SHOW_GTPHUB_PEERS_STRS "List all peers\n") -{ - show_peers_all(vty, 0); - return CMD_SUCCESS; -} - -DEFUN(show_gtphub_peers_stats, show_gtphub_peers_stats_cmd, "show gtphub peers stats", - SHOW_GTPHUB_PEERS_STRS "List all peers with I/O stats\n") -{ - show_peers_all(vty, 1); - return CMD_SUCCESS; -} - -DEFUN(show_gtphub_tunnels_summary, show_gtphub_tunnels_summary_cmd, "show gtphub tunnels summary", - SHOW_GTPHUB_TUNS_STRS "Summary of all tunnels\n") -{ - show_tunnels_summary(vty); - return CMD_SUCCESS; -} - -DEFUN(show_gtphub_tunnels_list, show_gtphub_tunnels_list_cmd, "show gtphub tunnels list", - SHOW_GTPHUB_TUNS_STRS "List all tunnels\n") -{ - show_tunnels_all(vty, 0); - return CMD_SUCCESS; -} - -DEFUN(show_gtphub_tunnels_stats, show_gtphub_tunnels_stats_cmd, "show gtphub tunnels stats", - SHOW_GTPHUB_TUNS_STRS "List all tunnels with I/O stats\n") -{ - show_tunnels_all(vty, 1); - return CMD_SUCCESS; -} - -DEFUN(show_gtphub, show_gtphub_cmd, "show gtphub all", - SHOW_GTPHUB_STRS "Summarize everything about the GTP hub\n") -{ - show_bind_stats_all(vty); - show_peers_summary(vty); - show_tunnels_summary(vty); - return CMD_SUCCESS; -} - - -int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg) -{ - g_hub = global_hub; - g_cfg = global_cfg; - - install_element_ve(&show_gtphub_cmd); - install_element_ve(&show_gtphub_peers_summary_cmd); - install_element_ve(&show_gtphub_peers_list_cmd); - install_element_ve(&show_gtphub_peers_stats_cmd); - install_element_ve(&show_gtphub_tunnels_summary_cmd); - install_element_ve(&show_gtphub_tunnels_list_cmd); - install_element_ve(&show_gtphub_tunnels_stats_cmd); - - install_element(CONFIG_NODE, &cfg_gtphub_cmd); - install_node(>phub_node, config_write_gtphub); - vty_install_default(GTPHUB_NODE); - - install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_short_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_sgsns_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_short_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_bind_to_ggsns_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_short_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_ggsn_proxy_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_short_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_proxy_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_sgsn_use_sender_cmd); - install_element(GTPHUB_NODE, &cfg_gtphub_no_sgsn_use_sender_cmd); - install_element(GTPHUB_NODE, &cfg_grx_ggsn_cmd); - - return 0; -} - -int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file) -{ - int rc; - - 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/src/gprs/osmo_sgsn.cfg b/src/gprs/osmo_sgsn.cfg deleted file mode 100644 index c4c9ec1cf..000000000 --- a/src/gprs/osmo_sgsn.cfg +++ /dev/null @@ -1,23 +0,0 @@ -! -! Osmocom SGSN (0.9.0.474-0ede2) configuration saved from vty -!! -! -line vty - no login -! -sgsn - gtp local-ip 192.168.100.11 - ggsn 0 remote-ip 192.168.100.239 - 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 192.168.100.11 - encapsulation udp local-port 23000 - encapsulation framerelay-gre enabled 0 -bssgp diff --git a/src/gprs/sgsn_ares.c b/src/gprs/sgsn_ares.c deleted file mode 100644 index d94d184a3..000000000 --- a/src/gprs/sgsn_ares.c +++ /dev/null @@ -1,173 +0,0 @@ -/* C-ARES DNS resolver integration */ - -/* - * (C) 2015 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 . - * - */ - -#include -#include - -#include - -struct cares_event_fd { - struct llist_head head; - struct osmo_fd fd; -}; - -struct cares_cb_data { - ares_host_callback cb; - void *data; -}; - -static void osmo_ares_reschedule(struct sgsn_instance *sgsn); -static void ares_cb(void *_arg, int status, int timeouts, struct hostent *hostent) -{ - struct cares_cb_data *arg = _arg; - - arg->cb(arg->data, status, timeouts, hostent); - osmo_ares_reschedule(sgsn); - talloc_free(arg); -} - -static int ares_osmo_fd_cb(struct osmo_fd *fd, unsigned int what) -{ - LOGP(DGPRS, LOGL_DEBUG, "C-ares fd(%d) ready(%d)\n", fd->fd, what); - - ares_process_fd(sgsn->ares_channel, - (what & BSC_FD_READ) ? fd->fd : ARES_SOCKET_BAD, - (what & BSC_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD); - osmo_ares_reschedule(sgsn); - return 0; -} - -static void ares_timeout_cb(void *data) -{ - struct sgsn_instance *sgsn = data; - - LOGP(DGPRS, LOGL_DEBUG, "C-ares triggering timeout\n"); - ares_process_fd(sgsn->ares_channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); - osmo_ares_reschedule(sgsn); -} - -static void osmo_ares_reschedule(struct sgsn_instance *sgsn) -{ - struct timeval *timeout, tv; - - osmo_timer_del(&sgsn->ares_timer); - timeout = ares_timeout(sgsn->ares_channel, NULL, &tv); - if (timeout) { - LOGP(DGPRS, LOGL_DEBUG, "C-ares scheduling timeout %llu.%llu\n", - (unsigned long long) tv.tv_sec, - (unsigned long long) tv.tv_usec); - osmo_timer_setup(&sgsn->ares_timer, ares_timeout_cb, sgsn); - osmo_timer_schedule(&sgsn->ares_timer, tv.tv_sec, tv.tv_usec); - } -} - -static void setup_ares_osmo_fd(void *data, int fd, int read, int write) -{ - struct cares_event_fd *ufd, *tmp; - - /* delete the entry */ - if (read == 0 && write == 0) { - llist_for_each_entry_safe(ufd, tmp, &sgsn->ares_fds, head) { - if (ufd->fd.fd != fd) - continue; - - LOGP(DGPRS, LOGL_DEBUG, - "Removing C-ares watched fd (%d)\n", fd); - osmo_fd_unregister(&ufd->fd); - llist_del(&ufd->head); - talloc_free(ufd); - return; - } - } - - /* Search for the fd or create a new one */ - llist_for_each_entry(ufd, &sgsn->ares_fds, head) { - if (ufd->fd.fd != fd) - continue; - - LOGP(DGPRS, LOGL_DEBUG, "Updating C-ares fd (%d)\n", fd); - goto update_fd; - } - - LOGP(DGPRS, LOGL_DEBUG, "Registering C-ares fd (%d)\n", fd); - ufd = talloc_zero(tall_bsc_ctx, struct cares_event_fd); - ufd->fd.fd = fd; - ufd->fd.cb = ares_osmo_fd_cb; - ufd->fd.data = data; - if (osmo_fd_register(&ufd->fd) != 0) - LOGP(DGPRS, LOGL_ERROR, "Failed to register C-ares fd (%d)\n", fd); - llist_add(&ufd->head, &sgsn->ares_fds); - -update_fd: - if (read) - ufd->fd.when |= BSC_FD_READ; - else - ufd->fd.when &= ~BSC_FD_READ; - - if (write) - ufd->fd.when |= BSC_FD_WRITE; - else - ufd->fd.when &= ~BSC_FD_WRITE; - - osmo_ares_reschedule(sgsn); -} - -int sgsn_ares_query(struct sgsn_instance *sgsn, const char *name, - ares_host_callback cb, void *data) -{ - struct cares_cb_data *cb_data; - - cb_data = talloc_zero(tall_bsc_ctx, struct cares_cb_data); - cb_data->cb = cb; - cb_data->data = data; - ares_gethostbyname(sgsn->ares_channel, name, AF_INET, ares_cb, cb_data); - osmo_ares_reschedule(sgsn); - return 0; -} - -int sgsn_ares_init(struct sgsn_instance *sgsn) -{ - struct ares_options options; - int optmask; - int rc; - - INIT_LLIST_HEAD(&sgsn->ares_fds); - memset(&options, 0, sizeof(options)); - options.sock_state_cb = setup_ares_osmo_fd; - options.sock_state_cb_data = sgsn; - - optmask = ARES_OPT_FLAGS | ARES_OPT_SOCK_STATE_CB | ARES_OPT_DOMAINS; - - if (sgsn->ares_servers) - optmask |= ARES_OPT_SERVERS; - - ares_library_init(ARES_LIB_INIT_ALL); - rc = ares_init_options(&sgsn->ares_channel, &options, optmask); - if (rc != ARES_SUCCESS) - return rc; - - if (sgsn->ares_servers) - rc = ares_set_servers(sgsn->ares_channel, sgsn->ares_servers); - - return rc; -} - -osmo_static_assert(ARES_SUCCESS == 0, ares_success_zero); diff --git a/src/gprs/sgsn_auth.c b/src/gprs/sgsn_auth.c deleted file mode 100644 index a64339c3e..000000000 --- a/src/gprs/sgsn_auth.c +++ /dev/null @@ -1,312 +0,0 @@ -/* MS authorization and subscriber data handling */ - -/* (C) 2009-2010 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include - -const struct value_string auth_state_names[] = { - { SGSN_AUTH_ACCEPTED, "accepted"}, - { SGSN_AUTH_REJECTED, "rejected"}, - { SGSN_AUTH_UNKNOWN, "unknown"}, - { SGSN_AUTH_AUTHENTICATE, "authenticate" }, - { SGSN_AUTH_UMTS_RESYNC, "UMTS-resync" }, - { 0, NULL } -}; - -const struct value_string *sgsn_auth_state_names = auth_state_names; - -void sgsn_auth_init(void) -{ - INIT_LLIST_HEAD(&sgsn->cfg.imsi_acl); -} - -/* temporary IMSI ACL hack */ -struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, struct sgsn_config *cfg) -{ - struct imsi_acl_entry *acl; - llist_for_each_entry(acl, &cfg->imsi_acl, list) { - if (!strcmp(imsi, acl->imsi)) - return acl; - } - return NULL; -} - -int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg) -{ - struct imsi_acl_entry *acl; - - if (sgsn_acl_lookup(imsi, cfg)) - return -EEXIST; - - acl = talloc_zero(NULL, struct imsi_acl_entry); - if (!acl) - return -ENOMEM; - osmo_strlcpy(acl->imsi, imsi, sizeof(acl->imsi)); - - llist_add(&acl->list, &cfg->imsi_acl); - - return 0; -} - -int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg) -{ - struct imsi_acl_entry *acl; - - acl = sgsn_acl_lookup(imsi, cfg); - if (!acl) - return -ENODEV; - - llist_del(&acl->list); - talloc_free(acl); - - return 0; -} - -enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mmctx) -{ - char mccmnc[16]; - int check_net = 0; - int check_acl = 0; - - OSMO_ASSERT(mmctx); - - switch (sgsn->cfg.auth_policy) { - case SGSN_AUTH_POLICY_OPEN: - return SGSN_AUTH_ACCEPTED; - - case SGSN_AUTH_POLICY_CLOSED: - check_net = 1; - check_acl = 1; - break; - - case SGSN_AUTH_POLICY_ACL_ONLY: - check_acl = 1; - break; - - case SGSN_AUTH_POLICY_REMOTE: - if (!mmctx->subscr) - return mmctx->auth_state; - - if (mmctx->subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING_MASK) - return mmctx->auth_state; - - if (sgsn->cfg.require_authentication && - (!mmctx->is_authenticated || - mmctx->subscr->sgsn_data->auth_triplets_updated)) - return SGSN_AUTH_AUTHENTICATE; - - if (mmctx->subscr->authorized) - return SGSN_AUTH_ACCEPTED; - - return SGSN_AUTH_REJECTED; - } - - if (!strlen(mmctx->imsi)) { - LOGMMCTXP(LOGL_NOTICE, mmctx, - "Missing IMSI, authorization state not known\n"); - return SGSN_AUTH_UNKNOWN; - } - - if (check_net) { - /* We simply assume that the IMSI exists, as long as it is part - * of 'our' network */ - snprintf(mccmnc, sizeof(mccmnc), "%03d%02d", - mmctx->ra.mcc, mmctx->ra.mnc); - if (strncmp(mccmnc, mmctx->imsi, 5) == 0) - return SGSN_AUTH_ACCEPTED; - } - - if (check_acl && sgsn_acl_lookup(mmctx->imsi, &sgsn->cfg)) - return SGSN_AUTH_ACCEPTED; - - return SGSN_AUTH_REJECTED; -} - -/* - * This function is directly called by e.g. the GMM layer. It returns either - * after calling sgsn_auth_update directly or after triggering an asynchronous - * procedure which will call sgsn_auth_update later on. - */ -int sgsn_auth_request(struct sgsn_mm_ctx *mmctx) -{ - struct gprs_subscr *subscr; - struct gsm_auth_tuple *at; - int need_update_location; - int rc; - - LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting authorization\n"); - - if (sgsn->cfg.auth_policy != SGSN_AUTH_POLICY_REMOTE) { - sgsn_auth_update(mmctx); - return 0; - } - - need_update_location = sgsn->cfg.require_update_location && - (mmctx->subscr == NULL || - mmctx->pending_req == GSM48_MT_GMM_ATTACH_REQ); - - /* This has the side effect of registering the subscr with the mmctx */ - subscr = gprs_subscr_get_or_create_by_mmctx(mmctx); - gprs_subscr_put(subscr); - - OSMO_ASSERT(mmctx->subscr != NULL); - - if (sgsn->cfg.require_authentication && !mmctx->is_authenticated) { - /* Find next tuple */ - at = sgsn_auth_get_tuple(mmctx, mmctx->auth_triplet.key_seq); - - if (!at) { - /* No valid tuple found, request fresh ones */ - mmctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; - LOGMMCTXP(LOGL_INFO, mmctx, - "Requesting authentication tuples\n"); - rc = gprs_subscr_request_auth_info(mmctx, NULL, NULL); - if (rc >= 0) - return 0; - - return rc; - } - - mmctx->auth_triplet = *at; - } else if (need_update_location) { - LOGMMCTXP(LOGL_INFO, mmctx, - "Missing information, requesting subscriber data\n"); - rc = gprs_subscr_request_update_location(mmctx); - if (rc >= 0) - return 0; - - return rc; - } - - sgsn_auth_update(mmctx); - return 0; -} - -void sgsn_auth_update(struct sgsn_mm_ctx *mmctx) -{ - enum sgsn_auth_state auth_state; - struct gprs_subscr *subscr = mmctx->subscr; - struct gsm_auth_tuple *at; - int gmm_cause; - - auth_state = sgsn_auth_state(mmctx); - - LOGMMCTXP(LOGL_DEBUG, mmctx, "Updating authorization (%s -> %s)\n", - get_value_string(sgsn_auth_state_names, mmctx->auth_state), - get_value_string(sgsn_auth_state_names, auth_state)); - - if (auth_state == SGSN_AUTH_UNKNOWN && subscr && - !(subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING_MASK)) { - /* Reject requests if gprs_subscr_request_update_location fails */ - LOGMMCTXP(LOGL_ERROR, mmctx, - "Missing information, authorization not possible\n"); - auth_state = SGSN_AUTH_REJECTED; - } - - if (auth_state == SGSN_AUTH_AUTHENTICATE && - mmctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) { - /* The current tuple is not valid, but we are possibly called - * because new auth tuples have been received */ - at = sgsn_auth_get_tuple(mmctx, mmctx->auth_triplet.key_seq); - if (!at) { - LOGMMCTXP(LOGL_ERROR, mmctx, - "Missing auth tuples, authorization not possible\n"); - auth_state = SGSN_AUTH_REJECTED; - } else { - mmctx->auth_triplet = *at; - } - } - - if (mmctx->auth_state == auth_state) - return; - - LOGMMCTXP(LOGL_INFO, mmctx, "Got authorization update: state %s -> %s\n", - get_value_string(sgsn_auth_state_names, mmctx->auth_state), - get_value_string(sgsn_auth_state_names, auth_state)); - - mmctx->auth_state = auth_state; - - switch (auth_state) { - case SGSN_AUTH_AUTHENTICATE: - if (subscr) - subscr->sgsn_data->auth_triplets_updated = 0; - - gsm0408_gprs_authenticate(mmctx); - break; - case SGSN_AUTH_ACCEPTED: - gsm0408_gprs_access_granted(mmctx); - break; - case SGSN_AUTH_REJECTED: - gmm_cause = - subscr ? subscr->sgsn_data->error_cause : - SGSN_ERROR_CAUSE_NONE; - - if (subscr && (subscr->flags & GPRS_SUBSCRIBER_CANCELLED) != 0) - gsm0408_gprs_access_cancelled(mmctx, gmm_cause); - else - gsm0408_gprs_access_denied(mmctx, gmm_cause); - break; - default: - break; - } -} - -struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx, - unsigned key_seq) -{ - unsigned count; - unsigned idx; - struct gsm_auth_tuple *at = NULL; - - struct sgsn_subscriber_data *sdata; - - if (!mmctx->subscr) - return NULL; - - if (key_seq == GSM_KEY_SEQ_INVAL) - /* Start with 0 after increment module array size */ - idx = ARRAY_SIZE(sdata->auth_triplets) - 1; - else - idx = key_seq; - - sdata = mmctx->subscr->sgsn_data; - - /* Find next tuple */ - for (count = ARRAY_SIZE(sdata->auth_triplets); count > 0; count--) { - idx = (idx + 1) % ARRAY_SIZE(sdata->auth_triplets); - - if (sdata->auth_triplets[idx].key_seq == GSM_KEY_SEQ_INVAL) - continue; - - if (sdata->auth_triplets[idx].use_count == 0) { - at = &sdata->auth_triplets[idx]; - at->use_count = 1; - return at; - } - } - - return NULL; -} diff --git a/src/gprs/sgsn_cdr.c b/src/gprs/sgsn_cdr.c deleted file mode 100644 index 16ea9d47a..000000000 --- a/src/gprs/sgsn_cdr.c +++ /dev/null @@ -1,259 +0,0 @@ -/* GPRS SGSN CDR dumper */ - -/* (C) 2015 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 . - * - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#include - -#include -#include - -/* TODO...avoid going through a global */ -extern struct sgsn_instance *sgsn; - -/** - * The CDR module will generate an entry like: - * - * IMSI, # Subscriber IMSI - * IMEI, # Subscriber IMEI - * MSISDN, # Subscriber MISDN - * Charging_Timestamp, # Event start Time - * Charging_UTC, # Time zone of event start time - * Duration, # Session DURATION - * Cell_Id, # CELL_ID - * Location_Area, # LAC - * GGSN_ADDR, # GGSN_ADDR - * SGSN_ADDR, # SGSN_ADDR - * APNI, # APNI - * PDP_ADDR, # PDP_ADDR - * VOL_IN, # VOL_IN in Bytes - * VOL_OUT, # VOL_OUT in Bytes - * CAUSE_FOR_TERM, # CAUSE_FOR_TERM - */ - - -static void maybe_print_header(FILE *cdr_file) -{ - if (ftell(cdr_file) != 0) - return; - - fprintf(cdr_file, "timestamp,imsi,imei,msisdn,cell_id,lac,hlr,event,pdp_duration,ggsn_addr,sgsn_addr,apni,eua_addr,vol_in,vol_out,charging_id\n"); -} - -static void cdr_log_mm(struct sgsn_instance *inst, const char *ev, - struct sgsn_mm_ctx *mmctx) -{ - FILE *cdr_file; - struct tm tm; - struct timeval tv; - - if (!inst->cfg.cdr.filename) - return; - - cdr_file = fopen(inst->cfg.cdr.filename, "a"); - if (!cdr_file) { - LOGP(DGPRS, LOGL_ERROR, "Failed to open %s\n", - inst->cfg.cdr.filename); - return; - } - - maybe_print_header(cdr_file); - gettimeofday(&tv, NULL); - gmtime_r(&tv.tv_sec, &tm); - fprintf(cdr_file, "%04d%02d%02d%02d%02d%02d%03d,%s,%s,%s,%d,%d,%s,%s\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (int)(tv.tv_usec / 1000), - mmctx->imsi, - mmctx->imei, - mmctx->msisdn, - mmctx->gb.cell_id, - mmctx->ra.lac, - mmctx->hlr, - ev); - - fclose(cdr_file); -} - -static void extract_eua(struct ul66_t *eua, char *eua_addr) -{ - if (eua->l < 2) - return; - - /* there is no addr for ETSI/PPP */ - if ((eua->v[0] & 0x0F) != 1) { - strcpy(eua_addr, "ETSI"); - return; - } - - if (eua->v[1] == 0x21 && eua->l == 6) - inet_ntop(AF_INET, &eua->v[2], eua_addr, INET_ADDRSTRLEN); - else if (eua->v[1] == 0x57 && eua->l == 18) - inet_ntop(AF_INET6, &eua->v[2], eua_addr, INET6_ADDRSTRLEN); - else { - /* e.g. both IPv4 and IPv6 */ - strcpy(eua_addr, "Unknown address"); - } -} - -static void cdr_log_pdp(struct sgsn_instance *inst, const char *ev, - struct sgsn_pdp_ctx *pdp) -{ - FILE *cdr_file; - char apni[(pdp->lib ? pdp->lib->apn_use.l : 0) + 1]; - char ggsn_addr[INET_ADDRSTRLEN + 1]; - char sgsn_addr[INET_ADDRSTRLEN + 1]; - char eua_addr[INET6_ADDRSTRLEN + 1]; - struct tm tm; - struct timeval tv; - time_t duration; - struct timespec tp; - - if (!inst->cfg.cdr.filename) - return; - - memset(apni, 0, sizeof(apni)); - memset(ggsn_addr, 0, sizeof(ggsn_addr)); - memset(eua_addr, 0, sizeof(eua_addr)); - - - if (pdp->lib) { - osmo_apn_to_str(apni, pdp->lib->apn_use.v, pdp->lib->apn_use.l); - inet_ntop(AF_INET, &pdp->lib->hisaddr0.s_addr, ggsn_addr, sizeof(ggsn_addr)); - extract_eua(&pdp->lib->eua, eua_addr); - } - - if (pdp->ggsn) - inet_ntop(AF_INET, &pdp->ggsn->gsn->gsnc.s_addr, sgsn_addr, sizeof(sgsn_addr)); - - cdr_file = fopen(inst->cfg.cdr.filename, "a"); - if (!cdr_file) { - LOGP(DGPRS, LOGL_ERROR, "Failed to open %s\n", - inst->cfg.cdr.filename); - return; - } - - maybe_print_header(cdr_file); - - clock_gettime(CLOCK_MONOTONIC, &tp); - gettimeofday(&tv, NULL); - - /* convert the timestamp to UTC */ - gmtime_r(&tv.tv_sec, &tm); - - /* Check the duration of the PDP context */ - duration = tp.tv_sec - pdp->cdr_start.tv_sec; - - fprintf(cdr_file, - "%04d%02d%02d%02d%02d%02d%03d,%s,%s,%s,%d,%d,%s,%s,%ld,%s,%s,%s,%s,%" PRIu64 ",%" PRIu64 ",%u\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (int)(tv.tv_usec / 1000), - pdp->mm ? pdp->mm->imsi : "N/A", - pdp->mm ? pdp->mm->imei : "N/A", - pdp->mm ? pdp->mm->msisdn : "N/A", - pdp->mm ? pdp->mm->gb.cell_id : -1, - pdp->mm ? pdp->mm->ra.lac : -1, - pdp->mm ? pdp->mm->hlr : "N/A", - ev, - (unsigned long ) duration, - ggsn_addr, - sgsn_addr, - apni, - eua_addr, - pdp->cdr_bytes_in, - pdp->cdr_bytes_out, - pdp->cdr_charging_id); - fclose(cdr_file); -} - -static void cdr_pdp_timeout(void *_data) -{ - struct sgsn_pdp_ctx *pdp = _data; - cdr_log_pdp(sgsn, "pdp-periodic", pdp); - osmo_timer_schedule(&pdp->cdr_timer, sgsn->cfg.cdr.interval, 0); -} - -static int handle_sgsn_sig(unsigned int subsys, unsigned int signal, - void *handler_data, void *_signal_data) -{ - struct sgsn_signal_data *signal_data = _signal_data; - struct sgsn_instance *inst = handler_data; - - if (subsys != SS_SGSN) - return 0; - - switch (signal) { - case S_SGSN_ATTACH: - cdr_log_mm(inst, "attach", signal_data->mm); - break; - case S_SGSN_UPDATE: - cdr_log_mm(inst, "update", signal_data->mm); - break; - case S_SGSN_DETACH: - cdr_log_mm(inst, "detach", signal_data->mm); - break; - case S_SGSN_MM_FREE: - cdr_log_mm(inst, "free", signal_data->mm); - break; - case S_SGSN_PDP_ACT: - clock_gettime(CLOCK_MONOTONIC, &signal_data->pdp->cdr_start); - signal_data->pdp->cdr_charging_id = signal_data->pdp->lib->cid; - cdr_log_pdp(inst, "pdp-act", signal_data->pdp); - osmo_timer_setup(&signal_data->pdp->cdr_timer, cdr_pdp_timeout, - signal_data->pdp); - osmo_timer_schedule(&signal_data->pdp->cdr_timer, inst->cfg.cdr.interval, 0); - break; - case S_SGSN_PDP_DEACT: - cdr_log_pdp(inst, "pdp-deact", signal_data->pdp); - osmo_timer_del(&signal_data->pdp->cdr_timer); - break; - case S_SGSN_PDP_TERMINATE: - cdr_log_pdp(inst, "pdp-terminate", signal_data->pdp); - osmo_timer_del(&signal_data->pdp->cdr_timer); - break; - case S_SGSN_PDP_FREE: - cdr_log_pdp(inst, "pdp-free", signal_data->pdp); - osmo_timer_del(&signal_data->pdp->cdr_timer); - break; - } - - return 0; -} - -int sgsn_cdr_init(struct sgsn_instance *sgsn) -{ - /* register for CDR related events */ - sgsn->cfg.cdr.interval = 10 * 60; - osmo_signal_register_handler(SS_SGSN, handle_sgsn_sig, sgsn); - - return 0; -} diff --git a/src/gprs/sgsn_ctrl.c b/src/gprs/sgsn_ctrl.c deleted file mode 100644 index 31ac74f1f..000000000 --- a/src/gprs/sgsn_ctrl.c +++ /dev/null @@ -1,69 +0,0 @@ -/* Control Interface Implementation for the SGSN */ -/* - * (C) 2014 by Holger Hans Peter Freyther - * (C) 2014 by sysmocom s.f.m.c. GmbH - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -extern vector ctrl_node_vec; - -static int get_subscriber_list(struct ctrl_cmd *cmd, void *d) -{ - struct sgsn_mm_ctx *mm; - - cmd->reply = talloc_strdup(cmd, ""); - llist_for_each_entry(mm, &sgsn_mm_ctxts, list) { - char *addr = NULL; - struct sgsn_pdp_ctx *pdp; - - if (strlen(mm->imsi) == 0) - continue; - - llist_for_each_entry(pdp, &mm->pdp_list, list) - addr = gprs_pdpaddr2str(pdp->lib->eua.v, - pdp->lib->eua.l); - - cmd->reply = talloc_asprintf_append( - cmd->reply, - "%s,%s\n", mm->imsi, addr ? addr : ""); - } - - return CTRL_CMD_REPLY; -} -CTRL_CMD_DEFINE_RO(subscriber_list, "subscriber-list-active-v1"); - -int sgsn_ctrl_cmds_install(void) -{ - int rc = 0; - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_subscriber_list); - return rc; -} - -struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *net, - const char *bind_addr, uint16_t port) -{ - return ctrl_interface_setup_dynip(net, bind_addr, port, NULL); -} diff --git a/src/gprs/sgsn_libgtp.c b/src/gprs/sgsn_libgtp.c deleted file mode 100644 index 90b4d1636..000000000 --- a/src/gprs/sgsn_libgtp.c +++ /dev/null @@ -1,885 +0,0 @@ -/* GPRS SGSN integration with libgtp of OpenGGSN */ -/* libgtp implements the GPRS Tunelling Protocol GTP per TS 09.60 / 29.060 */ - -/* (C) 2010 by Harald Welte - * (C) 2010 by On-Waves - * (C) 2015 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bscconfig.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef BUILD_IU -#include -#include -#endif - -#include -#include - -/* TS 23.003: The MSISDN shall take the dummy MSISDN value composed of - * 15 digits set to 0 (encoded as an E.164 international number) when - * the MSISDN is not available in messages in which the presence of the - * MSISDN parameter */ -static const uint8_t dummy_msisdn[] = - { 0x91, /* No extension, international, E.164 */ - 0, 0, 0, 0, 0, 0, 0, /* 14 digits of zeroes */ - 0xF0 /* 15th digit of zero + padding */ }; - -const struct value_string gtp_cause_strs[] = { - { GTPCAUSE_REQ_IMSI, "Request IMSI" }, - { GTPCAUSE_REQ_IMEI, "Request IMEI" }, - { GTPCAUSE_REQ_IMSI_IMEI, "Request IMSI and IMEI" }, - { GTPCAUSE_NO_ID_NEEDED, "No identity needed" }, - { GTPCAUSE_MS_REFUSES_X, "MS refuses" }, - { GTPCAUSE_MS_NOT_RESP_X, "MS is not GPRS responding" }, - { GTPCAUSE_ACC_REQ, "Request accepted" }, - { GTPCAUSE_NON_EXIST, "Non-existent" }, - { GTPCAUSE_INVALID_MESSAGE, "Invalid message format" }, - { GTPCAUSE_IMSI_NOT_KNOWN, "IMSI not known" }, - { GTPCAUSE_MS_DETACHED, "MS is GPRS detached" }, - { GTPCAUSE_MS_NOT_RESP, "MS is not GPRS responding" }, - { GTPCAUSE_MS_REFUSES, "MS refuses" }, - { GTPCAUSE_NO_RESOURCES, "No resources available" }, - { GTPCAUSE_NOT_SUPPORTED, "Service not supported" }, - { GTPCAUSE_MAN_IE_INCORRECT, "Mandatory IE incorrect" }, - { GTPCAUSE_MAN_IE_MISSING, "Mandatory IE missing" }, - { GTPCAUSE_OPT_IE_INCORRECT, "Optional IE incorrect" }, - { GTPCAUSE_SYS_FAIL, "System failure" }, - { GTPCAUSE_ROAMING_REST, "Roaming restrictions" }, - { GTPCAUSE_PTIMSI_MISMATCH, "P-TMSI Signature mismatch" }, - { GTPCAUSE_CONN_SUSP, "GPRS connection suspended" }, - { GTPCAUSE_AUTH_FAIL, "Authentication failure" }, - { GTPCAUSE_USER_AUTH_FAIL, "User authentication failed" }, - { GTPCAUSE_CONTEXT_NOT_FOUND, "Context not found" }, - { GTPCAUSE_ADDR_OCCUPIED, "All dynamic PDP addresses occupied" }, - { GTPCAUSE_NO_MEMORY, "No memory is available" }, - { GTPCAUSE_RELOC_FAIL, "Relocation failure" }, - { GTPCAUSE_UNKNOWN_MAN_EXTHEADER, "Unknown mandatory ext. header" }, - { GTPCAUSE_SEM_ERR_TFT, "Semantic error in TFT operation" }, - { GTPCAUSE_SYN_ERR_TFT, "Syntactic error in TFT operation" }, - { GTPCAUSE_SEM_ERR_FILTER, "Semantic errors in packet filter" }, - { GTPCAUSE_SYN_ERR_FILTER, "Syntactic errors in packet filter" }, - { GTPCAUSE_MISSING_APN, "Missing or unknown APN" }, - { GTPCAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" }, - { 0, NULL } -}; - -/* Generate the GTP IMSI IE according to 09.60 Section 7.9.2 */ -static uint64_t imsi_str2gtp(char *str) -{ - uint64_t imsi64 = 0; - unsigned int n; - unsigned int imsi_len = strlen(str); - - if (imsi_len > 16) { - LOGP(DGPRS, LOGL_NOTICE, "IMSI length > 16 not supported!\n"); - return 0; - } - - for (n = 0; n < 16; n++) { - uint64_t val; - if (n < imsi_len) - val = (str[n]-'0') & 0xf; - else - val = 0xf; - imsi64 |= (val << (n*4)); - } - return imsi64; -} - -/* generate a PDP context based on the IE's from the 04.08 message, - * and send the GTP create pdp context request to the GGSN */ -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) -{ - struct gprs_ra_id raid; - struct sgsn_pdp_ctx *pctx; - struct pdp_t *pdp; - uint64_t imsi_ui64; - size_t qos_len; - const uint8_t *qos; - int rc; - - LOGP(DGPRS, LOGL_ERROR, "Create PDP Context\n"); - pctx = sgsn_pdp_ctx_alloc(mmctx, nsapi); - if (!pctx) { - LOGP(DGPRS, LOGL_ERROR, "Couldn't allocate PDP Ctx\n"); - return NULL; - } - - imsi_ui64 = imsi_str2gtp(mmctx->imsi); - - rc = pdp_newpdp(&pdp, imsi_ui64, nsapi, NULL); - if (rc) { - LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n"); - return NULL; - } - pdp->priv = pctx; - pctx->lib = pdp; - pctx->ggsn = ggsn; - - //pdp->peer = /* sockaddr_in of GGSN (receive) */ - //pdp->ipif = /* not used by library */ - pdp->version = ggsn->gtp_version; - pdp->hisaddr0 = ggsn->remote_addr; - pdp->hisaddr1 = ggsn->remote_addr; - //pdp->cch_pdp = 512; /* Charging Flat Rate */ - - /* MS provided APN, subscription was verified by the caller */ - pdp->selmode = 0xFC | 0x00; - - /* IMSI, TEID/TEIC, FLLU/FLLC, TID, NSAPI set in pdp_newpdp */ - - /* Put the MSISDN in case we have it */ - if (mmctx->subscr && mmctx->subscr->sgsn_data->msisdn_len) { - pdp->msisdn.l = mmctx->subscr->sgsn_data->msisdn_len; - if (pdp->msisdn.l > sizeof(pdp->msisdn.v)) - pdp->msisdn.l = sizeof(pdp->msisdn.v); - memcpy(pdp->msisdn.v, mmctx->subscr->sgsn_data->msisdn, - pdp->msisdn.l); - } else { - /* use the dummy 15-digits-zero MSISDN value */ - pdp->msisdn.l = sizeof(dummy_msisdn); - memcpy(pdp->msisdn.v, dummy_msisdn, pdp->msisdn.l); - } - - /* End User Address from GMM requested PDP address */ - pdp->eua.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_PDP_ADDR); - if (pdp->eua.l > sizeof(pdp->eua.v)) - pdp->eua.l = sizeof(pdp->eua.v); - memcpy(pdp->eua.v, TLVP_VAL(tp, OSMO_IE_GSM_REQ_PDP_ADDR), - pdp->eua.l); - /* 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->eua.v[0] |= 0xf0; - - /* APN name from GMM */ - pdp->apn_use.l = TLVP_LEN(tp, GSM48_IE_GSM_APN); - if (pdp->apn_use.l > sizeof(pdp->apn_use.v)) - pdp->apn_use.l = sizeof(pdp->apn_use.v); - memcpy(pdp->apn_use.v, TLVP_VAL(tp, GSM48_IE_GSM_APN), - pdp->apn_use.l); - - /* Protocol Configuration Options from GMM */ - pdp->pco_req.l = TLVP_LEN(tp, GSM48_IE_GSM_PROTO_CONF_OPT); - if (pdp->pco_req.l > sizeof(pdp->pco_req.v)) - pdp->pco_req.l = sizeof(pdp->pco_req.v); - memcpy(pdp->pco_req.v, TLVP_VAL(tp, GSM48_IE_GSM_PROTO_CONF_OPT), - pdp->pco_req.l); - - /* QoS options from GMM or remote */ - if (TLVP_LEN(tp, OSMO_IE_GSM_SUB_QOS) > 0) { - qos_len = TLVP_LEN(tp, OSMO_IE_GSM_SUB_QOS); - qos = TLVP_VAL(tp, OSMO_IE_GSM_SUB_QOS); - } else { - qos_len = TLVP_LEN(tp, OSMO_IE_GSM_REQ_QOS); - qos = TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS); - } - - if (qos_len <= 3) { - pdp->qos_req.l = qos_len + 1; - if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) - pdp->qos_req.l = sizeof(pdp->qos_req.v); - pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */ - memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1); - } else { - pdp->qos_req.l = qos_len; - if (pdp->qos_req.l > sizeof(pdp->qos_req.v)) - pdp->qos_req.l = sizeof(pdp->qos_req.v); - memcpy(pdp->qos_req.v, qos, pdp->qos_req.l); - } - - /* charging characteristics if present */ - if (TLVP_LEN(tp, OSMO_IE_GSM_CHARG_CHAR) >= sizeof(pdp->cch_pdp)) - pdp->cch_pdp = tlvp_val16be(tp, OSMO_IE_GSM_CHARG_CHAR); - - /* SGSN address for control plane */ - pdp->gsnlc.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); - memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr, - sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); - - /* SGSN address for user plane - * Default to the control plane addr for now. If we are connected to a - * hnbgw via IuPS we'll need to send a PDP context update with the - * correct IP address after the RAB Assignment is complete */ - pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); - memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr, - sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); - - /* Encode RAT Type according to TS 29.060 7.7.50 */ - pdp->rattype.l = 1; - if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) - pdp->rattype.v[0] = 1; - else - pdp->rattype.v[0] = 2; - pdp->rattype_given = 1; - - /* Include RAI and ULI all the time */ - pdp->rai_given = 1; - pdp->rai.l = 6; - - /* Routing Area Identifier with LAC and RAC fixed values, as - * requested in 29.006 7.3.1 */ - raid = mmctx->ra; - raid.lac = 0xFFFE; - raid.rac = 0xFF; - gsm48_construct_ra(pdp->rai.v, &raid); - - /* Encode User Location Information accordint to TS 29.060 7.7.51 */ - pdp->userloc_given = 1; - pdp->userloc.l = 8; - switch (mmctx->ran_type) { - case MM_CTX_T_GERAN_Gb: - case MM_CTX_T_GERAN_Iu: - pdp->rattype.v[0] = 2; - /* User Location Information */ - pdp->userloc_given = 1; - pdp->userloc.l = 8; - pdp->userloc.v[0] = 0; /* CGI for GERAN */ - bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->gb.cell_id); - break; - case MM_CTX_T_UTRAN_Iu: - pdp->userloc.v[0] = 1; /* SAI for UTRAN */ - /* SAI is like CGI but with SAC instead of CID, so we can abuse this function */ - bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->iu.sac); - break; - } - - /* include the IMEI(SV) */ - pdp->imeisv_given = 1; - gsm48_encode_bcd_number(&pdp->imeisv.v[0], 8, 0, mmctx->imei); - pdp->imeisv.l = pdp->imeisv.v[0]; - memmove(&pdp->imeisv.v[0], &pdp->imeisv.v[1], 8); - - /* change pdp state to 'requested' */ - pctx->state = PDP_STATE_CR_REQ; - - rc = gtp_create_context_req(ggsn->gsn, pdp, pctx); - /* FIXME */ - - return pctx; -} - -/* SGSN wants to delete a PDP context */ -int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx) -{ - LOGPDPCTXP(LOGL_ERROR, pctx, "Delete PDP Context\n"); - - /* FIXME: decide if we need teardown or not ! */ - return gtp_delete_context_req(pctx->ggsn->gsn, pctx->lib, pctx, 1); -} - -struct cause_map { - uint8_t cause_in; - uint8_t cause_out; -}; - -static uint8_t cause_map(const struct cause_map *map, uint8_t in, uint8_t deflt) -{ - const struct cause_map *m; - - for (m = map; m->cause_in && m->cause_out; m++) { - if (m->cause_in == in) - return m->cause_out; - } - return deflt; -} - -/* how do we map from gtp cause to SM cause */ -static const struct cause_map gtp2sm_cause_map[] = { - { GTPCAUSE_NO_RESOURCES, GSM_CAUSE_INSUFF_RSRC }, - { GTPCAUSE_NOT_SUPPORTED, GSM_CAUSE_SERV_OPT_NOTSUPP }, - { GTPCAUSE_MAN_IE_INCORRECT, GSM_CAUSE_INV_MAND_INFO }, - { GTPCAUSE_MAN_IE_MISSING, GSM_CAUSE_INV_MAND_INFO }, - { GTPCAUSE_OPT_IE_INCORRECT, GSM_CAUSE_PROTO_ERR_UNSPEC }, - { GTPCAUSE_SYS_FAIL, GSM_CAUSE_NET_FAIL }, - { GTPCAUSE_ROAMING_REST, GSM_CAUSE_REQ_SERV_OPT_NOTSUB }, - { GTPCAUSE_PTIMSI_MISMATCH, GSM_CAUSE_PROTO_ERR_UNSPEC }, - { GTPCAUSE_CONN_SUSP, GSM_CAUSE_PROTO_ERR_UNSPEC }, - { GTPCAUSE_AUTH_FAIL, GSM_CAUSE_AUTH_FAILED }, - { GTPCAUSE_USER_AUTH_FAIL, GSM_CAUSE_ACT_REJ_GGSN }, - { GTPCAUSE_CONTEXT_NOT_FOUND, GSM_CAUSE_PROTO_ERR_UNSPEC }, - { GTPCAUSE_ADDR_OCCUPIED, GSM_CAUSE_INSUFF_RSRC }, - { GTPCAUSE_NO_MEMORY, GSM_CAUSE_INSUFF_RSRC }, - { GTPCAUSE_RELOC_FAIL, GSM_CAUSE_PROTO_ERR_UNSPEC }, - { GTPCAUSE_UNKNOWN_MAN_EXTHEADER, GSM_CAUSE_PROTO_ERR_UNSPEC }, - { GTPCAUSE_MISSING_APN, GSM_CAUSE_MISSING_APN }, - { GTPCAUSE_UNKNOWN_PDP, GSM_CAUSE_UNKNOWN_PDP }, - { 0, 0 } -}; - -static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx) -{ - struct sgsn_signal_data sig_data; - int rc; - struct gprs_llc_lle *lle; - - /* Inform others about it */ - memset(&sig_data, 0, sizeof(sig_data)); - sig_data.pdp = pctx; - osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data); - - /* Send PDP CTX ACT to MS */ - rc = gsm48_tx_gsm_act_pdp_acc(pctx); - if (rc < 0) - return rc; - - if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) { - /* Send SNDCP XID to MS */ - lle = &pctx->mm->gb.llme->lle[pctx->sapi]; - rc = sndcp_sn_xid_req(lle,pctx->nsapi); - if (rc < 0) - return rc; - } - - return 0; -} - -/* The GGSN has confirmed the creation of a PDP Context */ -static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) -{ - struct sgsn_pdp_ctx *pctx = cbp; - uint8_t reject_cause; - - LOGPDPCTXP(LOGL_INFO, pctx, "Received CREATE PDP CTX CONF, cause=%d(%s)\n", - cause, get_value_string(gtp_cause_strs, cause)); - - if (!pctx->mm) { - LOGP(DGPRS, LOGL_INFO, - "No MM context, aborting CREATE PDP CTX CONF\n"); - return -EIO; - } - - /* Check for cause value if it was really successful */ - if (cause < 0) { - LOGP(DGPRS, LOGL_NOTICE, "Create PDP ctx req timed out\n"); - if (pdp && pdp->version == 1) { - pdp->version = 0; - gtp_create_context_req(sgsn->gsn, pdp, cbp); - return 0; - } else { - reject_cause = GSM_CAUSE_NET_FAIL; - goto reject; - } - } - - /* Check for cause value if it was really successful */ - if (cause != GTPCAUSE_ACC_REQ) { - reject_cause = cause_map(gtp2sm_cause_map, cause, - GSM_CAUSE_ACT_REJ_GGSN); - goto reject; - } - - if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) { - /* Activate the SNDCP layer */ - sndcp_sm_activate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi); - return send_act_pdp_cont_acc(pctx); - } else if (pctx->mm->ran_type == MM_CTX_T_UTRAN_Iu) { -#ifdef BUILD_IU - /* Activate a radio bearer */ - iu_rab_act_ps(pdp->nsapi, pctx); - return 0; -#else - return -ENOTSUP; -#endif - } - - LOGP(DGPRS, LOGL_ERROR, "Unknown ran_type %d\n", - pctx->mm->ran_type); - reject_cause = GSM_CAUSE_PROTO_ERR_UNSPEC; - -reject: - /* - * In case of a timeout pdp will be NULL but we have a valid pointer - * in pctx->lib. For other rejects pctx->lib and pdp might be the - * same. - */ - pctx->state = PDP_STATE_NONE; - if (pctx->lib && pctx->lib != pdp) - pdp_freepdp(pctx->lib); - pctx->lib = NULL; - - if (pdp) - pdp_freepdp(pdp); - /* Send PDP CTX ACT REJ to MS */ - gsm48_tx_gsm_act_pdp_rej(pctx->mm, pctx->ti, reject_cause, - 0, NULL); - sgsn_pdp_ctx_free(pctx); - - return EOF; -} - -void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen) -{ - pdp->lib->gsnlu.l = alen; - memcpy(pdp->lib->gsnlu.v, addr, alen); - gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0); -} - -#ifdef BUILD_IU -/* Callback for RAB assignment response */ -int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies) -{ - uint8_t rab_id; - bool require_pdp_update = false; - struct sgsn_pdp_ctx *pdp = NULL; - RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem; - - rab_id = item->rAB_ID.buf[0]; - - pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id); - if (!pdp) { - LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id); - return -1; - } - - if (item->transportLayerAddress) { - LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf, - item->transportLayerAddress->size)); - switch (item->transportLayerAddress->size) { - case 7: - /* It must be IPv4 inside a X213 NSAP */ - memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4); - break; - case 4: - /* It must be a raw IPv4 address */ - memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4); - break; - case 16: - /* TODO: It must be a raw IPv6 address */ - case 19: - /* TODO: It must be IPv6 inside a X213 NSAP */ - default: - LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown " - "transport layer address size %u\n", - item->transportLayerAddress->size); - return -1; - } - require_pdp_update = true; - } - - /* The TEI on the RNC side might have changed, too */ - if (item->iuTransportAssociation && - item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI && - item->iuTransportAssociation->choice.gTP_TEI.buf && - item->iuTransportAssociation->choice.gTP_TEI.size >= 4) { - uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf); - LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n", - pdp->lib->teid_own, tei); - pdp->lib->teid_own = tei; - require_pdp_update = true; - } - - if (require_pdp_update) - gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0); - - if (pdp->state != PDP_STATE_CR_CONF) { - send_act_pdp_cont_acc(pdp); - pdp->state = PDP_STATE_CR_CONF; - } - return 0; - -} -#endif - -/* Confirmation of a PDP Context Delete */ -static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) -{ - struct sgsn_signal_data sig_data; - struct sgsn_pdp_ctx *pctx = cbp; - int rc = 0; - - LOGPDPCTXP(LOGL_INFO, pctx, "Received DELETE PDP CTX CONF, cause=%d(%s)\n", - cause, get_value_string(gtp_cause_strs, cause)); - - memset(&sig_data, 0, sizeof(sig_data)); - sig_data.pdp = pctx; - osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_DEACT, &sig_data); - - if (pctx->mm) { - if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) { - /* Deactivate the SNDCP layer */ - sndcp_sm_deactivate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi); - } else { -#ifdef BUILD_IU - /* Deactivate radio bearer */ - ranap_iu_rab_deact(pctx->mm->iu.ue_ctx, 1); -#else - return -ENOTSUP; -#endif - } - - /* Confirm deactivation of PDP context to MS */ - rc = gsm48_tx_gsm_deact_pdp_acc(pctx); - } else { - LOGPDPCTXP(LOGL_NOTICE, pctx, - "Not deactivating SNDCP layer since the MM context " - "is not available\n"); - } - - /* unlink the now non-existing library handle from the pdp - * context */ - pctx->lib = NULL; - - sgsn_pdp_ctx_free(pctx); - - return rc; -} - -/* Confirmation of an GTP ECHO request */ -static int echo_conf(struct pdp_t *pdp, void *cbp, int recovery) -{ - if (recovery < 0) { - LOGP(DGPRS, LOGL_NOTICE, "GTP Echo Request timed out\n"); - /* FIXME: if version == 1, retry with version 0 */ - } else { - DEBUGP(DGPRS, "GTP Rx Echo Response\n"); - } - return 0; -} - -/* Any message received by GGSN contains a recovery IE */ -static int cb_recovery(struct sockaddr_in *peer, uint8_t recovery) -{ - struct sgsn_ggsn_ctx *ggsn; - - ggsn = sgsn_ggsn_ctx_by_addr(&peer->sin_addr); - if (!ggsn) { - LOGP(DGPRS, LOGL_NOTICE, "Received Recovery IE for unknown GGSN\n"); - return -EINVAL; - } - - if (ggsn->remote_restart_ctr == -1) { - /* First received ECHO RESPONSE, note the restart ctr */ - ggsn->remote_restart_ctr = recovery; - } else if (ggsn->remote_restart_ctr != recovery) { - /* counter has changed (GGSN restart): release all PDP */ - LOGP(DGPRS, LOGL_NOTICE, "GGSN recovery (%u->%u), " - "releasing all PDP contexts\n", - ggsn->remote_restart_ctr, recovery); - ggsn->remote_restart_ctr = recovery; - drop_all_pdp_for_ggsn(ggsn); - } - return 0; -} - -/* libgtp callback for confirmations */ -static int cb_conf(int type, int cause, struct pdp_t *pdp, void *cbp) -{ - DEBUGP(DGPRS, "libgtp cb_conf(type=%d, cause=%d, pdp=%p, cbp=%p)\n", - type, cause, pdp, cbp); - - if (cause == EOF) - LOGP(DGPRS, LOGL_ERROR, "libgtp EOF (type=%u, pdp=%p, cbp=%p)\n", - type, pdp, cbp); - - switch (type) { - case GTP_ECHO_REQ: - /* libgtp hands us the RECOVERY number instead of a cause */ - return echo_conf(pdp, cbp, cause); - case GTP_CREATE_PDP_REQ: - return create_pdp_conf(pdp, cbp, cause); - case GTP_DELETE_PDP_REQ: - return delete_pdp_conf(pdp, cbp, cause); - default: - break; - } - return 0; -} - -/* Called whenever a PDP context is deleted for any reason */ -static int cb_delete_context(struct pdp_t *pdp) -{ - LOGP(DGPRS, LOGL_INFO, "PDP Context was deleted\n"); - return 0; -} - -/* Called when we receive a Version Not Supported message */ -static int cb_unsup_ind(struct sockaddr_in *peer) -{ - LOGP(DGPRS, LOGL_INFO, "GTP Version not supported Indication " - "from %s:%u\n", inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port)); - return 0; -} - -/* Called when we receive a Supported Ext Headers Notification */ -static int cb_extheader_ind(struct sockaddr_in *peer) -{ - LOGP(DGPRS, LOGL_INFO, "GTP Supported Ext Headers Noficiation " - "from %s:%u\n", inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port)); - return 0; -} - -/* Called whenever we recive a DATA packet */ -static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len) -{ - struct bssgp_paging_info pinfo; - struct sgsn_pdp_ctx *pdp; - struct sgsn_mm_ctx *mm; - struct msgb *msg; - uint8_t *ud; - - pdp = lib->priv; - if (!pdp) { - LOGP(DGPRS, LOGL_NOTICE, - "GTP DATA IND from GGSN for unknown PDP\n"); - return -EIO; - } - mm = pdp->mm; - if (!mm) { - LOGP(DGPRS, LOGL_ERROR, - "PDP context (address=%u) without MM context!\n", - pdp->address); - return -EIO; - } - - DEBUGP(DGPRS, "GTP DATA IND from GGSN for %s, length=%u\n", mm->imsi, - len); - - if (mm->ran_type == MM_CTX_T_UTRAN_Iu) { -#ifdef BUILD_IU - /* Ignore the packet for now and page the UE to get the RAB - * reestablished */ - ranap_iu_page_ps(mm->imsi, &mm->p_tmsi, mm->ra.lac, mm->ra.rac); - - return 0; -#else - return -ENOTSUP; -#endif - } - - msg = msgb_alloc_headroom(len+256, 128, "GTP->SNDCP"); - ud = msgb_put(msg, len); - memcpy(ud, packet, len); - - msgb_tlli(msg) = mm->gb.tlli; - msgb_bvci(msg) = mm->gb.bvci; - msgb_nsei(msg) = mm->gb.nsei; - - switch (mm->gmm_state) { - case GMM_REGISTERED_SUSPENDED: - /* initiate PS PAGING procedure */ - memset(&pinfo, 0, sizeof(pinfo)); - pinfo.mode = BSSGP_PAGING_PS; - pinfo.scope = BSSGP_PAGING_BVCI; - pinfo.bvci = mm->gb.bvci; - pinfo.imsi = mm->imsi; - pinfo.ptmsi = &mm->p_tmsi; - pinfo.drx_params = mm->drx_parms; - pinfo.qos[0] = 0; // FIXME - bssgp_tx_paging(mm->gb.nsei, 0, &pinfo); - rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PAGING_PS]); - /* FIXME: queue the packet we received from GTP */ - break; - case GMM_REGISTERED_NORMAL: - break; - default: - LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state " - "%u\n", mm->gb.tlli, mm->gmm_state); - msgb_free(msg); - return -1; - } - - rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_OUT]); - rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_OUT], len); - rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_UDATA_OUT]); - rate_ctr_add(&mm->ctrg->ctr[GMM_CTR_BYTES_UDATA_OUT], len); - - /* It is easier to have a global count */ - pdp->cdr_bytes_out += len; - - return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi], - pdp->nsapi, mm); -} - -/* Called by SNDCP when it has received/re-assembled a N-PDU */ -int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi, - struct msgb *msg, uint32_t npdu_len, uint8_t *npdu) -{ - struct sgsn_mm_ctx *mmctx; - struct sgsn_pdp_ctx *pdp; - - /* look-up the MM context for this message */ - mmctx = sgsn_mm_ctx_by_tlli(tlli, ra_id); - if (!mmctx) { - LOGP(DGPRS, LOGL_ERROR, - "Cannot find MM CTX for TLLI %08x\n", tlli); - return -EIO; - } - /* look-up the PDP context for this message */ - pdp = sgsn_pdp_ctx_by_nsapi(mmctx, nsapi); - if (!pdp) { - LOGP(DGPRS, LOGL_ERROR, "Cannot find PDP CTX for " - "TLLI=%08x, NSAPI=%u\n", tlli, nsapi); - return -EIO; - } - if (!pdp->lib) { - LOGP(DGPRS, LOGL_ERROR, "PDP CTX without libgtp\n"); - return -EIO; - } - - rate_ctr_inc(&pdp->ctrg->ctr[PDP_CTR_PKTS_UDATA_IN]); - rate_ctr_add(&pdp->ctrg->ctr[PDP_CTR_BYTES_UDATA_IN], npdu_len); - rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_UDATA_IN]); - rate_ctr_add(&mmctx->ctrg->ctr[GMM_CTR_BYTES_UDATA_IN], npdu_len); - - /* It is easier to have a global count */ - pdp->cdr_bytes_in += npdu_len; - - return gtp_data_req(pdp->ggsn->gsn, pdp->lib, npdu, npdu_len); -} - -/* libgtp select loop integration */ -static int sgsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what) -{ - struct sgsn_instance *sgi = fd->data; - int rc; - - if (!(what & BSC_FD_READ)) - return 0; - - switch (fd->priv_nr) { - case 0: - rc = gtp_decaps0(sgi->gsn); - break; - case 1: - rc = gtp_decaps1c(sgi->gsn); - break; - case 2: - rc = gtp_decaps1u(sgi->gsn); - break; - default: - rc = -EINVAL; - break; - } - return rc; -} - -static void sgsn_gtp_tmr_start(struct sgsn_instance *sgi) -{ - struct timeval next; - - /* Retrieve next retransmission as struct timeval */ - gtp_retranstimeout(sgi->gsn, &next); - - /* re-schedule the timer */ - osmo_timer_schedule(&sgi->gtp_timer, next.tv_sec, next.tv_usec/1000); -} - -/* timer callback for libgtp retransmissions and ping */ -static void sgsn_gtp_tmr_cb(void *data) -{ - struct sgsn_instance *sgi = data; - - /* Do all the retransmissions as needed */ - gtp_retrans(sgi->gsn); - - sgsn_gtp_tmr_start(sgi); -} - -int sgsn_gtp_init(struct sgsn_instance *sgi) -{ - int rc; - struct gsn_t *gsn; - - rc = gtp_new(&sgi->gsn, sgi->cfg.gtp_statedir, - &sgi->cfg.gtp_listenaddr.sin_addr, GTP_MODE_SGSN); - if (rc) { - LOGP(DGPRS, LOGL_ERROR, "Failed to create GTP: %d\n", rc); - return rc; - } - gsn = sgi->gsn; - - sgi->gtp_fd0.fd = gsn->fd0; - sgi->gtp_fd0.priv_nr = 0; - sgi->gtp_fd0.data = sgi; - sgi->gtp_fd0.when = BSC_FD_READ; - sgi->gtp_fd0.cb = sgsn_gtp_fd_cb; - rc = osmo_fd_register(&sgi->gtp_fd0); - if (rc < 0) - return rc; - - sgi->gtp_fd1c.fd = gsn->fd1c; - sgi->gtp_fd1c.priv_nr = 1; - sgi->gtp_fd1c.data = sgi; - sgi->gtp_fd1c.when = BSC_FD_READ; - sgi->gtp_fd1c.cb = sgsn_gtp_fd_cb; - rc = osmo_fd_register(&sgi->gtp_fd1c); - if (rc < 0) { - osmo_fd_unregister(&sgi->gtp_fd0); - return rc; - } - - sgi->gtp_fd1u.fd = gsn->fd1u; - sgi->gtp_fd1u.priv_nr = 2; - sgi->gtp_fd1u.data = sgi; - sgi->gtp_fd1u.when = BSC_FD_READ; - sgi->gtp_fd1u.cb = sgsn_gtp_fd_cb; - rc = osmo_fd_register(&sgi->gtp_fd1u); - if (rc < 0) { - osmo_fd_unregister(&sgi->gtp_fd0); - osmo_fd_unregister(&sgi->gtp_fd1c); - return rc; - } - - /* Start GTP re-transmission timer */ - osmo_timer_setup(&sgi->gtp_timer, sgsn_gtp_tmr_cb, sgi); - sgsn_gtp_tmr_start(sgi); - - /* Register callbackcs with libgtp */ - gtp_set_cb_delete_context(gsn, cb_delete_context); - gtp_set_cb_conf(gsn, cb_conf); - gtp_set_cb_recovery(gsn, cb_recovery); - gtp_set_cb_data_ind(gsn, cb_data_ind); - gtp_set_cb_unsup_ind(gsn, cb_unsup_ind); - gtp_set_cb_extheader_ind(gsn, cb_extheader_ind); - - return 0; -} diff --git a/src/gprs/sgsn_main.c b/src/gprs/sgsn_main.c deleted file mode 100644 index 25ee632cc..000000000 --- a/src/gprs/sgsn_main.c +++ /dev/null @@ -1,476 +0,0 @@ -/* GPRS SGSN Implementation */ - -/* (C) 2010 by Harald Welte - * (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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include - -#include "../../bscconfig.h" - -#if BUILD_IU -#include -#endif - -#define _GNU_SOURCE -#include - -void *tall_bsc_ctx; - -struct gprs_ns_inst *sgsn_nsi; -static int daemonize = 0; -const char *openbsc_copyright = - "Copyright (C) 2010 Harald Welte and On-Waves\r\n" - "License AGPLv3+: GNU AGPL version 3 or later \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 struct sgsn_instance sgsn_inst = { - .config_file = "osmo_sgsn.cfg", - .cfg = { - .gtp_statedir = "./", - .auth_policy = SGSN_AUTH_POLICY_CLOSED, - .gsup_server_port = OSMO_GSUP_PORT, - }, -}; -struct sgsn_instance *sgsn = &sgsn_inst; - -/* call-back function for the NS protocol */ -static int sgsn_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: - /* hand the message into the BSSGP implementation */ - rc = bssgp_rcvmsg(msg); - break; - default: - LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); - if (msg) - msgb_free(msg); - rc = -EIO; - break; - } - return rc; -} - -/* call-back function for the BSSGP protocol */ -int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) -{ - struct osmo_bssgp_prim *bp; - bp = container_of(oph, struct osmo_bssgp_prim, oph); - - switch (oph->sap) { - case SAP_BSSGP_LL: - switch (oph->primitive) { - case PRIM_BSSGP_UL_UD: - return gprs_llc_rcvmsg(oph->msg, bp->tp); - } - break; - case SAP_BSSGP_GMM: - switch (oph->primitive) { - case PRIM_BSSGP_GMM_SUSPEND: - return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli); - case PRIM_BSSGP_GMM_RESUME: - return gprs_gmm_rx_resume(bp->ra_id, bp->tlli, - bp->u.resume.suspend_ref); - } - break; - case SAP_BSSGP_NM: - break; - } - return 0; -} - -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; - } -} - -/* NSI that BSSGP uses when transmitting on NS */ -extern struct gprs_ns_inst *bssgp_nsi; - -extern int bsc_vty_go_parent(struct vty *vty); - -static struct vty_app_info vty_info = { - .name = "OsmoSGSN", - .version = PACKAGE_VERSION, - .go_parent_cb = bsc_vty_go_parent, - .is_config_node = bsc_vty_is_config_node, -}; - -static void print_help(void) -{ - printf("Some useful help...\n"); - printf(" -h --help\tthis text\n"); - printf(" -D --daemonize\tFork the process into a background daemon\n"); - printf(" -d option --debug\tenable Debugging\n"); - printf(" -s --disable-color\n"); - printf(" -c --config-file\tThe config file to use [%s]\n", sgsn->config_file); - printf(" -e --log-level number\tSet a global log level\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'}, - {NULL, 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': - sgsn_inst.config_file = strdup(optarg); - break; - case 'T': - log_set_print_timestamp(osmo_stderr_target, 1); - break; - case 'V': - print_version(1); - exit(0); - break; - case 'e': - log_set_log_level(osmo_stderr_target, atoi(optarg)); - break; - default: - /* ignore */ - break; - } - } -} - -/* default categories */ -static struct log_info_cat gprs_categories[] = { - [DMM] = { - .name = "DMM", - .description = "Layer3 Mobility Management (MM)", - .color = "\033[1;33m", - .enabled = 1, .loglevel = LOGL_NOTICE, - }, - [DPAG] = { - .name = "DPAG", - .description = "Paging Subsystem", - .color = "\033[1;38m", - .enabled = 1, .loglevel = LOGL_NOTICE, - }, - [DMEAS] = { - .name = "DMEAS", - .description = "Radio Measurement Processing", - .enabled = 0, .loglevel = LOGL_NOTICE, - }, - [DREF] = { - .name = "DREF", - .description = "Reference Counting", - .enabled = 0, .loglevel = LOGL_NOTICE, - }, - [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, - }, - [DLLC] = { - .name = "DLLC", - .description = "GPRS Logical Link Control Protocol (LLC)", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, - [DSNDCP] = { - .name = "DSNDCP", - .description = "GPRS Sub-Network Dependent Control Protocol (SNDCP)", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, - [DRANAP] = { - .name = "DRANAP", - .description = "RAN Application Part (RANAP)", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, - [DSUA] = { - .name = "DSUA", - .description = "SCCP User Adaptation (SUA)", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, - [DSLHC] = { - .name = "DSLHC", - .description = "RFC1144 TCP/IP Header compression (SLHC)", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, - [DV42BIS] = { - .name = "DV42BIS", - .description = "V.42bis data compression (SNDCP)", - .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 sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data); - -int main(int argc, char **argv) -{ - struct ctrl_handle *ctrl; - struct gsm_network dummy_network; - struct osmo_sccp_instance *sccp; - int rc; - - srand(time(NULL)); - tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn"); - 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); - osmo_stats_init(tall_bsc_ctx); - - vty_info.copyright = openbsc_copyright; - vty_init(&vty_info); - logging_vty_add_cmds(NULL); - osmo_stats_vty_add_cmds(&gprs_log_info); - sgsn_vty_init(&sgsn_inst.cfg); - ctrl_vty_init(tall_bsc_ctx); - osmo_ss7_init(); - - handle_options(argc, argv); - - rate_ctr_init(tall_bsc_ctx); - - gprs_ns_set_log_ss(DNS); - bssgp_set_log_ss(DBSSGP); - - sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb, tall_bsc_ctx); - if (!sgsn_nsi) { - LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); - exit(1); - } - bssgp_nsi = sgsn_inst.cfg.nsi = sgsn_nsi; - - gprs_llc_init("/usr/local/lib/osmocom/crypt/"); - sgsn_rate_ctr_init(); - sgsn_inst_init(); - - gprs_ns_vty_init(bssgp_nsi); - bssgp_vty_init(); - gprs_llc_vty_init(); - gprs_sndcp_vty_init(); - sgsn_auth_init(); - sgsn_cdr_init(&sgsn_inst); - /* FIXME: register signal handler for SS_L_NS */ - - rc = sgsn_parse_config(sgsn_inst.config_file); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Error in 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_SGSN); - if (rc < 0) - exit(1); - - /* start control interface after reading config for - * ctrl_vty_get_bind_addr() */ - ctrl = sgsn_controlif_setup(NULL, ctrl_vty_get_bind_addr(), - OSMO_CTRL_PORT_SGSN); - if (!ctrl) { - LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n"); - exit(1); - } - - if (sgsn_ctrl_cmds_install() != 0) { - LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n"); - exit(1); - } - - - rc = sgsn_gtp_init(&sgsn_inst); - if (rc) { - LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on GTP socket\n"); - exit(2); - } - - rc = gprs_subscr_init(&sgsn_inst); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot set up subscriber management\n"); - exit(2); - } - - rc = gprs_ns_nsip_listen(sgsn_nsi); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n"); - exit(2); - } - - rc = gprs_ns_frgre_listen(sgsn_nsi); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen GRE " - "socket. Do you have CAP_NET_RAW?\n"); - exit(2); - } - - if (sgsn->cfg.dynamic_lookup) { - if (sgsn_ares_init(sgsn) != 0) { - LOGP(DGPRS, LOGL_FATAL, - "Failed to initialize c-ares(%d)\n", rc); - exit(4); - } - } - -#ifdef BUILD_IU - sccp = osmo_sccp_simple_client(tall_bsc_ctx, "OsmoSGSN", - 2 /* FIXME: configurable */, - OSMO_SS7_ASP_PROT_M3UA, 0, - "127.0.0.4" /* FIXME: configurable */, - M3UA_PORT, - "127.0.0.1" /* FIXME: configurable */); - if (!sccp) { - printf("Setting up SCCP client failed.\n"); - return 8; - } - - ranap_iu_init(tall_bsc_ctx, DRANAP, "OsmoSGSN-IuPS", sccp, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event); -#endif - - if (daemonize) { - rc = osmo_daemonize(); - if (rc < 0) { - perror("Error during daemonize"); - exit(1); - } - } - - while (1) { - rc = osmo_select_main(0); - if (rc < 0) - exit(3); - } - - /* not reached */ - exit(0); -} diff --git a/src/gprs/sgsn_vty.c b/src/gprs/sgsn_vty.c deleted file mode 100644 index 3a5b2ca64..000000000 --- a/src/gprs/sgsn_vty.c +++ /dev/null @@ -1,1329 +0,0 @@ -/* - * (C) 2010-2016 by Harald Welte - * (C) 2010 by On-Waves - * (C) 2015 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 . - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "../../bscconfig.h" - -#ifdef BUILD_IU -#include -#endif - -static struct sgsn_config *g_cfg = NULL; - -const struct value_string sgsn_auth_pol_strs[] = { - { SGSN_AUTH_POLICY_OPEN, "accept-all" }, - { SGSN_AUTH_POLICY_CLOSED, "closed" }, - { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" }, - { SGSN_AUTH_POLICY_REMOTE, "remote" }, - { 0, NULL } -}; - -/* Section 11.2.2 / Table 11.3a GPRS Mobility management timers – MS side */ -#define GSM0408_T3312_SECS (10*60) /* periodic RAU interval, default 54min */ - -/* Section 11.2.2 / Table 11.4 MM timers netwokr side */ -#define GSM0408_T3322_SECS 6 /* DETACH_REQ -> DETACH_ACC */ -#define GSM0408_T3350_SECS 6 /* waiting for ATT/RAU/TMSI COMPL */ -#define GSM0408_T3360_SECS 6 /* waiting for AUTH/CIPH RESP */ -#define GSM0408_T3370_SECS 6 /* waiting for ID RESP */ - -/* Section 11.2.2 / Table 11.4a MM timers network side */ -#define GSM0408_T3313_SECS 30 /* waiting for paging response */ -#define GSM0408_T3314_SECS 44 /* force to STBY on expiry, Ready timer */ -#define GSM0408_T3316_SECS 44 - -/* Section 11.3 / Table 11.2d Timers of Session Management - network side */ -#define GSM0408_T3385_SECS 8 /* wait for ACT PDP CTX REQ */ -#define GSM0408_T3386_SECS 8 /* wait for MODIFY PDP CTX ACK */ -#define GSM0408_T3395_SECS 8 /* wait for DEACT PDP CTX ACK */ -#define GSM0408_T3397_SECS 8 /* wait for DEACT AA PDP CTX ACK */ - -#define DECLARE_TIMER(number, doc) \ - DEFUN(cfg_sgsn_T##number, \ - cfg_sgsn_T##number##_cmd, \ - "timer t" #number " <0-65535>", \ - "Configure GPRS Timers\n" \ - doc "\nTimer Value in seconds\n") \ -{ \ - int value = atoi(argv[0]); \ - \ - if (value < 0 || value > 65535) { \ - vty_out(vty, "Timer value %s out of range.%s", \ - argv[0], VTY_NEWLINE); \ - return CMD_WARNING; \ - } \ - \ - g_cfg->timers.T##number = value; \ - return CMD_SUCCESS; \ -} - -DECLARE_TIMER(3312, "Periodic RA Update timer (s)") -DECLARE_TIMER(3322, "Detach request -> accept timer (s)") -DECLARE_TIMER(3350, "Waiting for ATT/RAU/TMSI_COMPL timer (s)") -DECLARE_TIMER(3360, "Waiting for AUTH/CIPH response timer (s)") -DECLARE_TIMER(3370, "Waiting for IDENTITY response timer (s)") - -DECLARE_TIMER(3313, "Waiting for paging response timer (s)") -DECLARE_TIMER(3314, "Force to STANDBY on expiry timer (s)") -DECLARE_TIMER(3316, "AA-Ready timer (s)") - -DECLARE_TIMER(3385, "Wait for ACT PDP CTX REQ timer (s)") -DECLARE_TIMER(3386, "Wait for MODIFY PDP CTX ACK timer (s)") -DECLARE_TIMER(3395, "Wait for DEACT PDP CTX ACK timer (s)") -DECLARE_TIMER(3397, "Wait for DEACT AA PDP CTX ACK timer (s)") - - -#define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */ -/** Copy apn to a static buffer, replacing the length octets in apn_enc with '.' - * and terminating with a '\0'. Return the static buffer. - * len: the length of the encoded APN (which has no terminating zero). - */ -static char *gprs_apn2str(uint8_t *apn, unsigned int len) -{ - static char apnbuf[GSM48_MAX_APN_LEN+1]; - - if (!apn) - return ""; - osmo_apn_to_str(apnbuf, apn, len); - - return apnbuf+1; -} - -char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len) -{ - static char str[INET6_ADDRSTRLEN + 10]; - - if (!pdpa || len < 2) - return "none"; - - switch (pdpa[0] & 0x0f) { - case PDP_TYPE_ORG_IETF: - switch (pdpa[1]) { - case PDP_TYPE_N_IETF_IPv4: - if (len < 2 + 4) - break; - strcpy(str, "IPv4 "); - inet_ntop(AF_INET, pdpa+2, str+5, sizeof(str)-5); - return str; - case PDP_TYPE_N_IETF_IPv6: - if (len < 2 + 8) - break; - strcpy(str, "IPv6 "); - inet_ntop(AF_INET6, pdpa+2, str+5, sizeof(str)-5); - return str; - default: - break; - } - break; - case PDP_TYPE_ORG_ETSI: - if (pdpa[1] == PDP_TYPE_N_ETSI_PPP) - return "PPP"; - break; - default: - break; - } - - return "invalid"; -} - -static struct cmd_node sgsn_node = { - SGSN_NODE, - "%s(config-sgsn)# ", - 1, -}; - -static int config_write_sgsn(struct vty *vty) -{ - struct sgsn_ggsn_ctx *gctx; - struct imsi_acl_entry *acl; - struct apn_ctx *actx; - struct ares_addr_node *server; - - vty_out(vty, "sgsn%s", VTY_NEWLINE); - - vty_out(vty, " gtp local-ip %s%s", - inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE); - - llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) { - if (gctx->id == UINT32_MAX) - continue; - - vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id, - inet_ntoa(gctx->remote_addr), VTY_NEWLINE); - vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id, - gctx->gtp_version, VTY_NEWLINE); - } - - if (sgsn->cfg.dynamic_lookup) - vty_out(vty, " ggsn dynamic%s", VTY_NEWLINE); - - for (server = sgsn->ares_servers; server; server = server->next) - vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE); - - if (g_cfg->cipher != GPRS_ALGO_GEA0) - vty_out(vty, " encryption %s%s", - get_value_string(gprs_cipher_names, g_cfg->cipher), - VTY_NEWLINE); - if (g_cfg->gsup_server_addr.sin_addr.s_addr) - vty_out(vty, " gsup remote-ip %s%s", - inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE); - if (g_cfg->gsup_server_port) - vty_out(vty, " gsup remote-port %d%s", - g_cfg->gsup_server_port, VTY_NEWLINE); - vty_out(vty, " auth-policy %s%s", - get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy), - VTY_NEWLINE); - - vty_out(vty, " gsup oap-id %d%s", - (int)g_cfg->oap.client_id, VTY_NEWLINE); - if (g_cfg->oap.secret_k_present != 0) - vty_out(vty, " gsup oap-k %s%s", - osmo_hexdump_nospc(g_cfg->oap.secret_k, sizeof(g_cfg->oap.secret_k)), - VTY_NEWLINE); - if (g_cfg->oap.secret_opc_present != 0) - vty_out(vty, " gsup oap-opc %s%s", - osmo_hexdump_nospc(g_cfg->oap.secret_opc, sizeof(g_cfg->oap.secret_opc)), - VTY_NEWLINE); - - llist_for_each_entry(acl, &g_cfg->imsi_acl, list) - vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE); - - if (llist_empty(&sgsn_apn_ctxts)) - vty_out(vty, " ! apn * ggsn 0%s", VTY_NEWLINE); - llist_for_each_entry(actx, &sgsn_apn_ctxts, list) { - if (strlen(actx->imsi_prefix) > 0) - vty_out(vty, " apn %s imsi-prefix %s ggsn %u%s", - actx->name, actx->imsi_prefix, actx->ggsn->id, - VTY_NEWLINE); - else - vty_out(vty, " apn %s ggsn %u%s", actx->name, - actx->ggsn->id, VTY_NEWLINE); - } - - if (g_cfg->cdr.filename) - vty_out(vty, " cdr filename %s%s", g_cfg->cdr.filename, VTY_NEWLINE); - else - vty_out(vty, " no cdr filename%s", VTY_NEWLINE); - vty_out(vty, " cdr interval %d%s", g_cfg->cdr.interval, VTY_NEWLINE); - - vty_out(vty, " timer t3312 %d%s", g_cfg->timers.T3312, VTY_NEWLINE); - vty_out(vty, " timer t3322 %d%s", g_cfg->timers.T3322, VTY_NEWLINE); - vty_out(vty, " timer t3350 %d%s", g_cfg->timers.T3350, VTY_NEWLINE); - vty_out(vty, " timer t3360 %d%s", g_cfg->timers.T3360, VTY_NEWLINE); - vty_out(vty, " timer t3370 %d%s", g_cfg->timers.T3370, VTY_NEWLINE); - vty_out(vty, " timer t3313 %d%s", g_cfg->timers.T3313, VTY_NEWLINE); - vty_out(vty, " timer t3314 %d%s", g_cfg->timers.T3314, VTY_NEWLINE); - vty_out(vty, " timer t3316 %d%s", g_cfg->timers.T3316, VTY_NEWLINE); - vty_out(vty, " timer t3385 %d%s", g_cfg->timers.T3385, VTY_NEWLINE); - vty_out(vty, " timer t3386 %d%s", g_cfg->timers.T3386, VTY_NEWLINE); - vty_out(vty, " timer t3395 %d%s", g_cfg->timers.T3395, VTY_NEWLINE); - vty_out(vty, " timer t3397 %d%s", g_cfg->timers.T3397, VTY_NEWLINE); - - if (g_cfg->pcomp_rfc1144.active) { - vty_out(vty, " compression rfc1144 active slots %d%s", - g_cfg->pcomp_rfc1144.s01 + 1, VTY_NEWLINE); - } else if (g_cfg->pcomp_rfc1144.passive) { - vty_out(vty, " compression rfc1144 passive%s", VTY_NEWLINE); - } else - vty_out(vty, " no compression rfc1144%s", VTY_NEWLINE); - - if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 1) { - vty_out(vty, - " compression v42bis active direction sgsn codewords %d strlen %d%s", - g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, - VTY_NEWLINE); - } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 2) { - vty_out(vty, - " compression v42bis active direction ms codewords %d strlen %d%s", - g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, - VTY_NEWLINE); - } else if (g_cfg->dcomp_v42bis.active && g_cfg->dcomp_v42bis.p0 == 3) { - vty_out(vty, - " compression v42bis active direction both codewords %d strlen %d%s", - g_cfg->dcomp_v42bis.p1, g_cfg->dcomp_v42bis.p2, - VTY_NEWLINE); - } else if (g_cfg->dcomp_v42bis.passive) { - vty_out(vty, " compression v42bis passive%s", VTY_NEWLINE); - } else - vty_out(vty, " no compression v42bis%s", VTY_NEWLINE); - -#ifdef BUILD_IU - ranap_iu_vty_config_write(vty, " "); -#endif - - return CMD_SUCCESS; -} - -#define SGSN_STR "Configure the SGSN\n" -#define GGSN_STR "Configure the GGSN information\n" - -DEFUN(cfg_sgsn, cfg_sgsn_cmd, - "sgsn", - SGSN_STR) -{ - vty->node = SGSN_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd, - "gtp local-ip A.B.C.D", - "GTP Parameters\n" - "Set the IP address for the local GTP bind\n" - "IPv4 Address\n") -{ - inet_aton(argv[0], &g_cfg->gtp_listenaddr.sin_addr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd, - "ggsn <0-255> remote-ip A.B.C.D", - GGSN_STR "GGSN Number\n" IP_STR "IPv4 Address\n") -{ - uint32_t id = atoi(argv[0]); - struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); - - inet_aton(argv[1], &ggc->remote_addr); - - return CMD_SUCCESS; -} - -#if 0 -DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd, - "ggsn <0-255> remote-port <0-65535>", - "") -{ - uint32_t id = atoi(argv[0]); - struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); - uint16_t port = atoi(argv[1]); - -} -#endif - -DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd, - "ggsn <0-255> gtp-version (0|1)", - GGSN_STR "GGSN Number\n" "GTP Version\n" - "Version 0\n" "Version 1\n") -{ - uint32_t id = atoi(argv[0]); - struct sgsn_ggsn_ctx *ggc = sgsn_ggsn_ctx_find_alloc(id); - - if (atoi(argv[1])) - ggc->gtp_version = 1; - else - ggc->gtp_version = 0; - - return CMD_SUCCESS; -} - -DEFUN(cfg_ggsn_dynamic_lookup, cfg_ggsn_dynamic_lookup_cmd, - "ggsn dynamic", - GGSN_STR "Enable dynamic GRX based look-up (requires restart)\n") -{ - sgsn->cfg.dynamic_lookup = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_grx_ggsn, cfg_grx_ggsn_cmd, - "grx-dns-add A.B.C.D", - "Add DNS server\nIPv4 address\n") -{ - struct ares_addr_node *node = talloc_zero(tall_bsc_ctx, struct ares_addr_node); - node->family = AF_INET; - inet_aton(argv[0], &node->addr.addr4); - - node->next = sgsn->ares_servers; - sgsn->ares_servers = node; - return CMD_SUCCESS; -} - -#define APN_STR "Configure the information per APN\n" -#define APN_GW_STR "The APN gateway name optionally prefixed by '*' (wildcard)\n" - -static int add_apn_ggsn_mapping(struct vty *vty, const char *apn_str, - const char *imsi_prefix, int ggsn_id) -{ - struct apn_ctx *actx; - struct sgsn_ggsn_ctx *ggsn; - - ggsn = sgsn_ggsn_ctx_by_id(ggsn_id); - if (ggsn == NULL) { - vty_out(vty, "%% a GGSN with id %d has not been defined%s", - ggsn_id, VTY_NEWLINE); - return CMD_WARNING; - } - - actx = sgsn_apn_ctx_find_alloc(apn_str, imsi_prefix); - if (!actx) { - vty_out(vty, "%% unable to create APN context for %s/%s%s", - apn_str, imsi_prefix, VTY_NEWLINE); - return CMD_WARNING; - } - - actx->ggsn = ggsn; - - return CMD_SUCCESS; -} - -DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd, - "apn APNAME ggsn <0-255>", - APN_STR APN_GW_STR - "Select the GGSN to use when the APN gateway prefix matches\n" - "The GGSN id") -{ - - return add_apn_ggsn_mapping(vty, argv[0], "", atoi(argv[1])); -} - -DEFUN(cfg_apn_imsi_ggsn, cfg_apn_imsi_ggsn_cmd, - "apn APNAME imsi-prefix IMSIPRE ggsn <0-255>", - APN_STR APN_GW_STR - "Restrict rule to a certain IMSI prefix\n" - "An IMSI prefix\n" - "Select the GGSN to use when APN gateway and IMSI prefix match\n" - "The GGSN id") -{ - - return add_apn_ggsn_mapping(vty, argv[0], argv[1], atoi(argv[2])); -} - -const struct value_string gprs_mm_st_strs[] = { - { GMM_DEREGISTERED, "DEREGISTERED" }, - { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" }, - { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" }, - { GMM_REGISTERED_SUSPENDED, "REGISTERED (SUSPENDED)" }, - { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" }, - { 0, NULL } -}; - -static char *gtp_ntoa(struct ul16_t *ul) -{ - if (ul->l == 4) { - struct in_addr *ia = (struct in_addr *) ul; - return inet_ntoa(*ia); - } else { - return "UNKNOWN"; - } -} - -static void vty_dump_pdp(struct vty *vty, const char *pfx, - struct sgsn_pdp_ctx *pdp) -{ - const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)"; - vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s", - pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE); - if (pdp->lib) { - vty_out(vty, "%s APN: %s%s", pfx, - gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l), - VTY_NEWLINE); - vty_out(vty, "%s PDP Address: %s%s", pfx, - gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l), - VTY_NEWLINE); - vty_out(vty, "%s GTP Local Control(%s / TEIC: 0x%08x) ", pfx, - gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own); - vty_out(vty, "Data(%s / TEID: 0x%08x)%s", - gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE); - vty_out(vty, "%s GTP Remote Control(%s / TEIC: 0x%08x) ", pfx, - gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn); - vty_out(vty, "Data(%s / TEID: 0x%08x)%s", - gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE); - } - - vty_out_rate_ctr_group(vty, " ", pdp->ctrg); -} - -static void vty_dump_mmctx(struct vty *vty, const char *pfx, - struct sgsn_mm_ctx *mm, int pdp) -{ - vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s", - pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE); - vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s", - pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE); - vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, " - "Cell ID: %u%s", pfx, - get_value_string(gprs_mm_st_strs, mm->gmm_state), - mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac, - mm->gb.cell_id, VTY_NEWLINE); - - vty_out_rate_ctr_group(vty, " ", mm->ctrg); - - if (pdp) { - struct sgsn_pdp_ctx *pdp; - - llist_for_each_entry(pdp, &mm->pdp_list, list) - vty_dump_pdp(vty, " ", pdp); - } -} - -DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn", - SHOW_STR "Display information about the SGSN") -{ - if (sgsn->gsup_client) { - struct ipa_client_conn *link = sgsn->gsup_client->link; - vty_out(vty, - " Remote authorization: %sconnected to %s:%d via GSUP%s", - sgsn->gsup_client->is_connected ? "" : "not ", - link->addr, link->port, - VTY_NEWLINE); - } - /* FIXME: statistics */ - return CMD_SUCCESS; -} - -#define MMCTX_STR "MM Context\n" -#define INCLUDE_PDP_STR "Include PDP Context Information\n" - -#if 0 -DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd, - "show mm-context tlli HEX [pdp]", - SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR) -{ - uint32_t tlli; - struct sgsn_mm_ctx *mm; - - tlli = strtoul(argv[0], NULL, 16); - mm = sgsn_mm_ctx_by_tlli(tlli); - if (!mm) { - vty_out(vty, "No MM context for TLLI %08x%s", - tlli, VTY_NEWLINE); - return CMD_WARNING; - } - vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0); - return CMD_SUCCESS; -} -#endif - -DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd, - "show mm-context imsi IMSI [pdp]", - SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n" - INCLUDE_PDP_STR) -{ - struct sgsn_mm_ctx *mm; - - mm = sgsn_mm_ctx_by_imsi(argv[0]); - if (!mm) { - vty_out(vty, "No MM context for IMSI %s%s", - argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0); - return CMD_SUCCESS; -} - -DEFUN(swow_mmctx_all, show_mmctx_all_cmd, - "show mm-context all [pdp]", - SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR) -{ - struct sgsn_mm_ctx *mm; - - llist_for_each_entry(mm, &sgsn_mm_ctxts, list) - vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0); - - return CMD_SUCCESS; -} - -DEFUN(show_pdpctx_all, show_pdpctx_all_cmd, - "show pdp-context all", - SHOW_STR "Display information on PDP Context\n" "Show everything\n") -{ - struct sgsn_pdp_ctx *pdp; - - llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list) - vty_dump_pdp(vty, "", pdp); - - return CMD_SUCCESS; -} - - -DEFUN(imsi_acl, cfg_imsi_acl_cmd, - "imsi-acl (add|del) IMSI", - "Access Control List of foreign IMSIs\n" - "Add IMSI to ACL\n" - "Remove IMSI from ACL\n" - "IMSI of subscriber\n") -{ - char imsi_sanitized[GSM23003_IMSI_MAX_DIGITS+1]; - const char *op = argv[0]; - const char *imsi = imsi_sanitized; - int rc; - - /* Sanitize IMSI */ - if (strlen(argv[1]) > GSM23003_IMSI_MAX_DIGITS) { - vty_out(vty, "%% IMSI (%s) too long -- ignored!%s", - argv[1], VTY_NEWLINE); - return CMD_WARNING; - } - memset(imsi_sanitized, '0', sizeof(imsi_sanitized)); - strcpy(imsi_sanitized+GSM23003_IMSI_MAX_DIGITS-strlen(argv[1]),argv[1]); - - if (!strcmp(op, "add")) - rc = sgsn_acl_add(imsi, g_cfg); - else - rc = sgsn_acl_del(imsi, g_cfg); - - if (rc < 0) { - vty_out(vty, "%% unable to %s ACL%s", op, VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_encrypt, cfg_encrypt_cmd, - "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)", - "Set encryption algorithm for SGSN\n" - "Use GEA0 (no encryption)\n" - "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n") -{ - enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]); - if (c != GPRS_ALGO_GEA0) { - if (!gprs_cipher_supported(c)) { - vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - if (!g_cfg->require_authentication) { - vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s", - argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - } - - g_cfg->cipher = c; - - return CMD_SUCCESS; -} - -DEFUN(cfg_auth_policy, cfg_auth_policy_cmd, - "auth-policy (accept-all|closed|acl-only|remote)", - "Autorization Policy of SGSN\n" - "Accept all IMSIs (DANGEROUS)\n" - "Accept only home network subscribers or those in the ACL\n" - "Accept only subscribers in the ACL\n" - "Use remote subscription data only (HLR)\n") -{ - int val = get_string_value(sgsn_auth_pol_strs, argv[0]); - OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE); - g_cfg->auth_policy = val; - g_cfg->require_authentication = (val == SGSN_AUTH_POLICY_REMOTE); - g_cfg->require_update_location = (val == SGSN_AUTH_POLICY_REMOTE); - - return CMD_SUCCESS; -} - -/* Subscriber */ -#include - -static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending) -{ -#if 0 - char expire_time[200]; -#endif - struct gsm_auth_tuple *at; - int at_idx; - struct sgsn_subscriber_pdp_data *pdp; - - vty_out(vty, " Authorized: %d%s", - gsub->authorized, VTY_NEWLINE); - vty_out(vty, " LAC: %d/0x%x%s", - gsub->lac, gsub->lac, VTY_NEWLINE); - vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE); - if (gsub->tmsi != GSM_RESERVED_TMSI) - vty_out(vty, " TMSI: %08X%s", gsub->tmsi, - VTY_NEWLINE); - if (gsub->sgsn_data->msisdn_len > 0) - vty_out(vty, " MSISDN (BCD): %s%s", - osmo_hexdump(gsub->sgsn_data->msisdn, - gsub->sgsn_data->msisdn_len), - VTY_NEWLINE); - - if (strlen(gsub->imei) > 0) - vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE); - - for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets); - at_idx++) { - at = &gsub->sgsn_data->auth_triplets[at_idx]; - if (at->key_seq == GSM_KEY_SEQ_INVAL) - continue; - - vty_out(vty, " A3A8 tuple (used %d times): ", - at->use_count); - vty_out(vty, " CKSN: %d, ", - at->key_seq); - if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) { - vty_out(vty, "RAND: %s, ", - osmo_hexdump(at->vec.rand, - sizeof(at->vec.rand))); - vty_out(vty, "SRES: %s, ", - osmo_hexdump(at->vec.sres, - sizeof(at->vec.sres))); - vty_out(vty, "Kc: %s%s", - osmo_hexdump(at->vec.kc, - sizeof(at->vec.kc)), VTY_NEWLINE); - } - if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) { - vty_out(vty, " AUTN: %s, ", - osmo_hexdump(at->vec.autn, - sizeof(at->vec.autn))); - vty_out(vty, "RES: %s, ", - osmo_hexdump(at->vec.res, at->vec.res_len)); - vty_out(vty, "IK: %s, ", - osmo_hexdump(at->vec.ik, sizeof(at->vec.ik))); - vty_out(vty, "CK: %s, ", - osmo_hexdump(at->vec.ck, sizeof(at->vec.ck))); - } - } - - llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) { - vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s", - pdp->context_id, pdp->pdp_type, pdp->apn_str, - osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len), - VTY_NEWLINE); - } - -#if 0 - /* print the expiration time of a subscriber */ - if (gsub->expire_lu) { - strftime(expire_time, sizeof(expire_time), - "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu)); - expire_time[sizeof(expire_time) - 1] = '\0'; - vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE); - } -#endif - - if (gsub->flags) - vty_out(vty, " Flags: %s%s%s%s%s%s", - gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ? - "FIRST_CONTACT " : "", - gsub->flags & GPRS_SUBSCRIBER_CANCELLED ? - "CANCELLED " : "", - gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ? - "UPDATE_LOCATION_PENDING " : "", - gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ? - "AUTH_INFO_PENDING " : "", - gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ? - "ENABLE_PURGE " : "", - VTY_NEWLINE); - - vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE); -} - -DEFUN(show_subscr_cache, - show_subscr_cache_cmd, - "show subscriber cache", - SHOW_STR "Show information about subscribers\n" - "Display contents of subscriber cache\n") -{ - struct gprs_subscr *subscr; - - llist_for_each_entry(subscr, gprs_subscribers, entry) { - vty_out(vty, " Subscriber:%s", VTY_NEWLINE); - subscr_dump_full_vty(vty, subscr, 0); - } - - return CMD_SUCCESS; -} - -#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI " -#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \ - "Use the IMSI to select the subscriber\n" \ - "The IMSI\n" - -#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n" - -DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd, - UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc KC", - UPDATE_SUBSCR_HELP - UPDATE_SUBSCR_INSERT_HELP - "Update authentication triplet\n" - "Triplet index\n" - "Set SRES value\nSRES value (4 byte) in hex\n" - "Set RAND value\nRAND value (16 byte) in hex\n" - "Set Kc value\nKc value (8 byte) in hex\n") -{ - const char *imsi = argv[0]; - const int cksn = atoi(argv[1]) - 1; - const char *sres_str = argv[2]; - const char *rand_str = argv[3]; - const char *kc_str = argv[4]; - struct gsm_auth_tuple at = {0,}; - - struct gprs_subscr *subscr; - - subscr = gprs_subscr_get_by_imsi(imsi); - if (!subscr) { - vty_out(vty, "%% unable get subscriber record for %s%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - OSMO_ASSERT(subscr->sgsn_data); - - if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) { - vty_out(vty, "%% invalid SRES value '%s'%s", - sres_str, VTY_NEWLINE); - goto failed; - } - if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) { - vty_out(vty, "%% invalid RAND value '%s'%s", - rand_str, VTY_NEWLINE); - goto failed; - } - if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) { - vty_out(vty, "%% invalid Kc value '%s'%s", - kc_str, VTY_NEWLINE); - goto failed; - } - at.key_seq = cksn; - - subscr->sgsn_data->auth_triplets[cksn] = at; - subscr->sgsn_data->auth_triplets_updated = 1; - - gprs_subscr_put(subscr); - - return CMD_SUCCESS; - -failed: - gprs_subscr_put(subscr); - return CMD_SUCCESS; -} - -DEFUN(update_subscr_cancel, update_subscr_cancel_cmd, - UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)", - UPDATE_SUBSCR_HELP - "Cancel (remove) subscriber record\n" - "The MS moved to another SGSN\n" - "The subscription is no longer valid\n") -{ - const char *imsi = argv[0]; - const char *cancel_type = argv[1]; - - struct gprs_subscr *subscr; - - subscr = gprs_subscr_get_by_imsi(imsi); - if (!subscr) { - vty_out(vty, "%% no subscriber record for %s%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - if (strcmp(cancel_type, "update-procedure") == 0) - subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; - else - subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED; - - gprs_subscr_cancel(subscr); - gprs_subscr_put(subscr); - - return CMD_SUCCESS; -} - -DEFUN(update_subscr_create, update_subscr_create_cmd, - UPDATE_SUBSCR_STR "create", - UPDATE_SUBSCR_HELP - "Create a subscriber entry\n") -{ - const char *imsi = argv[0]; - - struct gprs_subscr *subscr; - - subscr = gprs_subscr_get_by_imsi(imsi); - if (subscr) { - vty_out(vty, "%% subscriber record already exists for %s%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - subscr = gprs_subscr_get_or_create(imsi); - subscr->keep_in_ram = 1; - gprs_subscr_put(subscr); - - return CMD_SUCCESS; -} - -DEFUN(update_subscr_destroy, update_subscr_destroy_cmd, - UPDATE_SUBSCR_STR "destroy", - UPDATE_SUBSCR_HELP - "Destroy a subscriber entry\n") -{ - const char *imsi = argv[0]; - - struct gprs_subscr *subscr; - - subscr = gprs_subscr_get_by_imsi(imsi); - if (!subscr) { - vty_out(vty, "%% subscriber record does not exist for %s%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - subscr->keep_in_ram = 0; - subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; - gprs_subscr_cancel(subscr); - if (subscr->use_count > 1) - vty_out(vty, "%% subscriber is still in use%s", - VTY_NEWLINE); - gprs_subscr_put(subscr); - - return CMD_SUCCESS; -} - -#define UL_ERR_STR "system-failure|data-missing|unexpected-data-value|" \ - "unknown-subscriber|roaming-not-allowed" - -#define UL_ERR_HELP \ - "Force error code SystemFailure\n" \ - "Force error code DataMissing\n" \ - "Force error code UnexpectedDataValue\n" \ - "Force error code UnknownSubscriber\n" \ - "Force error code RoamingNotAllowed\n" - -DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd, - UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")", - UPDATE_SUBSCR_HELP - "Complete the update location procedure\n" - "The update location request succeeded\n" - UL_ERR_HELP) -{ - const char *imsi = argv[0]; - const char *ret_code_str = argv[1]; - - struct gprs_subscr *subscr; - - const struct value_string cause_mapping[] = { - { GMM_CAUSE_NET_FAIL, "system-failure" }, - { GMM_CAUSE_INV_MAND_INFO, "data-missing" }, - { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" }, - { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" }, - { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" }, - { 0, NULL } - }; - - subscr = gprs_subscr_get_by_imsi(imsi); - if (!subscr) { - vty_out(vty, "%% unable to get subscriber record for %s%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - if (strcmp(ret_code_str, "ok") == 0) { - subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; - subscr->authorized = 1; - } else { - subscr->sgsn_data->error_cause = - get_string_value(cause_mapping, ret_code_str); - subscr->authorized = 0; - } - - gprs_subscr_update(subscr); - - gprs_subscr_put(subscr); - - return CMD_SUCCESS; -} - -DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd, - UPDATE_SUBSCR_STR "update-auth-info", - UPDATE_SUBSCR_HELP - "Complete the send authentication info procedure\n") -{ - const char *imsi = argv[0]; - - struct gprs_subscr *subscr; - - subscr = gprs_subscr_get_by_imsi(imsi); - if (!subscr) { - vty_out(vty, "%% unable to get subscriber record for %s%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - gprs_subscr_update_auth_info(subscr); - - gprs_subscr_put(subscr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd, - "gsup remote-ip A.B.C.D", - "GSUP Parameters\n" - "Set the IP address of the remote GSUP server\n" - "IPv4 Address\n") -{ - inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd, - "gsup remote-port <0-65535>", - "GSUP Parameters\n" - "Set the TCP port of the remote GSUP server\n" - "Remote TCP port\n") -{ - g_cfg->gsup_server_port = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_gsup_oap_id, cfg_gsup_oap_id_cmd, - "gsup oap-id <0-65535>", - "GSUP Parameters\n" - "Set the SGSN's OAP client ID\nOAP client ID (0 == disabled)\n") -{ - /* VTY ensures range */ - g_cfg->oap.client_id = (uint16_t)atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_gsup_oap_k, cfg_gsup_oap_k_cmd, - "gsup oap-k K", - "GSUP Parameters\n" - "Set the OAP shared secret K\nK value (16 byte) hex\n") -{ - const char *k = argv[0]; - - g_cfg->oap.secret_k_present = 0; - - if ((!k) || (strlen(k) == 0)) - goto disable; - - int k_len = osmo_hexparse(k, - g_cfg->oap.secret_k, - sizeof(g_cfg->oap.secret_k)); - if (k_len != 16) { - vty_out(vty, "%% need exactly 16 octets for oap-k, got %d.%s", - k_len, VTY_NEWLINE); - goto disable; - } - - g_cfg->oap.secret_k_present = 1; - return CMD_SUCCESS; - -disable: - if (g_cfg->oap.client_id > 0) { - vty_out(vty, "%% OAP client ID set, but invalid oap-k value disables OAP.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - return CMD_SUCCESS; -} - -DEFUN(cfg_gsup_oap_opc, cfg_gsup_oap_opc_cmd, - "gsup oap-opc OPC", - "GSUP Parameters\n" - "Set the OAP shared secret OPC\nOPC value (16 byte) hex\n") -{ - const char *opc = argv[0]; - - g_cfg->oap.secret_opc_present = 0; - - if ((!opc) || (strlen(opc) == 0)) - goto disable; - - int opc_len = osmo_hexparse(opc, - g_cfg->oap.secret_opc, - sizeof(g_cfg->oap.secret_opc)); - if (opc_len != 16) { - vty_out(vty, "%% need exactly 16 octets for oap-opc, got %d.%s", - opc_len, VTY_NEWLINE); - goto disable; - } - - g_cfg->oap.secret_opc_present = 1; - return CMD_SUCCESS; - -disable: - if (g_cfg->oap.client_id > 0) { - vty_out(vty, "%% OAP client ID set, but invalid oap-opc value disables OAP.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - return CMD_SUCCESS; -} - -DEFUN(cfg_apn_name, cfg_apn_name_cmd, - "access-point-name NAME", - "Configure a global list of allowed APNs\n" - "Add this NAME to the list\n") -{ - return add_apn_ggsn_mapping(vty, argv[0], "", 0); -} - -DEFUN(cfg_no_apn_name, cfg_no_apn_name_cmd, - "no access-point-name NAME", - NO_STR "Configure a global list of allowed APNs\n" - "Remove entry with NAME\n") -{ - struct apn_ctx *apn_ctx = sgsn_apn_ctx_by_name(argv[0], ""); - if (!apn_ctx) - return CMD_SUCCESS; - - sgsn_apn_ctx_free(apn_ctx); - return CMD_SUCCESS; -} - -DEFUN(cfg_cdr_filename, cfg_cdr_filename_cmd, - "cdr filename NAME", - "CDR\nSet filename\nname\n") -{ - talloc_free(g_cfg->cdr.filename); - g_cfg->cdr.filename = talloc_strdup(tall_vty_ctx, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_no_cdr_filename, cfg_no_cdr_filename_cmd, - "no cdr filename", - NO_STR "CDR\nDisable CDR generation\n") -{ - talloc_free(g_cfg->cdr.filename); - g_cfg->cdr.filename = NULL; - return CMD_SUCCESS; -} - -DEFUN(cfg_cdr_interval, cfg_cdr_interval_cmd, - "cdr interval <1-2147483647>", - "CDR\nPDP periodic log interval\nSeconds\n") -{ - g_cfg->cdr.interval = atoi(argv[0]); - return CMD_SUCCESS; -} - -#define COMPRESSION_STR "Configure compression\n" -DEFUN(cfg_no_comp_rfc1144, cfg_no_comp_rfc1144_cmd, - "no compression rfc1144", - NO_STR COMPRESSION_STR "disable rfc1144 TCP/IP header compression\n") -{ - g_cfg->pcomp_rfc1144.active = 0; - g_cfg->pcomp_rfc1144.passive = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_comp_rfc1144, cfg_comp_rfc1144_cmd, - "compression rfc1144 active slots <1-256>", - COMPRESSION_STR - "RFC1144 Header compresion scheme\n" - "Compression is actively proposed\n" - "Number of compression state slots\n" - "Number of compression state slots\n") -{ - g_cfg->pcomp_rfc1144.active = 1; - g_cfg->pcomp_rfc1144.passive = 1; - g_cfg->pcomp_rfc1144.s01 = atoi(argv[0]) - 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_comp_rfc1144p, cfg_comp_rfc1144p_cmd, - "compression rfc1144 passive", - COMPRESSION_STR - "RFC1144 Header compresion scheme\n" - "Compression is available on request\n") -{ - g_cfg->pcomp_rfc1144.active = 0; - g_cfg->pcomp_rfc1144.passive = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_no_comp_v42bis, cfg_no_comp_v42bis_cmd, - "no compression v42bis", - NO_STR COMPRESSION_STR "disable V.42bis data compression\n") -{ - g_cfg->dcomp_v42bis.active = 0; - g_cfg->dcomp_v42bis.passive = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_comp_v42bis, cfg_comp_v42bis_cmd, - "compression v42bis active direction (ms|sgsn|both) codewords <512-65535> strlen <6-250>", - COMPRESSION_STR - "V.42bis data compresion scheme\n" - "Compression is actively proposed\n" - "Direction in which the compression shall be active (p0)\n" - "Compress ms->sgsn direction only\n" - "Compress sgsn->ms direction only\n" - "Both directions\n" - "Number of codewords (p1)\n" - "Number of codewords\n" - "Maximum string length (p2)\n" "Maximum string length\n") -{ - g_cfg->dcomp_v42bis.active = 1; - g_cfg->dcomp_v42bis.passive = 1; - - switch (argv[0][0]) { - case 'm': - g_cfg->dcomp_v42bis.p0 = 1; - break; - case 's': - g_cfg->dcomp_v42bis.p0 = 2; - break; - case 'b': - g_cfg->dcomp_v42bis.p0 = 3; - break; - } - - g_cfg->dcomp_v42bis.p1 = atoi(argv[1]); - g_cfg->dcomp_v42bis.p2 = atoi(argv[2]); - return CMD_SUCCESS; -} - -DEFUN(cfg_comp_v42bisp, cfg_comp_v42bisp_cmd, - "compression v42bis passive", - COMPRESSION_STR - "V.42bis data compresion scheme\n" - "Compression is available on request\n") -{ - g_cfg->dcomp_v42bis.active = 0; - g_cfg->dcomp_v42bis.passive = 1; - return CMD_SUCCESS; -} - -int sgsn_vty_init(struct sgsn_config *cfg) -{ - g_cfg = cfg; - - install_element_ve(&show_sgsn_cmd); - //install_element_ve(&show_mmctx_tlli_cmd); - install_element_ve(&show_mmctx_imsi_cmd); - install_element_ve(&show_mmctx_all_cmd); - install_element_ve(&show_pdpctx_all_cmd); - install_element_ve(&show_subscr_cache_cmd); - - install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd); - install_element(ENABLE_NODE, &update_subscr_create_cmd); - install_element(ENABLE_NODE, &update_subscr_destroy_cmd); - install_element(ENABLE_NODE, &update_subscr_cancel_cmd); - install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd); - install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd); - - install_element(CONFIG_NODE, &cfg_sgsn_cmd); - install_node(&sgsn_node, config_write_sgsn); - vty_install_default(SGSN_NODE); - install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd); - install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd); - //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd); - install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd); - install_element(SGSN_NODE, &cfg_imsi_acl_cmd); - install_element(SGSN_NODE, &cfg_auth_policy_cmd); - install_element(SGSN_NODE, &cfg_encrypt_cmd); - install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd); - install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd); - install_element(SGSN_NODE, &cfg_gsup_oap_id_cmd); - install_element(SGSN_NODE, &cfg_gsup_oap_k_cmd); - install_element(SGSN_NODE, &cfg_gsup_oap_opc_cmd); - install_element(SGSN_NODE, &cfg_apn_ggsn_cmd); - install_element(SGSN_NODE, &cfg_apn_imsi_ggsn_cmd); - install_element(SGSN_NODE, &cfg_apn_name_cmd); - install_element(SGSN_NODE, &cfg_no_apn_name_cmd); - install_element(SGSN_NODE, &cfg_cdr_filename_cmd); - install_element(SGSN_NODE, &cfg_no_cdr_filename_cmd); - install_element(SGSN_NODE, &cfg_cdr_interval_cmd); - install_element(SGSN_NODE, &cfg_ggsn_dynamic_lookup_cmd); - install_element(SGSN_NODE, &cfg_grx_ggsn_cmd); - - install_element(SGSN_NODE, &cfg_sgsn_T3312_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3322_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3350_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3360_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3370_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3313_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3314_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3316_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3385_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3386_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3395_cmd); - install_element(SGSN_NODE, &cfg_sgsn_T3397_cmd); - - install_element(SGSN_NODE, &cfg_no_comp_rfc1144_cmd); - install_element(SGSN_NODE, &cfg_comp_rfc1144_cmd); - install_element(SGSN_NODE, &cfg_comp_rfc1144p_cmd); - install_element(SGSN_NODE, &cfg_no_comp_v42bis_cmd); - install_element(SGSN_NODE, &cfg_comp_v42bis_cmd); - install_element(SGSN_NODE, &cfg_comp_v42bisp_cmd); - -#ifdef BUILD_IU - ranap_iu_vty_init(SGSN_NODE, &g_cfg->iu.rab_assign_addr_enc); -#endif - return 0; -} - -int sgsn_parse_config(const char *config_file) -{ - int rc; - - /* make sure sgsn_vty_init() was called before this */ - OSMO_ASSERT(g_cfg); - - g_cfg->timers.T3312 = GSM0408_T3312_SECS; - g_cfg->timers.T3322 = GSM0408_T3322_SECS; - g_cfg->timers.T3350 = GSM0408_T3350_SECS; - g_cfg->timers.T3360 = GSM0408_T3360_SECS; - g_cfg->timers.T3370 = GSM0408_T3370_SECS; - g_cfg->timers.T3313 = GSM0408_T3313_SECS; - g_cfg->timers.T3314 = GSM0408_T3314_SECS; - g_cfg->timers.T3316 = GSM0408_T3316_SECS; - g_cfg->timers.T3385 = GSM0408_T3385_SECS; - g_cfg->timers.T3386 = GSM0408_T3386_SECS; - g_cfg->timers.T3395 = GSM0408_T3395_SECS; - g_cfg->timers.T3397 = GSM0408_T3397_SECS; - - 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; - } - - if (g_cfg->auth_policy == SGSN_AUTH_POLICY_REMOTE - && !(g_cfg->gsup_server_addr.sin_addr.s_addr - && g_cfg->gsup_server_port)) { - fprintf(stderr, "Configuration error:" - " 'auth-policy remote' requires both" - " 'gsup remote-ip' and 'gsup remote-port'\n"); - return -EINVAL; - } - - return 0; -} diff --git a/src/gprs/slhc.c b/src/gprs/slhc.c deleted file mode 100644 index cbdf8dbd8..000000000 --- a/src/gprs/slhc.c +++ /dev/null @@ -1,813 +0,0 @@ -/* - * Routines to compress and uncompress tcp packets (for transmission - * over low speed serial lines). - * - * 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 (from 1.19) - * PPP.05 02-15-90 [ks] - * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression - * PPP.15 09-90 [ks] improve mbuf handling - * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities - * - * - Feb 1991 Bill_Simpson@um.cc.umich.edu - * variable number of conversation slots - * allow zero or one slots - * separate routines - * status display - * - Jul 1994 Dmitry Gorodchanin - * Fixes for memory leaks. - * - Oct 1994 Dmitry Gorodchanin - * Modularization. - * - Jan 1995 Bjorn Ekwall - * Use ip_fast_csum from ip.h - * - July 1995 Christos A. Polyzols - * Spotted bug in tcp option checking - * - * - * This module is a difficult issue. It's clearly inet code but it's also clearly - * driver code belonging close to PPP and SLIP - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ERR_PTR(x) x - - -static unsigned char *encode(unsigned char *cp, unsigned short n); -static long decode(unsigned char **cpp); -static unsigned char * put16(unsigned char *cp, unsigned short x); -static unsigned short pull16(unsigned char **cpp); - -/* Replacement for kernel space function ip_fast_csum() */ -static uint16_t ip_fast_csum(uint8_t *iph, int ihl) -{ - int i; - uint16_t temp; - uint32_t accumulator = 0xFFFF; - - for(i=0;i0xFFFF) - { - accumulator++; - accumulator&=0xFFFF; - } - } - - return (uint16_t)(htons(~accumulator)&0xFFFF); -} - -/* Replacement for kernel space function put_unaligned() */ -static void put_unaligned(uint16_t val, void *ptr) -{ - memcpy(ptr,&val,sizeof(val)); -} - - -/* Allocate compression data structure - * slots must be in range 0 to 255 (zero meaning no compression) - * Returns pointer to structure or ERR_PTR() on error. - */ -struct slcompress * -slhc_init(const void *ctx, int rslots, int tslots) -{ - register short i; - register struct cstate *ts; - struct slcompress *comp; - - if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) - return NULL; - - comp = (struct slcompress *)talloc_zero_size(ctx,sizeof(struct slcompress)); - if (! comp) - goto out_fail; - - if (rslots > 0) { - size_t rsize = rslots * sizeof(struct cstate); - comp->rstate = (struct cstate *) talloc_zero_size(ctx, rsize); - if (! comp->rstate) - goto out_free; - comp->rslot_limit = rslots - 1; - } - - if (tslots > 0) { - size_t tsize = tslots * sizeof(struct cstate); - comp->tstate = (struct cstate *) talloc_zero_size(ctx, tsize); - if (! comp->tstate) - goto out_free2; - comp->tslot_limit = tslots - 1; - } - - comp->xmit_oldest = 0; - comp->xmit_current = 255; - comp->recv_current = 255; - /* - * don't accept any packets with implicit index until we get - * one with an explicit index. Otherwise the uncompress code - * will try to use connection 255, which is almost certainly - * out of range - */ - comp->flags |= SLF_TOSS; - - if ( tslots > 0 ) { - ts = comp->tstate; - for(i = comp->tslot_limit; i > 0; --i){ - ts[i].cs_this = i; - ts[i].next = &(ts[i - 1]); - } - ts[0].next = &(ts[comp->tslot_limit]); - ts[0].cs_this = 0; - } - return comp; - -out_free2: - talloc_free(comp->rstate); -out_free: - talloc_free(comp); -out_fail: - return NULL; -} - - -/* Free a compression data structure */ -void -slhc_free(struct slcompress *comp) -{ - DEBUGP(DSLHC, "slhc_free(): Freeing compression states...\n"); - - if ( comp == NULLSLCOMPR ) - return; - - if ( comp->tstate != NULLSLSTATE ) - talloc_free(comp->tstate ); - - if ( comp->rstate != NULLSLSTATE ) - talloc_free( comp->rstate ); - - talloc_free( comp ); -} - - -/* Put a short in host order into a char array in network order */ -static inline unsigned char * -put16(unsigned char *cp, unsigned short x) -{ - *cp++ = x >> 8; - *cp++ = x; - - return cp; -} - - -/* Encode a number */ -static unsigned char * -encode(unsigned char *cp, unsigned short n) -{ - if(n >= 256 || n == 0){ - *cp++ = 0; - cp = put16(cp,n); - } else { - *cp++ = n; - } - - DEBUGP(DSLHC, "encode(): n=%04x\n",n); - return cp; -} - -/* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16(unsigned char **cpp) -{ - short rval; - - rval = *(*cpp)++; - rval <<= 8; - rval |= *(*cpp)++; - return rval; -} - -/* Decode a number */ -static long -decode(unsigned char **cpp) -{ - register int x; - - x = *(*cpp)++; - if(x == 0){ - return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ - } else { - return x & 0xff; /* -1 if PULLCHAR returned error */ - } -} - -/* - * icp and isize are the original packet. - * ocp is a place to put a copy if necessary. - * cpp is initially a pointer to icp. If the copy is used, - * change it to ocp. - */ - -int -slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, - unsigned char *ocp, unsigned char **cpp, int compress_cid) -{ - register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); - register struct cstate *lcs = ocs; - register struct cstate *cs = lcs->next; - register unsigned long deltaS, deltaA; - register short changes = 0; - int hlen; - unsigned char new_seq[16]; - register unsigned char *cp = new_seq; - struct iphdr *ip; - struct tcphdr *th, *oth; - __sum16 csum; - - - /* - * Don't play with runt packets. - */ - - if(isizeprotocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) { - /* Send as regular IP */ - if(ip->protocol != IPPROTO_TCP) - comp->sls_o_nontcp++; - else - comp->sls_o_tcp++; - DEBUGP(DSLHC, "slhc_compress(): Not a TCP packat, will not touch...\n"); - return isize; - } - /* Extract TCP header */ - - th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); - hlen = ip->ihl*4 + th->doff*4; - - /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or - * some other control bit is set). Also uncompressible if - * it's a runt. - */ - if(hlen > isize || th->syn || th->fin || th->rst || - ! (th->ack)){ - /* TCP connection stuff; send as regular IP */ - comp->sls_o_tcp++; - DEBUGP(DSLHC, "slhc_compress(): Packet is part of a TCP connection, will not touch...\n"); - return isize; - } - /* - * Packet is compressible -- we're going to send either a - * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, - * we need to locate (or create) the connection state. - * - * States are kept in a circularly linked list with - * xmit_oldest pointing to the end of the list. The - * list is kept in lru order by moving a state to the - * head of the list whenever it is referenced. Since - * the list is short and, empirically, the connection - * we want is almost always near the front, we locate - * states via linear search. If we don't find a state - * for the datagram, the oldest state is (re-)used. - */ - - DEBUGP(DSLHC, "slhc_compress(): Compressible packet detected!\n"); - - for ( ; ; ) { - if( ip->saddr == cs->cs_ip.saddr - && ip->daddr == cs->cs_ip.daddr - && th->source == cs->cs_tcp.source - && th->dest == cs->cs_tcp.dest) - goto found; - - /* if current equal oldest, at end of list */ - if ( cs == ocs ) - break; - lcs = cs; - cs = cs->next; - comp->sls_o_searches++; - } - /* - * Didn't find it -- re-use oldest cstate. Send an - * uncompressed packet that tells the other side what - * connection number we're using for this conversation. - * - * Note that since the state list is circular, the oldest - * state points to the newest and we only need to set - * xmit_oldest to update the lru linkage. - */ - - DEBUGP(DSLHC, "slhc_compress(): Header not yet seen, will memorize header for the next turn...\n"); - comp->sls_o_misses++; - comp->xmit_oldest = lcs->cs_this; - goto uncompressed; - -found: - DEBUGP(DSLHC, "slhc_compress(): Header already seen, trying to compress...\n"); - /* - * Found it -- move to the front on the connection list. - */ - if(lcs == ocs) { - /* found at most recently used */ - } else if (cs == ocs) { - /* found at least recently used */ - comp->xmit_oldest = lcs->cs_this; - } else { - /* more than 2 elements */ - lcs->next = cs->next; - cs->next = ocs->next; - ocs->next = cs; - } - - /* - * Make sure that only what we expect to change changed. - * Check the following: - * IP protocol version, header length & type of service. - * The "Don't fragment" bit. - * The time-to-live field. - * The TCP header length. - * IP options, if any. - * TCP options, if any. - * If any of these things are different between the previous & - * current datagram, we send the current datagram `uncompressed'. - */ - oth = &cs->cs_tcp; - - /* Display a little more debug information about which of the - * header fields changed unexpectedly */ - if(ip->version != cs->cs_ip.version) - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->version != cs->cs_ip.version\n"); - if(ip->ihl != cs->cs_ip.ihl) - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ihl != cs->cs_ip.ihl\n"); - if(ip->tos != cs->cs_ip.tos) - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->tos != cs->cs_ip.tos\n"); - if((ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))) - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))\n"); - if(ip->ttl != cs->cs_ip.ttl) - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: ip->ttl != cs->cs_ip.ttl\n"); - if(th->doff != cs->cs_tcp.doff) - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: th->doff != cs->cs_tcp.doff\n"); - if(ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) { - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)\n"); - DEBUGP(DSLHC, "slhc_compress(): ip->ihl = %i\n", ip->ihl); - DEBUGP(DSLHC, "slhc_compress(): ip+1 = %s\n", - osmo_hexdump_nospc((uint8_t*)(ip+1),((ip->ihl)-5)*4)); - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: cs->cs_ipopt = %s\n", - osmo_hexdump_nospc((uint8_t*)(cs->cs_ipopt),((ip->ihl)-5)*4)); - } - if(th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0) { - DEBUGP(DSLHC, "slhc_compress(): Unexpected change: (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)\n"); - DEBUGP(DSLHC, "slhc_compress(): th->doff = %i\n", th->doff); - DEBUGP(DSLHC, "slhc_compress(): th+1 = %s\n", - osmo_hexdump_nospc((uint8_t*)(th+1),((th->doff)-5)*4)); - DEBUGP(DSLHC, "slhc_compress(): cs->cs_tcpopt = %s\n", - osmo_hexdump_nospc((uint8_t*)cs->cs_tcpopt, - ((th->doff)-5)*4)); - } - - - if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl - || ip->tos != cs->cs_ip.tos - || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000)) - || ip->ttl != cs->cs_ip.ttl - || th->doff != cs->cs_tcp.doff - || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) - || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){ - DEBUGP(DSLHC, "slhc_compress(): The header contains unexpected changes, can't compress...\n"); - goto uncompressed; - } - - /* - * Figure out which of the changing fields changed. The - * receiver expects changes in the order: urgent, window, - * ack, seq (the order minimizes the number of temporaries - * needed in this section of code). - */ - if(th->urg){ - deltaS = ntohs(th->urg_ptr); - DEBUGP(DSLHC, "slhc_compress(): flag: Urgent Pointer (U) = 1\n"); - cp = encode(cp,deltaS); - changes |= NEW_U; - } else if(th->urg_ptr != oth->urg_ptr){ - /* argh! URG not set but urp changed -- a sensible - * implementation should never do this but RFC793 - * doesn't prohibit the change so we have to deal - * with it. */ - DEBUGP(DSLHC, "slhc_compress(): URG not set but urp changed, can't compress...\n"); - goto uncompressed; - } - if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ - DEBUGP(DSLHC, "slhc_compress(): flag: Delta Window (W) = 1\n"); - cp = encode(cp,deltaS); - changes |= NEW_W; - } - if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ - if(deltaA > 0x0000ffff) { - DEBUGP(DSLHC, "slhc_compress(): (deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L, can't compress...\n"); - goto uncompressed; - } - DEBUGP(DSLHC, "slhc_compress(): flag: Delta Ack (A) = 1\n"); - cp = encode(cp,deltaA); - changes |= NEW_A; - } - if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ - if(deltaS > 0x0000ffff) { - DEBUGP(DSLHC, "slhc_compress(): (deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L, can't compress...\n"); - goto uncompressed; - } - DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1\n"); - cp = encode(cp,deltaS); - changes |= NEW_S; - } - - switch(changes){ - case 0: /* Nothing changed. If this packet contains data and the - * last one didn't, this is probably a data packet following - * an ack (normal on an interactive connection) and we send - * it compressed. Otherwise it's probably a retransmit, - * retransmitted ack or window probe. Send it uncompressed - * in case the other side missed the compressed version. - */ - if(ip->tot_len != cs->cs_ip.tot_len && - ntohs(cs->cs_ip.tot_len) == hlen) - break; - DEBUGP(DSLHC, "slhc_compress(): Retransmitted packet detected, can't compress...\n"); - goto uncompressed; - case SPECIAL_I: - case SPECIAL_D: - /* actual changes match one of our special case encodings -- - * send packet uncompressed. - */ - DEBUGP(DSLHC, "slhc_compress(): Special case detected, can't compress...\n"); - goto uncompressed; - case NEW_S|NEW_A: - if(deltaS == deltaA && - deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ - /* special case for echoed terminal traffic */ - DEBUGP(DSLHC, "slhc_compress(): Special case for echoed terminal traffic detected...\n"); - DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); - changes = SPECIAL_I; - cp = new_seq; - } - break; - case NEW_S: - if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ - /* special case for data xfer */ - DEBUGP(DSLHC, "slhc_compress(): Special case for data xfer detected...\n"); - DEBUGP(DSLHC, "slhc_compress(): flag: Delta Sequence (S) = 1, Delta Ack (A) = 1, Delta Window (W) = 1, Urgent Pointer (U) = 1\n"); - changes = SPECIAL_D; - cp = new_seq; - } - break; - } - deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); - if(deltaS != 1){ - DEBUGP(DSLHC, "slhc_compress(): flag: Delta IP ID (I) = 1\n"); - cp = encode(cp,deltaS); - changes |= NEW_I; - } - if(th->psh) { - DEBUGP(DSLHC, "slhc_compress(): flag: Push (P) = 1\n"); - changes |= TCP_PUSH_BIT; - } - /* Grab the cksum before we overwrite it below. Then update our - * state with this packet's header. - */ - csum = th->check; - memcpy(&cs->cs_ip,ip,20); - memcpy(&cs->cs_tcp,th,20); - /* We want to use the original packet as our compressed packet. - * (cp - new_seq) is the number of bytes we need for compressed - * sequence numbers. In addition we need one byte for the change - * mask, one for the connection id and two for the tcp checksum. - * So, (cp - new_seq) + 4 bytes of header are needed. - */ - deltaS = cp - new_seq; - if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ - cp = ocp; - *cpp = ocp; - DEBUGP(DSLHC, "slhc_compress(): flag: Connection number (C) = 1\n"); - *cp++ = changes | NEW_C; - *cp++ = cs->cs_this; - comp->xmit_current = cs->cs_this; - } else { - cp = ocp; - *cpp = ocp; - *cp++ = changes; - } - *(__sum16 *)cp = csum; - cp += 2; -/* deltaS is now the size of the change section of the compressed header */ - - DEBUGP(DSLHC, "slhc_compress(): Delta-list length (deltaS) = %li\n",deltaS); - DEBUGP(DSLHC, "slhc_compress(): Original header len (hlen) = %i\n",hlen); - - memcpy(cp,new_seq,deltaS); /* Write list of deltas */ - memcpy(cp+deltaS,icp+hlen,isize-hlen); - comp->sls_o_compressed++; - ocp[0] |= SL_TYPE_COMPRESSED_TCP; - return isize - hlen + deltaS + (cp - ocp); - - /* Update connection state cs & send uncompressed packet (i.e., - * a regular ip/tcp packet but with the 'conversation id' we hope - * to use on future compressed packets in the protocol field). - */ -uncompressed: - DEBUGP(DSLHC, "slhc_compress(): Packet will be sent uncompressed...\n"); - memcpy(&cs->cs_ip,ip,20); - memcpy(&cs->cs_tcp,th,20); - if (ip->ihl > 5) - memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); - if (th->doff > 5) - memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); - comp->xmit_current = cs->cs_this; - comp->sls_o_uncompressed++; - memcpy(ocp, icp, isize); - *cpp = ocp; - ocp[9] = cs->cs_this; - ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; - return isize; -} - - -int -slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) -{ - register int changes; - long x; - register struct tcphdr *thp; - register struct iphdr *ip; - register struct cstate *cs; - int len, hdrlen; - unsigned char *cp = icp; - - /* We've got a compressed packet; read the change byte */ - comp->sls_i_compressed++; - if(isize < 3){ - comp->sls_i_error++; - return 0; - } - changes = *cp++; - if(changes & NEW_C){ - /* Make sure the state index is in range, then grab the state. - * If we have a good state index, clear the 'discard' flag. - */ - x = *cp++; /* Read conn index */ - if(x < 0 || x > comp->rslot_limit) - goto bad; - - comp->flags &=~ SLF_TOSS; - comp->recv_current = x; - } else { - /* this packet has an implicit state index. If we've - * had a line error since the last time we got an - * explicit state index, we have to toss the packet. */ - if(comp->flags & SLF_TOSS){ - comp->sls_i_tossed++; - return 0; - } - } - cs = &comp->rstate[comp->recv_current]; - thp = &cs->cs_tcp; - ip = &cs->cs_ip; - - thp->check = *(__sum16 *)cp; - cp += 2; - - thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; -/* - * we can use the same number for the length of the saved header and - * the current one, because the packet wouldn't have been sent - * as compressed unless the options were the same as the previous one - */ - - hdrlen = ip->ihl * 4 + thp->doff * 4; - - switch(changes & SPECIALS_MASK){ - case SPECIAL_I: /* Echoed terminal traffic */ - DEBUGP(DSLHC, "slhc_uncompress(): Echoed terminal traffic detected\n"); - - { - register short i; - i = ntohs(ip->tot_len) - hdrlen; - thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); - thp->seq = htonl( ntohl(thp->seq) + i); - } - break; - - case SPECIAL_D: /* Unidirectional data */ - DEBUGP(DSLHC, "slhc_uncompress(): Unidirectional data detected\n"); - thp->seq = htonl( ntohl(thp->seq) + - ntohs(ip->tot_len) - hdrlen); - break; - - default: - DEBUGP(DSLHC, "slhc_uncompress(): default packet type detected\n"); - if(changes & NEW_U){ - thp->urg = 1; - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->urg_ptr = htons(x); - } else - thp->urg = 0; - if(changes & NEW_W){ - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->window = htons( ntohs(thp->window) + x); - } - if(changes & NEW_A){ - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); - } - if(changes & NEW_S){ - if((x = decode(&cp)) == -1) { - goto bad; - } - thp->seq = htonl( ntohl(thp->seq) + x); - } - break; - } - if(changes & NEW_I){ - if((x = decode(&cp)) == -1) { - goto bad; - } - ip->id = htons (ntohs (ip->id) + x); - } else - ip->id = htons (ntohs (ip->id) + 1); - - /* - * At this point, cp points to the first byte of data in the - * packet. Put the reconstructed TCP and IP headers back on the - * packet. Recalculate IP checksum (but not TCP checksum). - */ - - len = isize - (cp - icp); - if (len < 0) - goto bad; - len += hdrlen; - ip->tot_len = htons(len); - ip->check = 0; - - DEBUGP(DSLHC, "slhc_uncompress(): making space for the reconstructed header...\n"); - memmove(icp + hdrlen, cp, len - hdrlen); - - cp = icp; - memcpy(cp, ip, 20); - cp += 20; - - if (ip->ihl > 5) { - memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4); - cp += (ip->ihl - 5) * 4; - } - - put_unaligned(ip_fast_csum(icp, ip->ihl), - &((struct iphdr *)icp)->check); - - memcpy(cp, thp, 20); - cp += 20; - - if (thp->doff > 5) { - memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); - cp += ((thp->doff) - 5) * 4; - } - - return len; -bad: - DEBUGP(DSLHC, "slhc_uncompress(): bad packet detected!\n"); - comp->sls_i_error++; - return slhc_toss( comp ); -} - - -int -slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) -{ - register struct cstate *cs; - unsigned ihl; - - unsigned char index; - - if(isize < 20) { - /* The packet is shorter than a legal IP header */ - comp->sls_i_runt++; - DEBUGP(DSLHC, "slhc_remember(): The packet is shorter than a legal IP header ==> slhc_toss()\n"); - return slhc_toss( comp ); - } - /* Peek at the IP header's IHL field to find its length */ - ihl = icp[0] & 0xf; - if(ihl < 20 / 4){ - /* The IP header length field is too small */ - comp->sls_i_runt++; - DEBUGP(DSLHC, "slhc_remember(): The IP header length field is too small ==> slhc_toss()\n"); - return slhc_toss( comp ); - } - index = icp[9]; - icp[9] = IPPROTO_TCP; - - if (ip_fast_csum(icp, ihl)) { - /* Bad IP header checksum; discard */ - comp->sls_i_badcheck++; - DEBUGP(DSLHC, "slhc_remember(): Bad IP header checksum; discard ==> slhc_toss()\n"); - return slhc_toss( comp ); - } - if(index > comp->rslot_limit) { - comp->sls_i_error++; - DEBUGP(DSLHC, "slhc_remember(): index > comp->rslot_limit ==> slhc_toss()\n"); - return slhc_toss(comp); - } - - /* Update local state */ - cs = &comp->rstate[comp->recv_current = index]; - comp->flags &=~ SLF_TOSS; - memcpy(&cs->cs_ip,icp,20); - memcpy(&cs->cs_tcp,icp + ihl*4,20); - if (ihl > 5) - memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4); - if (cs->cs_tcp.doff > 5) - memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); - cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; - /* Put headers back on packet - * Neither header checksum is recalculated - */ - comp->sls_i_uncompressed++; - return isize; -} - -int -slhc_toss(struct slcompress *comp) -{ - DEBUGP(DSLHC, "slhc_toss(): Reset compression state...\n"); - if ( comp == NULLSLCOMPR ) - return 0; - - comp->flags |= SLF_TOSS; - return 0; -} - -void slhc_i_status(struct slcompress *comp) -{ - if (comp != NULLSLCOMPR) { - DEBUGP(DSLHC, "slhc_i_status(): %d Cmp, %d Uncmp, %d Bad, %d Tossed\n", - comp->sls_i_compressed, - comp->sls_i_uncompressed, - comp->sls_i_error, - comp->sls_i_tossed); - } -} - -void slhc_o_status(struct slcompress *comp) -{ - if (comp != NULLSLCOMPR) { - DEBUGP(DSLHC, "slhc_o_status(): %d Cmp, %d Uncmp, %d AsIs, %d NotTCP %d Searches, %d Misses\n", - comp->sls_o_compressed, - comp->sls_o_uncompressed, - comp->sls_o_tcp, - comp->sls_o_nontcp, - comp->sls_o_searches, - comp->sls_o_misses); - } -} - diff --git a/src/gprs/v42bis.c b/src/gprs/v42bis.c deleted file mode 100644 index a04b0af5c..000000000 --- a/src/gprs/v42bis.c +++ /dev/null @@ -1,767 +0,0 @@ -/* - * SpanDSP - a series of DSP components for telephony - * - * v42bis.c - * - * Written by Steve Underwood - * - * 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. - */ - -/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED. - Currently it performs the core compression and decompression functions OK. - However, a number of the bells and whistles in V.42bis are incomplete. */ - -/*! \file */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#define span_log(x,y,msg, ...) DEBUGP(DV42BIS,msg, ##__VA_ARGS__) -#define span_log_init(x,y,z) -#define span_log_set_protocol(x,y) - - -#define FALSE 0 -#define TRUE 1 - -/* Fixed parameters from the spec. */ -/* Character size (bits) */ -#define V42BIS_N3 8 -/* Number of characters in the alphabet */ -#define V42BIS_N4 256 -/* Index number of first dictionary entry used to store a string */ -#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6) -/* Number of control codewords */ -#define V42BIS_N6 3 -/* V.42bis/9.2 */ -#define V42BIS_ESC_STEP 51 - -/* Compreeibility monitoring parameters for assessing automated switches between - transparent and compressed mode */ -#define COMPRESSIBILITY_MONITOR (256*V42BIS_N3) -#define COMPRESSIBILITY_MONITOR_HYSTERESIS 11 - -/* Control code words in compressed mode */ -enum -{ - V42BIS_ETM = 0, /* Enter transparent mode */ - V42BIS_FLUSH = 1, /* Flush data */ - V42BIS_STEPUP = 2 /* Step up codeword size */ -}; - -/* Command codes in transparent mode */ -enum -{ - V42BIS_ECM = 0, /* Enter compression mode */ - V42BIS_EID = 1, /* Escape character in data */ - V42BIS_RESET = 2 /* Force reinitialisation */ -}; - -static __inline__ void push_octet(v42bis_comp_state_t *s, int octet) -{ - s->output_buf[s->output_octet_count++] = (uint8_t) octet; - if (s->output_octet_count >= s->max_output_len) - { - s->handler(s->user_data, s->output_buf, s->output_octet_count); - s->output_octet_count = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void push_octets(v42bis_comp_state_t *s, const uint8_t buf[], int len) -{ - int i; - int chunk; - - i = 0; - while ((s->output_octet_count + len - i) >= s->max_output_len) - { - chunk = s->max_output_len - s->output_octet_count; - memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); - s->handler(s->user_data, s->output_buf, s->max_output_len); - s->output_octet_count = 0; - i += chunk; - } - chunk = len - i; - if (chunk > 0) - { - memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk); - s->output_octet_count += chunk; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void push_compressed_code(v42bis_comp_state_t *s, int code) -{ - s->bit_buffer |= code << s->bit_count; - s->bit_count += s->v42bis_parm_c2; - while (s->bit_count >= 8) - { - push_octet(s, s->bit_buffer & 0xFF); - s->bit_buffer >>= 8; - s->bit_count -= 8; - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void push_octet_alignment(v42bis_comp_state_t *s) -{ - if ((s->bit_count & 7)) - { - s->bit_count += (8 - (s->bit_count & 7)); - while (s->bit_count >= 8) - { - push_octet(s, s->bit_buffer & 0xFF); - s->bit_buffer >>= 8; - s->bit_count -= 8; - } - } -} -/*- End of function --------------------------------------------------------*/ - -static __inline__ void flush_octets(v42bis_comp_state_t *s) -{ - if (s->output_octet_count > 0) - { - s->handler(s->user_data, s->output_buf, s->output_octet_count); - s->output_octet_count = 0; - } -} -/*- End of function --------------------------------------------------------*/ - -static void dictionary_init(v42bis_comp_state_t *s) -{ - int i; - - memset(s->dict, 0, sizeof(s->dict)); - for (i = 0; i < V42BIS_N4; i++) - s->dict[i + V42BIS_N6].node_octet = i; - s->v42bis_parm_c1 = V42BIS_N5; - s->v42bis_parm_c2 = V42BIS_N3 + 1; - s->v42bis_parm_c3 = V42BIS_N4 << 1; - s->last_matched = 0; - s->update_at = 0; - s->last_added = 0; - s->bit_buffer = 0; - s->bit_count = 0; - s->flushed_length = 0; - s->string_length = 0; - s->escape_code = 0; - s->transparent = TRUE; - s->escaped = FALSE; - s->compression_performance = COMPRESSIBILITY_MONITOR; -} -/*- End of function --------------------------------------------------------*/ - -static uint16_t match_octet(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) -{ - uint16_t e; - - if (at == 0) - return octet + V42BIS_N6; - e = s->dict[at].child; - while (e) - { - if (s->dict[e].node_octet == octet) - return e; - e = s->dict[e].next; - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static uint16_t add_octet_to_dictionary(v42bis_comp_state_t *s, uint16_t at, uint8_t octet) -{ - uint16_t newx; - uint16_t next; - uint16_t e; - - newx = s->v42bis_parm_c1; - s->dict[newx].node_octet = octet; - s->dict[newx].parent = at; - s->dict[newx].child = 0; - s->dict[newx].next = s->dict[at].child; - s->dict[at].child = newx; - next = newx; - /* 6.5 Recovering a dictionary entry to use next */ - do - { - /* 6.5(a) and (b) */ - if (++next == s->v42bis_parm_n2) - next = V42BIS_N5; - } - while (s->dict[next].child); - /* 6.5(c) We need to reuse a leaf node */ - if (s->dict[next].parent) - { - /* 6.5(d) Detach the leaf node from its parent, and re-use it */ - e = s->dict[next].parent; - if (s->dict[e].child == next) - { - s->dict[e].child = s->dict[next].next; - } - else - { - e = s->dict[e].child; - while (s->dict[e].next != next) - e = s->dict[e].next; - s->dict[e].next = s->dict[next].next; - } - } - s->v42bis_parm_c1 = next; - return newx; -} -/*- End of function --------------------------------------------------------*/ - -static void send_string(v42bis_comp_state_t *s) -{ - push_octets(s, s->string, s->string_length); - s->string_length = 0; - s->flushed_length = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void expand_codeword_to_string(v42bis_comp_state_t *s, uint16_t code) -{ - int i; - uint16_t p; - - /* Work out the length */ - for (i = 0, p = code; p; i++) - p = s->dict[p].parent; - s->string_length += i; - /* Now expand the known length of string */ - i = s->string_length - 1; - for (p = code; p; ) - { - s->string[i--] = s->dict[p].node_octet; - p = s->dict[p].parent; - } -} -/*- End of function --------------------------------------------------------*/ - -static void send_encoded_data(v42bis_comp_state_t *s, uint16_t code) -{ - int i; - - /* Update compressibility metric */ - /* Integrate at the compressed bit rate, and leak at the pre-compression bit rate */ - s->compression_performance += (s->v42bis_parm_c2 - s->compression_performance*s->string_length*V42BIS_N3/COMPRESSIBILITY_MONITOR); - if (s->transparent) - { - for (i = 0; i < s->string_length; i++) - { - push_octet(s, s->string[i]); - if (s->string[i] == s->escape_code) - { - push_octet(s, V42BIS_EID); - s->escape_code += V42BIS_ESC_STEP; - } - } - } - else - { - /* Allow for any escape octets in the string */ - for (i = 0; i < s->string_length; i++) - { - if (s->string[i] == s->escape_code) - s->escape_code += V42BIS_ESC_STEP; - } - /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */ - while (code >= s->v42bis_parm_c3) - { - /* We need to increase the codeword size */ - /* 7.4(a) */ - push_compressed_code(s, V42BIS_STEPUP); - /* 7.4(b) */ - s->v42bis_parm_c2++; - /* 7.4(c) */ - s->v42bis_parm_c3 <<= 1; - /* 7.4(d) this might need to be repeated, so we loop */ - } - /* 7.5 Transfer - output the last state of the string */ - push_compressed_code(s, code); - } - s->string_length = 0; - s->flushed_length = 0; -} -/*- End of function --------------------------------------------------------*/ - -static void go_compressed(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - - s = &ss->compress; - if (!s->transparent) - return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n"); - /* Switch out of transparent now, between codes. We need to send the octet which did not - match, just before switching. */ - if (s->last_matched) - { - s->update_at = s->last_matched; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - } - push_octet(s, s->escape_code); - push_octet(s, V42BIS_ECM); - s->bit_buffer = 0; - s->transparent = FALSE; -} -/*- End of function --------------------------------------------------------*/ - -static void go_transparent(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - - s = &ss->compress; - if (s->transparent) - return; - span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n"); - /* Switch into transparent now, between codes, and the unmatched octet should - go out in transparent mode, just below */ - if (s->last_matched) - { - s->update_at = s->last_matched; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - } - s->last_added = 0; - push_compressed_code(s, V42BIS_ETM); - push_octet_alignment(s); - s->transparent = TRUE; -} -/*- End of function --------------------------------------------------------*/ - -static void monitor_for_mode_change(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - - s = &ss->compress; - switch (s->compression_mode) - { - case V42BIS_COMPRESSION_MODE_DYNAMIC: - /* 7.8 Data compressibility test */ - if (s->transparent) - { - if (s->compression_performance < COMPRESSIBILITY_MONITOR - COMPRESSIBILITY_MONITOR_HYSTERESIS) - { - /* 7.8.1 Transition to compressed mode */ - go_compressed(ss); - } - } - else - { - if (s->compression_performance > COMPRESSIBILITY_MONITOR) - { - /* 7.8.2 Transition to transparent mode */ - go_transparent(ss); - } - } - /* 7.8.3 Reset function - TODO */ - break; - case V42BIS_COMPRESSION_MODE_ALWAYS: - if (s->transparent) - go_compressed(ss); - break; - case V42BIS_COMPRESSION_MODE_NEVER: - if (!s->transparent) - go_transparent(ss); - break; - } -} -/*- End of function --------------------------------------------------------*/ - -static int v42bis_comp_init(v42bis_comp_state_t *s, - int p1, - int p2, - put_msg_func_t handler, - void *user_data, - int max_output_len) -{ - memset(s, 0, sizeof(*s)); - s->v42bis_parm_n2 = p1; - s->v42bis_parm_n7 = p2; - s->handler = handler; - s->user_data = user_data; - s->max_output_len = (max_output_len < V42BIS_MAX_OUTPUT_LENGTH) ? max_output_len : V42BIS_MAX_OUTPUT_LENGTH; - s->output_octet_count = 0; - dictionary_init(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -static int comp_exit(v42bis_comp_state_t *s) -{ - s->v42bis_parm_n2 = 0; - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *ss, const uint8_t buf[], int len) -{ - v42bis_comp_state_t *s; - int i; - uint16_t code; - - s = &ss->compress; - if (!s->v42bis_parm_p0) - { - /* Compression is off - just push the incoming data out */ - push_octets(s, buf, len); - return 0; - } - for (i = 0; i < len; ) - { - /* 6.4 Add the string to the dictionary */ - if (s->update_at) - { - if (match_octet(s, s->update_at, buf[i]) == 0) - s->last_added = add_octet_to_dictionary(s, s->update_at, buf[i]); - s->update_at = 0; - } - /* Match string */ - while (i < len) - { - code = match_octet(s, s->last_matched, buf[i]); - if (code == 0) - { - s->update_at = s->last_matched; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - break; - } - if (code == s->last_added) - { - s->last_added = 0; - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - break; - } - s->last_matched = code; - /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry - created by the last invocation of the string matching procedure, then the - next character shall be read and appended to the string and this step - repeated. */ - s->string[s->string_length++] = buf[i++]; - /* 6.4(a) The string must not exceed N7 in length */ - if (s->string_length + s->flushed_length == s->v42bis_parm_n7) - { - send_encoded_data(s, s->last_matched); - s->last_matched = 0; - break; - } - } - monitor_for_mode_change(ss); - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - int len; - - s = &ss->compress; - if (s->update_at) - return 0; - if (s->last_matched) - { - len = s->string_length; - send_encoded_data(s, s->last_matched); - s->flushed_length += len; - } - if (!s->transparent) - { - s->update_at = s->last_matched; - s->last_matched = 0; - s->flushed_length = 0; - push_compressed_code(s, V42BIS_FLUSH); - push_octet_alignment(s); - } - flush_octets(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int len) -{ - v42bis_comp_state_t *s; - int i; - int j; - int yyy; - uint16_t code; - uint16_t p; - uint8_t ch; - uint8_t in; - - s = &ss->decompress; - if (!s->v42bis_parm_p0) - { - /* Compression is off - just push the incoming data out */ - push_octets(s, buf, len); - return 0; - } - for (i = 0; i < len; ) - { - if (s->transparent) - { - in = buf[i]; - if (s->escaped) - { - /* Command */ - s->escaped = FALSE; - switch (in) - { - case V42BIS_ECM: - /* Enter compressed mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n"); - send_string(s); - s->transparent = FALSE; - s->update_at = s->last_matched; - s->last_matched = 0; - i++; - continue; - case V42BIS_EID: - /* Escape symbol */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n"); - in = s->escape_code; - s->escape_code += V42BIS_ESC_STEP; - break; - case V42BIS_RESET: - /* Reset dictionary */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n"); - /* TODO: */ - send_string(s); - dictionary_init(s); - i++; - continue; - default: - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in); - return -1; - } - } - else if (in == s->escape_code) - { - s->escaped = TRUE; - i++; - continue; - } - - yyy = TRUE; - for (j = 0; j < 2 && yyy; j++) - { - if (s->update_at) - { - if (match_octet(s, s->update_at, in) == 0) - s->last_added = add_octet_to_dictionary(s, s->update_at, in); - s->update_at = 0; - } - - code = match_octet(s, s->last_matched, in); - if (code == 0) - { - s->update_at = s->last_matched; - send_string(s); - s->last_matched = 0; - } - else if (code == s->last_added) - { - s->last_added = 0; - send_string(s); - s->last_matched = 0; - } - else - { - s->last_matched = code; - s->string[s->string_length++] = in; - if (s->string_length + s->flushed_length == s->v42bis_parm_n7) - { - send_string(s); - s->last_matched = 0; - } - i++; - yyy = FALSE; - } - } - } - else - { - /* Get code from input */ - while (s->bit_count < s->v42bis_parm_c2 && i < len) - { - s->bit_buffer |= buf[i++] << s->bit_count; - s->bit_count += 8; - } - if (s->bit_count < s->v42bis_parm_c2) - continue; - code = s->bit_buffer & ((1 << s->v42bis_parm_c2) - 1); - s->bit_buffer >>= s->v42bis_parm_c2; - s->bit_count -= s->v42bis_parm_c2; - - if (code < V42BIS_N6) - { - /* We have a control code. */ - switch (code) - { - case V42BIS_ETM: - /* Enter transparent mode */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n"); - s->bit_count = 0; - s->transparent = TRUE; - s->last_matched = 0; - s->last_added = 0; - break; - case V42BIS_FLUSH: - /* Flush signal */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n"); - s->bit_count = 0; - break; - case V42BIS_STEPUP: - /* Increase code word size */ - span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n"); - s->v42bis_parm_c2++; - s->v42bis_parm_c3 <<= 1; - if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3)) - return -1; - break; - } - continue; - } - /* Regular codeword */ - if (code == s->v42bis_parm_c1) - return -1; - expand_codeword_to_string(s, code); - if (s->update_at) - { - ch = s->string[0]; - if ((p = match_octet(s, s->update_at, ch)) == 0) - { - s->last_added = add_octet_to_dictionary(s, s->update_at, ch); - if (code == s->v42bis_parm_c1) - return -1; - } - else if (p == s->last_added) - { - s->last_added = 0; - } - } - s->update_at = ((s->string_length + s->flushed_length) == s->v42bis_parm_n7) ? 0 : code; - /* Allow for any escapes which may be in this string */ - for (j = 0; j < s->string_length; j++) - { - if (s->string[j] == s->escape_code) - s->escape_code += V42BIS_ESC_STEP; - } - send_string(s); - } - } - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *ss) -{ - v42bis_comp_state_t *s; - int len; - - s = &ss->decompress; - len = s->string_length; - send_string(s); - s->flushed_length += len; - flush_octets(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode) -{ - s->compress.compression_mode = mode; -} -/*- End of function --------------------------------------------------------*/ - -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) -{ - int ret; - - if (negotiated_p1 < V42BIS_MIN_DICTIONARY_SIZE || negotiated_p1 > 65535) - return NULL; - if (negotiated_p2 < V42BIS_MIN_STRING_SIZE || negotiated_p2 > V42BIS_MAX_STRING_SIZE) - return NULL; - if (s == NULL) - { - if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL) - return NULL; - } - memset(s, 0, sizeof(*s)); - span_log_init(&s->logging, SPAN_LOG_NONE, NULL); - span_log_set_protocol(&s->logging, "V.42bis"); - - if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len))) - return NULL; - if ((ret = v42bis_comp_init(&s->decompress, negotiated_p1, negotiated_p2, decode_handler, decode_user_data, max_decode_len))) - { - comp_exit(&s->compress); - return NULL; - } - s->compress.v42bis_parm_p0 = negotiated_p0 & 2; - s->decompress.v42bis_parm_p0 = negotiated_p0 & 1; - - return s; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s) -{ - return 0; -} -/*- End of function --------------------------------------------------------*/ - -SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s) -{ - comp_exit(&s->compress); - comp_exit(&s->decompress); - talloc_free(s); - return 0; -} -/*- End of function --------------------------------------------------------*/ -/*- End of file ------------------------------------------------------------*/ diff --git a/src/ipaccess/Makefile.am b/src/ipaccess/Makefile.am deleted file mode 100644 index 4dfe24738..000000000 --- a/src/ipaccess/Makefile.am +++ /dev/null @@ -1,66 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - -I$(top_builddir) \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -OSMO_LIBS = \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(NULL) - -bin_PROGRAMS = \ - abisip-find \ - ipaccess-config \ - ipaccess-proxy \ - $(NULL) - -abisip_find_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(OSMO_LIBS) \ - $(NULL) - -abisip_find_SOURCES = \ - abisip-find.c \ - $(NULL) - -ipaccess_config_SOURCES = \ - ipaccess-config.c \ - ipaccess-firmware.c \ - network_listen.c \ - $(NULL) - -# FIXME: resolve the bogus dependencies patched around here: -ipaccess_config_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(OSMO_LIBS) \ - $(NULL) - -ipaccess_proxy_SOURCES = \ - ipaccess-proxy.c \ - $(NULL) - -ipaccess_proxy_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(OSMO_LIBS) \ - $(NULL) diff --git a/src/ipaccess/abisip-find.c b/src/ipaccess/abisip-find.c deleted file mode 100644 index 21d9f2290..000000000 --- a/src/ipaccess/abisip-find.c +++ /dev/null @@ -1,216 +0,0 @@ -/* ip.access nanoBTS configuration tool */ - -/* (C) 2009-2010 by Harald Welte - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include - -static int udp_sock(const char *ifname) -{ - int fd, rc, bc = 1; - struct sockaddr_in sa; - - fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (fd < 0) - return fd; - - if (ifname) { -#ifdef __FreeBSD__ - rc = setsockopt(fd, SOL_SOCKET, IP_RECVIF, ifname, - strlen(ifname)); -#else - rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, - strlen(ifname)); -#endif - if (rc < 0) - goto err; - } - - memset(&sa, 0, sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(3006); - sa.sin_addr.s_addr = INADDR_ANY; - - rc = bind(fd, (struct sockaddr *)&sa, sizeof(sa)); - if (rc < 0) - goto err; - - rc = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bc, sizeof(bc)); - if (rc < 0) - goto err; - -#if 0 - /* we cannot bind, since the response packets don't come from - * the broadcast address */ - sa.sin_family = AF_INET; - sa.sin_port = htons(3006); - inet_aton("255.255.255.255", &sa.sin_addr); - - rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); - if (rc < 0) - goto err; -#endif - return fd; - -err: - close(fd); - return rc; -} - -const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00, - IPAC_MSGT_ID_GET, - 0x01, IPAC_IDTAG_MACADDR, - 0x01, IPAC_IDTAG_IPADDR, - 0x01, IPAC_IDTAG_UNIT, - 0x01, IPAC_IDTAG_LOCATION1, - 0x01, IPAC_IDTAG_LOCATION2, - 0x01, IPAC_IDTAG_EQUIPVERS, - 0x01, IPAC_IDTAG_SWVERSION, - 0x01, IPAC_IDTAG_UNITNAME, - 0x01, IPAC_IDTAG_SERNR, - }; - - -static int bcast_find(int fd) -{ - struct sockaddr_in sa; - - sa.sin_family = AF_INET; - sa.sin_port = htons(3006); - inet_aton("255.255.255.255", &sa.sin_addr); - - return sendto(fd, find_pkt, sizeof(find_pkt), 0, (struct sockaddr *) &sa, sizeof(sa)); -} - -static int parse_response(unsigned char *buf, int len) -{ - uint8_t t_len; - uint8_t t_tag; - uint8_t *cur = buf; - - while (cur < buf + len) { - t_len = *cur++; - t_tag = *cur++; - - printf("%s='%s' ", ipa_ccm_idtag_name(t_tag), cur); - - cur += t_len; - } - printf("\n"); - return 0; -} - -static int read_response(int fd) -{ - unsigned char buf[255]; - struct sockaddr_in sa; - int len; - socklen_t sa_len = sizeof(sa); - - len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sa, &sa_len); - if (len < 0) - return len; - - /* 2 bytes length, 1 byte protocol */ - if (buf[2] != IPAC_PROTO_IPACCESS) - return 0; - - if (buf[4] != IPAC_MSGT_ID_RESP) - return 0; - - return parse_response(buf+6, len-6); -} - -static int bfd_cb(struct osmo_fd *bfd, unsigned int flags) -{ - if (flags & BSC_FD_READ) - return read_response(bfd->fd); - if (flags & BSC_FD_WRITE) { - bfd->when &= ~BSC_FD_WRITE; - return bcast_find(bfd->fd); - } - return 0; -} - -static struct osmo_timer_list timer; - -static void timer_cb(void *_data) -{ - struct osmo_fd *bfd = _data; - - bfd->when |= BSC_FD_WRITE; - - osmo_timer_schedule(&timer, 5, 0); -} - -int main(int argc, char **argv) -{ - struct osmo_fd bfd; - char *ifname = NULL; - int rc; - - printf("abisip-find (C) 2009 by Harald Welte\n"); - printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); - - if (argc < 2) { - fprintf(stdout, "you might need to specify the outgoing\n" - " network interface, e.g. ``%s eth0''\n", argv[0]); - } else { - ifname = argv[1]; - } - - bfd.cb = bfd_cb; - bfd.when = BSC_FD_READ | BSC_FD_WRITE; - bfd.fd = udp_sock(ifname); - if (bfd.fd < 0) { - perror("Cannot create local socket for broadcast udp"); - exit(1); - } - - rc = osmo_fd_register(&bfd); - if (rc < 0) { - fprintf(stderr, "Cannot register FD\n"); - exit(1); - } - - osmo_timer_setup(&timer, timer_cb, &bfd); - osmo_timer_schedule(&timer, 5, 0); - - printf("Trying to find ip.access BTS by broadcast UDP...\n"); - - while (1) { - rc = osmo_select_main(0); - if (rc < 0) - exit(3); - } - - exit(0); -} - diff --git a/src/ipaccess/ipaccess-config.c b/src/ipaccess/ipaccess-config.c deleted file mode 100644 index 6822c06a6..000000000 --- a/src/ipaccess/ipaccess-config.c +++ /dev/null @@ -1,1019 +0,0 @@ -/* ip.access nanoBTS configuration tool */ - -/* (C) 2009-2010 by Harald Welte - * (C) 2009-2011 by Holger Hans Peter Freyther - * (C) 2009-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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct gsm_network *bsc_gsmnet; - -static int net_listen_testnr; -static int restart; -static char *prim_oml_ip; -static char *bts_ip_addr, *bts_ip_mask, *bts_ip_gw; -static char *unit_id; -static uint16_t nv_flags; -static uint16_t nv_mask; -static char *software = NULL; -static int sw_load_state = 0; -static int oml_state = 0; -static int dump_files = 0; -static char *firmware_analysis = NULL; -static int found_trx = 0; -static int loop_tests = 0; - -static void *tall_ctx_config = NULL; -static struct abis_nm_sw_desc *sw_load1 = NULL; -static struct abis_nm_sw_desc *sw_load2 = NULL; - -/* -static uint8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 }; -static uint8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 }; -*/ - -extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what); -extern struct e1inp_line_ops ipaccess_e1inp_line_ops; - -/* Actively connect to a BTS. Currently used by ipaccess-config.c */ -static int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa) -{ - struct e1inp_ts *e1i_ts = &line->ts[0]; - struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd; - int ret, on = 1; - - bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - bfd->cb = ipaccess_fd_cb; - bfd->when = BSC_FD_READ | BSC_FD_WRITE; - bfd->data = line; - bfd->priv_nr = E1INP_SIGN_OML; - - if (bfd->fd < 0) { - LOGP(DLINP, LOGL_ERROR, "could not create TCP socket.\n"); - return -EIO; - } - - ret = setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "could not set socket option\n"); - close(bfd->fd); - return -EIO; - } - - ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa)); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "could not connect socket\n"); - close(bfd->fd); - return ret; - } - - ret = osmo_fd_register(bfd); - if (ret < 0) { - close(bfd->fd); - return ret; - } - return ret; - //return e1inp_line_register(line); -} - -/* configure pseudo E1 line in ip.access style and connect to BTS */ -static int ia_config_connect(struct gsm_bts *bts, struct sockaddr_in *sin) -{ - struct e1inp_line *line; - struct e1inp_ts *sign_ts, *rsl_ts; - struct e1inp_sign_link *oml_link, *rsl_link; - - line = talloc_zero(tall_bsc_ctx, struct e1inp_line); - if (!line) - return -ENOMEM; - - line->driver = e1inp_driver_find("ipa"); - if (!line->driver) { - fprintf(stderr, "cannot `ipa' driver, giving up.\n"); - return -EINVAL; - } - line->ops = &ipaccess_e1inp_line_ops; - - /* create E1 timeslots for signalling and TRAU frames */ - e1inp_ts_config_sign(&line->ts[1-1], line); - e1inp_ts_config_sign(&line->ts[2-1], line); - - /* create signalling links for TS1 */ - sign_ts = &line->ts[1-1]; - rsl_ts = &line->ts[2-1]; - oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, - bts->c0, 0xff, 0); - rsl_link = e1inp_sign_link_create(rsl_ts, E1INP_SIGN_RSL, - bts->c0, 0, 0); - - /* create back-links from bts/trx */ - bts->oml_link = oml_link; - bts->c0->rsl_link = rsl_link; - - /* default port at BTS for incoming connections is 3006 */ - if (sin->sin_port == 0) - sin->sin_port = htons(3006); - - return ipaccess_connect(line, sin); -} - -/* - * Callback function for NACK on the OML NM - * - * Currently we send the config requests but don't check the - * result. The nanoBTS will send us a NACK when we did something the - * BTS didn't like. - */ -static int ipacc_msg_nack(uint8_t mt) -{ - fprintf(stderr, "Failure to set attribute. This seems fatal\n"); - exit(-1); - return 0; -} - -static void check_restart_or_exit(struct gsm_bts_trx *trx) -{ - if (restart) { - abis_nm_ipaccess_restart(trx); - } else { - exit(0); - } -} - -static int ipacc_msg_ack(uint8_t mt, struct gsm_bts_trx *trx) -{ - if (sw_load_state == 1) { - fprintf(stderr, "The new software is activaed.\n"); - check_restart_or_exit(trx); - } else if (oml_state == 1) { - fprintf(stderr, "Set the NV Attributes.\n"); - check_restart_or_exit(trx); - } - - return 0; -} - -static const uint8_t phys_conf_min[] = { 0x02 }; - -static uint16_t build_physconf(uint8_t *physconf_buf, const struct rxlev_stats *st) -{ - uint16_t *whitelist = (uint16_t *) (physconf_buf + 4); - int num_arfcn; - unsigned int arfcnlist_size; - - /* Create whitelist from rxlevels */ - physconf_buf[0] = phys_conf_min[0]; - physconf_buf[1] = NM_IPAC_EIE_ARFCN_WHITE; - num_arfcn = ipac_rxlevstat2whitelist(whitelist, st, 0, 100); - arfcnlist_size = num_arfcn * 2; - *((uint16_t *) (physconf_buf+2)) = htons(arfcnlist_size); - DEBUGP(DNM, "physconf_buf (%s)\n", osmo_hexdump(physconf_buf, arfcnlist_size+4)); - return arfcnlist_size+4; -} - -static int nwl_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_bts_trx *trx; - uint8_t physconf_buf[2*NUM_ARFCNS+16]; - uint16_t physconf_len; - - switch (signal) { - case S_IPAC_NWL_COMPLETE: - trx = signal_data; - DEBUGP(DNM, "received S_IPAC_NWL_COMPLETE signal\n"); - switch (trx->ipaccess.test_nr) { - case NM_IPACC_TESTNO_CHAN_USAGE: - /* Dump RxLev results */ - //rxlev_stat_dump(&trx->ipaccess.rxlev_stat); - /* Create whitelist from results */ - physconf_len = build_physconf(physconf_buf, - &trx->ipaccess.rxlev_stat); - /* Start next test abbout BCCH channel usage */ - ipac_nwl_test_start(trx, NM_IPACC_TESTNO_BCCH_CHAN_USAGE, - physconf_buf, physconf_len); - break; - case NM_IPACC_TESTNO_BCCH_CHAN_USAGE: - /* Dump BCCH RxLev results */ - //rxlev_stat_dump(&trx->ipaccess.rxlev_stat); - /* Create whitelist from results */ - physconf_len = build_physconf(physconf_buf, - &trx->ipaccess.rxlev_stat); - /* Start next test about BCCH info */ - ipac_nwl_test_start(trx, NM_IPACC_TESTNO_BCCH_INFO, - physconf_buf, physconf_len); - break; - case NM_IPACC_TESTNO_BCCH_INFO: - /* re-start full process with CHAN_USAGE */ - if (loop_tests) { - DEBUGP(DNM, "starting next test cycle\n"); - ipac_nwl_test_start(trx, net_listen_testnr, phys_conf_min, - sizeof(phys_conf_min)); - } else { - exit(0); - } - break; - } - break; - } - return 0; -} - -static int nm_state_event(int evt, uint8_t obj_class, void *obj, - struct gsm_nm_state *old_state, struct gsm_nm_state *new_state, - struct abis_om_obj_inst *obj_inst); - -static int nm_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct ipacc_ack_signal_data *ipacc_data; - struct nm_statechg_signal_data *nsd; - - switch (signal) { - case S_NM_IPACC_NACK: - ipacc_data = signal_data; - return ipacc_msg_nack(ipacc_data->msg_type); - case S_NM_IPACC_ACK: - ipacc_data = signal_data; - return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->trx); - case S_NM_IPACC_RESTART_ACK: - printf("The BTS has acked the restart. Exiting.\n"); - exit(0); - break; - case S_NM_IPACC_RESTART_NACK: - printf("The BTS has nacked the restart. Exiting.\n"); - exit(0); - break; - case S_NM_STATECHG_OPER: - case S_NM_STATECHG_ADM: - nsd = signal_data; - nm_state_event(signal, nsd->obj_class, nsd->obj, nsd->old_state, - nsd->new_state, nsd->obj_inst); - break; - default: - break; - } - - return 0; -} - -/* callback function passed to the ABIS OML code */ -static int percent; -static int percent_old; -static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, - void *data, void *param) -{ - struct msgb *msg; - struct gsm_bts_trx *trx; - - if (hook != GSM_HOOK_NM_SWLOAD) - return 0; - - trx = (struct gsm_bts_trx *) data; - - switch (event) { - case NM_MT_LOAD_INIT_ACK: - fprintf(stdout, "Software Load Initiate ACK\n"); - break; - case NM_MT_LOAD_INIT_NACK: - fprintf(stderr, "ERROR: Software Load Initiate NACK\n"); - exit(5); - break; - case NM_MT_LOAD_END_ACK: - fprintf(stderr, "LOAD END ACK..."); - /* now make it the default */ - sw_load_state = 1; - - msg = msgb_alloc(1024, "sw: nvattr"); - msg->l2h = msgb_put(msg, 3); - msg->l3h = &msg->l2h[3]; - - /* activate software */ - if (sw_load1) - abis_nm_put_sw_desc(msg, sw_load1, true); - - if (sw_load2) - abis_nm_put_sw_desc(msg, sw_load2, true); - - /* fill in the data */ - msg->l2h[0] = NM_ATT_IPACC_CUR_SW_CFG; - msg->l2h[1] = msgb_l3len(msg) >> 8; - msg->l2h[2] = msgb_l3len(msg) & 0xff; - printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg)); - abis_nm_ipaccess_set_nvattr(trx, msg->l2h, msgb_l2len(msg)); - msgb_free(msg); - break; - case NM_MT_LOAD_END_NACK: - fprintf(stderr, "ERROR: Software Load End NACK\n"); - exit(3); - break; - case NM_MT_ACTIVATE_SW_NACK: - fprintf(stderr, "ERROR: Activate Software NACK\n"); - exit(4); - break; - case NM_MT_ACTIVATE_SW_ACK: - break; - case NM_MT_LOAD_SEG_ACK: - percent = abis_nm_software_load_status(trx->bts); - if (percent > percent_old) - printf("Software Download Progress: %d%%\n", percent); - percent_old = percent; - break; - case NM_MT_LOAD_ABORT: - fprintf(stderr, "ERROR: Load aborted by the BTS.\n"); - exit(6); - break; - } - return 0; -} - -static void nv_put_ip_if_cfg(struct msgb *nmsg, uint32_t ip, uint32_t mask) -{ - msgb_put_u8(nmsg, NM_ATT_IPACC_IP_IF_CFG); - - msgb_put_u32(nmsg, ip); - msgb_put_u32(nmsg, mask); -} - -static void nv_put_gw_cfg(struct msgb *nmsg, uint32_t addr, uint32_t mask, uint32_t gw) -{ - msgb_put_u8(nmsg, NM_ATT_IPACC_IP_GW_CFG); - msgb_put_u32(nmsg, addr); - msgb_put_u32(nmsg, mask); - msgb_put_u32(nmsg, gw); -} - -static void nv_put_unit_id(struct msgb *nmsg, const char *unit_id) -{ - msgb_tl16v_put(nmsg, NM_ATT_IPACC_UNIT_ID, strlen(unit_id)+1, - (const uint8_t *)unit_id); -} - -static void nv_put_prim_oml(struct msgb *nmsg, uint32_t ip, uint16_t port) -{ - int len; - - /* 0x88 + IP + port */ - len = 1 + sizeof(ip) + sizeof(port); - - msgb_put_u8(nmsg, NM_ATT_IPACC_PRIM_OML_CFG_LIST); - msgb_put_u16(nmsg, len); - - msgb_put_u8(nmsg, 0x88); - - /* IP address */ - msgb_put_u32(nmsg, ip); - - /* port number */ - msgb_put_u16(nmsg, port); -} - -static void nv_put_flags(struct msgb *nmsg, uint16_t nv_flags, uint16_t nv_mask) -{ - msgb_put_u8(nmsg, NM_ATT_IPACC_NV_FLAGS); - msgb_put_u16(nmsg, sizeof(nv_flags) + sizeof(nv_mask)); - msgb_put_u8(nmsg, nv_flags & 0xff); - msgb_put_u8(nmsg, nv_mask & 0xff); - msgb_put_u8(nmsg, nv_flags >> 8); - msgb_put_u8(nmsg, nv_mask >> 8); -} - -/* human-readable test names for the ip.access tests */ -static const struct value_string ipa_test_strs[] = { - { 64, "ccch-usage" }, - { 65, "bcch-usage" }, - { 66, "freq-sync" }, - { 67, "rtp-usage" }, - { 68, "rtp-perf" }, - { 69, "gprs-ccch" }, - { 70, "pccch-usage" }, - { 71, "gprs-usage" }, - { 72, "esta-mf" }, - { 73, "uplink-mf" }, - { 74, "dolink-mf" }, - { 75, "tbf-details" }, - { 76, "tbf-usage" }, - { 77, "llc-data" }, - { 78, "pdch-usage" }, - { 79, "power-control" }, - { 80, "link-adaption" }, - { 81, "tch-usage" }, - { 82, "amr-mf" }, - { 83, "rtp-multiplex-perf" }, - { 84, "rtp-multiplex-usage" }, - { 85, "srtp-multiplex-usage" }, - { 86, "abis-traffic" }, - { 89, "gprs-multiplex-perf" }, - { 90, "gprs-multiplex-usage" }, - { 0, NULL }, -}; - -/* human-readable names for the ip.access nanoBTS NVRAM Flags */ -static const struct value_string ipa_nvflag_strs[] = { - { 0x0001, "static-ip" }, - { 0x0002, "static-gw" }, - { 0x0004, "no-dhcp-vsi" }, - { 0x0008, "dhcp-enabled" }, - { 0x0040, "led-disabled" }, - { 0x0100, "secondary-oml-enabled" }, - { 0x0200, "diag-enabled" }, - { 0x0400, "cli-enabled" }, - { 0x0800, "http-enabled" }, - { 0x1000, "post-enabled" }, - { 0x2000, "snmp-enabled" }, - { 0, NULL } -}; - -/* set the flags in flags/mask according to a string-identified flag and 'enable' */ -static int ipa_nvflag_set(uint16_t *flags, uint16_t *mask, const char *name, int en) -{ - int rc; - rc = get_string_value(ipa_nvflag_strs, name); - if (rc < 0) - return rc; - - *mask |= rc; - if (en) - *flags |= rc; - else - *flags &= ~rc; - - return 0; -} - -static void bootstrap_om(struct gsm_bts_trx *trx) -{ - struct msgb *nmsg = msgb_alloc(1024, "nested msgb"); - int need_to_set_attr = 0; - int len; - - printf("OML link established using TRX %d\n", trx->nr); - - if (unit_id) { - len = strlen(unit_id); - if (len > nmsg->data_len-10) - goto out_err; - printf("setting Unit ID to '%s'\n", unit_id); - nv_put_unit_id(nmsg, unit_id); - need_to_set_attr = 1; - } - if (prim_oml_ip) { - struct in_addr ia; - - if (!inet_aton(prim_oml_ip, &ia)) { - fprintf(stderr, "invalid IP address: %s\n", - prim_oml_ip); - goto out_err; - } - - printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia)); - nv_put_prim_oml(nmsg, ntohl(ia.s_addr), 0); - need_to_set_attr = 1; - } - if (nv_mask) { - printf("setting NV Flags/Mask to 0x%04x/0x%04x\n", - nv_flags, nv_mask); - nv_put_flags(nmsg, nv_flags, nv_mask); - need_to_set_attr = 1; - } - if (bts_ip_addr && bts_ip_mask) { - struct in_addr ia_addr, ia_mask; - - if (!inet_aton(bts_ip_addr, &ia_addr)) { - fprintf(stderr, "invalid IP address: %s\n", - bts_ip_addr); - goto out_err; - } - - if (!inet_aton(bts_ip_mask, &ia_mask)) { - fprintf(stderr, "invalid IP address: %s\n", - bts_ip_mask); - goto out_err; - } - - printf("setting static IP Address/Mask\n"); - nv_put_ip_if_cfg(nmsg, ntohl(ia_addr.s_addr), ntohl(ia_mask.s_addr)); - need_to_set_attr = 1; - } - if (bts_ip_gw) { - struct in_addr ia_gw; - - if (!inet_aton(bts_ip_gw, &ia_gw)) { - fprintf(stderr, "invalid IP address: %s\n", - bts_ip_gw); - goto out_err; - } - - printf("setting static IP Gateway\n"); - /* we only set the default gateway with zero addr/mask */ - nv_put_gw_cfg(nmsg, 0, 0, ntohl(ia_gw.s_addr)); - need_to_set_attr = 1; - } - - if (need_to_set_attr) { - abis_nm_ipaccess_set_nvattr(trx, nmsg->head, nmsg->len); - oml_state = 1; - } - - if (restart && !prim_oml_ip && !software) { - printf("restarting BTS\n"); - abis_nm_ipaccess_restart(trx); - } - -out_err: - msgb_free(nmsg); -} - -static int nm_state_event(int evt, uint8_t obj_class, void *obj, - struct gsm_nm_state *old_state, struct gsm_nm_state *new_state, - struct abis_om_obj_inst *obj_inst) -{ - if (obj_class == NM_OC_BASEB_TRANSC) { - if (!found_trx && obj_inst->trx_nr != 0xff) { - struct gsm_bts_trx *trx = container_of(obj, struct gsm_bts_trx, bb_transc); - bootstrap_om(trx); - found_trx = 1; - } - } else if (evt == S_NM_STATECHG_OPER && - obj_class == NM_OC_RADIO_CARRIER && - new_state->availability == 3) { - struct gsm_bts_trx *trx = obj; - - if (net_listen_testnr) - ipac_nwl_test_start(trx, net_listen_testnr, - phys_conf_min, sizeof(phys_conf_min)); - else if (software) { - int rc; - printf("Attempting software upload with '%s'\n", software); - rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx); - if (rc < 0) { - fprintf(stderr, "Failed to start software load\n"); - exit(-3); - } - } - } - return 0; -} - -static struct abis_nm_sw_desc *create_swload(struct sdp_header *header) -{ - struct abis_nm_sw_desc *load; - - load = talloc_zero(tall_ctx_config, struct abis_nm_sw_desc); - - osmo_strlcpy((char *)load->file_id, header->firmware_info.sw_part, - sizeof(load->file_id)); - load->file_id_len = strlen((char*)load->file_id) + 1; - - osmo_strlcpy((char *)load->file_version, header->firmware_info.version, - sizeof(load->file_version)); - load->file_version_len = strlen((char*)load->file_version) + 1; - - return load; -} - -static int find_sw_load_params(const char *filename) -{ - struct stat stat; - struct sdp_header *header; - struct llist_head *entry; - int fd; - void *tall_firm_ctx = 0; - - entry = talloc_zero(tall_firm_ctx, struct llist_head); - INIT_LLIST_HEAD(entry); - - fd = open(filename, O_RDONLY); - if (!fd) { - perror("nada"); - return -1; - } - - /* verify the file */ - if (fstat(fd, &stat) == -1) { - perror("Can not stat the file"); - close(fd); - return -1; - } - - ipaccess_analyze_file(fd, stat.st_size, 0, entry); - if (close(fd) != 0) { - perror("Close failed.\n"); - return -1; - } - - /* try to find what we are looking for */ - llist_for_each_entry(header, entry, entry) { - if (ntohs(header->firmware_info.more_more_magic) == 0x1000) { - sw_load1 = create_swload(header); - } else if (ntohs(header->firmware_info.more_more_magic) == 0x2001) { - sw_load2 = create_swload(header); - } - } - - if (!sw_load1 || !sw_load2) { - fprintf(stderr, "Did not find data.\n"); - talloc_free(tall_firm_ctx); - return -1; - } - - talloc_free(tall_firm_ctx); - return 0; -} - -static void dump_entry(struct sdp_header_item *sub_entry, int part, int fd) -{ - int out_fd; - int copied; - char filename[4096]; - off_t target; - - if (!dump_files) - return; - - if (sub_entry->header_entry.something1 == 0) - return; - - snprintf(filename, sizeof(filename), "part.%d", part++); - out_fd = open(filename, O_WRONLY | O_CREAT, 0660); - if (out_fd < 0) { - perror("Can not dump firmware"); - return; - } - - target = sub_entry->absolute_offset + ntohl(sub_entry->header_entry.start) + 4; - if (lseek(fd, target, SEEK_SET) != target) { - perror("seek failed"); - close(out_fd); - return; - } - - for (copied = 0; copied < ntohl(sub_entry->header_entry.length); ++copied) { - char c; - if (read(fd, &c, sizeof(c)) != sizeof(c)) { - perror("copy failed"); - break; - } - - if (write(out_fd, &c, sizeof(c)) != sizeof(c)) { - perror("write failed"); - break; - } - } - - close(out_fd); -} - -static void analyze_firmware(const char *filename) -{ - struct stat stat; - struct sdp_header *header; - struct sdp_header_item *sub_entry; - struct llist_head *entry; - int fd; - void *tall_firm_ctx = 0; - int part = 0; - - entry = talloc_zero(tall_firm_ctx, struct llist_head); - INIT_LLIST_HEAD(entry); - - printf("Opening possible firmware '%s'\n", filename); - fd = open(filename, O_RDONLY); - if (!fd) { - perror("nada"); - return; - } - - /* verify the file */ - if (fstat(fd, &stat) == -1) { - perror("Can not stat the file"); - close(fd); - return; - } - - ipaccess_analyze_file(fd, stat.st_size, 0, entry); - - llist_for_each_entry(header, entry, entry) { - printf("Printing header information:\n"); - printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic)); - printf("header_length: %u\n", ntohl(header->firmware_info.header_length)); - printf("file_length: %u\n", ntohl(header->firmware_info.file_length)); - printf("sw_part: %.20s\n", header->firmware_info.sw_part); - printf("text1: %.64s\n", header->firmware_info.text1); - printf("time: %.12s\n", header->firmware_info.time); - printf("date: %.14s\n", header->firmware_info.date); - printf("text2: %.10s\n", header->firmware_info.text2); - printf("version: %.20s\n", header->firmware_info.version); - printf("subitems...\n"); - - llist_for_each_entry(sub_entry, &header->header_list, entry) { - printf("\tsomething1: %u\n", sub_entry->header_entry.something1); - printf("\ttext1: %.64s\n", sub_entry->header_entry.text1); - printf("\ttime: %.12s\n", sub_entry->header_entry.time); - printf("\tdate: %.14s\n", sub_entry->header_entry.date); - printf("\ttext2: %.10s\n", sub_entry->header_entry.text2); - printf("\tversion: %.20s\n", sub_entry->header_entry.version); - printf("\tlength: %u\n", ntohl(sub_entry->header_entry.length)); - printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1)); - printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2)); - printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start)); - printf("\tabs. offset: 0x%lx\n", sub_entry->absolute_offset); - printf("\n\n"); - - dump_entry(sub_entry, part++, fd); - } - printf("\n\n"); - } - - if (close(fd) != 0) { - perror("Close failed.\n"); - return; - } - - talloc_free(tall_firm_ctx); -} - -static void print_usage(void) -{ - printf("Usage: ipaccess-config IP_OF_BTS\n"); -} - -static void print_help(void) -{ -#if 0 - printf("Commands for reading from the BTS:\n"); - printf(" -D --dump\t\t\tDump the BTS configuration\n"); - printf("\n"); -#endif - printf("Commands for writing to the BTS:\n"); - printf(" -u --unit-id UNIT_ID\t\tSet the Unit ID of the BTS\n"); - printf(" -o --oml-ip IP\t\tSet primary OML IP (IP of your BSC)\n"); - printf(" -i --ip-address IP/MASK\tSet static IP address + netmask of BTS\n"); - printf(" -g --ip-gateway IP\t\tSet static IP gateway of BTS\n"); - printf(" -r --restart\t\t\tRestart the BTS (after other operations)\n"); - printf(" -n --nvram-flags FLAGS/MASK\tSet NVRAM attributes\n"); - printf(" -S --nvattr-set FLAG\tSet one additional NVRAM attribute\n"); - printf(" -U --nvattr-unset FLAG\tSet one additional NVRAM attribute\n"); - printf(" -l --listen TESTNR\t\tPerform specified test number\n"); - printf(" -L --Listen TEST_NAME\t\tPerform specified test\n"); - printf(" -s --stream-id ID\t\tSet the IPA Stream Identifier for OML\n"); - printf(" -d --software FIRMWARE\tDownload firmware into BTS\n"); - printf("\n"); - printf("Miscellaneous commands:\n"); - printf(" -h --help\t\t\tthis text\n"); - printf(" -H --HELP\t\t\tPrint parameter details.\n"); - printf(" -f --firmware FIRMWARE\tProvide firmware information\n"); - printf(" -w --write-firmware\t\tThis will dump the firmware parts to the filesystem. Use with -f.\n"); - printf(" -p --loop\t\t\tLoop the tests executed with the --listen command.\n"); -} - -static void print_value_string(const struct value_string *val, int size) -{ - int i; - - for (i = 0; i < size - 1; ++i) { - char sep = val[i + 1].str == NULL ? '.' : ','; - printf("%s%c ", val[i].str, sep); - } - printf("\n"); -} - -static void print_options(void) -{ - - printf("Options for NVRAM (-S,-U):\n "); - print_value_string(&ipa_nvflag_strs[0], ARRAY_SIZE(ipa_nvflag_strs)); - - printf("Options for Tests (-L):\n "); - print_value_string(&ipa_test_strs[0], ARRAY_SIZE(ipa_test_strs)); -} - -extern void bts_model_nanobts_init(); - -int main(int argc, char **argv) -{ - struct gsm_bts *bts; - struct sockaddr_in sin; - int rc, option_index = 0, stream_id = 0xff; - - tall_ctx_config = talloc_named_const(NULL, 0, "ipaccess-config"); - msgb_talloc_ctx_init(tall_ctx_config, 0); - - osmo_init_logging(&log_info); - log_parse_category_mask(osmo_stderr_target, "DNM,0"); - bts_model_nanobts_init(); - - printf("ipaccess-config (C) 2009-2010 by Harald Welte and others\n"); - printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); - - while (1) { - int c; - unsigned long ul; - char *slash; - static struct option long_options[] = { - { "unit-id", 1, 0, 'u' }, - { "oml-ip", 1, 0, 'o' }, - { "ip-address", 1, 0, 'i' }, - { "ip-gateway", 1, 0, 'g' }, - { "restart", 0, 0, 'r' }, - { "nvram-flags", 1, 0, 'n' }, - { "nvattr-set", 1, 0, 'S' }, - { "nvattr-unset", 1, 0, 'U' }, - { "help", 0, 0, 'h' }, - { "HELP", 0, 0, 'H' }, - { "listen", 1, 0, 'l' }, - { "Listen", 1, 0, 'L' }, - { "stream-id", 1, 0, 's' }, - { "software", 1, 0, 'd' }, - { "firmware", 1, 0, 'f' }, - { "write-firmware", 0, 0, 'w' }, - { "disable-color", 0, 0, 'c'}, - { "loop", 0, 0, 'p' }, - { 0, 0, 0, 0 }, - }; - - c = getopt_long(argc, argv, "u:o:i:g:rn:S:U:l:L:hs:d:f:wcpH", long_options, - &option_index); - - if (c == -1) - break; - - switch (c) { - case 'u': - unit_id = optarg; - break; - case 'o': - prim_oml_ip = optarg; - break; - case 'i': - slash = strchr(optarg, '/'); - if (!slash) - exit(2); - bts_ip_addr = optarg; - *slash = 0; - bts_ip_mask = slash+1; - break; - case 'g': - bts_ip_gw = optarg; - break; - case 'r': - restart = 1; - break; - case 'n': - slash = strchr(optarg, '/'); - if (!slash) - exit(2); - ul = strtoul(optarg, NULL, 16); - nv_flags = ul & 0xffff; - ul = strtoul(slash+1, NULL, 16); - nv_mask = ul & 0xffff; - break; - case 'S': - if (ipa_nvflag_set(&nv_flags, &nv_mask, optarg, 1) < 0) - exit(2); - break; - case 'U': - if (ipa_nvflag_set(&nv_flags, &nv_mask, optarg, 0) < 0) - exit(2); - break; - case 'l': - net_listen_testnr = atoi(optarg); - break; - case 'L': - net_listen_testnr = get_string_value(ipa_test_strs, - optarg); - if (net_listen_testnr < 0) { - fprintf(stderr, - "The test '%s' is not known. Use -H to" - " see available tests.\n", optarg); - exit(2); - } - break; - case 's': - stream_id = atoi(optarg); - break; - case 'd': - software = strdup(optarg); - if (find_sw_load_params(optarg) != 0) - exit(0); - break; - case 'f': - firmware_analysis = optarg; - break; - case 'w': - dump_files = 1; - break; - case 'c': - log_set_use_color(osmo_stderr_target, 0); - break; - case 'p': - loop_tests = 1; - break; - case 'h': - print_usage(); - print_help(); - exit(0); - case 'H': - print_options(); - exit(0); - } - }; - - if (firmware_analysis) - analyze_firmware(firmware_analysis); - - if (optind >= argc) { - /* only warn if we have not done anything else */ - if (!firmware_analysis) - fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n"); - exit(2); - } - libosmo_abis_init(tall_ctx_config); - - bsc_gsmnet = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); - if (!bsc_gsmnet) - exit(1); - - bts = gsm_bts_alloc_register(bsc_gsmnet, GSM_BTS_TYPE_NANOBTS, - HARDCODED_BSIC); - /* ip.access supports up to 4 chained TRX */ - gsm_bts_trx_alloc(bts); - gsm_bts_trx_alloc(bts); - gsm_bts_trx_alloc(bts); - bts->oml_tei = stream_id; - - osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL); - osmo_signal_register_handler(SS_IPAC_NWL, nwl_sig_cb, NULL); - - ipac_nwl_init(); - - printf("Trying to connect to ip.access BTS ...\n"); - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - inet_aton(argv[optind], &sin.sin_addr); - rc = ia_config_connect(bts, &sin); - if (rc < 0) { - perror("Error connecting to the BTS"); - exit(1); - } - - bts->oml_link->ts->sign.delay = 10; - bts->c0->rsl_link->ts->sign.delay = 10; - while (1) { - rc = osmo_select_main(0); - if (rc < 0) - exit(3); - } - - exit(0); -} - diff --git a/src/ipaccess/ipaccess-firmware.c b/src/ipaccess/ipaccess-firmware.c deleted file mode 100644 index 5f55bb526..000000000 --- a/src/ipaccess/ipaccess-firmware.c +++ /dev/null @@ -1,135 +0,0 @@ -/* Routines for parsing an ipacces SDP firmware file */ - -/* (C) 2009 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 . - * - */ - -#include -#include -#include - -#include -#include -#include -#include - -#define PART_LENGTH 138 - -osmo_static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); -osmo_static_assert(sizeof(struct sdp_firmware) == 158, _right_header_length); - -/* more magic, the second "int" in the header */ -static char more_magic[] = { 0x10, 0x02 }; - -int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset, struct llist_head *list) -{ - struct sdp_firmware *firmware_header = 0; - struct sdp_header *header; - char buf[4096]; - int rc, i; - uint16_t table_size; - uint16_t table_offset; - off_t table_start; - - - rc = read(fd, buf, sizeof(*firmware_header)); - if (rc < 0) { - perror("Can not read header start."); - return -1; - } - - firmware_header = (struct sdp_firmware *) &buf[0]; - if (strncmp(firmware_header->magic, " SDP", 4) != 0) { - fprintf(stderr, "Wrong magic.\n"); - return -1; - } - - if (memcmp(firmware_header->more_magic, more_magic, 2) != 0) { - fprintf(stderr, "Wrong more magic. Got: 0x%x 0x%x vs. 0x%x 0x%x\n", - firmware_header->more_magic[0] & 0xff, firmware_header->more_magic[1] & 0xff, - more_magic[0], more_magic[1]); - return -1; - } - - - if (ntohl(firmware_header->file_length) != st_size) { - fprintf(stderr, "The filesize and the header do not match.\n"); - return -1; - } - - /* add the firmware */ - header = talloc_zero(list, struct sdp_header); - header->firmware_info = *firmware_header; - INIT_LLIST_HEAD(&header->header_list); - llist_add(&header->entry, list); - - table_offset = ntohs(firmware_header->table_offset); - table_start = lseek(fd, table_offset, SEEK_CUR); - if (table_start == -1) { - fprintf(stderr, "Failed to seek to the rel position: 0x%x\n", table_offset); - return -1; - } - - if (read(fd, &table_size, sizeof(table_size)) != sizeof(table_size)) { - fprintf(stderr, "The table size could not be read.\n"); - return -1; - } - - table_size = ntohs(table_size); - - if (table_size % PART_LENGTH != 0) { - fprintf(stderr, "The part length seems to be wrong: 0x%x\n", table_size); - return -1; - } - - /* look into each firmware now */ - for (i = 0; i < table_size / PART_LENGTH; ++i) { - struct sdp_header_entry entry; - struct sdp_header_item *header_entry; - unsigned int offset = table_start + 2; - offset += i * 138; - - if (lseek(fd, offset, SEEK_SET) != offset) { - fprintf(stderr, "Can not seek to the offset: %u.\n", offset); - return -1; - } - - rc = read(fd, &entry, sizeof(entry)); - if (rc != sizeof(entry)) { - fprintf(stderr, "Can not read the header entry.\n"); - return -1; - } - - header_entry = talloc_zero(header, struct sdp_header_item); - header_entry->header_entry = entry; - header_entry->absolute_offset = base_offset; - llist_add(&header_entry->entry, &header->header_list); - - /* now we need to find the SDP file... */ - offset = ntohl(entry.start) + 4 + base_offset; - if (lseek(fd, offset, SEEK_SET) != offset) { - perror("can't seek to sdp"); - return -1; - } - - - ipaccess_analyze_file(fd, ntohl(entry.length), offset, list); - } - - return 0; -} - diff --git a/src/ipaccess/ipaccess-proxy.c b/src/ipaccess/ipaccess-proxy.c deleted file mode 100644 index d3674426c..000000000 --- a/src/ipaccess/ipaccess-proxy.c +++ /dev/null @@ -1,1226 +0,0 @@ -/* OpenBSC Abis/IP proxy ip.access nanoBTS */ - -/* (C) 2009 by Harald Welte - * (C) 2010 by On-Waves - * (C) 2010 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* one instance of an ip.access protocol proxy */ -struct ipa_proxy { - /* socket where we listen for incoming OML from BTS */ - struct osmo_fd oml_listen_fd; - /* socket where we listen for incoming RSL from BTS */ - struct osmo_fd rsl_listen_fd; - /* list of BTS's (struct ipa_bts_conn */ - struct llist_head bts_list; - /* the BSC reconnect timer */ - struct osmo_timer_list reconn_timer; - /* global GPRS NS data */ - struct in_addr gprs_addr; - struct in_addr listen_addr; -}; - -/* global pointer to the proxy structure */ -static struct ipa_proxy *ipp; - -struct ipa_proxy_conn { - struct osmo_fd fd; - struct llist_head tx_queue; - struct ipa_bts_conn *bts_conn; -}; -#define MAX_TRX 4 - -/* represents a particular BTS in our proxy */ -struct ipa_bts_conn { - /* list of BTS's (ipa_proxy->bts_list) */ - struct llist_head list; - /* back pointer to the proxy which we belong to */ - struct ipa_proxy *ipp; - /* the unit ID as determined by CCM */ - struct { - uint16_t site_id; - uint16_t bts_id; - } unit_id; - - /* incoming connections from BTS */ - struct ipa_proxy_conn *oml_conn; - struct ipa_proxy_conn *rsl_conn[MAX_TRX]; - - /* outgoing connections to BSC */ - struct ipa_proxy_conn *bsc_oml_conn; - struct ipa_proxy_conn *bsc_rsl_conn[MAX_TRX]; - - /* UDP sockets for BTS and BSC injection */ - struct osmo_fd udp_bts_fd; - struct osmo_fd udp_bsc_fd; - - /* NS data */ - struct in_addr bts_addr; - struct osmo_fd gprs_ns_fd; - int gprs_local_port; - uint16_t gprs_orig_port; - uint32_t gprs_orig_ip; - - char *id_tags[256]; - uint8_t *id_resp; - unsigned int id_resp_len; -}; - -enum ipp_fd_type { - OML_FROM_BTS = 1, - RSL_FROM_BTS = 2, - OML_TO_BSC = 3, - RSL_TO_BSC = 4, - UDP_TO_BTS = 5, - UDP_TO_BSC = 6, -}; - -/* some of the code against we link from OpenBSC needs this */ -void *tall_bsc_ctx; - -static char *listen_ipaddr; -static char *bsc_ipaddr; -static char *gprs_ns_ipaddr; - -static int gprs_ns_cb(struct osmo_fd *bfd, unsigned int what); - -#define PROXY_ALLOC_SIZE 1200 - -static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp, - uint16_t site_id, - uint16_t bts_id) -{ - struct ipa_bts_conn *ipbc; - - llist_for_each_entry(ipbc, &ipp->bts_list, list) { - if (ipbc->unit_id.site_id == site_id && - ipbc->unit_id.bts_id == bts_id) - return ipbc; - } - - return NULL; -} - -struct ipa_proxy_conn *alloc_conn(void) -{ - struct ipa_proxy_conn *ipc; - - ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn); - if (!ipc) - return NULL; - - INIT_LLIST_HEAD(&ipc->tx_queue); - - return ipc; -} - -static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp) -{ - unsigned int i, len; - - for (i = 0; i <= 0xff; i++) { - if (!TLVP_PRESENT(tlvp, i)) - continue; - - len = TLVP_LEN(tlvp, i); -#if 0 - if (!ipbc->id_tags[i]) - ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len); - else -#endif - ipbc->id_tags[i] = talloc_realloc_size(ipbc, - ipbc->id_tags[i], len); - if (!ipbc->id_tags[i]) - return -ENOMEM; - - memset(ipbc->id_tags[i], 0, len); - //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len); - } - return 0; -} - - -static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data); - -#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id) - -static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line, - struct ipa_bts_conn *ipbc, uint8_t trx_id) -{ - if (ipbc) - logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id, - ipbc->unit_id.bts_id, trx_id); - else - logp2(ss, lvl, file, line, 0, "unknown "); -} - -static int handle_udp_read(struct osmo_fd *bfd) -{ - struct ipa_bts_conn *ipbc = bfd->data; - struct ipa_proxy_conn *other_conn = NULL; - struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP"); - struct ipaccess_head *hh; - int ret; - - /* with UDP sockets, we cannot read partial packets but have to read - * all of it in one go */ - hh = (struct ipaccess_head *) msg->data; - ret = recv(bfd->fd, msg->data, msg->data_len, 0); - if (ret < 0) { - if (errno != EAGAIN) - LOGP(DLINP, LOGL_ERROR, "recv error %s\n", strerror(errno)); - msgb_free(msg); - return ret; - } - if (ret == 0) { - DEBUGP(DLINP, "UDP peer disappeared, dead socket\n"); - osmo_fd_unregister(bfd); - close(bfd->fd); - bfd->fd = -1; - msgb_free(msg); - return -EIO; - } - if (ret < sizeof(*hh)) { - DEBUGP(DLINP, "could not even read header!?!\n"); - msgb_free(msg); - return -EIO; - } - msgb_put(msg, ret); - msg->l2h = msg->data + sizeof(*hh); - DEBUGP(DLMI, "UDP RX: %s\n", osmo_hexdump(msg->data, msg->len)); - - if (hh->len != msg->len - sizeof(*hh)) { - DEBUGP(DLINP, "length (%u/%u) disagrees with header(%u)\n", - msg->len, msg->len - 3, hh->len); - msgb_free(msg); - return -EIO; - } - - switch (bfd->priv_nr & 0xff) { - case UDP_TO_BTS: - /* injection towards BTS */ - switch (hh->proto) { - case IPAC_PROTO_RSL: - /* FIXME: what to do about TRX > 0 */ - other_conn = ipbc->rsl_conn[0]; - break; - default: - DEBUGP(DLINP, "Unknown protocol 0x%02x, sending to " - "OML FD\n", hh->proto); - /* fall through */ - case IPAC_PROTO_IPACCESS: - case IPAC_PROTO_OML: - other_conn = ipbc->oml_conn; - break; - } - break; - case UDP_TO_BSC: - /* injection towards BSC */ - switch (hh->proto) { - case IPAC_PROTO_RSL: - /* FIXME: what to do about TRX > 0 */ - other_conn = ipbc->bsc_rsl_conn[0]; - break; - default: - DEBUGP(DLINP, "Unknown protocol 0x%02x, sending to " - "OML FD\n", hh->proto); - /* fall through */ - case IPAC_PROTO_IPACCESS: - case IPAC_PROTO_OML: - other_conn = ipbc->bsc_oml_conn; - break; - } - break; - default: - DEBUGP(DLINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr); - break; - } - - if (other_conn) { - /* enqueue the message for TX on the respective FD */ - msgb_enqueue(&other_conn->tx_queue, msg); - other_conn->fd.when |= BSC_FD_WRITE; - } else - msgb_free(msg); - - return 0; -} - -static int handle_udp_write(struct osmo_fd *bfd) -{ - /* not implemented yet */ - bfd->when &= ~BSC_FD_WRITE; - - return -EIO; -} - -/* callback from select.c in case one of the fd's can be read/written */ -static int udp_fd_cb(struct osmo_fd *bfd, unsigned int what) -{ - int rc = 0; - - if (what & BSC_FD_READ) - rc = handle_udp_read(bfd); - if (what & BSC_FD_WRITE) - rc = handle_udp_write(bfd); - - return rc; -} - - -static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd, - uint16_t site_id, uint16_t bts_id, - uint16_t trx_id, struct tlv_parsed *tlvp, - struct msgb *msg) -{ - struct ipa_bts_conn *ipbc; - uint16_t udp_port; - int ret = 0; - struct sockaddr_in sin; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - inet_aton(bsc_ipaddr, &sin.sin_addr); - - DEBUGP(DLINP, "(%u/%u/%u) New BTS connection: ", - site_id, bts_id, trx_id); - - /* OML needs to be established before RSL */ - if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) { - DEBUGPC(DLINP, "Not a OML connection ?!?\n"); - return -EIO; - } - - /* allocate new BTS connection data structure */ - ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn); - if (!ipbc) { - ret = -ENOMEM; - goto err_out; - } - - DEBUGPC(DLINP, "Created BTS Conn data structure\n"); - ipbc->ipp = ipp; - ipbc->unit_id.site_id = site_id; - ipbc->unit_id.bts_id = bts_id; - ipbc->oml_conn = ipc; - ipc->bts_conn = ipbc; - - /* store the content of the ID TAGS for later reference */ - store_idtags(ipbc, tlvp); - ipbc->id_resp_len = msg->len; - ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len); - memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len); - - /* Create OML TCP connection towards BSC */ - sin.sin_port = htons(IPA_TCP_PORT_OML); - ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc); - if (!ipbc->bsc_oml_conn) { - ret = -EIO; - goto err_bsc_conn; - } - - DEBUGP(DLINP, "(%u/%u/%u) OML Connected to BSC\n", - site_id, bts_id, trx_id); - - /* Create UDP socket for BTS packet injection */ - udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100); - ret = make_sock(&ipbc->udp_bts_fd, IPPROTO_UDP, INADDR_ANY, udp_port, - UDP_TO_BTS, udp_fd_cb, ipbc); - if (ret < 0) - goto err_udp_bts; - DEBUGP(DLINP, "(%u/%u/%u) Created UDP socket for injection " - "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port); - - /* Create UDP socket for BSC packet injection */ - udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100); - ret = make_sock(&ipbc->udp_bsc_fd, IPPROTO_UDP, INADDR_ANY, udp_port, - UDP_TO_BSC, udp_fd_cb, ipbc); - if (ret < 0) - goto err_udp_bsc; - DEBUGP(DLINP, "(%u/%u/%u) Created UDP socket for injection " - "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port); - - - /* GPRS NS related code */ - if (gprs_ns_ipaddr) { - struct sockaddr_in sock; - socklen_t len = sizeof(sock); - struct in_addr addr; - uint32_t ip; - - inet_aton(listen_ipaddr, &addr); - ip = ntohl(addr.s_addr); /* make_sock() needs host byte order */ - ret = make_sock(&ipbc->gprs_ns_fd, IPPROTO_UDP, ip, 0, 0, - gprs_ns_cb, ipbc); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Creating the GPRS socket failed.\n"); - goto err_udp_bsc; - } - - ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len); - ipbc->gprs_local_port = ntohs(sock.sin_port); - LOGP(DLINP, LOGL_NOTICE, - "Created GPRS NS Socket. Listening on: %s:%d\n", - inet_ntoa(sock.sin_addr), ipbc->gprs_local_port); - - ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len); - ipbc->bts_addr = sock.sin_addr; - } - - llist_add(&ipbc->list, &ipp->bts_list); - - return 0; - -err_udp_bsc: - osmo_fd_unregister(&ipbc->udp_bts_fd); -err_udp_bts: - osmo_fd_unregister(&ipbc->bsc_oml_conn->fd); - close(ipbc->bsc_oml_conn->fd.fd); - talloc_free(ipbc->bsc_oml_conn); - ipbc->bsc_oml_conn = NULL; -err_bsc_conn: - talloc_free(ipbc->id_resp); - talloc_free(ipbc); -#if 0 - osmo_fd_unregister(bfd); - close(bfd->fd); - talloc_free(bfd); -#endif -err_out: - return ret; -} - -static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg, - struct osmo_fd *bfd) -{ - struct tlv_parsed tlvp; - uint8_t msg_type = *(msg->l2h); - struct ipaccess_unit unit_data; - struct ipa_bts_conn *ipbc; - int ret = 0; - - switch (msg_type) { - case IPAC_MSGT_PING: - ret = ipa_ccm_send_pong(bfd->fd); - break; - case IPAC_MSGT_PONG: - DEBUGP(DLMI, "PONG!\n"); - break; - case IPAC_MSGT_ID_RESP: - DEBUGP(DLMI, "ID_RESP "); - /* parse tags, search for Unit ID */ - ipa_ccm_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2, - msgb_l2len(msg)-2); - DEBUGP(DLMI, "\n"); - - if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) { - LOGP(DLINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n"); - return -EIO; - } - - /* lookup BTS, create sign_link, ... */ - memset(&unit_data, 0, sizeof(unit_data)); - ipa_parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT), - &unit_data); - ipbc = find_bts_by_unitid(ipp, unit_data.site_id, unit_data.bts_id); - if (!ipbc) { - /* We have not found an ipbc (per-bts proxy instance) - * for this BTS yet. The first connection of a new BTS must - * be a OML connection. We allocate the associated data structures, - * and try to connect to the remote end */ - - return ipbc_alloc_connect(ipc, bfd, unit_data.site_id, - unit_data.bts_id, - unit_data.trx_id, &tlvp, msg); - /* if this fails, the caller will clean up bfd */ - } else { - struct sockaddr_in sin; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - inet_aton(bsc_ipaddr, &sin.sin_addr); - - DEBUGP(DLINP, "Identified BTS %u/%u/%u\n", - unit_data.site_id, unit_data.bts_id, unit_data.trx_id); - - if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) { - LOGP(DLINP, LOGL_ERROR, "Second OML connection from " - "same BTS ?!?\n"); - return 0; - } - - if (unit_data.trx_id >= MAX_TRX) { - LOGP(DLINP, LOGL_ERROR, "We don't support more " - "than %u TRX\n", MAX_TRX); - return -EINVAL; - } - - ipc->bts_conn = ipbc; - /* store TRX number in higher 8 bit of the bfd private number */ - bfd->priv_nr |= unit_data.trx_id << 8; - ipbc->rsl_conn[unit_data.trx_id] = ipc; - - /* Create RSL TCP connection towards BSC */ - sin.sin_port = htons(IPA_TCP_PORT_RSL); - ipbc->bsc_rsl_conn[unit_data.trx_id] = - connect_bsc(&sin, RSL_TO_BSC | (unit_data.trx_id << 8), ipbc); - if (!ipbc->bsc_oml_conn) - return -EIO; - DEBUGP(DLINP, "(%u/%u/%u) Connected RSL to BSC\n", - unit_data.site_id, unit_data.bts_id, unit_data.trx_id); - } - break; - case IPAC_MSGT_ID_GET: - DEBUGP(DLMI, "ID_GET\n"); - if ((bfd->priv_nr & 0xff) != OML_TO_BSC && - (bfd->priv_nr & 0xff) != RSL_TO_BSC) { - DEBUGP(DLINP, "IDentity REQuest from BTS ?!?\n"); - return -EIO; - } - ipbc = ipc->bts_conn; - if (!ipbc) { - DEBUGP(DLINP, "ID_GET from BSC before we have ID_RESP from BTS\n"); - return -EIO; - } - ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len); - if (ret != ipbc->id_resp_len) { - LOGP(DLINP, LOGL_ERROR, "Partial write: %d of %d\n", - ret, ipbc->id_resp_len); - return -EIO; - } - ret = 0; - break; - case IPAC_MSGT_ID_ACK: - DEBUGP(DLMI, "ID_ACK? -> ACK!\n"); - ret = ipa_ccm_send_id_ack(bfd->fd); - break; - default: - LOGP(DLMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type); - return 1; - break; - } - return ret; -} - -struct msgb *ipaccess_proxy_read_msg(struct osmo_fd *bfd, int *error) -{ - struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP"); - struct ipaccess_head *hh; - int len, ret = 0; - - if (!msg) { - *error = -ENOMEM; - return NULL; - } - - /* first read our 3-byte header */ - hh = (struct ipaccess_head *) msg->data; - ret = recv(bfd->fd, msg->data, 3, 0); - if (ret < 0) { - if (errno != EAGAIN) - LOGP(DLINP, LOGL_ERROR, "recv error: %s\n", strerror(errno)); - msgb_free(msg); - *error = ret; - return NULL; - } else if (ret == 0) { - msgb_free(msg); - *error = ret; - return NULL; - } - - msgb_put(msg, ret); - - /* then read te length as specified in header */ - msg->l2h = msg->data + sizeof(*hh); - len = ntohs(hh->len); - ret = recv(bfd->fd, msg->l2h, len, 0); - if (ret < len) { - LOGP(DLINP, LOGL_ERROR, "short read!\n"); - msgb_free(msg); - *error = -EIO; - return NULL; - } - msgb_put(msg, ret); - - return msg; -} - -static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc, - unsigned int priv_nr) -{ - struct ipa_proxy_conn *bsc_conn; - unsigned int trx_id = priv_nr >> 8; - - switch (priv_nr & 0xff) { - case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */ - bsc_conn = ipbc->bsc_oml_conn; - break; - case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */ - bsc_conn = ipbc->bsc_rsl_conn[trx_id]; - break; - case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */ - bsc_conn = ipbc->oml_conn; - break; - case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */ - bsc_conn = ipbc->rsl_conn[trx_id]; - break; - default: - bsc_conn = NULL; - break; - } - return bsc_conn; -} - -static void reconn_tmr_cb(void *data) -{ - struct ipa_proxy *ipp = data; - struct ipa_bts_conn *ipbc; - struct sockaddr_in sin; - int i; - - DEBUGP(DLINP, "Running reconnect timer\n"); - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - inet_aton(bsc_ipaddr, &sin.sin_addr); - - llist_for_each_entry(ipbc, &ipp->bts_list, list) { - /* if OML to BSC is dead, try to restore it */ - if (ipbc->oml_conn && !ipbc->bsc_oml_conn) { - sin.sin_port = htons(IPA_TCP_PORT_OML); - logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, 0); - LOGPC(DLINP, LOGL_NOTICE, "OML Trying to reconnect\n"); - ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc); - if (!ipbc->bsc_oml_conn) - goto reschedule; - logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, 0); - LOGPC(DLINP, LOGL_NOTICE, "OML Reconnected\n"); - } - /* if we (still) don't have a OML connection, skip RSL */ - if (!ipbc->oml_conn || !ipbc->bsc_oml_conn) - continue; - - for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) { - unsigned int priv_nr; - /* don't establish RSL links which we don't have */ - if (!ipbc->rsl_conn[i]) - continue; - if (ipbc->bsc_rsl_conn[i]) - continue; - priv_nr = ipbc->rsl_conn[i]->fd.priv_nr; - priv_nr &= ~0xff; - priv_nr |= RSL_TO_BSC; - sin.sin_port = htons(IPA_TCP_PORT_RSL); - logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, priv_nr >> 8); - LOGPC(DLINP, LOGL_NOTICE, "RSL Trying to reconnect\n"); - ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc); - if (!ipbc->bsc_rsl_conn[i]) - goto reschedule; - logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, priv_nr >> 8); - LOGPC(DLINP, LOGL_NOTICE, "RSL Reconnected\n"); - } - } - return; - -reschedule: - osmo_timer_schedule(&ipp->reconn_timer, 5, 0); -} - -static void handle_dead_socket(struct osmo_fd *bfd) -{ - struct ipa_proxy_conn *ipc = bfd->data; /* local conn */ - struct ipa_proxy_conn *bsc_conn; /* remote conn */ - struct ipa_bts_conn *ipbc = ipc->bts_conn; - unsigned int trx_id = bfd->priv_nr >> 8; - struct msgb *msg, *msg2; - - osmo_fd_unregister(bfd); - close(bfd->fd); - bfd->fd = -1; - - /* FIXME: clear tx_queue, remove all references, etc. */ - llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list) - msgb_free(msg); - - switch (bfd->priv_nr & 0xff) { - case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */ - /* The BTS started a connection with us but we got no - * IPAC_MSGT_ID_RESP message yet, in that scenario we did not - * allocate the ipa_bts_conn structure. */ - if (ipbc == NULL) - break; - ipbc->oml_conn = NULL; - bsc_conn = ipbc->bsc_oml_conn; - /* close the connection to the BSC */ - osmo_fd_unregister(&bsc_conn->fd); - close(bsc_conn->fd.fd); - llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list) - msgb_free(msg); - talloc_free(bsc_conn); - ipbc->bsc_oml_conn = NULL; - /* FIXME: do we need to delete the entire ipbc ? */ - break; - case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */ - ipbc->rsl_conn[trx_id] = NULL; - bsc_conn = ipbc->bsc_rsl_conn[trx_id]; - /* close the connection to the BSC */ - osmo_fd_unregister(&bsc_conn->fd); - close(bsc_conn->fd.fd); - llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list) - msgb_free(msg); - talloc_free(bsc_conn); - ipbc->bsc_rsl_conn[trx_id] = NULL; - break; - case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */ - ipbc->bsc_oml_conn = NULL; - bsc_conn = ipbc->oml_conn; - /* start reconnect timer */ - osmo_timer_schedule(&ipp->reconn_timer, 5, 0); - break; - case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */ - ipbc->bsc_rsl_conn[trx_id] = NULL; - bsc_conn = ipbc->rsl_conn[trx_id]; - /* start reconnect timer */ - osmo_timer_schedule(&ipp->reconn_timer, 5, 0); - break; - default: - bsc_conn = NULL; - break; - } - - talloc_free(ipc); -} - -static void patch_gprs_msg(struct ipa_bts_conn *ipbc, int priv_nr, struct msgb *msg) -{ - uint8_t *nsvci; - - if ((priv_nr & 0xff) != OML_FROM_BTS && (priv_nr & 0xff) != OML_TO_BSC) - return; - - if (msgb_l2len(msg) != 39) - return; - - /* - * Check if this is a IPA Set Attribute or IPA Set Attribute ACK - * and if the FOM Class is GPRS NSVC0 and then we will patch it. - * - * The patch assumes the message looks like the one from the trace - * but we only match messages with a specific size anyway... So - * this hack should work just fine. - */ - - if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 && - msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 && - msg->l2h[18] == 0xf5 && msg->l2h[19] == 0xf2) { - nsvci = &msg->l2h[23]; - ipbc->gprs_orig_port = *(uint16_t *)(nsvci+8); - ipbc->gprs_orig_ip = *(uint32_t *)(nsvci+10); - *(uint16_t *)(nsvci+8) = htons(ipbc->gprs_local_port); - *(uint32_t *)(nsvci+10) = ipbc->ipp->listen_addr.s_addr; - } else if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 && - msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 && - msg->l2h[18] == 0xf6 && msg->l2h[19] == 0xf2) { - nsvci = &msg->l2h[23]; - *(uint16_t *)(nsvci+8) = ipbc->gprs_orig_port; - *(uint32_t *)(nsvci+10) = ipbc->gprs_orig_ip; - } -} - -static int handle_tcp_read(struct osmo_fd *bfd) -{ - struct ipa_proxy_conn *ipc = bfd->data; - struct ipa_bts_conn *ipbc = ipc->bts_conn; - struct ipa_proxy_conn *bsc_conn; - struct msgb *msg; - struct ipaccess_head *hh; - int ret = 0; - char *btsbsc; - - if ((bfd->priv_nr & 0xff) <= 2) - btsbsc = "BTS"; - else - btsbsc = "BSC"; - - msg = ipaccess_proxy_read_msg(bfd, &ret); - if (!msg) { - if (ret == 0) { - logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8); - LOGPC(DLINP, LOGL_NOTICE, "%s disappeared, " - "dead socket\n", btsbsc); - handle_dead_socket(bfd); - } - return ret; - } - - msgb_put(msg, ret); - logp_ipbc_uid(DLMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8); - DEBUGPC(DLMI, "RX<-%s: %s\n", btsbsc, osmo_hexdump(msg->data, msg->len)); - - hh = (struct ipaccess_head *) msg->data; - if (hh->proto == IPAC_PROTO_IPACCESS) { - ret = ipaccess_rcvmsg(ipc, msg, bfd); - if (ret < 0) { - osmo_fd_unregister(bfd); - close(bfd->fd); - bfd->fd = -1; - talloc_free(bfd); - msgb_free(msg); - return ret; - } else if (ret == 0) { - /* we do not forward parts of the CCM protocol - * through the proxy but rather terminate it ourselves. */ - msgb_free(msg); - return ret; - } - } - - if (!ipbc) { - LOGP(DLINP, LOGL_ERROR, - "received %s packet but no ipc->bts_conn?!?\n", btsbsc); - msgb_free(msg); - return -EIO; - } - - bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr); - if (bsc_conn) { - if (gprs_ns_ipaddr) - patch_gprs_msg(ipbc, bfd->priv_nr, msg); - /* enqueue packet towards BSC */ - msgb_enqueue(&bsc_conn->tx_queue, msg); - /* mark respective filedescriptor as 'we want to write' */ - bsc_conn->fd.when |= BSC_FD_WRITE; - } else { - logp_ipbc_uid(DLINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8); - LOGPC(DLINP, LOGL_INFO, "Dropping packet from %s, " - "since remote connection is dead\n", btsbsc); - msgb_free(msg); - } - - return ret; -} - -/* a TCP socket is ready to be written to */ -static int handle_tcp_write(struct osmo_fd *bfd) -{ - struct ipa_proxy_conn *ipc = bfd->data; - struct ipa_bts_conn *ipbc = ipc->bts_conn; - struct llist_head *lh; - struct msgb *msg; - char *btsbsc; - int ret; - - if ((bfd->priv_nr & 0xff) <= 2) - btsbsc = "BTS"; - else - btsbsc = "BSC"; - - - /* get the next msg for this timeslot */ - if (llist_empty(&ipc->tx_queue)) { - bfd->when &= ~BSC_FD_WRITE; - return 0; - } - lh = ipc->tx_queue.next; - llist_del(lh); - msg = llist_entry(lh, struct msgb, list); - - logp_ipbc_uid(DLMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8); - DEBUGPC(DLMI, "TX %04x: %s\n", bfd->priv_nr, - osmo_hexdump(msg->data, msg->len)); - - ret = send(bfd->fd, msg->data, msg->len, 0); - msgb_free(msg); - - if (ret == 0) { - logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8); - LOGP(DLINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc); - handle_dead_socket(bfd); - } - - return ret; -} - -/* callback from select.c in case one of the fd's can be read/written */ -static int proxy_ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what) -{ - int rc = 0; - - if (what & BSC_FD_READ) { - rc = handle_tcp_read(bfd); - if (rc < 0) - return rc; - } - if (what & BSC_FD_WRITE) - rc = handle_tcp_write(bfd); - - return rc; -} - -/* callback of the listening filedescriptor */ -static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what) -{ - int ret; - struct ipa_proxy_conn *ipc; - struct osmo_fd *bfd; - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - - if (!(what & BSC_FD_READ)) - return 0; - - ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len); - if (ret < 0) { - perror("accept"); - return ret; - } - DEBUGP(DLINP, "accept()ed new %s link from %s\n", - (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL", - inet_ntoa(sa.sin_addr)); - - ipc = alloc_conn(); - if (!ipc) { - close(ret); - return -ENOMEM; - } - - bfd = &ipc->fd; - bfd->fd = ret; - bfd->data = ipc; - bfd->priv_nr = listen_bfd->priv_nr; - bfd->cb = proxy_ipaccess_fd_cb; - bfd->when = BSC_FD_READ; - ret = osmo_fd_register(bfd); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "could not register FD\n"); - close(bfd->fd); - talloc_free(ipc); - return ret; - } - - /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */ - ret = ipa_ccm_send_id_req(bfd->fd); - - return 0; -} - -static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port) -{ - int ret; - struct sockaddr_in addr; - socklen_t len = sizeof(addr); - memset(&addr, 0, sizeof(addr)); - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr = ip; - - ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to forward GPRS message.\n"); - } -} - -static int gprs_ns_cb(struct osmo_fd *bfd, unsigned int what) -{ - struct ipa_bts_conn *bts; - char buf[4096]; - int ret; - struct sockaddr_in sock; - socklen_t len = sizeof(sock); - - /* 1. get the data... */ - ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno)); - return -1; - } - - bts = bfd->data; - - /* 2. figure out where to send it to */ - if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) { - LOGP(DLINP, LOGL_DEBUG, "GPRS NS msg from network.\n"); - send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000); - } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) { - LOGP(DLINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n"); - send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000); - } else { - LOGP(DLINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr)); - } - - return 0; -} - -/* Actively connect to a BSC. */ -static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data) -{ - struct ipa_proxy_conn *ipc; - struct osmo_fd *bfd; - int ret, on = 1; - - ipc = alloc_conn(); - if (!ipc) - return NULL; - - ipc->bts_conn = data; - - bfd = &ipc->fd; - bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - bfd->cb = ipaccess_fd_cb; - bfd->when = BSC_FD_READ | BSC_FD_WRITE; - bfd->data = ipc; - bfd->priv_nr = priv_nr; - - if (bfd->fd < 0) { - LOGP(DLINP, LOGL_ERROR, "Could not create socket: %s\n", - strerror(errno)); - talloc_free(ipc); - return NULL; - } - - ret = setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Could not set socket option\n"); - close(bfd->fd); - talloc_free(ipc); - return NULL; - } - - ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa)); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Could not connect socket: %s\n", - inet_ntoa(sa->sin_addr)); - close(bfd->fd); - talloc_free(ipc); - return NULL; - } - - /* pre-fill tx_queue with identity request */ - ret = osmo_fd_register(bfd); - if (ret < 0) { - close(bfd->fd); - talloc_free(ipc); - return NULL; - } - - return ipc; -} - -static int ipaccess_proxy_setup(void) -{ - int ret; - - ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy); - if (!ipp) - return -ENOMEM; - INIT_LLIST_HEAD(&ipp->bts_list); - osmo_timer_setup(&ipp->reconn_timer, reconn_tmr_cb, ipp); - - /* Listen for OML connections */ - ret = make_sock(&ipp->oml_listen_fd, IPPROTO_TCP, INADDR_ANY, - IPA_TCP_PORT_OML, OML_FROM_BTS, listen_fd_cb, NULL); - if (ret < 0) - return ret; - - /* Listen for RSL connections */ - ret = make_sock(&ipp->rsl_listen_fd, IPPROTO_TCP, INADDR_ANY, - IPA_TCP_PORT_RSL, RSL_FROM_BTS, listen_fd_cb, NULL); - - if (ret < 0) - return ret; - - /* Connect the GPRS NS Socket */ - if (gprs_ns_ipaddr) { - inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr); - inet_aton(listen_ipaddr, &ipp->listen_addr); - } - - return ret; -} - -static void signal_handler(int signal) -{ - fprintf(stdout, "signal %u received\n", signal); - - switch (signal) { - 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_full(tall_bsc_ctx, stderr); - break; - default: - break; - } -} - -static void print_help(void) -{ - printf(" ipaccess-proxy is a proxy BTS.\n"); - printf(" -h --help. This help text.\n"); - printf(" -l --listen IP. The ip to listen to.\n"); - printf(" -b --bsc IP. The BSC IP address.\n"); - printf(" -g --gprs IP. Take GPRS NS from that IP.\n"); - printf("\n"); - printf(" -s --disable-color. Disable the color inside the logging message.\n"); - printf(" -e --log-level number. Set the global loglevel.\n"); - printf(" -T --timestamp. Prefix every log message with a timestamp.\n"); - printf(" -V --version. Print the version of OpenBSC.\n"); -} - -static void print_usage(void) -{ - printf("Usage: ipaccess-proxy [options]\n"); -} - -enum { - IPA_PROXY_OPT_LISTEN_NONE = 0, - IPA_PROXY_OPT_LISTEN_IP = (1 << 0), - IPA_PROXY_OPT_BSC_IP = (1 << 1), -}; - -static void handle_options(int argc, char** argv) -{ - int options_mask = 0; - - /* disable explicit missing arguments error output from getopt_long */ - opterr = 0; - - while (1) { - int option_index = 0, c; - static struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"disable-color", 0, 0, 's'}, - {"timestamp", 0, 0, 'T'}, - {"log-level", 1, 0, 'e'}, - {"listen", 1, 0, 'l'}, - {"bsc", 1, 0, 'b'}, - {0, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "hsTe:l:b:g:", - long_options, &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - print_usage(); - print_help(); - exit(0); - case 'l': - listen_ipaddr = optarg; - options_mask |= IPA_PROXY_OPT_LISTEN_IP; - break; - case 'b': - bsc_ipaddr = optarg; - options_mask |= IPA_PROXY_OPT_BSC_IP; - break; - case 'g': - gprs_ns_ipaddr = optarg; - break; - case 's': - log_set_use_color(osmo_stderr_target, 0); - 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 '?': - if (optopt) { - printf("ERROR: missing mandatory argument " - "for `%s' option\n", argv[optind-1]); - } else { - printf("ERROR: unknown option `%s'\n", - argv[optind-1]); - } - print_usage(); - print_help(); - exit(EXIT_FAILURE); - break; - default: - /* ignore */ - break; - } - } - if ((options_mask & (IPA_PROXY_OPT_LISTEN_IP | IPA_PROXY_OPT_BSC_IP)) - != (IPA_PROXY_OPT_LISTEN_IP | IPA_PROXY_OPT_BSC_IP)) { - printf("ERROR: You have to specify `--listen' and `--bsc' " - "options at least.\n"); - print_usage(); - print_help(); - exit(EXIT_FAILURE); - } -} - -int main(int argc, char **argv) -{ - int rc; - - tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy"); - msgb_talloc_ctx_init(tall_bsc_ctx, 0); - - osmo_init_logging(&log_info); - log_parse_category_mask(osmo_stderr_target, "DLINP:DLMI"); - - handle_options(argc, argv); - - rc = ipaccess_proxy_setup(); - if (rc < 0) - exit(1); - - signal(SIGUSR1, &signal_handler); - signal(SIGABRT, &signal_handler); - osmo_init_ignore_signals(); - - while (1) { - osmo_select_main(0); - } -} diff --git a/src/ipaccess/network_listen.c b/src/ipaccess/network_listen.c deleted file mode 100644 index 3b44ceb74..000000000 --- a/src/ipaccess/network_listen.c +++ /dev/null @@ -1,257 +0,0 @@ -/* ip.access nanoBTS network listen mode */ - -/* (C) 2009-2010 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define WHITELIST_MAX_SIZE ((NUM_ARFCNS*2)+2+1) - -int ipac_rxlevstat2whitelist(uint16_t *buf, const struct rxlev_stats *st, uint8_t min_rxlev, - uint16_t max_num_arfcns) -{ - int i; - unsigned int num_arfcn = 0; - - for (i = NUM_RXLEVS-1; i >= min_rxlev; i--) { - int16_t arfcn = -1; - - while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) { - *buf++ = htons(arfcn); - num_arfcn++; - - } - - if (num_arfcn > max_num_arfcns) - break; - } - - return num_arfcn; -} - -enum ipac_test_state { - IPAC_TEST_S_IDLE, - IPAC_TEST_S_RQD, - IPAC_TEST_S_EXEC, - IPAC_TEST_S_PARTIAL, -}; - -int ipac_nwl_test_start(struct gsm_bts_trx *trx, uint8_t testnr, - const uint8_t *phys_conf, unsigned int phys_conf_len) -{ - struct msgb *msg; - - if (trx->ipaccess.test_state != IPAC_TEST_S_IDLE) { - fprintf(stderr, "Cannot start test in state %u\n", trx->ipaccess.test_state); - return -EINVAL; - } - - switch (testnr) { - case NM_IPACC_TESTNO_CHAN_USAGE: - case NM_IPACC_TESTNO_BCCH_CHAN_USAGE: - rxlev_stat_reset(&trx->ipaccess.rxlev_stat); - break; - } - - msg = msgb_alloc_headroom(phys_conf_len+256, 128, "OML"); - - if (phys_conf && phys_conf_len) { - uint8_t *payload; - /* first put the phys conf header */ - msgb_tv16_put(msg, NM_ATT_PHYS_CONF, phys_conf_len); - payload = msgb_put(msg, phys_conf_len); - memcpy(payload, phys_conf, phys_conf_len); - } - - abis_nm_perform_test(trx->bts, NM_OC_RADIO_CARRIER, 0, trx->nr, 0xff, - testnr, 1, msg); - trx->ipaccess.test_nr = testnr; - - /* FIXME: start safety timer until when test is supposed to complete */ - - return 0; -} - -static uint16_t last_arfcn; -static struct gsm_sysinfo_freq nwl_si_freq[1024]; -#define FREQ_TYPE_NCELL_2 0x04 /* sub channel of SI 2 */ -#define FREQ_TYPE_NCELL_2bis 0x08 /* sub channel of SI 2bis */ -#define FREQ_TYPE_NCELL_2ter 0x10 /* sub channel of SI 2ter */ - -struct ipacc_ferr_elem { - int16_t freq_err; - uint8_t freq_qual; - uint8_t arfcn; -} __attribute__((packed)); - -struct ipacc_cusage_elem { - uint16_t arfcn:10, - rxlev:6; -} __attribute__ ((packed)); - -static int test_rep(void *_msg) -{ - struct msgb *msg = _msg; - struct abis_om_fom_hdr *foh = msgb_l3(msg); - uint16_t test_rep_len, ferr_list_len; - struct ipacc_ferr_elem *ife; - struct ipac_bcch_info binfo; - struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst; - int i, rc; - - DEBUGP(DNM, "TEST REPORT: "); - - if (foh->data[0] != NM_ATT_TEST_NO || - foh->data[2] != NM_ATT_TEST_REPORT) - return -EINVAL; - - DEBUGPC(DNM, "test_no=0x%02x ", foh->data[1]); - /* data[2] == NM_ATT_TEST_REPORT */ - /* data[3..4]: test_rep_len */ - memcpy(&test_rep_len, &foh->data[3], sizeof(uint16_t)); - test_rep_len = ntohs(test_rep_len); - /* data[5]: ip.access test result */ - DEBUGPC(DNM, "tst_res=%s\n", ipacc_testres_name(foh->data[5])); - - /* data[6]: ip.access nested IE. 3 == freq_err_list */ - switch (foh->data[6]) { - case NM_IPAC_EIE_FREQ_ERR_LIST: - /* data[7..8]: length of ferr_list */ - memcpy(&ferr_list_len, &foh->data[7], sizeof(uint16_t)); - ferr_list_len = ntohs(ferr_list_len); - - /* data[9...]: frequency error list elements */ - for (i = 0; i < ferr_list_len; i+= sizeof(*ife)) { - ife = (struct ipacc_ferr_elem *) (foh->data + 9 + i); - DEBUGP(DNM, "==> ARFCN %4u, Frequency Error %6hd\n", - ife->arfcn, ntohs(ife->freq_err)); - } - break; - case NM_IPAC_EIE_CHAN_USE_LIST: - /* data[7..8]: length of ferr_list */ - memcpy(&ferr_list_len, &foh->data[7], sizeof(uint16_t)); - ferr_list_len = ntohs(ferr_list_len); - - /* data[9...]: channel usage list elements */ - for (i = 0; i < ferr_list_len; i+= 2) { - uint16_t *cu_ptr = (uint16_t *)(foh->data + 9 + i); - uint16_t cu = ntohs(*cu_ptr); - uint16_t arfcn = cu & 0x3ff; - uint8_t rxlev = cu >> 10; - DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n", arfcn, rxlev); - rxlev_stat_input(&sign_link->trx->ipaccess.rxlev_stat, - arfcn, rxlev); - } - break; - case NM_IPAC_EIE_BCCH_INFO_TYPE: - break; - case NM_IPAC_EIE_BCCH_INFO: - rc = ipac_parse_bcch_info(&binfo, foh->data+6); - if (rc < 0) { - DEBUGP(DNM, "BCCH Info parsing failed\n"); - break; - } - DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %3d-%d, LAC %d CI %d BSIC %u\n", - binfo.arfcn, binfo.rx_lev, binfo.rx_qual, - binfo.cgi.mcc, binfo.cgi.mnc, - binfo.cgi.lac, binfo.cgi.ci, binfo.bsic); - - if (binfo.arfcn != last_arfcn) { - /* report is on a new arfcn, need to clear channel list */ - memset(nwl_si_freq, 0, sizeof(nwl_si_freq)); - last_arfcn = binfo.arfcn; - } - if (binfo.info_type & IPAC_BINF_NEIGH_BA_SI2) { - DEBUGP(DNM, "BA SI2: %s\n", osmo_hexdump(binfo.ba_list_si2, sizeof(binfo.ba_list_si2))); - gsm48_decode_freq_list(nwl_si_freq, binfo.ba_list_si2, sizeof(binfo.ba_list_si2), - 0x8c, FREQ_TYPE_NCELL_2); - } - if (binfo.info_type & IPAC_BINF_NEIGH_BA_SI2bis) { - DEBUGP(DNM, "BA SI2bis: %s\n", osmo_hexdump(binfo.ba_list_si2bis, sizeof(binfo.ba_list_si2bis))); - gsm48_decode_freq_list(nwl_si_freq, binfo.ba_list_si2bis, sizeof(binfo.ba_list_si2bis), - 0x8e, FREQ_TYPE_NCELL_2bis); - } - if (binfo.info_type & IPAC_BINF_NEIGH_BA_SI2ter) { - DEBUGP(DNM, "BA SI2ter: %s\n", osmo_hexdump(binfo.ba_list_si2ter, sizeof(binfo.ba_list_si2ter))); - gsm48_decode_freq_list(nwl_si_freq, binfo.ba_list_si2ter, sizeof(binfo.ba_list_si2ter), - 0x8e, FREQ_TYPE_NCELL_2ter); - } - for (i = 0; i < ARRAY_SIZE(nwl_si_freq); i++) { - if (nwl_si_freq[i].mask) - DEBUGP(DNM, "Neighbor Cell on ARFCN %u\n", i); - } - break; - default: - break; - } - - switch (foh->data[5]) { - case NM_IPACC_TESTRES_SUCCESS: - case NM_IPACC_TESTRES_STOPPED: - case NM_IPACC_TESTRES_TIMEOUT: - case NM_IPACC_TESTRES_NO_CHANS: - sign_link->trx->ipaccess.test_state = IPAC_TEST_S_IDLE; - /* Send signal to notify higher layers of test completion */ - DEBUGP(DNM, "dispatching S_IPAC_NWL_COMPLETE signal\n"); - osmo_signal_dispatch(SS_IPAC_NWL, S_IPAC_NWL_COMPLETE, - sign_link->trx); - break; - case NM_IPACC_TESTRES_PARTIAL: - sign_link->trx->ipaccess.test_state = IPAC_TEST_S_PARTIAL; - break; - } - - return 0; -} - -static int nwl_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - switch (signal) { - case S_NM_TEST_REP: - return test_rep(signal_data); - default: - break; - } - - return 0; -} - -void ipac_nwl_init(void) -{ - osmo_signal_register_handler(SS_NM, nwl_sig_cb, NULL); -} diff --git a/src/libbsc/Makefile.am b/src/libbsc/Makefile.am deleted file mode 100644 index e78bde624..000000000 --- a/src/libbsc/Makefile.am +++ /dev/null @@ -1,57 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - -I$(top_builddir) \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -noinst_LIBRARIES = \ - libbsc.a \ - $(NULL) - -libbsc_a_SOURCES = \ - abis_nm.c \ - abis_nm_vty.c \ - abis_om2000.c \ - abis_om2000_vty.c \ - abis_rsl.c \ - bsc_rll.c \ - bsc_subscriber.c \ - paging.c \ - bts_ericsson_rbs2000.c \ - bts_ipaccess_nanobts.c \ - bts_siemens_bs11.c \ - bts_nokia_site.c \ - bts_unknown.c \ - bts_sysmobts.c \ - chan_alloc.c \ - handover_decision.c \ - handover_logic.c \ - meas_rep.c \ - pcu_sock.c \ - rest_octets.c \ - system_information.c \ - e1_config.c \ - bsc_api.c \ - bsc_msc.c bsc_vty.c \ - gsm_04_08_utils.c \ - gsm_04_80_utils.c \ - bsc_init.c \ - bts_init.c \ - bsc_rf_ctrl.c \ - arfcn_range_encode.c \ - bsc_ctrl_commands.c \ - bsc_ctrl_lookup.c \ - net_init.c \ - bsc_dyn_ts.c \ - bts_ipaccess_nanobts_omlattr.c \ - $(NULL) - diff --git a/src/libbsc/abis_nm.c b/src/libbsc/abis_nm.c deleted file mode 100644 index cf20d7c49..000000000 --- a/src/libbsc/abis_nm.c +++ /dev/null @@ -1,2924 +0,0 @@ -/* GSM Network Management (OML) messages on the A-bis interface - * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ - -/* (C) 2008-2009 by Harald Welte - * - * 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 . - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define OM_ALLOC_SIZE 1024 -#define OM_HEADROOM_SIZE 128 -#define IPACC_SEGMENT_SIZE 245 - -int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len) -{ - if (!bts->model) - return -EIO; - return tlv_parse(tp, &bts->model->nm_att_tlvdef, buf, len, 0, 0); -} - -static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (arr[i] == mt) - return 1; - } - - return 0; -} - -#if 0 -/* is this msgtype the usual ACK/NACK type ? */ -static int is_ack_nack(enum abis_nm_msgtype mt) -{ - return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack)); -} -#endif - -/* is this msgtype a report ? */ -static int is_report(enum abis_nm_msgtype mt) -{ - return is_in_arr(mt, abis_nm_reports, ARRAY_SIZE(abis_nm_reports)); -} - -#define MT_ACK(x) (x+1) -#define MT_NACK(x) (x+2) - -static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len) -{ - oh->mdisc = ABIS_OM_MDISC_FOM; - oh->placement = ABIS_OM_PLACEMENT_ONLY; - oh->sequence = 0; - oh->length = len; -} - -static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len, - uint8_t msg_type, uint8_t obj_class, - uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr) -{ - struct abis_om_fom_hdr *foh = - (struct abis_om_fom_hdr *) oh->data; - - fill_om_hdr(oh, len+sizeof(*foh)); - foh->msg_type = msg_type; - foh->obj_class = obj_class; - foh->obj_inst.bts_nr = bts_nr; - foh->obj_inst.trx_nr = trx_nr; - foh->obj_inst.ts_nr = ts_nr; - return foh; -} - -static struct msgb *nm_msgb_alloc(void) -{ - return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, - "OML"); -} - -int _abis_nm_sendmsg(struct msgb *msg) -{ - msg->l2h = msg->data; - - if (!msg->dst) { - LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__); - return -EINVAL; - } - - return abis_sendmsg(msg); -} - -/* Send a OML NM Message from BSC to BTS */ -static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg) -{ - msg->dst = bts->oml_link; - - /* queue OML messages */ - if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) { - bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg); - return _abis_nm_sendmsg(msg); - } else { - msgb_enqueue(&bts->abis_queue, msg); - return 0; - } - -} - -int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg) -{ - OBSC_NM_W_ACK_CB(msg) = 1; - return abis_nm_queue_msg(bts, msg); -} - -static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg) -{ - OBSC_NM_W_ACK_CB(msg) = 0; - return abis_nm_queue_msg(bts, msg); -} - -static int abis_nm_rcvmsg_sw(struct msgb *mb); - -int nm_is_running(struct gsm_nm_state *s) { - return (s->operational == NM_OPSTATE_ENABLED) && ( - (s->availability == NM_AVSTATE_OK) || - (s->availability == 0xff) - ); -} - -/* Update the administrative state of a given object in our in-memory data - * structures and send an event to the higher layer */ -static int update_admstate(struct gsm_bts *bts, uint8_t obj_class, - struct abis_om_obj_inst *obj_inst, uint8_t adm_state) -{ - struct gsm_nm_state *nm_state, new_state; - struct nm_statechg_signal_data nsd; - - memset(&nsd, 0, sizeof(nsd)); - - nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst); - if (!nsd.obj) - return -EINVAL; - nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst); - if (!nm_state) - return -1; - - new_state = *nm_state; - new_state.administrative = adm_state; - - nsd.bts = bts; - nsd.obj_class = obj_class; - nsd.old_state = nm_state; - nsd.new_state = &new_state; - nsd.obj_inst = obj_inst; - osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd); - - nm_state->administrative = adm_state; - - return 0; -} - -static int abis_nm_rx_statechg_rep(struct msgb *mb) -{ - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - struct gsm_bts *bts = sign_link->trx->bts; - struct tlv_parsed tp; - struct gsm_nm_state *nm_state, new_state; - - DEBUGPC(DNM, "STATE CHG: "); - - memset(&new_state, 0, sizeof(new_state)); - - nm_state = gsm_objclass2nmstate(bts, foh->obj_class, &foh->obj_inst); - if (!nm_state) { - DEBUGPC(DNM, "unknown object class\n"); - return -EINVAL; - } - - new_state = *nm_state; - - abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh)); - if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) { - new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE); - DEBUGPC(DNM, "OP_STATE=%s ", - abis_nm_opstate_name(new_state.operational)); - } - if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) { - if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0) - new_state.availability = 0xff; - else - new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS); - DEBUGPC(DNM, "AVAIL=%s(%02x) ", - abis_nm_avail_name(new_state.availability), - new_state.availability); - } else - new_state.availability = 0xff; - if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) { - new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE); - DEBUGPC(DNM, "ADM=%2s ", - get_value_string(abis_nm_adm_state_names, - new_state.administrative)); - } - DEBUGPC(DNM, "\n"); - - if ((new_state.administrative != 0 && nm_state->administrative == 0) || - new_state.operational != nm_state->operational || - new_state.availability != nm_state->availability) { - /* Update the operational state of a given object in our in-memory data - * structures and send an event to the higher layer */ - struct nm_statechg_signal_data nsd; - nsd.obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst); - nsd.obj_class = foh->obj_class; - nsd.old_state = nm_state; - nsd.new_state = &new_state; - nsd.obj_inst = &foh->obj_inst; - nsd.bts = bts; - osmo_signal_dispatch(SS_NM, S_NM_STATECHG_OPER, &nsd); - nm_state->operational = new_state.operational; - nm_state->availability = new_state.availability; - if (nm_state->administrative == 0) - nm_state->administrative = new_state.administrative; - } -#if 0 - if (op_state == 1) { - /* try to enable objects that are disabled */ - abis_nm_opstart(bts, foh->obj_class, - foh->obj_inst.bts_nr, - foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr); - } -#endif - return 0; -} - -static inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type, - const char *severity, const uint8_t *p_val, - const char *text) -{ - enum abis_nm_pcause_type pcause = p_val[0]; - enum abis_mm_event_causes cause = osmo_load16be(p_val + 1); - - LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr); - if (type) - LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type); - if (severity) - LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity); - - LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ", - get_value_string(abis_nm_pcause_type_names, pcause)); - - if (pcause == NM_PCAUSE_T_MANUF) - LOGPC(DNM, LOGL_ERROR, "%s, ", - get_value_string(abis_mm_event_cause_names, cause)); - else - LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]); - - if (text) { - LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text); - } - - LOGPC(DNM, LOGL_ERROR, "\n"); -} - -static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type, - const char *severity, const char *text) -{ - enum abis_mm_event_causes cause = osmo_load16be(p_val + 1); - - switch (cause) { - case OSMO_EVT_PCU_VERS: - if (text) { - LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text); - osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version)); - } else { - LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr); - bts->pcu_version[0] = '\0'; - } - break; - default: - log_oml_fail_rep(bts, type, severity, p_val, text); - }; -} - -static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts) -{ - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - struct tlv_parsed tp; - int rc = 0; - const uint8_t *p_val = NULL; - char *p_text = NULL; - const char *e_type = NULL, *severity = NULL; - - abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, - oh->length-sizeof(*foh)); - - if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) { - p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT); - p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, - TLVP_LEN(&tp, NM_ATT_ADD_TEXT)); - } - - if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE)) - e_type = abis_nm_event_type_name(*TLVP_VAL(&tp, - NM_ATT_EVENT_TYPE)); - - if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY)) - severity = abis_nm_severity_name(*TLVP_VAL(&tp, - NM_ATT_SEVERITY)); - - if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) { - p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE); - - switch (p_val[0]) { - case NM_PCAUSE_T_MANUF: - handle_manufact_report(bts, p_val, e_type, severity, - p_text); - break; - default: - log_oml_fail_rep(bts, e_type, severity, p_val, p_text); - }; - } else { - LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without " - "Probable Cause?!\n", bts->nr); - rc = -EINVAL; - } - - if (p_text) - talloc_free(p_text); - - return rc; -} - -static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts) -{ - struct abis_om_fom_hdr *foh = msgb_l3(mb); - uint8_t mt = foh->msg_type; - - abis_nm_debugp_foh(DNM, foh); - - //nmh->cfg->report_cb(mb, foh); - - switch (mt) { - case NM_MT_STATECHG_EVENT_REP: - return abis_nm_rx_statechg_rep(mb); - break; - case NM_MT_SW_ACTIVATED_REP: - DEBUGPC(DNM, "Software Activated Report\n"); - osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb); - break; - case NM_MT_FAILURE_EVENT_REP: - rx_fail_evt_rep(mb, bts); - osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb); - break; - case NM_MT_TEST_REP: - DEBUGPC(DNM, "Test Report\n"); - osmo_signal_dispatch(SS_NM, S_NM_TEST_REP, mb); - break; - default: - DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt); - break; - - }; - - return 0; -} - -/* Activate the specified software into the BTS */ -static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, - uint8_t i2, const struct abis_nm_sw_desc *sw_desc) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint16_t len = abis_nm_sw_desc_len(sw_desc, true); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2); - abis_nm_put_sw_desc(msg, sw_desc, true); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr, - const size_t size) -{ - int res = 0; - int i; - - for (i = 1; i < size; ++i) { - if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version, - OSMO_MIN(sw_descr[i].file_version_len, - sw_descr[res].file_version_len)) < 0) { - res = i; - } - } - - return res; -} - -static inline bool handle_attr(const struct gsm_bts *bts, enum bts_attribute id, uint8_t *val, uint8_t len) -{ - switch (id) { - case BTS_TYPE_VARIANT: - LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val); - break; - case BTS_SUB_MODEL: - LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val); - break; - default: - return false; - } - return true; -} - -/* Parse Attribute Response Info - return pointer to the actual content */ -static inline uint8_t *parse_attr_resp_info_unreported(uint8_t bts_nr, uint8_t *ari, uint16_t ari_len, uint16_t *out_len) -{ - uint8_t num_unreported = ari[0], i; - - DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n", - bts_nr, ari_len, num_unreported); - - /* +1 because we have to account for number of unreported attributes, prefixing the list: */ - for (i = 0; i < num_unreported; i++) - LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n", - bts_nr, get_value_string(abis_nm_att_names, ari[i + 1])); - - /* the data starts right after the list of unreported attributes + space for length of that list */ - *out_len = ari_len - (num_unreported + 2); - - return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */ -} - -/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.30 Manufacturer Id */ -static inline uint8_t *parse_attr_resp_info_manuf_id(struct gsm_bts *bts, uint8_t *data, uint16_t *data_len) -{ - struct tlv_parsed tp; - uint16_t m_id_len = 0; - uint8_t adjust = 0, i; - - abis_nm_tlv_parse(&tp, bts, data, *data_len); - if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_ID, 2)) { - m_id_len = TLVP_LEN(&tp, NM_ATT_MANUF_ID); - - /* log potential BTS feature vector overflow */ - if (m_id_len > sizeof(bts->_features_data)) - LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: feature vector is truncated to %u bytes\n", - bts->nr, MAX_BTS_FEATURES/8); - - /* check that max. expected BTS attribute is above given feature vector length */ - if (m_id_len > OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT)) - LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: reported unexpectedly long (%u bytes) " - "feature vector - most likely it was compiled against newer BSC headers. " - "Consider upgrading your BSC to later version.\n", - bts->nr, m_id_len); - - memcpy(bts->_features_data, TLVP_VAL(&tp, NM_ATT_MANUF_ID), sizeof(bts->_features_data)); - adjust = m_id_len + 3; /* adjust for parsed TL16V struct */ - - for (i = 0; i < _NUM_BTS_FEAT; i++) - if (gsm_bts_has_feature(bts, i) != gsm_btsmodel_has_feature(bts->model, i)) - LOGP(DNM, LOGL_NOTICE, "BTS%u feature '%s' reported via OML does not match statically " - "set feature: %u != %u. Please fix.\n", bts->nr, - get_value_string(gsm_bts_features_descs, i), - gsm_bts_has_feature(bts, i), gsm_btsmodel_has_feature(bts->model, i)); - } - - *data_len -= adjust; - - return data + adjust; -} - -/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */ -static inline uint8_t *parse_attr_resp_info_manuf_state(const struct gsm_bts_trx *trx, uint8_t *data, uint16_t *data_len) -{ - struct tlv_parsed tp; - const uint8_t *power; - uint8_t adjust = 0; - - if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */ - return data; - - abis_nm_tlv_parse(&tp, trx->bts, data, *data_len); - if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) { - power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE); - LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power); - adjust = 2; /* adjust for parsed TV struct */ - } - - *data_len -= adjust; - - return data + adjust; -} - -/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */ -static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx) -{ - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts; - struct tlv_parsed tp; - uint8_t *data, i; - uint16_t data_len; - int rc; - struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR]; - - abis_nm_debugp_foh(DNM, foh); - - DEBUGPC(DNM, "Get Attributes Response for BTS%u\n", bts->nr); - - abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh)); - if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) { - LOGP(DNM, LOGL_ERROR, "BTS%u: Get Attributes Response without Response Info?!\n", bts->nr); - return -EINVAL; - } - - data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI), - &data_len); - - data = parse_attr_resp_info_manuf_state(trx, data, &data_len); - data = parse_attr_resp_info_manuf_id(bts, data, &data_len); - - /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */ - rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr)); - if (rc > 0) { - for (i = 0; i < rc; i++) { - if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id), - sw_descr[i].file_version, sw_descr[i].file_version_len)) - LOGP(DNM, LOGL_NOTICE, "BTS%u: ARI reported sw[%d/%d]: %s is %s\n", - bts->nr, i, rc, sw_descr[i].file_id, sw_descr[i].file_version); - } - } else - LOGP(DNM, LOGL_ERROR, "BTS%u: failed to parse SW-Config part of Get Attribute Response Info: %s\n", - bts->nr, strerror(-rc)); - - return 0; -} - -/* 3GPP TS 52.021 §6.2.5 */ -static int abis_nm_rx_sw_act_req(struct msgb *mb) -{ - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - struct tlv_parsed tp; - const uint8_t *sw_config; - int ret, sw_config_len, len; - struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR]; - - abis_nm_debugp_foh(DNM, foh); - - DEBUGPC(DNM, "SW Activate Request: "); - - DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n"); - - ret = abis_nm_sw_act_req_ack(sign_link->trx->bts, foh->obj_class, - foh->obj_inst.bts_nr, - foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr, 0, - foh->data, oh->length-sizeof(*foh)); - if (ret != 0) { - LOGP(DNM, LOGL_ERROR, - "Sending SW ActReq ACK failed: %d\n", ret); - return ret; - } - - abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh)); - sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG); - sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG); - if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) { - LOGP(DNM, LOGL_ERROR, - "SW config not found! Can't continue.\n"); - return -EINVAL; - } else { - DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len)); - } - - /* Parse up to two sw descriptions from the data */ - len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0], - ARRAY_SIZE(sw_descr)); - if (len <= 0) { - LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n"); - return -EINVAL; - } - - ret = abis_nm_select_newest_sw(&sw_descr[0], len); - DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len); - - return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class, - foh->obj_inst.bts_nr, - foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr, - &sw_descr[ret]); -} - -/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */ -static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb) -{ - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - struct tlv_parsed tp; - uint8_t adm_state; - - abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh)); - if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) - return -EINVAL; - - adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE); - - return update_admstate(sign_link->trx->bts, foh->obj_class, &foh->obj_inst, adm_state); -} - -static int abis_nm_rx_lmt_event(struct msgb *mb) -{ - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - struct tlv_parsed tp; - - DEBUGP(DNM, "LMT Event "); - abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh)); - if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) && - TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) { - uint8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION); - DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF"); - } - if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) && - TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) { - uint8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV); - DEBUGPC(DNM, "Level=%u ", level); - } - if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) && - TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) { - char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME); - DEBUGPC(DNM, "Username=%s ", name); - } - DEBUGPC(DNM, "\n"); - /* FIXME: parse LMT LOGON TIME */ - return 0; -} - -void abis_nm_queue_send_next(struct gsm_bts *bts) -{ - int wait = 0; - struct msgb *msg; - /* the queue is empty */ - while (!llist_empty(&bts->abis_queue)) { - msg = msgb_dequeue(&bts->abis_queue); - wait = OBSC_NM_W_ACK_CB(msg); - _abis_nm_sendmsg(msg); - - if (wait) - break; - } - - bts->abis_nm_pend = wait; -} - -/* Receive a OML NM Message from BTS */ -static int abis_nm_rcvmsg_fom(struct msgb *mb) -{ - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - uint8_t mt = foh->msg_type; - /* sign_link might get deleted via osmo_signal_dispatch -> save bts */ - struct gsm_bts *bts = sign_link->trx->bts; - int ret = 0; - - /* check for unsolicited message */ - if (is_report(mt)) - return abis_nm_rcvmsg_report(mb, bts); - - if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs))) - return abis_nm_rcvmsg_sw(mb); - - if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) { - struct nm_nack_signal_data nack_data; - struct tlv_parsed tp; - - abis_nm_debugp_foh(DNM, foh); - - DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt)); - - abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh)); - if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, "CAUSE=%s\n", - abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); - else - DEBUGPC(DNM, "\n"); - - nack_data.msg = mb; - nack_data.mt = mt; - nack_data.bts = bts; - osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data); - abis_nm_queue_send_next(bts); - return 0; - } -#if 0 - /* check if last message is to be acked */ - if (is_ack_nack(nmh->last_msgtype)) { - if (mt == MT_ACK(nmh->last_msgtype)) { - DEBUGP(DNM, "received ACK (0x%x)\n", foh->msg_type); - /* we got our ACK, continue sending the next msg */ - } else if (mt == MT_NACK(nmh->last_msgtype)) { - /* we got a NACK, signal this to the caller */ - DEBUGP(DNM, "received NACK (0x%x)\n", foh->msg_type); - /* FIXME: somehow signal this to the caller */ - } else { - /* really strange things happen */ - return -EINVAL; - } - } -#endif - - switch (mt) { - case NM_MT_CHG_ADM_STATE_ACK: - ret = abis_nm_rx_chg_adm_state_ack(mb); - break; - case NM_MT_SW_ACT_REQ: - ret = abis_nm_rx_sw_act_req(mb); - break; - case NM_MT_BS11_LMT_SESSION: - ret = abis_nm_rx_lmt_event(mb); - break; - case NM_MT_OPSTART_ACK: - abis_nm_debugp_foh(DNM, foh); - DEBUGPC(DNM, "Opstart ACK\n"); - break; - case NM_MT_SET_CHAN_ATTR_ACK: - abis_nm_debugp_foh(DNM, foh); - DEBUGPC(DNM, "Set Channel Attributes ACK\n"); - break; - case NM_MT_SET_RADIO_ATTR_ACK: - abis_nm_debugp_foh(DNM, foh); - DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n"); - break; - case NM_MT_CONN_MDROP_LINK_ACK: - abis_nm_debugp_foh(DNM, foh); - DEBUGPC(DNM, "CONN MDROP LINK ACK\n"); - break; - case NM_MT_IPACC_RESTART_ACK: - osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL); - break; - case NM_MT_IPACC_RESTART_NACK: - osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL); - break; - case NM_MT_SET_BTS_ATTR_ACK: - break; - case NM_MT_GET_ATTR_RESP: - ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr)); - break; - default: - abis_nm_debugp_foh(DNM, foh); - LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n", - get_value_string(abis_nm_msgtype_names, mt)); - } - - abis_nm_queue_send_next(bts); - return ret; -} - -static int abis_nm_rx_ipacc(struct msgb *mb); - -static int abis_nm_rcvmsg_manuf(struct msgb *mb) -{ - int rc; - struct e1inp_sign_link *sign_link = mb->dst; - int bts_type = sign_link->trx->bts->type; - - switch (bts_type) { - case GSM_BTS_TYPE_NANOBTS: - case GSM_BTS_TYPE_OSMOBTS: - rc = abis_nm_rx_ipacc(mb); - abis_nm_queue_send_next(sign_link->trx->bts); - break; - default: - LOGP(DNM, LOGL_ERROR, "don't know how to parse OML for this " - "BTS type (%u)\n", bts_type); - rc = 0; - break; - } - - return rc; -} - -/* High-Level API */ -/* Entry-point where L2 OML from BTS enters the NM code */ -int abis_nm_rcvmsg(struct msgb *msg) -{ - struct abis_om_hdr *oh = msgb_l2(msg); - int rc = 0; - - /* Various consistency checks */ - if (oh->placement != ABIS_OM_PLACEMENT_ONLY) { - LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n", - oh->placement); - if (oh->placement != ABIS_OM_PLACEMENT_FIRST) { - rc = -EINVAL; - goto err; - } - } - if (oh->sequence != 0) { - LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n", - oh->sequence); - rc = -EINVAL; - goto err; - } -#if 0 - unsigned int l2_len = msg->tail - (uint8_t *)msgb_l2(msg); - unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr); - if (oh->length + hlen > l2_len) { - LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n", - oh->length + sizeof(*oh), l2_len); - return -EINVAL; - } - if (oh->length + hlen < l2_len) - LOGP(DNM, LOGL_ERROR, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len); -#endif - msg->l3h = (unsigned char *)oh + sizeof(*oh); - - switch (oh->mdisc) { - case ABIS_OM_MDISC_FOM: - rc = abis_nm_rcvmsg_fom(msg); - break; - case ABIS_OM_MDISC_MANUF: - rc = abis_nm_rcvmsg_manuf(msg); - break; - case ABIS_OM_MDISC_MMI: - case ABIS_OM_MDISC_TRAU: - LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n", - oh->mdisc); - break; - default: - LOGP(DNM, LOGL_ERROR, "unknown ABIS OML message discriminator 0x%x\n", - oh->mdisc); - rc = -EINVAL; - break; - } -err: - msgb_free(msg); - return rc; -} - -#if 0 -/* initialized all resources */ -struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg) -{ - struct abis_nm_h *nmh; - - nmh = malloc(sizeof(*nmh)); - if (!nmh) - return NULL; - - nmh->cfg = cfg; - - return nmh; -} - -/* free all resources */ -void abis_nm_fini(struct abis_nm_h *nmh) -{ - free(nmh); -} -#endif - -/* Here we are trying to define a high-level API that can be used by - * the actual BSC implementation. However, the architecture is currently - * still under design. Ideally the calls to this API would be synchronous, - * while the underlying stack behind the APi runs in a traditional select - * based state machine. - */ - -/* 6.2 Software Load: */ -enum sw_state { - SW_STATE_NONE, - SW_STATE_WAIT_INITACK, - SW_STATE_WAIT_SEGACK, - SW_STATE_WAIT_ENDACK, - SW_STATE_WAIT_ACTACK, - SW_STATE_ERROR, -}; - -struct abis_nm_sw { - struct gsm_bts *bts; - int trx_nr; - gsm_cbfn *cbfn; - void *cb_data; - int forced; - - /* this will become part of the SW LOAD INITIATE */ - uint8_t obj_class; - uint8_t obj_instance[3]; - - uint8_t file_id[255]; - uint8_t file_id_len; - - uint8_t file_version[255]; - uint8_t file_version_len; - - uint8_t window_size; - uint8_t seg_in_window; - - int fd; - FILE *stream; - enum sw_state state; - int last_seg; -}; - -static struct abis_nm_sw g_sw; - -static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg) -{ - if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) { - msgb_v_put(msg, NM_ATT_SW_DESCR); - msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - } else if (sw->bts->type == GSM_BTS_TYPE_BS11) { - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - } else { - LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n"); - } -} - -/* 6.2.1 / 8.3.1: Load Data Initiate */ -static int sw_load_init(struct abis_nm_sw *sw) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t len = 3*2 + sw->file_id_len + sw->file_version_len; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class, - sw->obj_instance[0], sw->obj_instance[1], - sw->obj_instance[2]); - - sw_add_file_id_and_ver(sw, msg); - msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size); - - return abis_nm_sendmsg(sw->bts, msg); -} - -static int is_last_line(FILE *stream) -{ - char next_seg_buf[256]; - long pos; - - /* check if we're sending the last line */ - pos = ftell(stream); - - /* Did ftell fail? Then we are at the end for sure */ - if (pos < 0) - return 1; - - if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) { - int rc = fseek(stream, pos, SEEK_SET); - if (rc < 0) - return rc; - return 1; - } - - fseek(stream, pos, SEEK_SET); - return 0; -} - -/* 6.2.2 / 8.3.2 Load Data Segment */ -static int sw_load_segment(struct abis_nm_sw *sw) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - char seg_buf[256]; - char *line_buf = seg_buf+2; - unsigned char *tlv; - int len; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - - switch (sw->bts->type) { - case GSM_BTS_TYPE_BS11: - if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) { - perror("fgets reading segment"); - return -EINVAL; - } - seg_buf[0] = 0x00; - - /* check if we're sending the last line */ - sw->last_seg = is_last_line(sw->stream); - if (sw->last_seg) - seg_buf[1] = 0; - else - seg_buf[1] = 1 + sw->seg_in_window++; - - len = strlen(line_buf) + 2; - tlv = msgb_put(msg, TLV_GROSS_LEN(len)); - tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (uint8_t *)seg_buf); - /* BS11 wants CR + LF in excess of the TLV length !?! */ - tlv[1] -= 2; - - /* we only now know the exact length for the OM hdr */ - len = strlen(line_buf)+2; - break; - case GSM_BTS_TYPE_NANOBTS: { - osmo_static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough); - len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE); - if (len < 0) { - perror("read failed"); - return -EINVAL; - } - - if (len != IPACC_SEGMENT_SIZE) - sw->last_seg = 1; - - ++sw->seg_in_window; - msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const uint8_t *) seg_buf); - len += 3; - break; - } - default: - LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n"); - /* FIXME: Other BTS types */ - return -1; - } - - fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class, - sw->obj_instance[0], sw->obj_instance[1], - sw->obj_instance[2]); - - return abis_nm_sendmsg_direct(sw->bts, msg); -} - -/* 6.2.4 / 8.3.4 Load Data End */ -static int sw_load_end(struct abis_nm_sw *sw) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class, - sw->obj_instance[0], sw->obj_instance[1], - sw->obj_instance[2]); - - sw_add_file_id_and_ver(sw, msg); - return abis_nm_sendmsg(sw->bts, msg); -} - -/* Activate the specified software into the BTS */ -static int sw_activate(struct abis_nm_sw *sw) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t len = 2*2 + sw->file_id_len + sw->file_version_len; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class, - sw->obj_instance[0], sw->obj_instance[1], - sw->obj_instance[2]); - - /* FIXME: this is BS11 specific format */ - msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id); - msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len, - sw->file_version); - - return abis_nm_sendmsg(sw->bts, msg); -} - -struct sdp_firmware { - char magic[4]; - char more_magic[4]; - unsigned int header_length; - unsigned int file_length; -} __attribute__ ((packed)); - -static int parse_sdp_header(struct abis_nm_sw *sw) -{ - struct sdp_firmware firmware_header; - int rc; - struct stat stat; - - rc = read(sw->fd, &firmware_header, sizeof(firmware_header)); - if (rc != sizeof(firmware_header)) { - LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n"); - return -1; - } - - if (strncmp(firmware_header.magic, " SDP", 4) != 0) { - LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n"); - return -1; - } - - if (firmware_header.more_magic[0] != 0x10 || - firmware_header.more_magic[1] != 0x02 || - firmware_header.more_magic[2] != 0x00 || - firmware_header.more_magic[3] != 0x00) { - LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n"); - return -1; - } - - - if (fstat(sw->fd, &stat) == -1) { - LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n"); - return -1; - } - - if (ntohl(firmware_header.file_length) != stat.st_size) { - LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n"); - return -1; - } - - /* go back to the start as we checked the whole filesize.. */ - lseek(sw->fd, 0l, SEEK_SET); - LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n" - "There might be checksums in the file that are not\n" - "verified and incomplete firmware might be flashed.\n" - "There is absolutely no WARRANTY that flashing will\n" - "work.\n"); - return 0; -} - -static int sw_open_file(struct abis_nm_sw *sw, const char *fname) -{ - char file_id[12+1]; - char file_version[80+1]; - int rc; - - sw->fd = open(fname, O_RDONLY); - if (sw->fd < 0) - return sw->fd; - - switch (sw->bts->type) { - case GSM_BTS_TYPE_BS11: - sw->stream = fdopen(sw->fd, "r"); - if (!sw->stream) { - perror("fdopen"); - return -1; - } - /* read first line and parse file ID and VERSION */ - rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n", - file_id, file_version); - if (rc != 2) { - perror("parsing header line of software file"); - return -1; - } - strcpy((char *)sw->file_id, file_id); - sw->file_id_len = strlen(file_id); - strcpy((char *)sw->file_version, file_version); - sw->file_version_len = strlen(file_version); - /* rewind to start of file */ - rewind(sw->stream); - break; - case GSM_BTS_TYPE_NANOBTS: - /* TODO: extract that from the filename or content */ - rc = parse_sdp_header(sw); - if (rc < 0) { - fprintf(stderr, "Could not parse the ipaccess SDP header\n"); - return -1; - } - - strcpy((char *)sw->file_id, "id"); - sw->file_id_len = 3; - strcpy((char *)sw->file_version, "version"); - sw->file_version_len = 8; - break; - default: - /* We don't know how to treat them yet */ - close(sw->fd); - return -EINVAL; - } - - return 0; -} - -static void sw_close_file(struct abis_nm_sw *sw) -{ - switch (sw->bts->type) { - case GSM_BTS_TYPE_BS11: - fclose(sw->stream); - break; - default: - close(sw->fd); - break; - } -} - -/* Fill the window */ -static int sw_fill_window(struct abis_nm_sw *sw) -{ - int rc; - - while (sw->seg_in_window < sw->window_size) { - rc = sw_load_segment(sw); - if (rc < 0) - return rc; - if (sw->last_seg) - break; - } - return 0; -} - -/* callback function from abis_nm_rcvmsg() handler */ -static int abis_nm_rcvmsg_sw(struct msgb *mb) -{ - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - int rc = -1; - struct abis_nm_sw *sw = &g_sw; - enum sw_state old_state = sw->state; - - //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type); - - switch (sw->state) { - case SW_STATE_WAIT_INITACK: - switch (foh->msg_type) { - case NM_MT_LOAD_INIT_ACK: - /* fill window with segments */ - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_INIT_ACK, mb, - sw->cb_data, NULL); - rc = sw_fill_window(sw); - sw->state = SW_STATE_WAIT_SEGACK; - abis_nm_queue_send_next(sign_link->trx->bts); - break; - case NM_MT_LOAD_INIT_NACK: - if (sw->forced) { - DEBUGP(DNM, "FORCED: Ignoring Software Load " - "Init NACK\n"); - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_INIT_ACK, mb, - sw->cb_data, NULL); - rc = sw_fill_window(sw); - sw->state = SW_STATE_WAIT_SEGACK; - } else { - DEBUGP(DNM, "Software Load Init NACK\n"); - /* FIXME: cause */ - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_INIT_NACK, mb, - sw->cb_data, NULL); - sw->state = SW_STATE_ERROR; - } - abis_nm_queue_send_next(sign_link->trx->bts); - break; - } - break; - case SW_STATE_WAIT_SEGACK: - switch (foh->msg_type) { - case NM_MT_LOAD_SEG_ACK: - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_SEG_ACK, mb, - sw->cb_data, NULL); - sw->seg_in_window = 0; - if (!sw->last_seg) { - /* fill window with more segments */ - rc = sw_fill_window(sw); - sw->state = SW_STATE_WAIT_SEGACK; - } else { - /* end the transfer */ - sw->state = SW_STATE_WAIT_ENDACK; - rc = sw_load_end(sw); - } - abis_nm_queue_send_next(sign_link->trx->bts); - break; - case NM_MT_LOAD_ABORT: - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_ABORT, mb, - sw->cb_data, NULL); - break; - } - break; - case SW_STATE_WAIT_ENDACK: - switch (foh->msg_type) { - case NM_MT_LOAD_END_ACK: - sw_close_file(sw); - DEBUGP(DNM, "Software Load End (BTS %u)\n", - sw->bts->nr); - sw->state = SW_STATE_NONE; - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_END_ACK, mb, - sw->cb_data, NULL); - rc = 0; - abis_nm_queue_send_next(sign_link->trx->bts); - break; - case NM_MT_LOAD_END_NACK: - if (sw->forced) { - DEBUGP(DNM, "FORCED: Ignoring Software Load" - "End NACK\n"); - sw->state = SW_STATE_NONE; - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_END_ACK, mb, - sw->cb_data, NULL); - } else { - DEBUGP(DNM, "Software Load End NACK\n"); - /* FIXME: cause */ - sw->state = SW_STATE_ERROR; - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_LOAD_END_NACK, mb, - sw->cb_data, NULL); - } - abis_nm_queue_send_next(sign_link->trx->bts); - break; - } - case SW_STATE_WAIT_ACTACK: - switch (foh->msg_type) { - case NM_MT_ACTIVATE_SW_ACK: - /* we're done */ - DEBUGP(DNM, "Activate Software DONE!\n"); - sw->state = SW_STATE_NONE; - rc = 0; - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_ACTIVATE_SW_ACK, mb, - sw->cb_data, NULL); - abis_nm_queue_send_next(sign_link->trx->bts); - break; - case NM_MT_ACTIVATE_SW_NACK: - DEBUGP(DNM, "Activate Software NACK\n"); - /* FIXME: cause */ - sw->state = SW_STATE_ERROR; - if (sw->cbfn) - sw->cbfn(GSM_HOOK_NM_SWLOAD, - NM_MT_ACTIVATE_SW_NACK, mb, - sw->cb_data, NULL); - abis_nm_queue_send_next(sign_link->trx->bts); - break; - } - case SW_STATE_NONE: - switch (foh->msg_type) { - case NM_MT_ACTIVATE_SW_ACK: - rc = 0; - break; - } - break; - case SW_STATE_ERROR: - break; - } - - if (rc) - DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n", - foh->msg_type, old_state, sw->state); - - return rc; -} - -/* Load the specified software into the BTS */ -int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname, - uint8_t win_size, int forced, - gsm_cbfn *cbfn, void *cb_data) -{ - struct abis_nm_sw *sw = &g_sw; - int rc; - - DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n", - bts->nr, fname); - - if (sw->state != SW_STATE_NONE) - return -EBUSY; - - sw->bts = bts; - sw->trx_nr = trx_nr; - - switch (bts->type) { - case GSM_BTS_TYPE_BS11: - sw->obj_class = NM_OC_SITE_MANAGER; - sw->obj_instance[0] = 0xff; - sw->obj_instance[1] = 0xff; - sw->obj_instance[2] = 0xff; - break; - case GSM_BTS_TYPE_NANOBTS: - sw->obj_class = NM_OC_BASEB_TRANSC; - sw->obj_instance[0] = sw->bts->nr; - sw->obj_instance[1] = sw->trx_nr; - sw->obj_instance[2] = 0xff; - break; - case GSM_BTS_TYPE_UNKNOWN: - default: - LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n"); - return -1; - break; - } - sw->window_size = win_size; - sw->state = SW_STATE_WAIT_INITACK; - sw->cbfn = cbfn; - sw->cb_data = cb_data; - sw->forced = forced; - - rc = sw_open_file(sw, fname); - if (rc < 0) { - sw->state = SW_STATE_NONE; - return rc; - } - - return sw_load_init(sw); -} - -int abis_nm_software_load_status(struct gsm_bts *bts) -{ - struct abis_nm_sw *sw = &g_sw; - struct stat st; - int rc, percent; - - rc = fstat(sw->fd, &st); - if (rc < 0) { - perror("ERROR during stat"); - return rc; - } - - if (sw->stream) - percent = (ftell(sw->stream) * 100) / st.st_size; - else - percent = (lseek(sw->fd, 0, SEEK_CUR) * 100) / st.st_size; - return percent; -} - -/* Activate the specified software into the BTS */ -int abis_nm_software_activate(struct gsm_bts *bts, const char *fname, - gsm_cbfn *cbfn, void *cb_data) -{ - struct abis_nm_sw *sw = &g_sw; - int rc; - - DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n", - bts->nr, fname); - - if (sw->state != SW_STATE_NONE) - return -EBUSY; - - sw->bts = bts; - sw->obj_class = NM_OC_SITE_MANAGER; - sw->obj_instance[0] = 0xff; - sw->obj_instance[1] = 0xff; - sw->obj_instance[2] = 0xff; - sw->state = SW_STATE_WAIT_ACTACK; - sw->cbfn = cbfn; - sw->cb_data = cb_data; - - /* Open the file in order to fill some sw struct members */ - rc = sw_open_file(sw, fname); - if (rc < 0) { - sw->state = SW_STATE_NONE; - return rc; - } - sw_close_file(sw); - - return sw_activate(sw); -} - -static void fill_nm_channel(struct abis_nm_channel *ch, uint8_t bts_port, - uint8_t ts_nr, uint8_t subslot_nr) -{ - ch->attrib = NM_ATT_ABIS_CHANNEL; - ch->bts_port = bts_port; - ch->timeslot = ts_nr; - ch->subslot = subslot_nr; -} - -int abis_nm_establish_tei(struct gsm_bts *bts, uint8_t trx_nr, - uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot, - uint8_t tei) -{ - struct abis_om_hdr *oh; - struct abis_nm_channel *ch; - uint8_t len = sizeof(*ch) + 2; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER, - bts->bts_nr, trx_nr, 0xff); - - msgb_tv_put(msg, NM_ATT_TEI, tei); - - ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); - fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); - - return abis_nm_sendmsg(bts, msg); -} - -/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */ -int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx, - uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot) -{ - struct gsm_bts *bts = trx->bts; - struct abis_om_hdr *oh; - struct abis_nm_channel *ch; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN, - NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff); - - ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); - fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); - - return abis_nm_sendmsg(bts, msg); -} - -#if 0 -int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst, - struct abis_nm_abis_channel *chan) -{ -} -#endif - -int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts, - uint8_t e1_port, uint8_t e1_timeslot, - uint8_t e1_subslot) -{ - struct gsm_bts *bts = ts->trx->bts; - struct abis_om_hdr *oh; - struct abis_nm_channel *ch; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF, - NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr); - - ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); - fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); - - DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n", - gsm_ts_name(ts), - e1_port, e1_timeslot, e1_subslot); - - return abis_nm_sendmsg(bts, msg); -} - -#if 0 -int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst, - struct abis_nm_abis_channel *chan, - uint8_t subchan) -{ -} -#endif - -/* 3GPP TS 52.021 § 8.11.1 */ -int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr, - const uint8_t *attr, uint8_t attr_len) -{ - struct abis_om_hdr *oh; - struct msgb *msg; - - if (bts->type != GSM_BTS_TYPE_OSMOBTS) { - LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n", - bts->nr, btstype2str(bts->type)); - return -EINVAL; - } - - DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr); - - msg = nm_msgb_alloc(); - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class, - bts_nr, trx_nr, ts_nr); - msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr); - - return abis_nm_sendmsg(bts, msg); -} - -/* Chapter 8.6.1 */ -int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t *cur; - - DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff); - cur = msgb_put(msg, attr_len); - memcpy(cur, attr, attr_len); - - return abis_nm_sendmsg(bts, msg); -} - -/* Chapter 8.6.2 */ -int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, uint8_t *attr, int attr_len) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t *cur; - - DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER, - trx->bts->bts_nr, trx->nr, 0xff); - cur = msgb_put(msg, attr_len); - memcpy(cur, attr, attr_len); - - return abis_nm_sendmsg(trx->bts, msg); -} - -int abis_nm_update_max_power_red(struct gsm_bts_trx *trx) -{ - uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 }; - return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr)); -} - -static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb, - const char **reason) -{ - int i; - - *reason = "Reason unknown"; - - /* As it turns out, the BS-11 has some very peculiar restrictions - * on the channel combinations it allows */ - switch (ts->trx->bts->type) { - case GSM_BTS_TYPE_BS11: - switch (chan_comb) { - case NM_CHANC_TCHHalf: - case NM_CHANC_TCHHalf2: - case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH: - /* not supported */ - *reason = "TCH/H is not supported."; - return -EINVAL; - case NM_CHANC_SDCCH: - /* only one SDCCH/8 per TRX */ - for (i = 0; i < TRX_NR_TS; i++) { - if (i == ts->nr) - continue; - if (ts->trx->ts[i].nm_chan_comb == - NM_CHANC_SDCCH) { - *reason = "Only one SDCCH/8 per TRX allowed."; - return -EINVAL; - } - } - /* not allowed for TS0 of BCCH-TRX */ - if (ts->trx == ts->trx->bts->c0 && - ts->nr == 0) { - *reason = "SDCCH/8 must be on TS0."; - return -EINVAL; - } - - /* not on the same TRX that has a BCCH+SDCCH4 - * combination */ - if (ts->trx != ts->trx->bts->c0 && - (ts->trx->ts[0].nm_chan_comb == 5 || - ts->trx->ts[0].nm_chan_comb == 8)) { - *reason = "SDCCH/8 and BCCH must be on the same TRX."; - return -EINVAL; - } - break; - case NM_CHANC_mainBCCH: - case NM_CHANC_BCCHComb: - /* allowed only for TS0 of C0 */ - if (ts->trx != ts->trx->bts->c0 || ts->nr != 0) { - *reason = "Main BCCH must be on TS0."; - return -EINVAL; - } - break; - case NM_CHANC_BCCH: - /* allowed only for TS 2/4/6 of C0 */ - if (ts->trx != ts->trx->bts->c0) { - *reason = "BCCH must be on C0."; - return -EINVAL; - } - if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) { - *reason = "BCCH must be on TS 2/4/6."; - return -EINVAL; - } - break; - case 8: /* this is not like 08.58, but in fact - * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */ - /* FIXME: only one CBCH allowed per cell */ - break; - } - break; - case GSM_BTS_TYPE_NANOBTS: - switch (ts->nr) { - case 0: - if (ts->trx->nr == 0) { - /* only on TRX0 */ - switch (chan_comb) { - case NM_CHANC_BCCH: - case NM_CHANC_mainBCCH: - case NM_CHANC_BCCHComb: - return 0; - break; - default: - *reason = "TS0 of TRX0 must carry a BCCH."; - return -EINVAL; - } - } else { - switch (chan_comb) { - case NM_CHANC_TCHFull: - case NM_CHANC_TCHHalf: - case NM_CHANC_IPAC_TCHFull_TCHHalf: - return 0; - default: - *reason = "TS0 must carry a TCH/F or TCH/H."; - return -EINVAL; - } - } - break; - case 1: - if (ts->trx->nr == 0) { - switch (chan_comb) { - case NM_CHANC_SDCCH_CBCH: - if (ts->trx->ts[0].nm_chan_comb == - NM_CHANC_mainBCCH) - return 0; - *reason = "TS0 must be the main BCCH for CBCH."; - return -EINVAL; - case NM_CHANC_SDCCH: - case NM_CHANC_TCHFull: - case NM_CHANC_TCHHalf: - case NM_CHANC_IPAC_TCHFull_TCHHalf: - case NM_CHANC_IPAC_TCHFull_PDCH: - case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH: - return 0; - default: - *reason = "TS1 must carry a CBCH, SDCCH or TCH."; - return -EINVAL; - } - } else { - switch (chan_comb) { - case NM_CHANC_SDCCH: - case NM_CHANC_TCHFull: - case NM_CHANC_TCHHalf: - case NM_CHANC_IPAC_TCHFull_TCHHalf: - return 0; - default: - *reason = "TS1 must carry a SDCCH or TCH."; - return -EINVAL; - } - } - break; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - switch (chan_comb) { - case NM_CHANC_TCHFull: - case NM_CHANC_TCHHalf: - case NM_CHANC_IPAC_TCHFull_TCHHalf: - return 0; - case NM_CHANC_IPAC_PDCH: - case NM_CHANC_IPAC_TCHFull_PDCH: - case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH: - if (ts->trx->nr == 0) - return 0; - else { - *reason = "PDCH must be on TRX0."; - return -EINVAL; - } - } - break; - } - *reason = "Unknown combination"; - return -EINVAL; - case GSM_BTS_TYPE_OSMOBTS: - /* no known restrictions */ - return 0; - default: - /* unknown BTS type */ - return 0; - } - return 0; -} - -/* Chapter 8.6.3 */ -int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb) -{ - struct gsm_bts *bts = ts->trx->bts; - struct abis_om_hdr *oh; - uint8_t zero = 0x00; - struct msgb *msg = nm_msgb_alloc(); - uint8_t len = 2 + 2; - const char *reason = NULL; - - if (bts->type == GSM_BTS_TYPE_BS11) - len += 4 + 2 + 2 + 3; - - DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts)); - if (verify_chan_comb(ts, chan_comb, &reason) < 0) { - msgb_free(msg); - LOGP(DNM, LOGL_ERROR, - "Invalid Channel Combination %d on %s. Reason: %s\n", - chan_comb, gsm_ts_name(ts), reason); - return -EINVAL; - } - ts->nm_chan_comb = chan_comb; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR, - NM_OC_CHANNEL, bts->bts_nr, - ts->trx->nr, ts->nr); - msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb); - if (ts->hopping.enabled) { - unsigned int i; - uint8_t *len; - - msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn); - msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio); - - /* build the ARFCN list */ - msgb_put_u8(msg, NM_ATT_ARFCN_LIST); - len = msgb_put(msg, 1); - *len = 0; - for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) { - if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) { - msgb_put_u16(msg, i); - /* At least BS-11 wants a TLV16 here */ - if (bts->type == GSM_BTS_TYPE_BS11) - *len += 1; - else - *len += sizeof(uint16_t); - } - } - } - msgb_tv_put(msg, NM_ATT_TSC, gsm_ts_tsc(ts)); /* training sequence */ - if (bts->type == GSM_BTS_TYPE_BS11) - msgb_tlv_put(msg, 0x59, 1, &zero); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_sw_act_req_ack(struct gsm_bts *bts, uint8_t obj_class, uint8_t i1, - uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK; - uint8_t len = att_len; - - if (nack) { - len += 2; - msgtype = NM_MT_SW_ACT_REQ_NACK; - } - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3); - - if (attr) { - uint8_t *ptr = msgb_put(msg, att_len); - memcpy(ptr, attr, att_len); - } - if (nack) - msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP); - - return abis_nm_sendmsg_direct(bts, msg); -} - -int abis_nm_raw_msg(struct gsm_bts *bts, int len, uint8_t *rawmsg) -{ - struct msgb *msg = nm_msgb_alloc(); - struct abis_om_hdr *oh; - uint8_t *data; - - oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh)); - fill_om_hdr(oh, len); - data = msgb_put(msg, len); - memcpy(data, rawmsg, len); - - return abis_nm_sendmsg(bts, msg); -} - -/* Siemens specific commands */ -static int __simple_cmd(struct gsm_bts *bts, uint8_t msg_type) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER, - 0xff, 0xff, 0xff); - - return abis_nm_sendmsg(bts, msg); -} - -/* Chapter 8.9.2 */ -int abis_nm_opstart(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2) -{ - struct abis_om_hdr *oh; - struct abis_om_fom_hdr *foh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2); - - abis_nm_debugp_foh(DNM, foh); - DEBUGPC(DNM, "Sending OPSTART\n"); - - return abis_nm_sendmsg(bts, msg); -} - -/* Chapter 8.8.5 */ -int abis_nm_chg_adm_state(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, - uint8_t i1, uint8_t i2, enum abis_nm_adm_state adm_state) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2); - msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_conn_mdrop_link(struct gsm_bts *bts, uint8_t e1_port0, uint8_t ts0, - uint8_t e1_port1, uint8_t ts1) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t *attr; - - DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n", - e1_port0, ts0, e1_port1, ts1); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK, - NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00); - - attr = msgb_put(msg, 3); - attr[0] = NM_ATT_MDROP_LINK; - attr[1] = e1_port0; - attr[2] = ts0; - - attr = msgb_put(msg, 3); - attr[0] = NM_ATT_MDROP_NEXT; - attr[1] = e1_port1; - attr[2] = ts1; - - return abis_nm_sendmsg(bts, msg); -} - -/* Chapter 8.7.1 */ -int abis_nm_perform_test(struct gsm_bts *bts, uint8_t obj_class, - uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr, - uint8_t test_nr, uint8_t auton_report, struct msgb *msg) -{ - struct abis_om_hdr *oh; - - DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(test_nr)); - - if (!msg) - msg = nm_msgb_alloc(); - - msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report); - msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr); - oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST, - obj_class, bts_nr, trx_nr, ts_nr); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_event_reports(struct gsm_bts *bts, int on) -{ - if (on == 0) - return __simple_cmd(bts, NM_MT_STOP_EVENT_REP); - else - return __simple_cmd(bts, NM_MT_REST_EVENT_REP); -} - -/* Siemens (or BS-11) specific commands */ - -int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect) -{ - if (reconnect == 0) - return __simple_cmd(bts, NM_MT_BS11_DISCONNECT); - else - return __simple_cmd(bts, NM_MT_BS11_RECONNECT); -} - -int abis_nm_bs11_restart(struct gsm_bts *bts) -{ - return __simple_cmd(bts, NM_MT_BS11_RESTART); -} - - -struct bs11_date_time { - uint16_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t min; - uint8_t sec; -} __attribute__((packed)); - - -void get_bs11_date_time(struct bs11_date_time *aet) -{ - time_t t; - struct tm *tm; - - t = time(NULL); - tm = localtime(&t); - aet->sec = tm->tm_sec; - aet->min = tm->tm_min; - aet->hour = tm->tm_hour; - aet->day = tm->tm_mday; - aet->month = tm->tm_mon; - aet->year = htons(1900 + tm->tm_year); -} - -int abis_nm_bs11_reset_resource(struct gsm_bts *bts) -{ - return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE); -} - -int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin) -{ - if (begin) - return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX); - else - return __simple_cmd(bts, NM_MT_BS11_END_DB_TX); -} - -int abis_nm_bs11_create_object(struct gsm_bts *bts, - enum abis_bs11_objtype type, uint8_t idx, - uint8_t attr_len, const uint8_t *attr) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t *cur; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ, - NM_OC_BS11, type, 0, idx); - cur = msgb_put(msg, attr_len); - memcpy(cur, attr, attr_len); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_delete_object(struct gsm_bts *bts, - enum abis_bs11_objtype type, uint8_t idx) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, - NM_OC_BS11, type, 0, idx); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, uint8_t idx) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t zero = 0x00; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ, - NM_OC_BS11_ENVABTSE, 0, idx, 0xff); - msgb_tlv_put(msg, 0x99, 1, &zero); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_create_bport(struct gsm_bts *bts, uint8_t idx) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT, - idx, 0xff, 0xff); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_delete_bport(struct gsm_bts *bts, uint8_t idx) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ, NM_OC_BS11_BPORT, - idx, 0xff, 0xff); - - return abis_nm_sendmsg(bts, msg); -} - -static const uint8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL }; -int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER, - 0xff, 0xff, 0xff); - msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr); - - return abis_nm_sendmsg(bts, msg); -} - -/* like abis_nm_conn_terr_traf + set_tei */ -int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, uint8_t e1_port, - uint8_t e1_timeslot, uint8_t e1_subslot, - uint8_t tei) -{ - struct abis_om_hdr *oh; - struct abis_nm_channel *ch; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR, - NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff); - - ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); - fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); - msgb_tv_put(msg, NM_ATT_TEI, tei); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, uint8_t level) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, - NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr); - msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level); - - return abis_nm_sendmsg(trx->bts, msg); -} - -int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t attr = NM_ATT_BS11_TXPWR; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR, - NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr); - msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr); - - return abis_nm_sendmsg(trx->bts, msg); -} - -int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t attr[] = { NM_ATT_BS11_PLL_MODE }; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR, - NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00); - msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_get_cclk(struct gsm_bts *bts) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY, - NM_ATT_BS11_CCLK_TYPE }; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR, - NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00); - msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr); - - return abis_nm_sendmsg(bts, msg); - -} - -//static const uint8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 }; - -int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on) -{ - return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on); -} - -int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on) -{ - return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on); -} - -int abis_nm_bs11_logon(struct gsm_bts *bts, uint8_t level, const char *name, int on) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - struct bs11_date_time bdt; - - get_bs11_date_time(&bdt); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - if (on) { - uint8_t len = 3*2 + sizeof(bdt) - + 1 + strlen(name); - fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON, - NM_OC_BS11_BTSE, 0xff, 0xff, 0xff); - msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME, - sizeof(bdt), (uint8_t *) &bdt); - msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV, - 1, &level); - msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME, - strlen(name), (uint8_t *)name); - } else { - fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF, - NM_OC_BS11_BTSE, 0xff, 0xff, 0xff); - } - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password) -{ - struct abis_om_hdr *oh; - struct msgb *msg; - - if (strlen(password) != 10) - return -EINVAL; - - msg = nm_msgb_alloc(); - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR, - NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00); - msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const uint8_t *)password); - - return abis_nm_sendmsg(bts, msg); -} - -/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */ -int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked) -{ - struct abis_om_hdr *oh; - struct msgb *msg; - uint8_t tlv_value; - - msg = nm_msgb_alloc(); - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11, - BS11_OBJ_LI, 0x00, 0x00); - - if (locked) - tlv_value = BS11_LI_PLL_LOCKED; - else - tlv_value = BS11_LI_PLL_STANDALONE; - - msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value); - - return abis_nm_sendmsg(bts, msg); -} - -/* Set the calibration value of the PLL (work value/set value) - * It depends on the login which one is changed */ -int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value) -{ - struct abis_om_hdr *oh; - struct msgb *msg; - uint8_t tlv_value[2]; - - msg = nm_msgb_alloc(); - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11, - BS11_OBJ_TRX1, 0x00, 0x00); - - tlv_value[0] = value>>8; - tlv_value[1] = value&0xff; - - msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, tlv_value); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_get_state(struct gsm_bts *bts) -{ - return __simple_cmd(bts, NM_MT_BS11_GET_STATE); -} - -/* BS11 SWL */ - -void *tall_fle_ctx; - -struct abis_nm_bs11_sw { - struct gsm_bts *bts; - char swl_fname[PATH_MAX]; - uint8_t win_size; - int forced; - struct llist_head file_list; - gsm_cbfn *user_cb; /* specified by the user */ -}; -static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw; - -struct file_list_entry { - struct llist_head list; - char fname[PATH_MAX]; -}; - -struct file_list_entry *fl_dequeue(struct llist_head *queue) -{ - struct llist_head *lh; - - if (llist_empty(queue)) - return NULL; - - lh = queue->next; - llist_del(lh); - - return llist_entry(lh, struct file_list_entry, list); -} - -static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw) -{ - char linebuf[255]; - struct llist_head *lh, *lh2; - FILE *swl; - int rc = 0; - - swl = fopen(bs11_sw->swl_fname, "r"); - if (!swl) - return -ENODEV; - - /* zero the stale file list, if any */ - llist_for_each_safe(lh, lh2, &bs11_sw->file_list) { - llist_del(lh); - talloc_free(lh); - } - - while (fgets(linebuf, sizeof(linebuf), swl)) { - char file_id[12+1]; - char file_version[80+1]; - struct file_list_entry *fle; - static char dir[PATH_MAX]; - - if (strlen(linebuf) < 4) - continue; - - rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version); - if (rc < 0) { - perror("ERR parsing SWL file"); - rc = -EINVAL; - goto out; - } - if (rc < 2) - continue; - - fle = talloc_zero(tall_fle_ctx, struct file_list_entry); - if (!fle) { - rc = -ENOMEM; - goto out; - } - - /* construct new filename */ - osmo_strlcpy(dir, bs11_sw->swl_fname, sizeof(dir)); - strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1); - strcat(fle->fname, "/"); - strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname)); - - llist_add_tail(&fle->list, &bs11_sw->file_list); - } - -out: - fclose(swl); - return rc; -} - -/* bs11 swload specific callback, passed to abis_nm core swload */ -static int bs11_swload_cbfn(unsigned int hook, unsigned int event, - struct msgb *msg, void *data, void *param) -{ - struct abis_nm_bs11_sw *bs11_sw = data; - struct file_list_entry *fle; - int rc = 0; - - switch (event) { - case NM_MT_LOAD_END_ACK: - fle = fl_dequeue(&bs11_sw->file_list); - if (fle) { - /* start download the next file of our file list */ - rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname, - bs11_sw->win_size, - bs11_sw->forced, - &bs11_swload_cbfn, bs11_sw); - talloc_free(fle); - } else { - /* activate the SWL */ - rc = abis_nm_software_activate(bs11_sw->bts, - bs11_sw->swl_fname, - bs11_swload_cbfn, - bs11_sw); - } - break; - case NM_MT_LOAD_SEG_ACK: - case NM_MT_LOAD_END_NACK: - case NM_MT_LOAD_INIT_ACK: - case NM_MT_LOAD_INIT_NACK: - case NM_MT_ACTIVATE_SW_NACK: - case NM_MT_ACTIVATE_SW_ACK: - default: - /* fallthrough to the user callback */ - if (bs11_sw->user_cb) - rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL); - break; - } - - return rc; -} - -/* Siemens provides a SWL file that is a mere listing of all the other - * files that are part of a software release. We need to upload first - * the list file, and then each file that is listed in the list file */ -int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname, - uint8_t win_size, int forced, gsm_cbfn *cbfn) -{ - struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw; - struct file_list_entry *fle; - int rc = 0; - - INIT_LLIST_HEAD(&bs11_sw->file_list); - bs11_sw->bts = bts; - bs11_sw->win_size = win_size; - bs11_sw->user_cb = cbfn; - bs11_sw->forced = forced; - - osmo_strlcpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname)); - rc = bs11_read_swl_file(bs11_sw); - if (rc < 0) - return rc; - - /* dequeue next item in file list */ - fle = fl_dequeue(&bs11_sw->file_list); - if (!fle) - return -EINVAL; - - /* start download the next file of our file list */ - rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced, - bs11_swload_cbfn, bs11_sw); - talloc_free(fle); - return rc; -} - -#if 0 -static uint8_t req_attr_btse[] = { - NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION, - NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV, - NM_ATT_BS11_LMT_USER_NAME, - - 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME, - - NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY, - - NM_ATT_BS11_SW_LOAD_STORED }; - -static uint8_t req_attr_btsm[] = { - NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME, - NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID, - NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG, - NM_ATT_SW_DESCR, NM_ATT_GET_ARI }; -#endif - -static uint8_t req_attr[] = { - NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE, - 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO, - 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL }; - -int abis_nm_bs11_get_serno(struct gsm_bts *bts) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - /* SiemensHW CCTRL object */ - fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11, - 0x03, 0x00, 0x00); - msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_set_ext_time(struct gsm_bts *bts) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - struct bs11_date_time aet; - - get_bs11_date_time(&aet); - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - /* SiemensHW CCTRL object */ - fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER, - 0xff, 0xff, 0xff); - msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (uint8_t *) &aet); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - uint8_t attr = NM_ATT_BS11_LINE_CFG; - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR, - NM_OC_BS11_BPORT, bport, 0xff, 0x02); - msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr); - - return abis_nm_sendmsg(bts, msg); -} - -int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, uint8_t bport, enum abis_bs11_line_cfg line_cfg) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - struct bs11_date_time aet; - - get_bs11_date_time(&aet); - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT, - bport, 0xff, 0x02); - msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg); - - return abis_nm_sendmsg(bts, msg); -} - -/* ip.access nanoBTS specific commands */ -static const char ipaccess_magic[] = "com.ipaccess"; - - -static int abis_nm_rx_ipacc(struct msgb *msg) -{ - struct in_addr addr; - struct abis_om_hdr *oh = msgb_l2(msg); - struct abis_om_fom_hdr *foh; - uint8_t idstrlen = oh->data[0]; - struct tlv_parsed tp; - struct ipacc_ack_signal_data signal; - struct e1inp_sign_link *sign_link = msg->dst; - - if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) { - LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n"); - return -EINVAL; - } - - foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen); - abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh)); - - abis_nm_debugp_foh(DNM, foh); - - DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type); - - switch (foh->msg_type) { - case NM_MT_IPACC_RSL_CONNECT_ACK: - DEBUGPC(DNM, "RSL CONNECT ACK "); - if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) { - memcpy(&addr, - TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr)); - - DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr)); - } - if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT)) - DEBUGPC(DNM, "PORT=%u ", - ntohs(*((uint16_t *) - TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT)))); - if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID)) - DEBUGPC(DNM, "STREAM=0x%02x ", - *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID)); - DEBUGPC(DNM, "\n"); - break; - case NM_MT_IPACC_RSL_CONNECT_NACK: - LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK "); - if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", - abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); - else - LOGPC(DNM, LOGL_ERROR, "\n"); - break; - case NM_MT_IPACC_SET_NVATTR_ACK: - DEBUGPC(DNM, "SET NVATTR ACK\n"); - /* FIXME: decode and show the actual attributes */ - break; - case NM_MT_IPACC_SET_NVATTR_NACK: - LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK "); - if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", - abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); - else - LOGPC(DNM, LOGL_ERROR, "\n"); - break; - case NM_MT_IPACC_GET_NVATTR_ACK: - DEBUGPC(DNM, "GET NVATTR ACK\n"); - /* FIXME: decode and show the actual attributes */ - break; - case NM_MT_IPACC_GET_NVATTR_NACK: - LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK "); - if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", - abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); - else - LOGPC(DNM, LOGL_ERROR, "\n"); - break; - case NM_MT_IPACC_SET_ATTR_ACK: - DEBUGPC(DNM, "SET ATTR ACK\n"); - break; - case NM_MT_IPACC_SET_ATTR_NACK: - LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK "); - if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", - abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); - else - LOGPC(DNM, LOGL_ERROR, "\n"); - break; - default: - DEBUGPC(DNM, "unknown\n"); - break; - } - - /* signal handling */ - switch (foh->msg_type) { - case NM_MT_IPACC_RSL_CONNECT_NACK: - case NM_MT_IPACC_SET_NVATTR_NACK: - case NM_MT_IPACC_GET_NVATTR_NACK: - signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr); - signal.msg_type = foh->msg_type; - osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal); - break; - case NM_MT_IPACC_SET_NVATTR_ACK: - signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr); - signal.msg_type = foh->msg_type; - osmo_signal_dispatch(SS_NM, S_NM_IPACC_ACK, &signal); - break; - default: - break; - } - - return 0; -} - -/* send an ip-access manufacturer specific message */ -int abis_nm_ipaccess_msg(struct gsm_bts *bts, uint8_t msg_type, - uint8_t obj_class, uint8_t bts_nr, - uint8_t trx_nr, uint8_t ts_nr, - uint8_t *attr, int attr_len) -{ - struct msgb *msg = nm_msgb_alloc(); - struct abis_om_hdr *oh; - struct abis_om_fom_hdr *foh; - uint8_t *data; - - /* construct the 12.21 OM header, observe the erroneous length */ - oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh)); - fill_om_hdr(oh, sizeof(*foh) + attr_len); - oh->mdisc = ABIS_OM_MDISC_MANUF; - - /* add the ip.access magic */ - data = msgb_put(msg, sizeof(ipaccess_magic)+1); - *data++ = sizeof(ipaccess_magic); - memcpy(data, ipaccess_magic, sizeof(ipaccess_magic)); - - /* fill the 12.21 FOM header */ - foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh)); - foh->msg_type = msg_type; - foh->obj_class = obj_class; - foh->obj_inst.bts_nr = bts_nr; - foh->obj_inst.trx_nr = trx_nr; - foh->obj_inst.ts_nr = ts_nr; - - if (attr && attr_len) { - data = msgb_put(msg, attr_len); - memcpy(data, attr, attr_len); - } - - return abis_nm_sendmsg(bts, msg); -} - -/* set some attributes in NVRAM */ -int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, uint8_t *attr, - int attr_len) -{ - return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR, - NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr, - attr_len); -} - -int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, - uint32_t ip, uint16_t port, uint8_t stream) -{ - struct in_addr ia; - uint8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0, - NM_ATT_IPACC_DST_IP_PORT, 0, 0, - NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 }; - - int attr_len = sizeof(attr); - - ia.s_addr = htonl(ip); - attr[1] = stream; - attr[3] = port >> 8; - attr[4] = port & 0xff; - *(uint32_t *)(attr+6) = ia.s_addr; - - /* if ip == 0, we use the default IP */ - if (ip == 0) - attr_len -= 5; - - DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n", - inet_ntoa(ia), port, stream); - - return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT, - NM_OC_BASEB_TRANSC, trx->bts->bts_nr, - trx->nr, 0xff, attr, attr_len); -} - -/* restart / reboot an ip.access nanoBTS */ -int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx) -{ - struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC, - trx->bts->nr, trx->nr, 0xff); - - return abis_nm_sendmsg_direct(trx->bts, msg); -} - -int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class, - uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr, - uint8_t *attr, uint8_t attr_len) -{ - return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR, - obj_class, bts_nr, trx_nr, ts_nr, - attr, attr_len); -} - -void abis_nm_ipaccess_cgi(uint8_t *buf, struct gsm_bts *bts) -{ - /* we simply reuse the GSM48 function and overwrite the RAC - * with the Cell ID */ - gsm48_ra_id_by_bts(buf, bts); - *((uint16_t *)(buf + 5)) = htons(bts->cell_identity); -} - -void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked) -{ - int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; - - trx->mo.nm_state.administrative = new_state; - if (!trx->bts || !trx->bts->oml_link) - return; - - abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER, - trx->bts->bts_nr, trx->nr, 0xff, - new_state); -} - -static const struct value_string ipacc_testres_names[] = { - { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" }, - { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" }, - { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" }, - { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" }, - { NM_IPACC_TESTRES_STOPPED, "STOPPED" }, - { 0, NULL } -}; - -const char *ipacc_testres_name(uint8_t res) -{ - return get_value_string(ipacc_testres_names, res); -} - -void ipac_parse_cgi(struct cell_global_id *cid, const uint8_t *buf) -{ - cid->mcc = (buf[0] & 0xf) * 100; - cid->mcc += (buf[0] >> 4) * 10; - cid->mcc += (buf[1] & 0xf) * 1; - - if (buf[1] >> 4 == 0xf) { - cid->mnc = (buf[2] & 0xf) * 10; - cid->mnc += (buf[2] >> 4) * 1; - } else { - cid->mnc = (buf[2] & 0xf) * 100; - cid->mnc += (buf[2] >> 4) * 10; - cid->mnc += (buf[1] >> 4) * 1; - } - - cid->lac = ntohs(*((uint16_t *)&buf[3])); - cid->ci = ntohs(*((uint16_t *)&buf[5])); -} - -/* parse BCCH information IEI from wire format to struct ipac_bcch_info */ -int ipac_parse_bcch_info(struct ipac_bcch_info *binf, uint8_t *buf) -{ - uint8_t *cur = buf; - uint16_t len __attribute__((unused)); - - memset(binf, 0, sizeof(*binf)); - - if (cur[0] != NM_IPAC_EIE_BCCH_INFO) - return -EINVAL; - cur++; - - len = ntohs(*(uint16_t *)cur); - cur += 2; - - binf->info_type = ntohs(*(uint16_t *)cur); - cur += 2; - - if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL) - binf->freq_qual = *cur >> 2; - - binf->arfcn = (*cur++ & 3) << 8; - binf->arfcn |= *cur++; - - if (binf->info_type & IPAC_BINF_RXLEV) - binf->rx_lev = *cur & 0x3f; - cur++; - - if (binf->info_type & IPAC_BINF_RXQUAL) - binf->rx_qual = *cur & 0x7; - cur++; - - if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL) - binf->freq_err = ntohs(*(uint16_t *)cur); - cur += 2; - - if (binf->info_type & IPAC_BINF_FRAME_OFFSET) - binf->frame_offset = ntohs(*(uint16_t *)cur); - cur += 2; - - if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET) - binf->frame_nr_offset = ntohl(*(uint32_t *)cur); - cur += 4; - -#if 0 - /* Somehow this is not set correctly */ - if (binf->info_type & IPAC_BINF_BSIC) -#endif - binf->bsic = *cur & 0x3f; - cur++; - - ipac_parse_cgi(&binf->cgi, cur); - cur += 7; - - if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) { - memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2)); - cur += sizeof(binf->ba_list_si2); - } - - if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) { - memcpy(binf->ba_list_si2bis, cur, - sizeof(binf->ba_list_si2bis)); - cur += sizeof(binf->ba_list_si2bis); - } - - if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) { - memcpy(binf->ba_list_si2ter, cur, - sizeof(binf->ba_list_si2ter)); - cur += sizeof(binf->ba_list_si2ter); - } - - return 0; -} - -void abis_nm_clear_queue(struct gsm_bts *bts) -{ - struct msgb *msg; - - while (!llist_empty(&bts->abis_queue)) { - msg = msgb_dequeue(&bts->abis_queue); - msgb_free(msg); - } - - bts->abis_nm_pend = 0; -} diff --git a/src/libbsc/abis_nm_ipaccess.c b/src/libbsc/abis_nm_ipaccess.c deleted file mode 100644 index b8225383a..000000000 --- a/src/libbsc/abis_nm_ipaccess.c +++ /dev/null @@ -1,87 +0,0 @@ -/* GSM Network Management (OML) messages on the A-bis interface - * Extensions for the ip.access A-bis over IP protocol*/ - -/* (C) 2008-2009 by Harald Welte - * - * 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 . - * - */ - -/* A list of all the 'embedded' attributes of ip.access */ -enum ipa_embedded_att { - IPA_ATT_ARFCN_WHITELIST = 0x01, - IPA_ATT_ARFCN_BLACKLIST = 0x02, - IPA_ATT_FREQ_ERR_LIST = 0x03, - IPA_ATT_CHAN_USAGE_LIST = 0x04, - IPA_ATT_BCCH_INF_TYPE = 0x05, - IPA_ATT_BCCH_INF = 0x06, - IPA_ATT_CONFIG = 0x07, - IPA_ATT_RESULT_DETAILS = 0x08, - IPA_ATT_RXLEV_THRESH = 0x09, - IPA_ATT_FREQ_SYNC_OPT = 0x0a, - IPA_ATT_MAC_ADDR = 0x0b, - IPA_ATT_HW_SW_COMPAT_NR = 0x0c, - IPA_ATT_MANUF_SER_NR = 0x0d, - IPA_ATT_OEM_ID = 0x0e, - IPA_ATT_DATETIME_MANUF = 0x0f, - IPA_ATT_DATETIME_CALIB = 0x10, - IPA_ATT_BEACON_INF = 0x11, - IPA_ATT_FREQ_ERR = 0x12, - IPA_ATT_SNMP_COMM_STRING = 0x13, - IPA_ATT_SNMP_TRAP_ADDR = 0x14, - IPA_ATT_SNMP_TRAP_PORT = 0x15, - IPA_ATT_SNMP_MAN_ADDR = 0x16, - IPA_ATT_SNMP_SYS_CONTACT = 0x17, - IPA_ATT_FACTORY_ID = 0x18, - IPA_ATT_FACTORY_SERIAL = 0x19, - IPA_ATT_LOGGED_EVT_IND = 0x1a, - IPA_ATT_LOCAL_ADD_TEXT = 0x1b, - IPA_ATT_FREQ_BANDS = 0x1c, - IPA_ATT_MAX_TA = 0x1d, - IPA_ATT_CIPH_ALG = 0x1e, - IPA_ATT_CHAN_TYPES = 0x1f, - IPA_ATT_CHAN_MODES = 0x20, - IPA_ATT_GPRS_CODING_SCHEMES = 0x21, - IPA_ATT_RTP_FEATURES = 0x22, - IPA_ATT_RSL_FEATURES = 0x23, - IPA_ATT_BTS_HW_CLASS = 0x24, - IPA_ATT_BTS_ID = 0x25, - IPA_ATT_BCAST_L2_MSG = 0x26, -}; - -/* append an ip.access channel list to the given msgb */ -static int ipa_chan_list_append(struct msgb *msg, uint8_t ie, - uint16_t *arfcns, int arfcn_count) -{ - int i; - uint8_t *u8; - uint16_t *u16; - - /* tag */ - u8 = msgb_push(msg, 1); - *u8 = ie; - - /* length in octets */ - u16 = msgb_push(msg, 2); - *u16 = htons(arfcn_count * 2); - - for (i = 0; i < arfcn_count; i++) { - u16 = msgb_push(msg, 2); - *u16 = htons(arfcns[i]); - } - - return 0; -} diff --git a/src/libbsc/abis_nm_vty.c b/src/libbsc/abis_nm_vty.c deleted file mode 100644 index 6ec0a4a21..000000000 --- a/src/libbsc/abis_nm_vty.c +++ /dev/null @@ -1,191 +0,0 @@ -/* VTY interface for A-bis OML (Netowrk Management) */ - -/* (C) 2009-2010 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -extern struct gsm_network *bsc_gsmnet; - -static struct cmd_node oml_node = { - OML_NODE, - "%s(oml)# ", - 1, -}; - -struct oml_node_state { - struct gsm_bts *bts; - uint8_t obj_class; - uint8_t obj_inst[3]; -}; - -static int dummy_config_write(struct vty *v) -{ - return CMD_SUCCESS; -} - -/* FIXME: auto-generate those strings from the value_string lists */ -#define NM_OBJCLASS_VTY "(site-manager|bts|radio-carrier|baseband-transceiver|channel|adjc|handover|power-contorl|btse|rack|test|envabtse|bport|gprs-nse|gprs-cell|gprs-nsvc|siemenshw)" -#define NM_OBJCLASS_VTY_HELP "Site Manager Object\n" \ - "BTS Object\n" \ - "Radio Carrier Object\n" \ - "Baseband Transceiver Object\n" \ - "Channel (Timeslot) Object\n" \ - "Adjacent Object (Siemens)\n" \ - "Handover Object (Siemens)\n" \ - "Power Control Object (Siemens)\n" \ - "BTSE Object (Siemens)\n" \ - "Rack Object (Siemens)\n" \ - "Test Object (Siemens)\n" \ - "ENVABTSE Object (Siemens)\n" \ - "BPORT Object (Siemens)\n" \ - "GPRS NSE Object (ip.access/osmo-bts)\n" \ - "GPRS Cell Object (ip.acecss/osmo-bts)\n" \ - "GPRS NSVC Object (ip.acecss/osmo-bts)\n" \ - "SIEMENSHW Object (Siemens)\n" - - -DEFUN(oml_class_inst, oml_class_inst_cmd, - "bts <0-255> oml class " NM_OBJCLASS_VTY - " instance <0-255> <0-255> <0-255>", - "BTS related commands\n" "BTS Number\n" - "Manipulate the OML managed objects\n" - "Object Class\n" NM_OBJCLASS_VTY_HELP - "Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n") -{ - struct gsm_bts *bts; - struct oml_node_state *oms; - int bts_nr = atoi(argv[0]); - - bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr); - if (!bts) { - vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - oms = talloc_zero(tall_bsc_ctx, struct oml_node_state); - if (!oms) - return CMD_WARNING; - - oms->bts = bts; - oms->obj_class = get_string_value(abis_nm_obj_class_names, argv[1]); - oms->obj_inst[0] = atoi(argv[2]); - oms->obj_inst[1] = atoi(argv[3]); - oms->obj_inst[2] = atoi(argv[4]); - - vty->index = oms; - vty->node = OML_NODE; - - return CMD_SUCCESS; - -} - -DEFUN(oml_classnum_inst, oml_classnum_inst_cmd, - "bts <0-255> oml class <0-255> instance <0-255> <0-255> <0-255>", - "BTS related commands\n" "BTS Number\n" - "Manipulate the OML managed objects\n" - "Object Class\n" "Object Class\n" - "Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n") -{ - struct gsm_bts *bts; - struct oml_node_state *oms; - int bts_nr = atoi(argv[0]); - - bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr); - if (!bts) { - vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - oms = talloc_zero(tall_bsc_ctx, struct oml_node_state); - if (!oms) - return CMD_WARNING; - - oms->bts = bts; - oms->obj_class = atoi(argv[1]); - oms->obj_inst[0] = atoi(argv[2]); - oms->obj_inst[1] = atoi(argv[3]); - oms->obj_inst[2] = atoi(argv[4]); - - vty->index = oms; - vty->node = OML_NODE; - - return CMD_SUCCESS; -} - -DEFUN(oml_chg_adm_state, oml_chg_adm_state_cmd, - "change-adm-state (locked|unlocked|shutdown|null)", - "Change the Administrative State\n" - "Locked\n" "Unlocked\n" "Shutdown\n" "NULL\n") -{ - struct oml_node_state *oms = vty->index; - enum abis_nm_adm_state state; - - state = get_string_value(abis_nm_adm_state_names, argv[0]); - - abis_nm_chg_adm_state(oms->bts, oms->obj_class, oms->obj_inst[0], - oms->obj_inst[1], oms->obj_inst[2], state); - - return CMD_SUCCESS; -} - -DEFUN(oml_opstart, oml_opstart_cmd, - "opstart", "Send an OPSTART message to the object") -{ - struct oml_node_state *oms = vty->index; - - abis_nm_opstart(oms->bts, oms->obj_class, oms->obj_inst[0], - oms->obj_inst[1], oms->obj_inst[2]); - - return CMD_SUCCESS; -} - -int abis_nm_vty_init(void) -{ - install_element(ENABLE_NODE, &oml_class_inst_cmd); - install_element(ENABLE_NODE, &oml_classnum_inst_cmd); - install_node(&oml_node, dummy_config_write); - - vty_install_default(OML_NODE); - install_element(OML_NODE, &oml_chg_adm_state_cmd); - install_element(OML_NODE, &oml_opstart_cmd); - - return 0; -} diff --git a/src/libbsc/abis_om2000.c b/src/libbsc/abis_om2000.c deleted file mode 100644 index 82a14b269..000000000 --- a/src/libbsc/abis_om2000.c +++ /dev/null @@ -1,2776 +0,0 @@ -/* Ericsson RBS 2xxx GSM O&M (OM2000) messages on the A-bis interface - * implemented based on protocol trace analysis, no formal documentation */ - -/* (C) 2010-2011,2016 by Harald Welte - * - * 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 . - * - */ - - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* FIXME: move to libosmocore */ -struct osmo_fsm_inst *osmo_fsm_inst_alloc_child_id(struct osmo_fsm *fsm, - struct osmo_fsm_inst *parent, - uint32_t parent_term_event, - const char *id) -{ - struct osmo_fsm_inst *fi; - - fi = osmo_fsm_inst_alloc(fsm, parent, NULL, parent->log_level, - id ? id : parent->id); - if (!fi) { - /* indicate immediate termination to caller */ - osmo_fsm_inst_dispatch(parent, parent_term_event, NULL); - return NULL; - } - - LOGPFSM(fi, "is child of %s\n", osmo_fsm_inst_name(parent)); - - fi->proc.parent = parent; - fi->proc.parent_term_event = parent_term_event; - llist_add(&fi->proc.child, &parent->proc.children); - - return fi; -} - - -#define OM_ALLOC_SIZE 1024 -#define OM_HEADROOM_SIZE 128 - -#define OM2K_TIMEOUT 10 -#define TRX_FSM_TIMEOUT 60 -#define BTS_FSM_TIMEOUT 60 - -/* use following functions from abis_nm.c: - * om2k_msgb_alloc() - * abis_om2k_sendmsg() - */ - -struct abis_om2k_hdr { - struct abis_om_hdr om; - uint16_t msg_type; - struct abis_om2k_mo mo; - uint8_t data[0]; -} __attribute__ ((packed)); - -enum abis_om2k_msgtype { - OM2K_MSGT_ABORT_SP_CMD = 0x0000, - OM2K_MSGT_ABORT_SP_COMPL = 0x0002, - OM2K_MSGT_ALARM_REP_ACK = 0x0004, - OM2K_MSGT_ALARM_REP_NACK = 0x0005, - OM2K_MSGT_ALARM_REP = 0x0006, - OM2K_MSGT_ALARM_STATUS_REQ = 0x0008, - OM2K_MSGT_ALARM_STATUS_REQ_ACK = 0x000a, - OM2K_MSGT_ALARM_STATUS_REQ_REJ = 0x000b, - OM2K_MSGT_ALARM_STATUS_RES_ACK = 0x000c, - OM2K_MSGT_ALARM_STATUS_RES_NACK = 0x000d, - OM2K_MSGT_ALARM_STATUS_RES = 0x000e, - OM2K_MSGT_CAL_TIME_RESP = 0x0010, - OM2K_MSGT_CAL_TIME_REJ = 0x0011, - OM2K_MSGT_CAL_TIME_REQ = 0x0012, - - OM2K_MSGT_CON_CONF_REQ = 0x0014, - OM2K_MSGT_CON_CONF_REQ_ACK = 0x0016, - OM2K_MSGT_CON_CONF_REQ_REJ = 0x0017, - OM2K_MSGT_CON_CONF_RES_ACK = 0x0018, - OM2K_MSGT_CON_CONF_RES_NACK = 0x0019, - OM2K_MSGT_CON_CONF_RES = 0x001a, - - OM2K_MSGT_CONNECT_CMD = 0x001c, - OM2K_MSGT_CONNECT_COMPL = 0x001e, - OM2K_MSGT_CONNECT_REJ = 0x001f, - - OM2K_MSGT_DISABLE_REQ = 0x0028, - OM2K_MSGT_DISABLE_REQ_ACK = 0x002a, - OM2K_MSGT_DISABLE_REQ_REJ = 0x002b, - OM2K_MSGT_DISABLE_RES_ACK = 0x002c, - OM2K_MSGT_DISABLE_RES_NACK = 0x002d, - OM2K_MSGT_DISABLE_RES = 0x002e, - OM2K_MSGT_DISCONNECT_CMD = 0x0030, - OM2K_MSGT_DISCONNECT_COMPL = 0x0032, - OM2K_MSGT_DISCONNECT_REJ = 0x0033, - OM2K_MSGT_ENABLE_REQ = 0x0034, - OM2K_MSGT_ENABLE_REQ_ACK = 0x0036, - OM2K_MSGT_ENABLE_REQ_REJ = 0x0037, - OM2K_MSGT_ENABLE_RES_ACK = 0x0038, - OM2K_MSGT_ENABLE_RES_NACK = 0x0039, - OM2K_MSGT_ENABLE_RES = 0x003a, - - OM2K_MSGT_FAULT_REP_ACK = 0x0040, - OM2K_MSGT_FAULT_REP_NACK = 0x0041, - OM2K_MSGT_FAULT_REP = 0x0042, - - OM2K_MSGT_IS_CONF_REQ = 0x0060, - OM2K_MSGT_IS_CONF_REQ_ACK = 0x0062, - OM2K_MSGT_IS_CONF_REQ_REJ = 0x0063, - OM2K_MSGT_IS_CONF_RES_ACK = 0x0064, - OM2K_MSGT_IS_CONF_RES_NACK = 0x0065, - OM2K_MSGT_IS_CONF_RES = 0x0066, - - OM2K_MSGT_OP_INFO = 0x0074, - OM2K_MSGT_OP_INFO_ACK = 0x0076, - OM2K_MSGT_OP_INFO_REJ = 0x0077, - OM2K_MSGT_RESET_CMD = 0x0078, - OM2K_MSGT_RESET_COMPL = 0x007a, - OM2K_MSGT_RESET_REJ = 0x007b, - OM2K_MSGT_RX_CONF_REQ = 0x007c, - OM2K_MSGT_RX_CONF_REQ_ACK = 0x007e, - OM2K_MSGT_RX_CONF_REQ_REJ = 0x007f, - OM2K_MSGT_RX_CONF_RES_ACK = 0x0080, - OM2K_MSGT_RX_CONF_RES_NACK = 0x0081, - OM2K_MSGT_RX_CONF_RES = 0x0082, - OM2K_MSGT_START_REQ = 0x0084, - OM2K_MSGT_START_REQ_ACK = 0x0086, - OM2K_MSGT_START_REQ_REJ = 0x0087, - OM2K_MSGT_START_RES_ACK = 0x0088, - OM2K_MSGT_START_RES_NACK = 0x0089, - OM2K_MSGT_START_RES = 0x008a, - OM2K_MSGT_STATUS_REQ = 0x008c, - OM2K_MSGT_STATUS_RESP = 0x008e, - OM2K_MSGT_STATUS_REJ = 0x008f, - - OM2K_MSGT_TEST_REQ = 0x0094, - OM2K_MSGT_TEST_REQ_ACK = 0x0096, - OM2K_MSGT_TEST_REQ_REJ = 0x0097, - OM2K_MSGT_TEST_RES_ACK = 0x0098, - OM2K_MSGT_TEST_RES_NACK = 0x0099, - OM2K_MSGT_TEST_RES = 0x009a, - - OM2K_MSGT_TF_CONF_REQ = 0x00a0, - OM2K_MSGT_TF_CONF_REQ_ACK = 0x00a2, - OM2K_MSGT_TF_CONF_REQ_REJ = 0x00a3, - OM2K_MSGT_TF_CONF_RES_ACK = 0x00a4, - OM2K_MSGT_TF_CONF_RES_NACK = 0x00a5, - OM2K_MSGT_TF_CONF_RES = 0x00a6, - OM2K_MSGT_TS_CONF_REQ = 0x00a8, - OM2K_MSGT_TS_CONF_REQ_ACK = 0x00aa, - OM2K_MSGT_TS_CONF_REQ_REJ = 0x00ab, - OM2K_MSGT_TS_CONF_RES_ACK = 0x00ac, - OM2K_MSGT_TS_CONF_RES_NACK = 0x00ad, - OM2K_MSGT_TS_CONF_RES = 0x00ae, - OM2K_MSGT_TX_CONF_REQ = 0x00b0, - OM2K_MSGT_TX_CONF_REQ_ACK = 0x00b2, - OM2K_MSGT_TX_CONF_REQ_REJ = 0x00b3, - OM2K_MSGT_TX_CONF_RES_ACK = 0x00b4, - OM2K_MSGT_TX_CONF_RES_NACK = 0x00b5, - OM2K_MSGT_TX_CONF_RES = 0x00b6, - - OM2K_MSGT_CAPA_REQ = 0x00e8, - OM2K_MSGT_CAPA_REQ_ACK = 0x00ea, - OM2K_MSGT_CAPA_REQ_REJ = 0x00eb, - OM2K_MSGT_CAPA_RES = 0x00ee, - OM2K_MSGT_CAPA_RES_ACK = 0x00ec, - OM2K_MSGT_CAPA_RES_NACK = 0x00ed, - - OM2K_MSGT_NEGOT_REQ_ACK = 0x0104, - OM2K_MSGT_NEGOT_REQ_NACK = 0x0105, - OM2K_MSGT_NEGOT_REQ = 0x0106, -}; - -enum abis_om2k_dei { - OM2K_DEI_ACCORDANCE_IND = 0x00, - OM2K_DEI_BCC = 0x06, - OM2K_DEI_BS_AG_BKS_RES = 0x07, - OM2K_DEI_BSIC = 0x09, - OM2K_DEI_BA_PA_MFRMS = 0x0a, - OM2K_DEI_CBCH_INDICATOR = 0x0b, - OM2K_DEI_CCCH_OPTIONS = 0x0c, - OM2K_DEI_CAL_TIME = 0x0d, - OM2K_DEI_COMBINATION = 0x0f, - OM2K_DEI_CON_CONN_LIST = 0x10, - OM2K_DEI_DRX_DEV_MAX = 0x12, - OM2K_DEI_END_LIST_NR = 0x13, - OM2K_DEI_EXT_COND_MAP_1 = 0x14, - OM2K_DEI_EXT_COND_MAP_2 = 0x15, - OM2K_DEI_FILLING_MARKER = 0x1c, - OM2K_DEI_FN_OFFSET = 0x1d, - OM2K_DEI_FREQ_LIST = 0x1e, - OM2K_DEI_FREQ_SPEC_RX = 0x1f, - OM2K_DEI_FREQ_SPEC_TX = 0x20, - OM2K_DEI_HSN = 0x21, - OM2K_DEI_ICM_INDICATOR = 0x22, - OM2K_DEI_INT_FAULT_MAP_1A = 0x23, - OM2K_DEI_INT_FAULT_MAP_1B = 0x24, - OM2K_DEI_INT_FAULT_MAP_2A = 0x25, - OM2K_DEI_INT_FAULT_MAP_2A_EXT = 0x26, - OM2K_DEI_IS_CONN_LIST = 0x27, - OM2K_DEI_LIST_NR = 0x28, - OM2K_DEI_LOCAL_ACCESS = 0x2a, - OM2K_DEI_MAIO = 0x2b, - OM2K_DEI_MO_STATE = 0x2c, - OM2K_DEI_NY1 = 0x2d, - OM2K_DEI_OP_INFO = 0x2e, - OM2K_DEI_POWER = 0x2f, - OM2K_DEI_REASON_CODE = 0x32, - OM2K_DEI_RX_DIVERSITY = 0x33, - OM2K_DEI_REPL_UNIT_MAP = 0x34, - OM2K_DEI_RESULT_CODE = 0x35, - OM2K_DEI_T3105 = 0x38, - OM2K_DEI_TF_MODE = 0x3a, - OM2K_DEI_TS_NR = 0x3c, - OM2K_DEI_TSC = 0x3d, - OM2K_DEI_BTS_VERSION = 0x40, - OM2K_DEI_OML_IWD_VERSION = 0x41, - OM2K_DEI_RSL_IWD_VERSION = 0x42, - OM2K_DEI_OML_FUNC_MAP_1 = 0x43, - OM2K_DEI_OML_FUNC_MAP_2 = 0x44, - OM2K_DEI_RSL_FUNC_MAP_1 = 0x45, - OM2K_DEI_RSL_FUNC_MAP_2 = 0x46, - OM2K_DEI_EXT_RANGE = 0x47, - OM2K_DEI_REQ_IND = 0x48, - OM2K_DEI_REPL_UNIT_MAP_EXT = 0x50, - OM2K_DEI_ICM_BOUND_PARAMS = 0x74, - OM2K_DEI_LSC = 0x79, - OM2K_DEI_LSC_FILT_TIME = 0x7a, - OM2K_DEI_CALL_SUPV_TIME = 0x7b, - OM2K_DEI_ICM_CHAN_RATE = 0x7e, - OM2K_DEI_HW_INFO_SIG = 0x84, - OM2K_DEI_TF_SYNC_SRC = 0x86, - OM2K_DEI_TTA = 0x87, - OM2K_DEI_CAPA_SIG = 0x8a, - OM2K_DEI_NEGOT_REC1 = 0x90, - OM2K_DEI_NEGOT_REC2 = 0x91, - OM2K_DEI_ENCR_ALG = 0x92, - OM2K_DEI_INTERF_REJ_COMB = 0x94, - OM2K_DEI_FS_OFFSET = 0x98, - OM2K_DEI_EXT_COND_MAP_2_EXT = 0x9c, - OM2K_DEI_TSS_MO_STATE = 0x9d, -}; - -const struct tlv_definition om2k_att_tlvdef = { - .def = { - [OM2K_DEI_ACCORDANCE_IND] = { TLV_TYPE_TV }, - [OM2K_DEI_BCC] = { TLV_TYPE_TV }, - [OM2K_DEI_BS_AG_BKS_RES] = { TLV_TYPE_TV }, - [OM2K_DEI_BSIC] = { TLV_TYPE_TV }, - [OM2K_DEI_BA_PA_MFRMS] = { TLV_TYPE_TV }, - [OM2K_DEI_CBCH_INDICATOR] = { TLV_TYPE_TV }, - [OM2K_DEI_INT_FAULT_MAP_1A] = { TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_INT_FAULT_MAP_1B] = { TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_INT_FAULT_MAP_2A] = { TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_INT_FAULT_MAP_2A_EXT]={ TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_CCCH_OPTIONS] = { TLV_TYPE_TV }, - [OM2K_DEI_CAL_TIME] = { TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_COMBINATION] = { TLV_TYPE_TV }, - [OM2K_DEI_CON_CONN_LIST] = { TLV_TYPE_TLV }, - [OM2K_DEI_DRX_DEV_MAX] = { TLV_TYPE_TV }, - [OM2K_DEI_END_LIST_NR] = { TLV_TYPE_TV }, - [OM2K_DEI_EXT_COND_MAP_1] = { TLV_TYPE_FIXED, 2 }, - [OM2K_DEI_EXT_COND_MAP_2] = { TLV_TYPE_FIXED, 2 }, - [OM2K_DEI_FILLING_MARKER] = { TLV_TYPE_TV }, - [OM2K_DEI_FN_OFFSET] = { TLV_TYPE_FIXED, 2 }, - [OM2K_DEI_FREQ_LIST] = { TLV_TYPE_TLV }, - [OM2K_DEI_FREQ_SPEC_RX] = { TLV_TYPE_FIXED, 2 }, - [OM2K_DEI_FREQ_SPEC_TX] = { TLV_TYPE_FIXED, 2 }, - [OM2K_DEI_HSN] = { TLV_TYPE_TV }, - [OM2K_DEI_ICM_INDICATOR] = { TLV_TYPE_TV }, - [OM2K_DEI_IS_CONN_LIST] = { TLV_TYPE_TLV }, - [OM2K_DEI_LIST_NR] = { TLV_TYPE_TV }, - [OM2K_DEI_LOCAL_ACCESS] = { TLV_TYPE_TV }, - [OM2K_DEI_MAIO] = { TLV_TYPE_TV }, - [OM2K_DEI_MO_STATE] = { TLV_TYPE_TV }, - [OM2K_DEI_NY1] = { TLV_TYPE_TV }, - [OM2K_DEI_OP_INFO] = { TLV_TYPE_TV }, - [OM2K_DEI_POWER] = { TLV_TYPE_TV }, - [OM2K_DEI_REASON_CODE] = { TLV_TYPE_TV }, - [OM2K_DEI_RX_DIVERSITY] = { TLV_TYPE_TV }, - [OM2K_DEI_RESULT_CODE] = { TLV_TYPE_TV }, - [OM2K_DEI_T3105] = { TLV_TYPE_TV }, - [OM2K_DEI_TF_MODE] = { TLV_TYPE_TV }, - [OM2K_DEI_TS_NR] = { TLV_TYPE_TV }, - [OM2K_DEI_TSC] = { TLV_TYPE_TV }, - [OM2K_DEI_BTS_VERSION] = { TLV_TYPE_FIXED, 12 }, - [OM2K_DEI_OML_IWD_VERSION] = { TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_RSL_IWD_VERSION] = { TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_OML_FUNC_MAP_1] = { TLV_TYPE_TLV }, - [OM2K_DEI_OML_FUNC_MAP_2] = { TLV_TYPE_TLV }, - [OM2K_DEI_RSL_FUNC_MAP_1] = { TLV_TYPE_TLV }, - [OM2K_DEI_RSL_FUNC_MAP_2] = { TLV_TYPE_TLV }, - [OM2K_DEI_EXT_RANGE] = { TLV_TYPE_TV }, - [OM2K_DEI_REQ_IND] = { TLV_TYPE_TV }, - [OM2K_DEI_REPL_UNIT_MAP] = { TLV_TYPE_FIXED, 6 }, - [OM2K_DEI_REPL_UNIT_MAP_EXT] = {TLV_TYPE_FIXED, 6}, - [OM2K_DEI_ICM_BOUND_PARAMS] = { TLV_TYPE_FIXED, 5 }, - [OM2K_DEI_LSC] = { TLV_TYPE_TV }, - [OM2K_DEI_LSC_FILT_TIME] = { TLV_TYPE_TV }, - [OM2K_DEI_CALL_SUPV_TIME] = { TLV_TYPE_TV }, - [OM2K_DEI_ICM_CHAN_RATE] = { TLV_TYPE_TV }, - [OM2K_DEI_HW_INFO_SIG] = { TLV_TYPE_FIXED, 2 }, - [OM2K_DEI_TF_SYNC_SRC] = { TLV_TYPE_TV }, - [OM2K_DEI_TTA] = { TLV_TYPE_TV }, - [OM2K_DEI_CAPA_SIG] = { TLV_TYPE_FIXED, 2 }, - [OM2K_DEI_NEGOT_REC1] = { TLV_TYPE_TLV }, - [OM2K_DEI_NEGOT_REC2] = { TLV_TYPE_TLV }, - [OM2K_DEI_ENCR_ALG] = { TLV_TYPE_TV }, - [OM2K_DEI_INTERF_REJ_COMB] = { TLV_TYPE_TV }, - [OM2K_DEI_FS_OFFSET] = { TLV_TYPE_FIXED, 5 }, - [OM2K_DEI_EXT_COND_MAP_2_EXT] = { TLV_TYPE_FIXED, 4 }, - [OM2K_DEI_TSS_MO_STATE] = { TLV_TYPE_FIXED, 4 }, - }, -}; - -static const struct value_string om2k_msgcode_vals[] = { - { 0x0000, "Abort SP Command" }, - { 0x0002, "Abort SP Complete" }, - { 0x0004, "Alarm Report ACK" }, - { 0x0005, "Alarm Report NACK" }, - { 0x0006, "Alarm Report" }, - { 0x0008, "Alarm Status Request" }, - { 0x000a, "Alarm Status Request Accept" }, - { 0x000b, "Alarm Status Request Reject" }, - { 0x000c, "Alarm Status Result ACK" }, - { 0x000d, "Alarm Status Result NACK" }, - { 0x000e, "Alarm Status Result" }, - { 0x0010, "Calendar Time Response" }, - { 0x0011, "Calendar Time Reject" }, - { 0x0012, "Calendar Time Request" }, - { 0x0014, "CON Configuration Request" }, - { 0x0016, "CON Configuration Request Accept" }, - { 0x0017, "CON Configuration Request Reject" }, - { 0x0018, "CON Configuration Result ACK" }, - { 0x0019, "CON Configuration Result NACK" }, - { 0x001a, "CON Configuration Result" }, - { 0x001c, "Connect Command" }, - { 0x001e, "Connect Complete" }, - { 0x001f, "Connect Reject" }, - { 0x0028, "Disable Request" }, - { 0x002a, "Disable Request Accept" }, - { 0x002b, "Disable Request Reject" }, - { 0x002c, "Disable Result ACK" }, - { 0x002d, "Disable Result NACK" }, - { 0x002e, "Disable Result" }, - { 0x0030, "Disconnect Command" }, - { 0x0032, "Disconnect Complete" }, - { 0x0033, "Disconnect Reject" }, - { 0x0034, "Enable Request" }, - { 0x0036, "Enable Request Accept" }, - { 0x0037, "Enable Request Reject" }, - { 0x0038, "Enable Result ACK" }, - { 0x0039, "Enable Result NACK" }, - { 0x003a, "Enable Result" }, - { 0x003c, "Escape Downlink Normal" }, - { 0x003d, "Escape Downlink NACK" }, - { 0x003e, "Escape Uplink Normal" }, - { 0x003f, "Escape Uplink NACK" }, - { 0x0040, "Fault Report ACK" }, - { 0x0041, "Fault Report NACK" }, - { 0x0042, "Fault Report" }, - { 0x0044, "File Package End Command" }, - { 0x0046, "File Package End Result" }, - { 0x0047, "File Package End Reject" }, - { 0x0048, "File Relation Request" }, - { 0x004a, "File Relation Response" }, - { 0x004b, "File Relation Request Reject" }, - { 0x004c, "File Segment Transfer" }, - { 0x004e, "File Segment Transfer Complete" }, - { 0x004f, "File Segment Transfer Reject" }, - { 0x0050, "HW Information Request" }, - { 0x0052, "HW Information Request Accept" }, - { 0x0053, "HW Information Request Reject" }, - { 0x0054, "HW Information Result ACK" }, - { 0x0055, "HW Information Result NACK" }, - { 0x0056, "HW Information Result" }, - { 0x0060, "IS Configuration Request" }, - { 0x0062, "IS Configuration Request Accept" }, - { 0x0063, "IS Configuration Request Reject" }, - { 0x0064, "IS Configuration Result ACK" }, - { 0x0065, "IS Configuration Result NACK" }, - { 0x0066, "IS Configuration Result" }, - { 0x0068, "Load Data End" }, - { 0x006a, "Load Data End Result" }, - { 0x006b, "Load Data End Reject" }, - { 0x006c, "Load Data Init" }, - { 0x006e, "Load Data Init Accept" }, - { 0x006f, "Load Data Init Reject" }, - { 0x0070, "Loop Control Command" }, - { 0x0072, "Loop Control Complete" }, - { 0x0073, "Loop Control Reject" }, - { 0x0074, "Operational Information" }, - { 0x0076, "Operational Information Accept" }, - { 0x0077, "Operational Information Reject" }, - { 0x0078, "Reset Command" }, - { 0x007a, "Reset Complete" }, - { 0x007b, "Reset Reject" }, - { 0x007c, "RX Configuration Request" }, - { 0x007e, "RX Configuration Request Accept" }, - { 0x007f, "RX Configuration Request Reject" }, - { 0x0080, "RX Configuration Result ACK" }, - { 0x0081, "RX Configuration Result NACK" }, - { 0x0082, "RX Configuration Result" }, - { 0x0084, "Start Request" }, - { 0x0086, "Start Request Accept" }, - { 0x0087, "Start Request Reject" }, - { 0x0088, "Start Result ACK" }, - { 0x0089, "Start Result NACK" }, - { 0x008a, "Start Result" }, - { 0x008c, "Status Request" }, - { 0x008e, "Status Response" }, - { 0x008f, "Status Reject" }, - { 0x0094, "Test Request" }, - { 0x0096, "Test Request Accept" }, - { 0x0097, "Test Request Reject" }, - { 0x0098, "Test Result ACK" }, - { 0x0099, "Test Result NACK" }, - { 0x009a, "Test Result" }, - { 0x00a0, "TF Configuration Request" }, - { 0x00a2, "TF Configuration Request Accept" }, - { 0x00a3, "TF Configuration Request Reject" }, - { 0x00a4, "TF Configuration Result ACK" }, - { 0x00a5, "TF Configuration Result NACK" }, - { 0x00a6, "TF Configuration Result" }, - { 0x00a8, "TS Configuration Request" }, - { 0x00aa, "TS Configuration Request Accept" }, - { 0x00ab, "TS Configuration Request Reject" }, - { 0x00ac, "TS Configuration Result ACK" }, - { 0x00ad, "TS Configuration Result NACK" }, - { 0x00ae, "TS Configuration Result" }, - { 0x00b0, "TX Configuration Request" }, - { 0x00b2, "TX Configuration Request Accept" }, - { 0x00b3, "TX Configuration Request Reject" }, - { 0x00b4, "TX Configuration Result ACK" }, - { 0x00b5, "TX Configuration Result NACK" }, - { 0x00b6, "TX Configuration Result" }, - { 0x00bc, "DIP Alarm Report ACK" }, - { 0x00bd, "DIP Alarm Report NACK" }, - { 0x00be, "DIP Alarm Report" }, - { 0x00c0, "DIP Alarm Status Request" }, - { 0x00c2, "DIP Alarm Status Response" }, - { 0x00c3, "DIP Alarm Status Reject" }, - { 0x00c4, "DIP Quality Report I ACK" }, - { 0x00c5, "DIP Quality Report I NACK" }, - { 0x00c6, "DIP Quality Report I" }, - { 0x00c8, "DIP Quality Report II ACK" }, - { 0x00c9, "DIP Quality Report II NACK" }, - { 0x00ca, "DIP Quality Report II" }, - { 0x00dc, "DP Configuration Request" }, - { 0x00de, "DP Configuration Request Accept" }, - { 0x00df, "DP Configuration Request Reject" }, - { 0x00e0, "DP Configuration Result ACK" }, - { 0x00e1, "DP Configuration Result NACK" }, - { 0x00e2, "DP Configuration Result" }, - { 0x00e4, "Capabilities HW Info Report ACK" }, - { 0x00e5, "Capabilities HW Info Report NACK" }, - { 0x00e6, "Capabilities HW Info Report" }, - { 0x00e8, "Capabilities Request" }, - { 0x00ea, "Capabilities Request Accept" }, - { 0x00eb, "Capabilities Request Reject" }, - { 0x00ec, "Capabilities Result ACK" }, - { 0x00ed, "Capabilities Result NACK" }, - { 0x00ee, "Capabilities Result" }, - { 0x00f0, "FM Configuration Request" }, - { 0x00f2, "FM Configuration Request Accept" }, - { 0x00f3, "FM Configuration Request Reject" }, - { 0x00f4, "FM Configuration Result ACK" }, - { 0x00f5, "FM Configuration Result NACK" }, - { 0x00f6, "FM Configuration Result" }, - { 0x00f8, "FM Report Request" }, - { 0x00fa, "FM Report Response" }, - { 0x00fb, "FM Report Reject" }, - { 0x00fc, "FM Start Command" }, - { 0x00fe, "FM Start Complete" }, - { 0x00ff, "FM Start Reject" }, - { 0x0100, "FM Stop Command" }, - { 0x0102, "FM Stop Complete" }, - { 0x0103, "FM Stop Reject" }, - { 0x0104, "Negotiation Request ACK" }, - { 0x0105, "Negotiation Request NACK" }, - { 0x0106, "Negotiation Request" }, - { 0x0108, "BTS Initiated Request ACK" }, - { 0x0109, "BTS Initiated Request NACK" }, - { 0x010a, "BTS Initiated Request" }, - { 0x010c, "Radio Channels Release Command" }, - { 0x010e, "Radio Channels Release Complete" }, - { 0x010f, "Radio Channels Release Reject" }, - { 0x0118, "Feature Control Command" }, - { 0x011a, "Feature Control Complete" }, - { 0x011b, "Feature Control Reject" }, - - { 0, NULL } -}; - -/* TS 12.21 Section 9.4: Attributes */ -static const struct value_string om2k_attr_vals[] = { - { 0x00, "Accordance indication" }, - { 0x01, "Alarm Id" }, - { 0x02, "Alarm Data" }, - { 0x03, "Alarm Severity" }, - { 0x04, "Alarm Status" }, - { 0x05, "Alarm Status Type" }, - { 0x06, "BCC" }, - { 0x07, "BS_AG_BKS_RES" }, - { 0x09, "BSIC" }, - { 0x0a, "BA_PA_MFRMS" }, - { 0x0b, "CBCH Indicator" }, - { 0x0c, "CCCH Options" }, - { 0x0d, "Calendar Time" }, - { 0x0f, "Channel Combination" }, - { 0x10, "CON Connection List" }, - { 0x11, "Data End Indication" }, - { 0x12, "DRX_DEV_MAX" }, - { 0x13, "End List Number" }, - { 0x14, "External Condition Map Class 1" }, - { 0x15, "External Condition Map Class 2" }, - { 0x16, "File Relation Indication" }, - { 0x17, "File Revision" }, - { 0x18, "File Segment Data" }, - { 0x19, "File Segment Length" }, - { 0x1a, "File Segment Sequence Number" }, - { 0x1b, "File Size" }, - { 0x1c, "Filling Marker" }, - { 0x1d, "FN Offset" }, - { 0x1e, "Frequency List" }, - { 0x1f, "Frequency Specifier RX" }, - { 0x20, "Frequency Specifier TX" }, - { 0x21, "HSN" }, - { 0x22, "ICM Indicator" }, - { 0x23, "Internal Fault Map Class 1A" }, - { 0x24, "Internal Fault Map Class 1B" }, - { 0x25, "Internal Fault Map Class 2A" }, - { 0x26, "Internal Fault Map Class 2A Extension" }, - { 0x27, "IS Connection List" }, - { 0x28, "List Number" }, - { 0x29, "File Package State Indication" }, - { 0x2a, "Local Access State" }, - { 0x2b, "MAIO" }, - { 0x2c, "MO State" }, - { 0x2d, "Ny1" }, - { 0x2e, "Operational Information" }, - { 0x2f, "Power" }, - { 0x30, "RU Position Data" }, - { 0x31, "Protocol Error" }, - { 0x32, "Reason Code" }, - { 0x33, "Receiver Diversity" }, - { 0x34, "Replacement Unit Map" }, - { 0x35, "Result Code" }, - { 0x36, "RU Revision Data" }, - { 0x38, "T3105" }, - { 0x39, "Test Loop Setting" }, - { 0x3a, "TF Mode" }, - { 0x3b, "TF Compensation Value" }, - { 0x3c, "Time Slot Number" }, - { 0x3d, "TSC" }, - { 0x3e, "RU Logical Id" }, - { 0x3f, "RU Serial Number Data" }, - { 0x40, "BTS Version" }, - { 0x41, "OML IWD Version" }, - { 0x42, "RWL IWD Version" }, - { 0x43, "OML Function Map 1" }, - { 0x44, "OML Function Map 2" }, - { 0x45, "RSL Function Map 1" }, - { 0x46, "RSL Function Map 2" }, - { 0x47, "Extended Range Indicator" }, - { 0x48, "Request Indicators" }, - { 0x49, "DIP Alarm Condition Map" }, - { 0x4a, "ES Incoming" }, - { 0x4b, "ES Outgoing" }, - { 0x4e, "SES Incoming" }, - { 0x4f, "SES Outgoing" }, - { 0x50, "Replacement Unit Map Extension" }, - { 0x52, "UAS Incoming" }, - { 0x53, "UAS Outgoing" }, - { 0x58, "DF Incoming" }, - { 0x5a, "DF Outgoing" }, - { 0x5c, "SF" }, - { 0x60, "S Bits Setting" }, - { 0x61, "CRC-4 Use Option" }, - { 0x62, "T Parameter" }, - { 0x63, "N Parameter" }, - { 0x64, "N1 Parameter" }, - { 0x65, "N3 Parameter" }, - { 0x66, "N4 Parameter" }, - { 0x67, "P Parameter" }, - { 0x68, "Q Parameter" }, - { 0x69, "BI_Q1" }, - { 0x6a, "BI_Q2" }, - { 0x74, "ICM Boundary Parameters" }, - { 0x77, "AFT" }, - { 0x78, "AFT RAI" }, - { 0x79, "Link Supervision Control" }, - { 0x7a, "Link Supervision Filtering Time" }, - { 0x7b, "Call Supervision Time" }, - { 0x7c, "Interval Length UAS Incoming" }, - { 0x7d, "Interval Length UAS Outgoing" }, - { 0x7e, "ICM Channel Rate" }, - { 0x7f, "Attribute Identifier" }, - { 0x80, "FM Frequency List" }, - { 0x81, "FM Frequency Report" }, - { 0x82, "FM Percentile" }, - { 0x83, "FM Clear Indication" }, - { 0x84, "HW Info Signature" }, - { 0x85, "MO Record" }, - { 0x86, "TF Synchronisation Source" }, - { 0x87, "TTA" }, - { 0x88, "End Segment Number" }, - { 0x89, "Segment Number" }, - { 0x8a, "Capabilities Signature" }, - { 0x8c, "File Relation List" }, - { 0x90, "Negotiation Record I" }, - { 0x91, "Negotiation Record II" }, - { 0x92, "Encryption Algorithm" }, - { 0x94, "Interference Rejection Combining" }, - { 0x95, "Dedication Information" }, - { 0x97, "Feature Code" }, - { 0x98, "FS Offset" }, - { 0x99, "ESB Timeslot" }, - { 0x9a, "Master TG Instance" }, - { 0x9b, "Master TX Chain Delay" }, - { 0x9c, "External Condition Class 2 Extension" }, - { 0x9d, "TSs MO State" }, - { 0, NULL } -}; - -const struct value_string om2k_mo_class_short_vals[] = { - { 0x01, "TRXC" }, - { 0x03, "TS" }, - { 0x04, "TF" }, - { 0x05, "IS" }, - { 0x06, "CON" }, - { 0x07, "DP" }, - { 0x0a, "CF" }, - { 0x0b, "TX" }, - { 0x0c, "RX" }, - { 0, NULL } -}; - -const struct value_string om2k_result_strings[] = { - { 0x02, "Wrong state or out of sequence" }, - { 0x03, "File error" }, - { 0x04, "Fault, unspecified" }, - { 0x05, "Tuning fault" }, - { 0x06, "Protocol error" }, - { 0x07, "MO not connected" }, - { 0x08, "Parameter error" }, - { 0x09, "Optional function not supported" }, - { 0x0a, "Local access state LOCALLY DISCONNECTED" }, - { 0, NULL } -}; - -const struct value_string om2k_accordance_strings[] = { - { 0x00, "Data according to request" }, - { 0x01, "Data not according to request" }, - { 0x02, "Inconsistent MO data" }, - { 0x03, "Capability constraint violation" }, - { 0, NULL } -}; - -const struct value_string om2k_mostate_vals[] = { - { 0x00, "RESET" }, - { 0x01, "STARTED" }, - { 0x02, "ENABLED" }, - { 0x03, "DISABLED" }, - { 0, NULL } -}; - -/* entire decoded OM2K message (header + parsed TLV) */ -struct om2k_decoded_msg { - struct abis_om2k_hdr o2h; - uint16_t msg_type; - struct tlv_parsed tp; -}; - -/* resolve the OM2000 Managed Object by BTS + MO Address */ -static struct om2k_mo * -get_om2k_mo(struct gsm_bts *bts, const struct abis_om2k_mo *abis_mo) -{ - struct om2k_mo *mo = NULL; - struct gsm_bts_trx *trx; - - switch (abis_mo->class) { - case OM2K_MO_CLS_CF: - mo = &bts->rbs2000.cf.om2k_mo; - break; - case OM2K_MO_CLS_CON: - mo = &bts->rbs2000.con.om2k_mo; - break; - case OM2K_MO_CLS_IS: - mo = &bts->rbs2000.is.om2k_mo; - break; - case OM2K_MO_CLS_TF: - mo = &bts->rbs2000.tf.om2k_mo; - break; - - case OM2K_MO_CLS_TRXC: - trx = gsm_bts_trx_num(bts, abis_mo->inst); - if (!trx) - return NULL; - mo = &trx->rbs2000.trxc.om2k_mo; - break; - case OM2K_MO_CLS_TX: - trx = gsm_bts_trx_num(bts, abis_mo->inst); - if (!trx) - return NULL; - mo = &trx->rbs2000.tx.om2k_mo; - break; - case OM2K_MO_CLS_RX: - trx = gsm_bts_trx_num(bts, abis_mo->inst); - if (!trx) - return NULL; - mo = &trx->rbs2000.rx.om2k_mo; - break; - case OM2K_MO_CLS_TS: - trx = gsm_bts_trx_num(bts, abis_mo->assoc_so); - if (!trx) - return NULL; - if (abis_mo->inst >= ARRAY_SIZE(trx->ts)) - return NULL; - mo = &trx->ts[abis_mo->inst].rbs2000.om2k_mo; - break; - default: - return NULL; - }; - - return mo; -} - -static struct msgb *om2k_msgb_alloc(void) -{ - return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, - "OM2000"); -} - -static int abis_om2k_tlv_parse(struct tlv_parsed *tp, const uint8_t *buf, int len) -{ - return tlv_parse(tp, &om2k_att_tlvdef, buf, len, 0, 0); -} - -static int abis_om2k_msg_tlv_parse(struct tlv_parsed *tp, struct abis_om2k_hdr *oh) -{ - return abis_om2k_tlv_parse(tp, oh->data, oh->om.length - 6); -} - -/* decode/parse the message */ -static int om2k_decode_msg(struct om2k_decoded_msg *odm, struct msgb *msg) -{ - struct abis_om2k_hdr *o2h = msgb_l2(msg); - odm->msg_type = ntohs(o2h->msg_type); - odm->o2h = *o2h; - return abis_om2k_msg_tlv_parse(&odm->tp, o2h); -} - -static char *om2k_mo_name(const struct abis_om2k_mo *mo) -{ - static char mo_buf[64]; - - memset(mo_buf, 0, sizeof(mo_buf)); - snprintf(mo_buf, sizeof(mo_buf), "%s/%02x/%02x/%02x", - get_value_string(om2k_mo_class_short_vals, mo->class), - mo->bts, mo->assoc_so, mo->inst); - return mo_buf; -} - -/* resolve the gsm_nm_state data structure for a given MO */ -static struct gsm_nm_state * -mo2nm_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - struct gsm_bts_trx *trx; - struct gsm_nm_state *nm_state = NULL; - - switch (mo->class) { - case OM2K_MO_CLS_TRXC: - trx = gsm_bts_trx_num(bts, mo->inst); - if (!trx) - return NULL; - nm_state = &trx->mo.nm_state; - break; - case OM2K_MO_CLS_TS: - trx = gsm_bts_trx_num(bts, mo->assoc_so); - if (!trx) - return NULL; - if (mo->inst >= ARRAY_SIZE(trx->ts)) - return NULL; - nm_state = &trx->ts[mo->inst].mo.nm_state; - break; - case OM2K_MO_CLS_TF: - nm_state = &bts->rbs2000.tf.mo.nm_state; - break; - case OM2K_MO_CLS_IS: - nm_state = &bts->rbs2000.is.mo.nm_state; - break; - case OM2K_MO_CLS_CON: - nm_state = &bts->rbs2000.con.mo.nm_state; - break; - case OM2K_MO_CLS_DP: - nm_state = &bts->rbs2000.con.mo.nm_state; - break; - case OM2K_MO_CLS_CF: - nm_state = &bts->mo.nm_state; - break; - case OM2K_MO_CLS_TX: - trx = gsm_bts_trx_num(bts, mo->inst); - if (!trx) - return NULL; - /* FIXME */ - break; - case OM2K_MO_CLS_RX: - trx = gsm_bts_trx_num(bts, mo->inst); - if (!trx) - return NULL; - /* FIXME */ - break; - } - - return nm_state; -} - -static void *mo2obj(struct gsm_bts *bts, struct abis_om2k_mo *mo) -{ - struct gsm_bts_trx *trx; - - switch (mo->class) { - case OM2K_MO_CLS_TX: - case OM2K_MO_CLS_RX: - case OM2K_MO_CLS_TRXC: - return gsm_bts_trx_num(bts, mo->inst); - case OM2K_MO_CLS_TS: - trx = gsm_bts_trx_num(bts, mo->assoc_so); - if (!trx) - return NULL; - if (mo->inst >= ARRAY_SIZE(trx->ts)) - return NULL; - return &trx->ts[mo->inst]; - case OM2K_MO_CLS_TF: - case OM2K_MO_CLS_IS: - case OM2K_MO_CLS_CON: - case OM2K_MO_CLS_DP: - case OM2K_MO_CLS_CF: - return bts; - } - - return NULL; -} - -static void update_mo_state(struct gsm_bts *bts, struct abis_om2k_mo *mo, - uint8_t mo_state) -{ - struct gsm_nm_state *nm_state = mo2nm_state(bts, mo); - struct gsm_nm_state new_state; - struct nm_statechg_signal_data nsd; - - if (!nm_state) - return; - - new_state = *nm_state; - /* NOTICE: 12.21 Availability state values != OM2000 */ - new_state.availability = mo_state; - - memset(&nsd, 0, sizeof(nsd)); - - nsd.bts = bts; - nsd.obj = mo2obj(bts, mo); - nsd.old_state = nm_state; - nsd.new_state = &new_state; - nsd.om2k_mo = mo; - - osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd); - - nm_state->availability = new_state.availability; -} - -static void update_op_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo, - uint8_t op_state) -{ - struct gsm_nm_state *nm_state = mo2nm_state(bts, mo); - struct gsm_nm_state new_state; - - if (!nm_state) - return; - - new_state = *nm_state; - switch (op_state) { - case 1: - new_state.operational = NM_OPSTATE_ENABLED; - break; - case 0: - new_state.operational = NM_OPSTATE_DISABLED; - break; - default: - new_state.operational = NM_OPSTATE_NULL; - break; - } - - nm_state->operational = new_state.operational; -} - -static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg) -{ - struct abis_om2k_hdr *o2h; - struct gsm_bts_trx *trx; - - msg->l2h = msg->data; - o2h = (struct abis_om2k_hdr *) msg->l2h; - - /* Compute the length in the OML header */ - o2h->om.length = 6 + msgb_l2len(msg)-sizeof(*o2h); - - switch (o2h->mo.class) { - case OM2K_MO_CLS_TRXC: - case OM2K_MO_CLS_TX: - case OM2K_MO_CLS_RX: - /* Route through per-TRX OML Link to the appropriate TRX */ - trx = gsm_bts_trx_by_nr(bts, o2h->mo.inst); - if (!trx) { - LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to " - "non-existing TRX\n", om2k_mo_name(&o2h->mo)); - return -ENODEV; - } - msg->dst = trx->oml_link; - break; - case OM2K_MO_CLS_TS: - /* Route through per-TRX OML Link to the appropriate TRX */ - trx = gsm_bts_trx_by_nr(bts, o2h->mo.assoc_so); - if (!trx) { - LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to " - "non-existing TRX\n", om2k_mo_name(&o2h->mo)); - return -ENODEV; - } - msg->dst = trx->oml_link; - break; - default: - /* Route through the IXU/DXU OML Link */ - msg->dst = bts->oml_link; - break; - } - - return _abis_nm_sendmsg(msg); -} - -static void fill_om2k_hdr(struct abis_om2k_hdr *o2h, const struct abis_om2k_mo *mo, - uint16_t msg_type) -{ - o2h->om.mdisc = ABIS_OM_MDISC_FOM; - o2h->om.placement = ABIS_OM_PLACEMENT_ONLY; - o2h->om.sequence = 0; - /* We fill o2h->om.length later during om2k_sendmsg() */ - o2h->msg_type = htons(msg_type); - memcpy(&o2h->mo, mo, sizeof(o2h->mo)); -} - -static int abis_om2k_cal_time_resp(struct gsm_bts *bts) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - time_t tm_t; - struct tm *tm; - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, &bts->rbs2000.cf.om2k_mo.addr, - OM2K_MSGT_CAL_TIME_RESP); - - tm_t = time(NULL); - tm = localtime(&tm_t); - - msgb_put_u8(msg, OM2K_DEI_CAL_TIME); - msgb_put_u8(msg, tm->tm_year % 100); - msgb_put_u8(msg, tm->tm_mon + 1); - msgb_put_u8(msg, tm->tm_mday); - msgb_put_u8(msg, tm->tm_hour); - msgb_put_u8(msg, tm->tm_min); - msgb_put_u8(msg, tm->tm_sec); - - return abis_om2k_sendmsg(bts, msg); -} - -static int abis_om2k_tx_simple(struct gsm_bts *bts, const struct abis_om2k_mo *mo, - uint8_t msg_type) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, mo, msg_type); - - DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo), - get_value_string(om2k_msgcode_vals, msg_type)); - - return abis_om2k_sendmsg(bts, msg); -} - -int abis_om2k_tx_reset_cmd(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_RESET_CMD); -} - -int abis_om2k_tx_start_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_START_REQ); -} - -int abis_om2k_tx_status_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_STATUS_REQ); -} - -int abis_om2k_tx_connect_cmd(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_CONNECT_CMD); -} - -int abis_om2k_tx_disconnect_cmd(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_DISCONNECT_CMD); -} - -int abis_om2k_tx_test_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_TEST_REQ); -} - -int abis_om2k_tx_enable_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_ENABLE_REQ); -} - -int abis_om2k_tx_disable_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_DISABLE_REQ); -} - -int abis_om2k_tx_op_info(struct gsm_bts *bts, const struct abis_om2k_mo *mo, - uint8_t operational) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, mo, OM2K_MSGT_OP_INFO); - - msgb_tv_put(msg, OM2K_DEI_OP_INFO, operational); - - DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo), - get_value_string(om2k_msgcode_vals, OM2K_MSGT_OP_INFO)); - - /* we update the state here... and send the signal at ACK */ - update_op_state(bts, mo, operational); - - return abis_om2k_sendmsg(bts, msg); -} - -int abis_om2k_tx_cap_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo) -{ - return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_CAPA_REQ); -} - -static void om2k_fill_is_conn_grp(struct om2k_is_conn_grp *grp, uint16_t icp1, - uint16_t icp2, uint8_t cont_idx) -{ - grp->icp1 = htons(icp1); - grp->icp2 = htons(icp2); - grp->cont_idx = cont_idx; -} - -int abis_om2k_tx_is_conf_req(struct gsm_bts *bts) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - struct is_conn_group *grp; - unsigned int num_grps = 0, i = 0; - struct om2k_is_conn_grp *cg; - - /* count number of groups in linked list */ - llist_for_each_entry(grp, &bts->rbs2000.is.conn_groups, list) - num_grps++; - - if (!num_grps) - return -EINVAL; - - /* allocate buffer for oml group array */ - cg = talloc_zero_array(bts, struct om2k_is_conn_grp, num_grps); - - /* fill array with data from linked list */ - llist_for_each_entry(grp, &bts->rbs2000.is.conn_groups, list) - om2k_fill_is_conn_grp(&cg[i++], grp->icp1, grp->icp2, grp->ci); - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, &bts->rbs2000.is.om2k_mo.addr, - OM2K_MSGT_IS_CONF_REQ); - - msgb_tv_put(msg, OM2K_DEI_LIST_NR, 1); - msgb_tv_put(msg, OM2K_DEI_END_LIST_NR, 1); - - msgb_tlv_put(msg, OM2K_DEI_IS_CONN_LIST, - num_grps * sizeof(*cg), (uint8_t *)cg); - - talloc_free(cg); - - DEBUGP(DNM, "Tx MO=%s %s\n", - om2k_mo_name(&bts->rbs2000.is.om2k_mo.addr), - get_value_string(om2k_msgcode_vals, OM2K_MSGT_IS_CONF_REQ)); - - return abis_om2k_sendmsg(bts, msg); -} - -int abis_om2k_tx_con_conf_req(struct gsm_bts *bts) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - struct con_group *grp; - unsigned int num_grps = 0; - - /* count number of groups in linked list */ - llist_for_each_entry(grp, &bts->rbs2000.con.conn_groups, list) - num_grps++; - - if (!num_grps) - return -EINVAL; - - /* first build the value part of the OM2K_DEI_CON_CONN_LIST DEI */ - msgb_put_u8(msg, num_grps); - llist_for_each_entry(grp, &bts->rbs2000.con.conn_groups, list) { - struct con_path *cp; - unsigned int num_paths = 0; - llist_for_each_entry(cp, &grp->paths, list) - num_paths++; - msgb_put_u8(msg, num_paths); - llist_for_each_entry(cp, &grp->paths, list) { - struct om2k_con_path *om2k_cp; - om2k_cp = (struct om2k_con_path *) msgb_put(msg, sizeof(*om2k_cp)); - om2k_cp->ccp = htons(cp->ccp); - om2k_cp->ci = cp->ci; - om2k_cp->tag = cp->tag; - om2k_cp->tei = cp->tei; - } - } - msgb_push_u8(msg, msgb_length(msg)); - msgb_push_u8(msg, OM2K_DEI_CON_CONN_LIST); - - /* pre-pend the list number DEIs */ - msgb_tv_push(msg, OM2K_DEI_END_LIST_NR, 1); - msgb_tv_push(msg, OM2K_DEI_LIST_NR, 1); - - /* pre-pend the OM2K header */ - o2k = (struct abis_om2k_hdr *) msgb_push(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, &bts->rbs2000.con.om2k_mo.addr, - OM2K_MSGT_CON_CONF_REQ); - - DEBUGP(DNM, "Tx MO=%s %s\n", - om2k_mo_name(&bts->rbs2000.con.om2k_mo.addr), - get_value_string(om2k_msgcode_vals, OM2K_MSGT_CON_CONF_REQ)); - - return abis_om2k_sendmsg(bts, msg); -} - -static void om2k_trx_to_mo(struct abis_om2k_mo *mo, - const struct gsm_bts_trx *trx, - enum abis_om2k_mo_cls cls) -{ - mo->class = cls; - mo->bts = 0; - mo->inst = trx->nr; - mo->assoc_so = 255; -} - -static void om2k_ts_to_mo(struct abis_om2k_mo *mo, - const struct gsm_bts_trx_ts *ts) -{ - mo->class = OM2K_MO_CLS_TS; - mo->bts = 0; - mo->inst = ts->nr; - mo->assoc_so = ts->trx->nr; -} - -/* Configure a Receiver MO */ -int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - struct abis_om2k_mo mo; - - om2k_trx_to_mo(&mo, trx, OM2K_MO_CLS_RX); - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, &mo, OM2K_MSGT_RX_CONF_REQ); - - msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_RX, trx->arfcn); - msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x02); /* A */ - - return abis_om2k_sendmsg(trx->bts, msg); -} - -/* Configure a Transmitter MO */ -int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - struct abis_om2k_mo mo; - - om2k_trx_to_mo(&mo, trx, OM2K_MO_CLS_TX); - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, &mo, OM2K_MSGT_TX_CONF_REQ); - - msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_TX, trx->arfcn); - msgb_tv_put(msg, OM2K_DEI_POWER, trx->nominal_power-trx->max_power_red); - msgb_tv_put(msg, OM2K_DEI_FILLING_MARKER, 0); /* Filling enabled */ - msgb_tv_put(msg, OM2K_DEI_BCC, trx->bts->bsic & 0x7); - /* Dedication Information is optional */ - - return abis_om2k_sendmsg(trx->bts, msg); -} - -enum abis_om2k_tf_mode { - OM2K_TF_MODE_MASTER = 0x00, - OM2K_TF_MODE_STANDALONE = 0x01, - OM2K_TF_MODE_SLAVE = 0x02, - OM2K_TF_MODE_UNDEFINED = 0xff, -}; - -static const uint8_t fs_offset_undef[5] = { 0xff, 0xff, 0xff, 0xff, 0xff }; - -int abis_om2k_tx_tf_conf_req(struct gsm_bts *bts) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, &bts->rbs2000.tf.om2k_mo.addr, - OM2K_MSGT_TF_CONF_REQ); - - msgb_tv_put(msg, OM2K_DEI_TF_MODE, OM2K_TF_MODE_STANDALONE); - msgb_tv_put(msg, OM2K_DEI_TF_SYNC_SRC, 0x00); - msgb_tv_fixed_put(msg, OM2K_DEI_FS_OFFSET, - sizeof(fs_offset_undef), fs_offset_undef); - - DEBUGP(DNM, "Tx MO=%s %s\n", - om2k_mo_name(&bts->rbs2000.tf.om2k_mo.addr), - get_value_string(om2k_msgcode_vals, OM2K_MSGT_TF_CONF_REQ)); - - return abis_om2k_sendmsg(bts, msg); -} - -static uint8_t pchan2comb(enum gsm_phys_chan_config pchan) -{ - switch (pchan) { - case GSM_PCHAN_CCCH: - return 4; - case GSM_PCHAN_CCCH_SDCCH4: - return 5; - case GSM_PCHAN_SDCCH8_SACCH8C: - return 3; - case GSM_PCHAN_TCH_F: - case GSM_PCHAN_TCH_H: - case GSM_PCHAN_PDCH: - case GSM_PCHAN_TCH_F_PDCH: - case GSM_PCHAN_TCH_F_TCH_H_PDCH: - return 8; - default: - return 0; - } -} - -static uint8_t ts2comb(struct gsm_bts_trx_ts *ts) -{ - switch (ts->pchan) { - case GSM_PCHAN_TCH_F_PDCH: - LOGP(DNM, LOGL_ERROR, "%s pchan %s not intended for use" - " with OM2000, use %s instead\n", - gsm_ts_and_pchan_name(ts), - gsm_pchan_name(GSM_PCHAN_TCH_F_PDCH), - gsm_pchan_name(GSM_PCHAN_TCH_F_TCH_H_PDCH)); - /* If we allowed initialization of TCH/F_PDCH, it would fail - * when we try to send the ip.access specific RSL PDCH Act - * message for it. Rather fail completely right now: */ - return 0; - case GSM_PCHAN_TCH_F_TCH_H_PDCH: - return pchan2comb(GSM_PCHAN_TCH_F); - default: - return pchan2comb(ts->pchan); - } -} - -static int put_freq_list(uint8_t *buf, uint16_t arfcn) -{ - buf[0] = 0x00; /* TX/RX address */ - buf[1] = (arfcn >> 8); - buf[2] = (arfcn & 0xff); - - return 3; -} - -/* Compute a frequency list in OM2000 fomrmat */ -static int om2k_gen_freq_list(uint8_t *list, struct gsm_bts_trx_ts *ts) -{ - uint8_t *cur = list; - int len; - - if (ts->hopping.enabled) { - unsigned int i; - for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) { - if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) - cur += put_freq_list(cur, i); - } - } else - cur += put_freq_list(cur, ts->trx->arfcn); - - len = cur - list; - - return len; -} - -const uint8_t icm_bound_params[] = { 0x02, 0x06, 0x0c, 0x16, 0x06 }; - -int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - struct abis_om2k_mo mo; - uint8_t freq_list[64*3]; /* BA max size: 64 ARFCN */ - int freq_list_len; - - om2k_ts_to_mo(&mo, ts); - - memset(freq_list, 0, sizeof(freq_list)); - freq_list_len = om2k_gen_freq_list(freq_list, ts); - if (freq_list_len < 0) - return freq_list_len; - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, &mo, OM2K_MSGT_TS_CONF_REQ); - - msgb_tv_put(msg, OM2K_DEI_COMBINATION, ts2comb(ts)); - msgb_tv_put(msg, OM2K_DEI_TS_NR, ts->nr); - msgb_tlv_put(msg, OM2K_DEI_FREQ_LIST, freq_list_len, freq_list); - msgb_tv_put(msg, OM2K_DEI_HSN, ts->hopping.hsn); - msgb_tv_put(msg, OM2K_DEI_MAIO, ts->hopping.maio); - msgb_tv_put(msg, OM2K_DEI_BSIC, ts->trx->bts->bsic); - msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x02); /* A */ - msgb_tv16_put(msg, OM2K_DEI_FN_OFFSET, 0); - msgb_tv_put(msg, OM2K_DEI_EXT_RANGE, 0); /* Off */ - /* Optional: Interference Rejection Combining */ - msgb_tv_put(msg, OM2K_DEI_INTERF_REJ_COMB, 0x00); - switch (ts->pchan) { - case GSM_PCHAN_CCCH: - msgb_tv_put(msg, OM2K_DEI_BA_PA_MFRMS, 0x06); - msgb_tv_put(msg, OM2K_DEI_BS_AG_BKS_RES, 0x01); - msgb_tv_put(msg, OM2K_DEI_DRX_DEV_MAX, 0x05); - /* Repeat Paging/IMM.ASS: True, Allow Paging Type 3: Yes, Page for 5 seconds (default) */ - msgb_tv_put(msg, OM2K_DEI_CCCH_OPTIONS, 0x01); - break; - case GSM_PCHAN_CCCH_SDCCH4: - msgb_tv_put(msg, OM2K_DEI_T3105, ts->trx->bts->network->T3105 / 10); - msgb_tv_put(msg, OM2K_DEI_NY1, 35); - msgb_tv_put(msg, OM2K_DEI_BA_PA_MFRMS, 0x06); - msgb_tv_put(msg, OM2K_DEI_CBCH_INDICATOR, 0); - msgb_tv_put(msg, OM2K_DEI_TSC, gsm_ts_tsc(ts)); - msgb_tv_put(msg, OM2K_DEI_BS_AG_BKS_RES, 0x01); - msgb_tv_put(msg, OM2K_DEI_ICM_INDICATOR, 0); - msgb_tv_put(msg, OM2K_DEI_DRX_DEV_MAX, 0x05); - /* Repeat Paging/IMM.ASS: True, Allow Paging Type 3: Yes, Page for 5 seconds (default) */ - msgb_tv_put(msg, OM2K_DEI_CCCH_OPTIONS, 0x01); - msgb_tv_fixed_put(msg, OM2K_DEI_ICM_BOUND_PARAMS, - sizeof(icm_bound_params), icm_bound_params); - break; - case GSM_PCHAN_SDCCH8_SACCH8C: - msgb_tv_put(msg, OM2K_DEI_T3105, ts->trx->bts->network->T3105 / 10); - msgb_tv_put(msg, OM2K_DEI_NY1, 35); - msgb_tv_put(msg, OM2K_DEI_CBCH_INDICATOR, 0); - msgb_tv_put(msg, OM2K_DEI_TSC, gsm_ts_tsc(ts)); - /* Disable RF RESOURCE INDICATION on idle channels */ - msgb_tv_put(msg, OM2K_DEI_ICM_INDICATOR, 0); - msgb_tv_fixed_put(msg, OM2K_DEI_ICM_BOUND_PARAMS, - sizeof(icm_bound_params), icm_bound_params); - break; - default: - msgb_tv_put(msg, OM2K_DEI_T3105, ts->trx->bts->network->T3105 / 10); - msgb_tv_put(msg, OM2K_DEI_NY1, 35); - msgb_tv_put(msg, OM2K_DEI_TSC, gsm_ts_tsc(ts)); - /* Disable RF RESOURCE INDICATION on idle channels */ - msgb_tv_put(msg, OM2K_DEI_ICM_INDICATOR, 0); - msgb_tv_fixed_put(msg, OM2K_DEI_ICM_BOUND_PARAMS, - sizeof(icm_bound_params), icm_bound_params); - msgb_tv_put(msg, OM2K_DEI_TTA, 10); /* Timer for Time Alignment */ - if (ts->pchan == GSM_PCHAN_TCH_H) - msgb_tv_put(msg, OM2K_DEI_ICM_CHAN_RATE, 1); /* TCH/H */ - else - msgb_tv_put(msg, OM2K_DEI_ICM_CHAN_RATE, 0); /* TCH/F */ - msgb_tv_put(msg, OM2K_DEI_LSC, 1); /* enabled */ - msgb_tv_put(msg, OM2K_DEI_LSC_FILT_TIME, 10); /* units of 100ms */ - msgb_tv_put(msg, OM2K_DEI_CALL_SUPV_TIME, 8); - msgb_tv_put(msg, OM2K_DEI_ENCR_ALG, 0x00); - /* Not sure what those below mean */ - msgb_tv_put(msg, 0x9e, 0x00); - msgb_tv_put(msg, 0x9f, 0x37); - msgb_tv_put(msg, 0xa0, 0x01); - break; - } - - DEBUGP(DNM, "Tx MO=%s %s\n", - om2k_mo_name(&mo), - get_value_string(om2k_msgcode_vals, OM2K_MSGT_TS_CONF_REQ)); - - return abis_om2k_sendmsg(ts->trx->bts, msg); -} - - -/*********************************************************************** - * OM2000 Managed Object (MO) FSM - ***********************************************************************/ - -#define S(x) (1 << (x)) - -enum om2k_event_name { - OM2K_MO_EVT_START, - OM2K_MO_EVT_RX_CONN_COMPL, - OM2K_MO_EVT_RX_RESET_COMPL, - OM2K_MO_EVT_RX_START_REQ_ACCEPT, - OM2K_MO_EVT_RX_START_RES, - OM2K_MO_EVT_RX_CFG_REQ_ACCEPT, - OM2K_MO_EVT_RX_CFG_RES, - OM2K_MO_EVT_RX_ENA_REQ_ACCEPT, - OM2K_MO_EVT_RX_ENA_RES, - OM2K_MO_EVT_RX_OPINFO_ACC, -}; - -static const struct value_string om2k_event_names[] = { - { OM2K_MO_EVT_START, "START" }, - { OM2K_MO_EVT_RX_CONN_COMPL, "RX-CONN-COMPL" }, - { OM2K_MO_EVT_RX_RESET_COMPL, "RX-RESET-COMPL" }, - { OM2K_MO_EVT_RX_START_REQ_ACCEPT, "RX-RESET-REQ-ACCEPT" }, - { OM2K_MO_EVT_RX_START_RES, "RX-START-RESULT" }, - { OM2K_MO_EVT_RX_CFG_REQ_ACCEPT, "RX-CFG-REQ-ACCEPT" }, - { OM2K_MO_EVT_RX_CFG_RES, "RX-CFG-RESULT" }, - { OM2K_MO_EVT_RX_ENA_REQ_ACCEPT, "RX-ENABLE-REQ-ACCEPT" }, - { OM2K_MO_EVT_RX_ENA_RES, "RX-ENABLE-RESULT" }, - { OM2K_MO_EVT_RX_OPINFO_ACC, "RX-OPINFO-ACCEPT" }, - { 0, NULL } -}; - -enum om2k_mo_fsm_state { - OM2K_ST_INIT, - OM2K_ST_WAIT_CONN_COMPL, - OM2K_ST_WAIT_RES_COMPL, - OM2K_ST_WAIT_START_ACCEPT, - OM2K_ST_WAIT_START_RES, - OM2K_ST_WAIT_CFG_ACCEPT, - OM2K_ST_WAIT_CFG_RES, - OM2K_ST_WAIT_ENABLE_ACCEPT, - OM2K_ST_WAIT_ENABLE_RES, - OM2K_ST_WAIT_OPINFO_ACCEPT, - OM2K_ST_DONE, - OM2K_ST_ERROR, -}; - -struct om2k_mo_fsm_priv { - struct gsm_bts_trx *trx; - struct om2k_mo *mo; - uint8_t ts_nr; -}; - -static void om2k_mo_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - - OSMO_ASSERT(event == OM2K_MO_EVT_START); - - switch (omfp->mo->addr.class) { - case OM2K_MO_CLS_CF: - /* no Connect required, is always connected */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr); - break; - case OM2K_MO_CLS_TRXC: - /* no Connect required, start with Reset */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL, - OM2K_TIMEOUT, 0); - abis_om2k_tx_reset_cmd(omfp->trx->bts, &omfp->mo->addr); - break; - default: - /* start with Connect */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CONN_COMPL, - OM2K_TIMEOUT, 0); - abis_om2k_tx_connect_cmd(omfp->trx->bts, &omfp->mo->addr); - break; - } -} - -static void om2k_mo_st_wait_conn_compl(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - - switch (omfp->mo->addr.class) { -#if 0 - case OM2K_MO_CLS_TF: - /* skip the reset, hope that helps */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr); - break; -#endif - default: - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL, - OM2K_TIMEOUT, 0); - abis_om2k_tx_reset_cmd(omfp->trx->bts, &omfp->mo->addr); - break; - } -} - -static void om2k_mo_st_wait_res_compl(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr); -} - -static void om2k_mo_st_wait_start_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_decoded_msg *omd = data; - - switch (omd->msg_type) { - case OM2K_MSGT_START_REQ_ACK: - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_RES, - OM2K_TIMEOUT, 0); - break; - case OM2K_MSGT_START_REQ_REJ: - osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0); - break; - } -} - -static void om2k_mo_st_wait_start_res(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - struct gsm_bts_trx_ts *ts; - - switch (omfp->mo->addr.class) { - case OM2K_MO_CLS_CF: - case OM2K_MO_CLS_TRXC: - /* Transition directly to Operational Info */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_op_info(omfp->trx->bts, &omfp->mo->addr, 1); - return; - case OM2K_MO_CLS_DP: - /* Transition directoy to WAIT_ENABLE_ACCEPT */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr); - return; -#if 0 - case OM2K_MO_CLS_TF: - /* skip the config, hope that helps speeding things up */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr); - return; -#endif - } - - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CFG_ACCEPT, - OM2K_TIMEOUT, 0); - switch (omfp->mo->addr.class) { - case OM2K_MO_CLS_TF: - abis_om2k_tx_tf_conf_req(omfp->trx->bts); - break; - case OM2K_MO_CLS_IS: - abis_om2k_tx_is_conf_req(omfp->trx->bts); - break; - case OM2K_MO_CLS_CON: - abis_om2k_tx_con_conf_req(omfp->trx->bts); - break; - case OM2K_MO_CLS_TX: - abis_om2k_tx_tx_conf_req(omfp->trx); - break; - case OM2K_MO_CLS_RX: - abis_om2k_tx_rx_conf_req(omfp->trx); - break; - case OM2K_MO_CLS_TS: - ts = mo2obj(omfp->trx->bts, &omfp->mo->addr); - abis_om2k_tx_ts_conf_req(ts); - break; - } -} - -static void om2k_mo_st_wait_cfg_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - uint32_t timeout = OM2K_TIMEOUT; - - if (omfp->mo->addr.class == OM2K_MO_CLS_TF) - timeout = 600; - - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CFG_RES, timeout, 0); -} - -static void om2k_mo_st_wait_cfg_res(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - struct om2k_decoded_msg *omd = data; - uint8_t accordance; - - if (!TLVP_PRESENT(&omd->tp, OM2K_DEI_ACCORDANCE_IND)) { - osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0); - return; - } - accordance = *TLVP_VAL(&omd->tp, OM2K_DEI_ACCORDANCE_IND); - - if (accordance != 0) { - /* accordance not OK */ - osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0); - return; - } - - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr); -} - -static void om2k_mo_st_wait_enable_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - struct om2k_decoded_msg *omd = data; - - switch (omd->msg_type) { - case OM2K_MSGT_ENABLE_REQ_REJ: - osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0); - break; - case OM2K_MSGT_ENABLE_REQ_ACK: - if (omfp->mo->addr.class == OM2K_MO_CLS_IS && - omfp->trx->bts->rbs2000.use_superchannel) - e1inp_ericsson_set_altc(omfp->trx->bts->oml_link->ts->line, 1); - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_RES, - OM2K_TIMEOUT, 0); - } -} - -static void om2k_mo_st_wait_enable_res(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - //struct om2k_decoded_msg *omd = data; - /* TODO: check if state is actually enabled now? */ - - osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT, - OM2K_TIMEOUT, 0); - abis_om2k_tx_op_info(omfp->trx->bts, &omfp->mo->addr, 1); -} - -static void om2k_mo_st_wait_opinfo_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - - /* if we have just received opinfo accept for the timeslot, - * start dynamic TCH switching procedures */ - if (omfp->mo->addr.class == OM2K_MO_CLS_TS) { - struct gsm_bts_trx_ts *ts; - ts = mo2obj(omfp->trx->bts, &omfp->mo->addr); - dyn_ts_init(ts); - } - osmo_fsm_inst_state_chg(fi, OM2K_ST_DONE, 0, 0); -} - -static void om2k_mo_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - omfp->mo->fsm = NULL; - osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); -} - -static void om2k_mo_s_error_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) -{ - struct om2k_mo_fsm_priv *omfp = fi->priv; - - omfp->mo->fsm = NULL; - osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL); -} - -static const struct osmo_fsm_state om2k_is_states[] = { - [OM2K_ST_INIT] = { - .name = "INIT", - .in_event_mask = S(OM2K_MO_EVT_START), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_CONN_COMPL) | - S(OM2K_ST_WAIT_START_ACCEPT) | - S(OM2K_ST_WAIT_RES_COMPL), - .action = om2k_mo_st_init, - }, - [OM2K_ST_WAIT_CONN_COMPL] = { - .name = "WAIT-CONN-COMPL", - .in_event_mask = S(OM2K_MO_EVT_RX_CONN_COMPL), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_START_ACCEPT) | - S(OM2K_ST_WAIT_RES_COMPL), - .action = om2k_mo_st_wait_conn_compl, - }, - [OM2K_ST_WAIT_RES_COMPL] = { - .name = "WAIT-RES-COMPL", - .in_event_mask = S(OM2K_MO_EVT_RX_RESET_COMPL), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_START_ACCEPT), - .action = om2k_mo_st_wait_res_compl, - }, - [OM2K_ST_WAIT_START_ACCEPT] = { - .name = "WAIT-START-ACCEPT", - .in_event_mask = S(OM2K_MO_EVT_RX_START_REQ_ACCEPT), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_START_RES), - .action =om2k_mo_st_wait_start_accept, - }, - [OM2K_ST_WAIT_START_RES] = { - .name = "WAIT-START-RES", - .in_event_mask = S(OM2K_MO_EVT_RX_START_RES), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_CFG_ACCEPT) | - S(OM2K_ST_WAIT_OPINFO_ACCEPT), - .action = om2k_mo_st_wait_start_res, - }, - [OM2K_ST_WAIT_CFG_ACCEPT] = { - .name = "WAIT-CFG-ACCEPT", - .in_event_mask = S(OM2K_MO_EVT_RX_CFG_REQ_ACCEPT), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_CFG_RES), - .action = om2k_mo_st_wait_cfg_accept, - }, - [OM2K_ST_WAIT_CFG_RES] = { - .name = "WAIT-CFG-RES", - .in_event_mask = S(OM2K_MO_EVT_RX_CFG_RES), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_ENABLE_ACCEPT), - .action = om2k_mo_st_wait_cfg_res, - }, - [OM2K_ST_WAIT_ENABLE_ACCEPT] = { - .name = "WAIT-ENABLE-ACCEPT", - .in_event_mask = S(OM2K_MO_EVT_RX_ENA_REQ_ACCEPT), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_ENABLE_RES), - .action = om2k_mo_st_wait_enable_accept, - }, - [OM2K_ST_WAIT_ENABLE_RES] = { - .name = "WAIT-ENABLE-RES", - .in_event_mask = S(OM2K_MO_EVT_RX_ENA_RES), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR) | - S(OM2K_ST_WAIT_OPINFO_ACCEPT), - .action = om2k_mo_st_wait_enable_res, - }, - [OM2K_ST_WAIT_OPINFO_ACCEPT] = { - .name = "WAIT-OPINFO-ACCEPT", - .in_event_mask = S(OM2K_MO_EVT_RX_OPINFO_ACC), - .out_state_mask = S(OM2K_ST_DONE) | - S(OM2K_ST_ERROR), - .action = om2k_mo_st_wait_opinfo_accept, - }, - [OM2K_ST_DONE] = { - .name = "DONE", - .in_event_mask = 0, - .out_state_mask = 0, - .onenter = om2k_mo_s_done_onenter, - }, - [OM2K_ST_ERROR] = { - .name = "ERROR", - .in_event_mask = 0, - .out_state_mask = 0, - .onenter = om2k_mo_s_error_onenter, - }, - -}; - -static int om2k_mo_timer_cb(struct osmo_fsm_inst *fi) -{ - osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0); - return 0; -} - -static struct osmo_fsm om2k_mo_fsm = { - .name = "OM2000-MO", - .states = om2k_is_states, - .num_states = ARRAY_SIZE(om2k_is_states), - .log_subsys = DNM, - .event_names = om2k_event_names, - .timer_cb = om2k_mo_timer_cb, -}; - -struct osmo_fsm_inst *om2k_mo_fsm_start(struct osmo_fsm_inst *parent, - uint32_t term_event, - struct gsm_bts_trx *trx, struct om2k_mo *mo) -{ - struct osmo_fsm_inst *fi; - struct om2k_mo_fsm_priv *omfp; - char idbuf[64]; - - snprintf(idbuf, sizeof(idbuf), "%s-%s", parent->id, - om2k_mo_name(&mo->addr)); - - fi = osmo_fsm_inst_alloc_child_id(&om2k_mo_fsm, parent, - term_event, idbuf); - if (!fi) - return NULL; - - mo->fsm = fi; - omfp = talloc_zero(fi, struct om2k_mo_fsm_priv); - omfp->mo = mo; - omfp->trx = trx; - fi->priv = omfp; - - osmo_fsm_inst_dispatch(fi, OM2K_MO_EVT_START, NULL); - - return fi; -} - -int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo, - struct om2k_decoded_msg *odm) -{ - switch (odm->msg_type) { - case OM2K_MSGT_CONNECT_COMPL: - case OM2K_MSGT_CONNECT_REJ: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_CONN_COMPL, odm); - break; - - case OM2K_MSGT_RESET_COMPL: - case OM2K_MSGT_RESET_REJ: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_RESET_COMPL, odm); - break; - - case OM2K_MSGT_START_REQ_ACK: - case OM2K_MSGT_START_REQ_REJ: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_START_REQ_ACCEPT, odm); - break; - - case OM2K_MSGT_START_RES: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_START_RES, odm); - break; - - case OM2K_MSGT_CON_CONF_REQ_ACK: - case OM2K_MSGT_IS_CONF_REQ_ACK: - case OM2K_MSGT_RX_CONF_REQ_ACK: - case OM2K_MSGT_TF_CONF_REQ_ACK: - case OM2K_MSGT_TS_CONF_REQ_ACK: - case OM2K_MSGT_TX_CONF_REQ_ACK: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_CFG_REQ_ACCEPT, odm); - break; - - case OM2K_MSGT_CON_CONF_RES: - case OM2K_MSGT_IS_CONF_RES: - case OM2K_MSGT_RX_CONF_RES: - case OM2K_MSGT_TF_CONF_RES: - case OM2K_MSGT_TS_CONF_RES: - case OM2K_MSGT_TX_CONF_RES: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_CFG_RES, odm); - break; - - case OM2K_MSGT_ENABLE_REQ_ACK: - case OM2K_MSGT_ENABLE_REQ_REJ: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_ENA_REQ_ACCEPT, odm); - break; - case OM2K_MSGT_ENABLE_RES: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_ENA_RES, odm); - break; - - case OM2K_MSGT_OP_INFO_ACK: - case OM2K_MSGT_OP_INFO_REJ: - osmo_fsm_inst_dispatch(mo->fsm, - OM2K_MO_EVT_RX_OPINFO_ACC, odm); - break; - default: - return -1; - } - - return 0; -} - -/*********************************************************************** - * OM2000 TRX Finite State Machine, initializes TRXC and all siblings - ***********************************************************************/ - -enum om2k_trx_event { - OM2K_TRX_EVT_START, - OM2K_TRX_EVT_TRXC_DONE, - OM2K_TRX_EVT_TX_DONE, - OM2K_TRX_EVT_RX_DONE, - OM2K_TRX_EVT_TS_DONE, - OM2K_TRX_EVT_STOP, -}; - -static struct value_string om2k_trx_events[] = { - { OM2K_TRX_EVT_START, "START" }, - { OM2K_TRX_EVT_TRXC_DONE, "TRXC-DONE" }, - { OM2K_TRX_EVT_TX_DONE, "TX-DONE" }, - { OM2K_TRX_EVT_RX_DONE, "RX-DONE" }, - { OM2K_TRX_EVT_TS_DONE, "TS-DONE" }, - { OM2K_TRX_EVT_STOP, "STOP" }, - { 0, NULL } -}; - -enum om2k_trx_state { - OM2K_TRX_S_INIT, - OM2K_TRX_S_WAIT_TRXC, - OM2K_TRX_S_WAIT_TX, - OM2K_TRX_S_WAIT_RX, - OM2K_TRX_S_WAIT_TS, - OM2K_TRX_S_DONE, - OM2K_TRX_S_ERROR -}; - -struct om2k_trx_fsm_priv { - struct gsm_bts_trx *trx; - uint8_t next_ts_nr; -}; - -static void om2k_trx_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_trx_fsm_priv *otfp = fi->priv; - - /* First initialize TRXC */ - osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TRXC, - TRX_FSM_TIMEOUT, 0); - om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TRXC_DONE, otfp->trx, - &otfp->trx->rbs2000.trxc.om2k_mo); -} - -static void om2k_trx_s_wait_trxc(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_trx_fsm_priv *otfp = fi->priv; - - /* Initialize TX after TRXC */ - osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TX, - TRX_FSM_TIMEOUT, 0); - om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TX_DONE, otfp->trx, - &otfp->trx->rbs2000.tx.om2k_mo); -} - -static void om2k_trx_s_wait_tx(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_trx_fsm_priv *otfp = fi->priv; - - /* Initialize RX after TX */ - osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_RX, - TRX_FSM_TIMEOUT, 0); - om2k_mo_fsm_start(fi, OM2K_TRX_EVT_RX_DONE, otfp->trx, - &otfp->trx->rbs2000.rx.om2k_mo); -} - -static void om2k_trx_s_wait_rx(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_trx_fsm_priv *otfp = fi->priv; - struct gsm_bts_trx_ts *ts; - - /* Initialize Timeslots after TX */ - osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TS, - TRX_FSM_TIMEOUT, 0); - otfp->next_ts_nr = 0; - ts = &otfp->trx->ts[otfp->next_ts_nr++]; - om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx, - &ts->rbs2000.om2k_mo); -} - -static void om2k_trx_s_wait_ts(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_trx_fsm_priv *otfp = fi->priv; - struct gsm_bts_trx_ts *ts; - - if (otfp->next_ts_nr < 8) { - /* iterate to the next timeslot */ - ts = &otfp->trx->ts[otfp->next_ts_nr++]; - om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx, - &ts->rbs2000.om2k_mo); - } else { - /* only after all 8 TS */ - osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_DONE, 0, 0); - } -} - -static void om2k_trx_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) -{ - struct om2k_trx_fsm_priv *otfp = fi->priv; - gsm_bts_trx_set_system_infos(otfp->trx); - osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); -} - -static const struct osmo_fsm_state om2k_trx_states[] = { - [OM2K_TRX_S_INIT] = { - .in_event_mask = S(OM2K_TRX_EVT_START), - .out_state_mask = S(OM2K_TRX_S_WAIT_TRXC), - .name = "INIT", - .action = om2k_trx_s_init, - }, - [OM2K_TRX_S_WAIT_TRXC] = { - .in_event_mask = S(OM2K_TRX_EVT_TRXC_DONE), - .out_state_mask = S(OM2K_TRX_S_ERROR) | - S(OM2K_TRX_S_WAIT_TX), - .name = "WAIT-TRXC", - .action = om2k_trx_s_wait_trxc, - }, - [OM2K_TRX_S_WAIT_TX] = { - .in_event_mask = S(OM2K_TRX_EVT_TX_DONE), - .out_state_mask = S(OM2K_TRX_S_ERROR) | - S(OM2K_TRX_S_WAIT_RX), - .name = "WAIT-TX", - .action = om2k_trx_s_wait_tx, - }, - [OM2K_TRX_S_WAIT_RX] = { - .in_event_mask = S(OM2K_TRX_EVT_RX_DONE), - .out_state_mask = S(OM2K_TRX_S_ERROR) | - S(OM2K_TRX_S_WAIT_TS), - .name = "WAIT-RX", - .action = om2k_trx_s_wait_rx, - }, - [OM2K_TRX_S_WAIT_TS] = { - .in_event_mask = S(OM2K_TRX_EVT_TS_DONE), - .out_state_mask = S(OM2K_TRX_S_ERROR) | - S(OM2K_TRX_S_DONE), - .name = "WAIT-TS", - .action = om2k_trx_s_wait_ts, - }, - [OM2K_TRX_S_DONE] = { - .name = "DONE", - .onenter = om2k_trx_s_done_onenter, - }, - [OM2K_TRX_S_ERROR] = { - .name = "ERROR", - }, -}; - -static int om2k_trx_timer_cb(struct osmo_fsm_inst *fi) -{ - osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_ERROR, 0, 0); - return 0; -} - -static struct osmo_fsm om2k_trx_fsm = { - .name = "OM2000-TRX", - .states = om2k_trx_states, - .num_states = ARRAY_SIZE(om2k_trx_states), - .log_subsys = DNM, - .event_names = om2k_trx_events, - .timer_cb = om2k_trx_timer_cb, -}; - -struct osmo_fsm_inst *om2k_trx_fsm_start(struct osmo_fsm_inst *parent, - struct gsm_bts_trx *trx, - uint32_t term_event) -{ - struct osmo_fsm_inst *fi; - struct om2k_trx_fsm_priv *otfp; - char idbuf[32]; - - snprintf(idbuf, sizeof(idbuf), "%u/%u", trx->bts->nr, trx->nr); - - fi = osmo_fsm_inst_alloc_child_id(&om2k_trx_fsm, parent, term_event, - idbuf); - if (!fi) - return NULL; - - otfp = talloc_zero(fi, struct om2k_trx_fsm_priv); - otfp->trx = trx; - fi->priv = otfp; - - osmo_fsm_inst_dispatch(fi, OM2K_TRX_EVT_START, NULL); - - return fi; -} - - -/*********************************************************************** - * OM2000 BTS Finite State Machine, initializes CF and all siblings - ***********************************************************************/ - -enum om2k_bts_event { - OM2K_BTS_EVT_START, - OM2K_BTS_EVT_CF_DONE, - OM2K_BTS_EVT_IS_DONE, - OM2K_BTS_EVT_CON_DONE, - OM2K_BTS_EVT_TF_DONE, - OM2K_BTS_EVT_TRX_DONE, - OM2K_BTS_EVT_STOP, -}; - -static const struct value_string om2k_bts_events[] = { - { OM2K_BTS_EVT_START, "START" }, - { OM2K_BTS_EVT_CF_DONE, "CF-DONE" }, - { OM2K_BTS_EVT_IS_DONE, "IS-DONE" }, - { OM2K_BTS_EVT_CON_DONE, "CON-DONE" }, - { OM2K_BTS_EVT_TF_DONE, "TF-DONE" }, - { OM2K_BTS_EVT_TRX_DONE, "TRX-DONE" }, - { OM2K_BTS_EVT_STOP, "STOP" }, - { 0, NULL } -}; - -enum om2k_bts_state { - OM2K_BTS_S_INIT, - OM2K_BTS_S_WAIT_CF, - OM2K_BTS_S_WAIT_IS, - OM2K_BTS_S_WAIT_CON, - OM2K_BTS_S_WAIT_TF, - OM2K_BTS_S_WAIT_TRX, - OM2K_BTS_S_DONE, - OM2K_BTS_S_ERROR, -}; - -struct om2k_bts_fsm_priv { - struct gsm_bts *bts; - uint8_t next_trx_nr; -}; - -static void om2k_bts_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_bts_fsm_priv *obfp = fi->priv; - struct gsm_bts *bts = obfp->bts; - - OSMO_ASSERT(event == OM2K_BTS_EVT_START); - osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CF, - BTS_FSM_TIMEOUT, 0); - om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CF_DONE, bts->c0, - &bts->rbs2000.cf.om2k_mo); -} - -static void om2k_bts_s_wait_cf(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_bts_fsm_priv *obfp = fi->priv; - struct gsm_bts *bts = obfp->bts; - - OSMO_ASSERT(event == OM2K_BTS_EVT_CF_DONE); - /* TF can take a long time to initialize, wait for 10min */ - osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TF, 600, 0); - om2k_mo_fsm_start(fi, OM2K_BTS_EVT_TF_DONE, bts->c0, - &bts->rbs2000.tf.om2k_mo); -} - -static void om2k_bts_s_wait_tf(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_bts_fsm_priv *obfp = fi->priv; - struct gsm_bts *bts = obfp->bts; - - OSMO_ASSERT(event == OM2K_BTS_EVT_TF_DONE); - - osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CON, - BTS_FSM_TIMEOUT, 0); - om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CON_DONE, bts->c0, - &bts->rbs2000.con.om2k_mo); -} - -static void om2k_bts_s_wait_con(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_bts_fsm_priv *obfp = fi->priv; - struct gsm_bts *bts = obfp->bts; - - OSMO_ASSERT(event == OM2K_BTS_EVT_CON_DONE); - - osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_IS, - BTS_FSM_TIMEOUT, 0); - om2k_mo_fsm_start(fi, OM2K_BTS_EVT_IS_DONE, bts->c0, - &bts->rbs2000.is.om2k_mo); -} - -static void om2k_bts_s_wait_is(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_bts_fsm_priv *obfp = fi->priv; - struct gsm_bts_trx *trx; - - OSMO_ASSERT(event == OM2K_BTS_EVT_IS_DONE); - - osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX, - BTS_FSM_TIMEOUT, 0); - obfp->next_trx_nr = 0; - trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++); - om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE); -} - -static void om2k_bts_s_wait_trx(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct om2k_bts_fsm_priv *obfp = fi->priv; - - OSMO_ASSERT(event == OM2K_BTS_EVT_TRX_DONE); - - if (obfp->next_trx_nr < obfp->bts->num_trx) { - struct gsm_bts_trx *trx; - trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++); - om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE); - } else { - osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_DONE, 0, 0); - } -} - -static void om2k_bts_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) -{ - osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL); -} - -static const struct osmo_fsm_state om2k_bts_states[] = { - [OM2K_BTS_S_INIT] = { - .in_event_mask = S(OM2K_BTS_EVT_START), - .out_state_mask = S(OM2K_BTS_S_WAIT_CF), - .name = "INIT", - .action = om2k_bts_s_init, - }, - [OM2K_BTS_S_WAIT_CF] = { - .in_event_mask = S(OM2K_BTS_EVT_CF_DONE), - .out_state_mask = S(OM2K_BTS_S_ERROR) | - S(OM2K_BTS_S_WAIT_TF), - .name = "WAIT-CF", - .action = om2k_bts_s_wait_cf, - }, - [OM2K_BTS_S_WAIT_TF] = { - .in_event_mask = S(OM2K_BTS_EVT_TF_DONE), - .out_state_mask = S(OM2K_BTS_S_ERROR) | - S(OM2K_BTS_S_WAIT_CON), - .name = "WAIT-TF", - .action = om2k_bts_s_wait_tf, - }, - [OM2K_BTS_S_WAIT_CON] = { - .in_event_mask = S(OM2K_BTS_EVT_CON_DONE), - .out_state_mask = S(OM2K_BTS_S_ERROR) | - S(OM2K_BTS_S_WAIT_IS), - .name = "WAIT-CON", - .action = om2k_bts_s_wait_con, - }, - [OM2K_BTS_S_WAIT_IS] = { - .in_event_mask = S(OM2K_BTS_EVT_IS_DONE), - .out_state_mask = S(OM2K_BTS_S_ERROR) | - S(OM2K_BTS_S_WAIT_TRX), - .name = "WAIT-IS", - .action = om2k_bts_s_wait_is, - }, - [OM2K_BTS_S_WAIT_TRX] = { - .in_event_mask = S(OM2K_BTS_EVT_TRX_DONE), - .out_state_mask = S(OM2K_BTS_S_ERROR) | - S(OM2K_BTS_S_DONE), - .name = "WAIT-TRX", - .action = om2k_bts_s_wait_trx, - }, - [OM2K_BTS_S_DONE] = { - .name = "DONE", - .onenter = om2k_bts_s_done_onenter, - }, - [OM2K_BTS_S_ERROR] = { - .name = "ERROR", - }, -}; - -static int om2k_bts_timer_cb(struct osmo_fsm_inst *fi) -{ - osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_ERROR, 0, 0); - return 0; -} - -static struct osmo_fsm om2k_bts_fsm = { - .name = "OM2000-BTS", - .states = om2k_bts_states, - .num_states = ARRAY_SIZE(om2k_bts_states), - .log_subsys = DNM, - .event_names = om2k_bts_events, - .timer_cb = om2k_bts_timer_cb, -}; - -struct osmo_fsm_inst * -om2k_bts_fsm_start(struct gsm_bts *bts) -{ - struct osmo_fsm_inst *fi; - struct om2k_bts_fsm_priv *obfp; - char idbuf[16]; - - snprintf(idbuf, sizeof(idbuf), "%u", bts->nr); - - fi = osmo_fsm_inst_alloc(&om2k_bts_fsm, bts, NULL, - LOGL_DEBUG, idbuf); - if (!fi) - return NULL; - fi->priv = obfp = talloc_zero(fi, struct om2k_bts_fsm_priv); - obfp->bts = bts; - - osmo_fsm_inst_dispatch(fi, OM2K_BTS_EVT_START, NULL); - - return fi; -} - - -/*********************************************************************** - * OM2000 Negotiation - ***********************************************************************/ - -static int abis_om2k_tx_negot_req_ack(struct gsm_bts *bts, const struct abis_om2k_mo *mo, - uint8_t *data, unsigned int len) -{ - struct msgb *msg = om2k_msgb_alloc(); - struct abis_om2k_hdr *o2k; - - o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k)); - fill_om2k_hdr(o2k, mo, OM2K_MSGT_NEGOT_REQ_ACK); - - msgb_tlv_put(msg, OM2K_DEI_NEGOT_REC2, len, data); - - DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo), - get_value_string(om2k_msgcode_vals, OM2K_MSGT_NEGOT_REQ_ACK)); - - return abis_om2k_sendmsg(bts, msg); -} - -struct iwd_version { - uint8_t gen_char[3+1]; - uint8_t rev_char[3+1]; -}; - -struct iwd_type { - uint8_t num_vers; - struct iwd_version v[8]; -}; - -static int om2k_rx_negot_req(struct msgb *msg) -{ - struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst; - struct abis_om2k_hdr *o2h = msgb_l2(msg); - struct iwd_type iwd_types[16]; - uint8_t num_iwd_types = o2h->data[2]; - uint8_t *cur = o2h->data+3; - unsigned int i, v; - - uint8_t out_buf[1024]; - uint8_t *out_cur = out_buf+1; - uint8_t out_num_types = 0; - - memset(iwd_types, 0, sizeof(iwd_types)); - - /* Parse the RBS-supported IWD versions into iwd_types array */ - for (i = 0; i < num_iwd_types; i++) { - uint8_t num_versions = *cur++; - uint8_t iwd_type = *cur++; - - iwd_types[iwd_type].num_vers = num_versions; - - for (v = 0; v < num_versions; v++) { - struct iwd_version *iwd_v = &iwd_types[iwd_type].v[v]; - - memcpy(iwd_v->gen_char, cur, 3); - cur += 3; - memcpy(iwd_v->rev_char, cur, 3); - cur += 3; - - DEBUGP(DNM, "\tIWD Type %u Gen %s Rev %s\n", iwd_type, - iwd_v->gen_char, iwd_v->rev_char); - } - } - - /* Select the last version for each IWD type */ - for (i = 0; i < ARRAY_SIZE(iwd_types); i++) { - struct iwd_type *type = &iwd_types[i]; - struct iwd_version *last_v; - - if (type->num_vers == 0) - continue; - - out_num_types++; - - last_v = &type->v[type->num_vers-1]; - - *out_cur++ = i; - memcpy(out_cur, last_v->gen_char, 3); - out_cur += 3; - memcpy(out_cur, last_v->rev_char, 3); - out_cur += 3; - } - - out_buf[0] = out_num_types; - - return abis_om2k_tx_negot_req_ack(sign_link->trx->bts, &o2h->mo, out_buf, out_cur - out_buf); -} - - -/*********************************************************************** - * OM2000 Receive Message Handler - ***********************************************************************/ - -static int om2k_rx_nack(struct msgb *msg) -{ - struct abis_om2k_hdr *o2h = msgb_l2(msg); - uint16_t msg_type = ntohs(o2h->msg_type); - struct tlv_parsed tp; - - LOGP(DNM, LOGL_ERROR, "Rx MO=%s %s", om2k_mo_name(&o2h->mo), - get_value_string(om2k_msgcode_vals, msg_type)); - - abis_om2k_msg_tlv_parse(&tp, o2h); - if (TLVP_PRESENT(&tp, OM2K_DEI_REASON_CODE)) - LOGPC(DNM, LOGL_ERROR, ", Reason 0x%02x", - *TLVP_VAL(&tp, OM2K_DEI_REASON_CODE)); - - if (TLVP_PRESENT(&tp, OM2K_DEI_RESULT_CODE)) - LOGPC(DNM, LOGL_ERROR, ", Result %s", - get_value_string(om2k_result_strings, - *TLVP_VAL(&tp, OM2K_DEI_RESULT_CODE))); - LOGPC(DNM, LOGL_ERROR, "\n"); - - return 0; -} - -static int process_mo_state(struct gsm_bts *bts, struct om2k_decoded_msg *odm) -{ - uint8_t mo_state; - - if (!TLVP_PRESENT(&odm->tp, OM2K_DEI_MO_STATE)) - return -EIO; - mo_state = *TLVP_VAL(&odm->tp, OM2K_DEI_MO_STATE); - - LOGP(DNM, LOGL_DEBUG, "Rx MO=%s %s, MO State: %s\n", - om2k_mo_name(&odm->o2h.mo), - get_value_string(om2k_msgcode_vals, odm->msg_type), - get_value_string(om2k_mostate_vals, mo_state)); - - /* Throw error message in case we see an enable rsponse that does - * not yield an enabled mo-state */ - if (odm->msg_type == OM2K_MSGT_ENABLE_RES - && mo_state != OM2K_MO_S_ENABLED) { - LOGP(DNM, LOGL_ERROR, - "Rx MO=%s %s Failed to enable MO State!\n", - om2k_mo_name(&odm->o2h.mo), - get_value_string(om2k_msgcode_vals, odm->msg_type)); - } - - update_mo_state(bts, &odm->o2h.mo, mo_state); - - return 0; -} - -/* Display fault report bits (helper function of display_fault_maps()) */ -static bool display_fault_bits(const uint8_t *vect, uint16_t len, - uint8_t dei, const struct abis_om2k_mo *mo) -{ - uint16_t i; - int k; - bool faults_present = false; - int first = 1; - char string[255]; - - /* Check if errors are present at all */ - for (i = 0; i < len; i++) - if (vect[i]) - faults_present = true; - if (!faults_present) - return false; - - sprintf(string, "Fault Report: %s (", - get_value_string(om2k_attr_vals, dei)); - - for (i = 0; i < len; i++) { - for (k = 0; k < 8; k++) { - if ((vect[i] >> k) & 1) { - if (!first) - sprintf(string + strlen(string), ","); - sprintf(string + strlen(string), "%d", k + i*8); - first = 0; - } - } - } - - sprintf(string + strlen(string), ")\n"); - DEBUGP(DNM, "Rx MO=%s %s", om2k_mo_name(mo), string); - - return true; -} - -/* Display fault report maps */ -static void display_fault_maps(const uint8_t *src, unsigned int src_len, - const struct abis_om2k_mo *mo) -{ - uint8_t tag; - uint16_t tag_len; - const uint8_t *val; - int src_pos = 0; - int rc; - int tlv_count = 0; - uint16_t msg_code; - bool faults_present = false; - - /* Chop off header */ - src+=4; - src_len-=4; - - /* Check message type */ - msg_code = (*src & 0xff) << 8; - src++; - src_len--; - msg_code |= (*src & 0xff); - src++; - src_len--; - if (msg_code != OM2K_MSGT_FAULT_REP) { - LOGP(DNM, LOGL_ERROR, "Rx MO=%s Fault report: invalid message code!\n", - om2k_mo_name(mo)); - return; - } - - /* Chop off mo-interface */ - src += 4; - src_len -= 4; - - /* Iterate over each TLV element */ - while (1) { - - /* Bail if an the maximum number of TLV fields - * have been parsed */ - if (tlv_count >= 11) { - LOGP(DNM, LOGL_ERROR, - "Rx MO=%s Fault Report: too many tlv elements!\n", - om2k_mo_name(mo)); - return; - } - - /* Parse TLV field */ - rc = tlv_parse_one(&tag, &tag_len, &val, &om2k_att_tlvdef, - src + src_pos, src_len - src_pos); - if (rc > 0) - src_pos += rc; - else { - LOGP(DNM, LOGL_ERROR, - "Rx MO=%s Fault Report: invalid tlv element!\n", - om2k_mo_name(mo)); - return; - } - - switch (tag) { - case OM2K_DEI_INT_FAULT_MAP_1A: - case OM2K_DEI_INT_FAULT_MAP_1B: - case OM2K_DEI_INT_FAULT_MAP_2A: - case OM2K_DEI_EXT_COND_MAP_1: - case OM2K_DEI_EXT_COND_MAP_2: - case OM2K_DEI_REPL_UNIT_MAP: - case OM2K_DEI_INT_FAULT_MAP_2A_EXT: - case OM2K_DEI_EXT_COND_MAP_2_EXT: - case OM2K_DEI_REPL_UNIT_MAP_EXT: - faults_present |= display_fault_bits(val, tag_len, - tag, mo); - break; - } - - /* Stop when no further TLV elements can be expected */ - if (src_len - src_pos < 2) - break; - - tlv_count++; - } - - if (!faults_present) { - DEBUGP(DNM, "Rx MO=%s Fault Report: All faults ceased!\n", - om2k_mo_name(mo)); - } -} - -int abis_om2k_rcvmsg(struct msgb *msg) -{ - struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst; - struct gsm_bts *bts = sign_link->trx->bts; - struct abis_om2k_hdr *o2h = msgb_l2(msg); - struct abis_om_hdr *oh = &o2h->om; - uint16_t msg_type = ntohs(o2h->msg_type); - struct om2k_decoded_msg odm; - struct om2k_mo *mo; - int rc = 0; - - /* Various consistency checks */ - if (oh->placement != ABIS_OM_PLACEMENT_ONLY) { - LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n", - oh->placement); - if (oh->placement != ABIS_OM_PLACEMENT_FIRST) - return -EINVAL; - } - if (oh->sequence != 0) { - LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n", - oh->sequence); - return -EINVAL; - } - - msg->l3h = (unsigned char *)o2h + sizeof(*o2h); - - if (oh->mdisc != ABIS_OM_MDISC_FOM) { - LOGP(DNM, LOGL_ERROR, "unknown ABIS OM2000 message discriminator 0x%x\n", - oh->mdisc); - return -EINVAL; - } - - DEBUGP(DNM, "Rx MO=%s %s (%s)\n", om2k_mo_name(&o2h->mo), - get_value_string(om2k_msgcode_vals, msg_type), - osmo_hexdump(msg->l2h, msgb_l2len(msg))); - - om2k_decode_msg(&odm, msg); - - process_mo_state(bts, &odm); - - switch (msg_type) { - case OM2K_MSGT_CAL_TIME_REQ: - rc = abis_om2k_cal_time_resp(bts); - break; - case OM2K_MSGT_FAULT_REP: - display_fault_maps(msg->l2h, msgb_l2len(msg), &o2h->mo); - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_FAULT_REP_ACK); - break; - case OM2K_MSGT_NEGOT_REQ: - rc = om2k_rx_negot_req(msg); - break; - case OM2K_MSGT_START_RES: - /* common processing here */ - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_START_RES_ACK); - /* below we dispatch into MO */ - break; - case OM2K_MSGT_IS_CONF_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_IS_CONF_RES_ACK); - break; - case OM2K_MSGT_CON_CONF_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_CON_CONF_RES_ACK); - break; - case OM2K_MSGT_TX_CONF_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TX_CONF_RES_ACK); - break; - case OM2K_MSGT_RX_CONF_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_RX_CONF_RES_ACK); - break; - case OM2K_MSGT_TS_CONF_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TS_CONF_RES_ACK); - break; - case OM2K_MSGT_TF_CONF_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TF_CONF_RES_ACK); - break; - case OM2K_MSGT_ENABLE_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_ENABLE_RES_ACK); - break; - case OM2K_MSGT_DISABLE_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_DISABLE_RES_ACK); - break; - case OM2K_MSGT_TEST_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TEST_RES_ACK); - break; - case OM2K_MSGT_CAPA_RES: - rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_CAPA_RES_ACK); - break; - /* ERrors */ - case OM2K_MSGT_START_REQ_REJ: - case OM2K_MSGT_CONNECT_REJ: - case OM2K_MSGT_OP_INFO_REJ: - case OM2K_MSGT_DISCONNECT_REJ: - case OM2K_MSGT_TEST_REQ_REJ: - case OM2K_MSGT_CON_CONF_REQ_REJ: - case OM2K_MSGT_IS_CONF_REQ_REJ: - case OM2K_MSGT_TX_CONF_REQ_REJ: - case OM2K_MSGT_RX_CONF_REQ_REJ: - case OM2K_MSGT_TS_CONF_REQ_REJ: - case OM2K_MSGT_TF_CONF_REQ_REJ: - case OM2K_MSGT_ENABLE_REQ_REJ: - case OM2K_MSGT_ALARM_STATUS_REQ_REJ: - case OM2K_MSGT_DISABLE_REQ_REJ: - rc = om2k_rx_nack(msg); - break; - } - - /* Resolve the MO for this message */ - mo = get_om2k_mo(bts, &o2h->mo); - if (!mo) { - LOGP(DNM, LOGL_ERROR, "Couldn't resolve MO for OM2K msg " - "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type), - msgb_hexdump(msg)); - return 0; - } - if (!mo->fsm) { - LOGP(DNM, LOGL_ERROR, "MO object should not generate any message. fsm == NULL " - "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type), - msgb_hexdump(msg)); - return 0; - } - - /* Dispatch message to that MO */ - om2k_mo_fsm_recvmsg(bts, mo, &odm); - - msgb_free(msg); - return rc; -} - -static void om2k_mo_init(struct om2k_mo *mo, uint8_t class, - uint8_t bts_nr, uint8_t assoc_so, uint8_t inst) -{ - mo->addr.class = class; - mo->addr.bts = bts_nr; - mo->addr.assoc_so = assoc_so; - mo->addr.inst = inst; -} - -/* initialize the OM2K_MO members of gsm_bts_trx and its timeslots */ -void abis_om2k_trx_init(struct gsm_bts_trx *trx) -{ - struct gsm_bts *bts = trx->bts; - unsigned int i; - - OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000); - - om2k_mo_init(&trx->rbs2000.trxc.om2k_mo, OM2K_MO_CLS_TRXC, - bts->nr, 255, trx->nr); - om2k_mo_init(&trx->rbs2000.tx.om2k_mo, OM2K_MO_CLS_TX, - bts->nr, 255, trx->nr); - om2k_mo_init(&trx->rbs2000.rx.om2k_mo, OM2K_MO_CLS_RX, - bts->nr, 255, trx->nr); - - for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { - om2k_mo_init(&trx->ts[i].rbs2000.om2k_mo, OM2K_MO_CLS_TS, - bts->nr, trx->nr, i); - } -} - -/* initialize the OM2K_MO members of gsm_bts */ -void abis_om2k_bts_init(struct gsm_bts *bts) -{ - OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000); - - om2k_mo_init(&bts->rbs2000.cf.om2k_mo, OM2K_MO_CLS_CF, - bts->nr, 0xFF, 0); - om2k_mo_init(&bts->rbs2000.is.om2k_mo, OM2K_MO_CLS_IS, - bts->nr, 0xFF, 0); - om2k_mo_init(&bts->rbs2000.con.om2k_mo, OM2K_MO_CLS_CON, - bts->nr, 0xFF, 0); - om2k_mo_init(&bts->rbs2000.dp.om2k_mo, OM2K_MO_CLS_DP, - bts->nr, 0xFF, 0); - om2k_mo_init(&bts->rbs2000.tf.om2k_mo, OM2K_MO_CLS_TF, - bts->nr, 0xFF, 0); -} - -static __attribute__((constructor)) void abis_om2k_init(void) -{ - osmo_fsm_register(&om2k_mo_fsm); - osmo_fsm_register(&om2k_bts_fsm); - osmo_fsm_register(&om2k_trx_fsm); -} diff --git a/src/libbsc/abis_om2000_vty.c b/src/libbsc/abis_om2000_vty.c deleted file mode 100644 index a6bc4c78c..000000000 --- a/src/libbsc/abis_om2000_vty.c +++ /dev/null @@ -1,609 +0,0 @@ -/* VTY interface for A-bis OM2000 */ - -/* (C) 2010-2011 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -extern struct gsm_network *bsc_gsmnet; - -static struct cmd_node om2k_node = { - OM2K_NODE, - "%s(om2k)# ", - 1, -}; - -static struct cmd_node om2k_con_group_node = { - OM2K_CON_GROUP_NODE, - "%s(om2k-con-group)# ", - 1, -}; - -struct con_group; - -struct oml_node_state { - struct gsm_bts *bts; - struct abis_om2k_mo mo; - struct con_group *cg; -}; - -static int dummy_config_write(struct vty *v) -{ - return CMD_SUCCESS; -} - -/* FIXME: auto-generate those strings from the value_string lists */ -#define OM2K_OBJCLASS_VTY "(trxc|ts|tf|is|con|dp|cf|tx|rx)" -#define OM2K_OBJCLASS_VTY_HELP "TRX Controller\n" \ - "Timeslot\n" \ - "Timing Function\n" \ - "Interface Switch\n" \ - "Abis Concentrator\n" \ - "Digital Path\n" \ - "Central Function\n" \ - "Transmitter\n" \ - "Receiver\n" - -DEFUN(om2k_class_inst, om2k_class_inst_cmd, - "bts <0-255> om2000 class " OM2K_OBJCLASS_VTY - " <0-255> <0-255> <0-255>", - "BTS related commands\n" "BTS Number\n" - "Manipulate the OM2000 managed objects\n" - "Object Class\n" OM2K_OBJCLASS_VTY_HELP - "BTS Number\n" "Associated SO Instance\n" "Instance Number\n") -{ - struct gsm_bts *bts; - struct oml_node_state *oms; - int bts_nr = atoi(argv[0]); - - bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr); - if (!bts) { - vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - if (bts->type != GSM_BTS_TYPE_RBS2000) { - vty_out(vty, "%% BTS %d not an Ericsson RBS%s", - bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - oms = talloc_zero(tall_bsc_ctx, struct oml_node_state); - if (!oms) - return CMD_WARNING; - - oms->bts = bts; - oms->mo.class = get_string_value(om2k_mo_class_short_vals, argv[1]); - oms->mo.bts = atoi(argv[2]); - oms->mo.assoc_so = atoi(argv[3]); - oms->mo.inst = atoi(argv[4]); - - vty->index = oms; - vty->node = OM2K_NODE; - - return CMD_SUCCESS; - -} - -DEFUN(om2k_classnum_inst, om2k_classnum_inst_cmd, - "bts <0-255> om2000 class <0-255> <0-255> <0-255> <0-255>", - "BTS related commands\n" "BTS Number\n" - "Manipulate the OML managed objects\n" - "Object Class\n" "Object Class\n" - "BTS Number\n" "Associated SO Instance\n" "Instance Number\n") -{ - struct gsm_bts *bts; - struct oml_node_state *oms; - int bts_nr = atoi(argv[0]); - - bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr); - if (!bts) { - vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - oms = talloc_zero(tall_bsc_ctx, struct oml_node_state); - if (!oms) - return CMD_WARNING; - - oms->bts = bts; - oms->mo.class = atoi(argv[1]); - oms->mo.bts = atoi(argv[2]); - oms->mo.assoc_so = atoi(argv[3]); - oms->mo.inst = atoi(argv[4]); - - vty->index = oms; - vty->node = OM2K_NODE; - - return CMD_SUCCESS; -} - -DEFUN(om2k_reset, om2k_reset_cmd, - "reset-command", - "Reset the MO\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_reset_cmd(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_start, om2k_start_cmd, - "start-request", - "Start the MO\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_start_req(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_status, om2k_status_cmd, - "status-request", - "Get the MO Status\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_status_req(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_connect, om2k_connect_cmd, - "connect-command", - "Connect the MO\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_connect_cmd(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_disconnect, om2k_disconnect_cmd, - "disconnect-command", - "Disconnect the MO\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_disconnect_cmd(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_enable, om2k_enable_cmd, - "enable-request", - "Enable the MO\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_enable_req(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_disable, om2k_disable_cmd, - "disable-request", - "Disable the MO\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_disable_req(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_op_info, om2k_op_info_cmd, - "operational-info <0-1>", - "Set operational information\n" - "Set operational info to 0 or 1\n") -{ - struct oml_node_state *oms = vty->index; - int oper = atoi(argv[0]); - - abis_om2k_tx_op_info(oms->bts, &oms->mo, oper); - return CMD_SUCCESS; -} - -DEFUN(om2k_test, om2k_test_cmd, - "test-request", - "Test the MO\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_test_req(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -DEFUN(om2k_cap_req, om2k_cap_req_cmd, - "capabilities-request", - "Request MO capabilities\n") -{ - struct oml_node_state *oms = vty->index; - - abis_om2k_tx_cap_req(oms->bts, &oms->mo); - return CMD_SUCCESS; -} - -static struct con_group *con_group_find_or_create(struct gsm_bts *bts, uint8_t cg) -{ - struct con_group *ent; - - llist_for_each_entry(ent, &bts->rbs2000.con.conn_groups, list) { - if (ent->cg == cg) - return ent; - } - - ent = talloc_zero(bts, struct con_group); - ent->bts = bts; - ent->cg = cg; - INIT_LLIST_HEAD(&ent->paths); - llist_add_tail(&ent->list, &bts->rbs2000.con.conn_groups); - - return ent; -} - -static int con_group_del(struct gsm_bts *bts, uint8_t cg_id) -{ - struct con_group *cg, *cg2; - - llist_for_each_entry_safe(cg, cg2, &bts->rbs2000.con.conn_groups, list) { - if (cg->cg == cg_id) { - llist_del(&cg->list); - talloc_free(cg); - return 0; - }; - } - return -ENOENT; -} - -static void con_group_add_path(struct con_group *cg, uint16_t ccp, - uint8_t ci, uint8_t tag, uint8_t tei) -{ - struct con_path *cp = talloc_zero(cg, struct con_path); - - cp->ccp = ccp; - cp->ci = ci; - cp->tag = tag; - cp->tei = tei; - llist_add(&cp->list, &cg->paths); -} - -static int con_group_del_path(struct con_group *cg, uint16_t ccp, - uint8_t ci, uint8_t tag, uint8_t tei) -{ - struct con_path *cp, *cp2; - llist_for_each_entry_safe(cp, cp2, &cg->paths, list) { - if (cp->ccp == ccp && cp->ci == ci && cp->tag == tag && - cp->tei == tei) { - llist_del(&cp->list); - talloc_free(cp); - return 0; - } - } - return -ENOENT; -} - -DEFUN(cfg_om2k_con_group, cfg_om2k_con_group_cmd, - "con-connection-group <1-31>", - "Configure a CON (Concentrator) Connection Group\n" - "CON Connection Group Number\n") -{ - struct gsm_bts *bts = vty->index; - struct con_group *cg; - uint8_t cgid = atoi(argv[0]); - - if (bts->type != GSM_BTS_TYPE_RBS2000) { - vty_out(vty, "%% CON MO only exists in RBS2000%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - cg = con_group_find_or_create(bts, cgid); - if (!cg) { - vty_out(vty, "%% Cannot create CON Group%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - vty->node = OM2K_CON_GROUP_NODE; - vty->index = cg; - - return CMD_SUCCESS; -} - -DEFUN(del_om2k_con_group, del_om2k_con_group_cmd, - "del-connection-group <1-31>", - "Delete a CON (Concentrator) Connection Group\n" - "CON Connection Group Number\n") -{ - struct gsm_bts *bts = vty->index; - int rc; - uint8_t cgid = atoi(argv[0]); - - if (bts->type != GSM_BTS_TYPE_RBS2000) { - vty_out(vty, "%% CON MO only exists in RBS2000%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - rc = con_group_del(bts, cgid); - if (rc != 0) { - vty_out(vty, "%% Cannot delete CON Group%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -#define CON_PATH_HELP "CON Path (In/Out)\n" \ - "Add CON Path to Concentration Group\n" \ - "Delete CON Path from Concentration Group\n" \ - "CON Conection Point\n" \ - "Contiguity Index\n" \ - -DEFUN(cfg_om2k_con_path_dec, cfg_om2k_con_path_dec_cmd, - "con-path (add|del) <0-2047> <0-255> deconcentrated <0-63>", - CON_PATH_HELP "De-concentrated in/outlet\n" "TEI Value\n") -{ - struct con_group *cg = vty->index; - uint16_t ccp = atoi(argv[1]); - uint8_t ci = atoi(argv[2]); - uint8_t tei = atoi(argv[3]); - - if (!strcmp(argv[0], "add")) - con_group_add_path(cg, ccp, ci, 0, tei); - else { - if (con_group_del_path(cg, ccp, ci, 0, tei) < 0) { - vty_out(vty, "%% No matching CON Path%s", - VTY_NEWLINE); - return CMD_WARNING; - } - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_om2k_con_path_conc, cfg_om2k_con_path_conc_cmd, - "con-path (add|del) <0-2047> <0-255> concentrated <1-16>", - CON_PATH_HELP "Concentrated in/outlet\n" "Tag Number\n") -{ - struct con_group *cg = vty->index; - uint16_t ccp = atoi(argv[1]); - uint8_t ci = atoi(argv[2]); - uint8_t tag = atoi(argv[3]); - - if (!strcmp(argv[0], "add")) - con_group_add_path(cg, ccp, ci, tag, 0xff); - else { - if (con_group_del_path(cg, ccp, ci, tag, 0xff) < 0) { - vty_out(vty, "%% No matching CON list entry%s", - VTY_NEWLINE); - return CMD_WARNING; - } - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_alt_mode, cfg_bts_alt_mode_cmd, - "abis-lower-transport (single-timeslot|super-channel)", - "Configure thee Abis Lower Transport\n" - "Single Timeslot (classic Abis)\n" - "SuperChannel (Packet Abis)\n") -{ - struct gsm_bts *bts = vty->index; - struct con_group *cg; - - if (bts->type != GSM_BTS_TYPE_RBS2000) { - vty_out(vty, "%% Command only works for RBS2000%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[0], "super-channel")) - bts->rbs2000.use_superchannel = 1; - else - bts->rbs2000.use_superchannel = 0; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_is_conn_list, cfg_bts_is_conn_list_cmd, - "is-connection-list (add|del) <0-2047> <0-2047> <0-255>", - "Interface Switch Connection List\n" - "Add to IS list\n" "Delete from IS list\n" - "ICP1\n" "ICP2\n" "Contiguity Index\n") -{ - struct gsm_bts *bts = vty->index; - uint16_t icp1 = atoi(argv[1]); - uint16_t icp2 = atoi(argv[2]); - uint8_t ci = atoi(argv[3]); - struct is_conn_group *grp, *grp2; - - if (bts->type != GSM_BTS_TYPE_RBS2000) { - vty_out(vty, "%% IS MO only exists in RBS2000%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[0], "add")) { - grp = talloc_zero(bts, struct is_conn_group); - grp->icp1 = icp1; - grp->icp2 = icp2; - grp->ci = ci; - llist_add_tail(&grp->list, &bts->rbs2000.is.conn_groups); - } else { - llist_for_each_entry_safe(grp, grp2, &bts->rbs2000.is.conn_groups, list) { - if (grp->icp1 == icp1 && grp->icp2 == icp2 - && grp->ci == ci) { - llist_del(&grp->list); - talloc_free(grp); - return CMD_SUCCESS; - } - } - vty_out(vty, "%% No matching IS Conn Group found!%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - - -DEFUN(om2k_conf_req, om2k_conf_req_cmd, - "configuration-request", - "Send the configuration request for current MO\n") -{ - struct oml_node_state *oms = vty->index; - struct gsm_bts *bts = oms->bts; - struct gsm_bts_trx *trx = NULL; - struct gsm_bts_trx_ts *ts = NULL; - - switch (oms->mo.class) { - case OM2K_MO_CLS_IS: - abis_om2k_tx_is_conf_req(bts); - break; - case OM2K_MO_CLS_TS: - trx = gsm_bts_trx_by_nr(bts, oms->mo.assoc_so); - if (!trx) { - vty_out(vty, "%% BTS %u has no TRX %u%s", bts->nr, - oms->mo.assoc_so, VTY_NEWLINE); - return CMD_WARNING; - } - if (oms->mo.inst >= ARRAY_SIZE(trx->ts)) { - vty_out(vty, "%% Timeslot %u out of range%s", - oms->mo.inst, VTY_NEWLINE); - return CMD_WARNING; - } - ts = &trx->ts[oms->mo.inst]; - abis_om2k_tx_ts_conf_req(ts); - break; - case OM2K_MO_CLS_RX: - case OM2K_MO_CLS_TX: - case OM2K_MO_CLS_TRXC: - trx = gsm_bts_trx_by_nr(bts, oms->mo.inst); - if (!trx) { - vty_out(vty, "%% BTS %u has no TRX %u%s", bts->nr, - oms->mo.inst, VTY_NEWLINE); - return CMD_WARNING; - } - switch (oms->mo.class) { - case OM2K_MO_CLS_RX: - abis_om2k_tx_rx_conf_req(trx); - break; - case OM2K_MO_CLS_TX: - abis_om2k_tx_tx_conf_req(trx); - break; - default: - break; - } - break; - case OM2K_MO_CLS_TF: - abis_om2k_tx_tf_conf_req(bts); - break; - default: - vty_out(vty, "%% Don't know how to configure MO%s", - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -static void dump_con_group(struct vty *vty, struct con_group *cg) -{ - struct con_path *cp; - - llist_for_each_entry(cp, &cg->paths, list) { - vty_out(vty, " con-path add %u %u ", cp->ccp, cp->ci); - if (cp->tei == 0xff) { - vty_out(vty, "concentrated %u%s", cp->tag, - VTY_NEWLINE); - } else { - vty_out(vty, "deconcentrated %u%s", cp->tei, - VTY_NEWLINE); - } - } -} - -void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts) -{ - struct is_conn_group *igrp; - struct con_group *cgrp; - - llist_for_each_entry(igrp, &bts->rbs2000.is.conn_groups, list) - vty_out(vty, " is-connection-list add %u %u %u%s", - igrp->icp1, igrp->icp2, igrp->ci, VTY_NEWLINE); - - llist_for_each_entry(cgrp, &bts->rbs2000.con.conn_groups, list) { - vty_out(vty, " con-connection-group %u%s", cgrp->cg, - VTY_NEWLINE); - dump_con_group(vty, cgrp); - } - if (bts->rbs2000.use_superchannel) - vty_out(vty, " abis-lower-transport super-channel%s", - VTY_NEWLINE); -} - -int abis_om2k_vty_init(void) -{ - install_element(ENABLE_NODE, &om2k_class_inst_cmd); - install_element(ENABLE_NODE, &om2k_classnum_inst_cmd); - install_node(&om2k_node, dummy_config_write); - - vty_install_default(OM2K_NODE); - install_element(OM2K_NODE, &om2k_reset_cmd); - install_element(OM2K_NODE, &om2k_start_cmd); - install_element(OM2K_NODE, &om2k_status_cmd); - install_element(OM2K_NODE, &om2k_connect_cmd); - install_element(OM2K_NODE, &om2k_disconnect_cmd); - install_element(OM2K_NODE, &om2k_enable_cmd); - install_element(OM2K_NODE, &om2k_disable_cmd); - install_element(OM2K_NODE, &om2k_op_info_cmd); - install_element(OM2K_NODE, &om2k_test_cmd); - install_element(OM2K_NODE, &om2k_cap_req_cmd); - install_element(OM2K_NODE, &om2k_conf_req_cmd); - - install_node(&om2k_con_group_node, dummy_config_write); - vty_install_default(OM2K_CON_GROUP_NODE); - install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_dec_cmd); - install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_conc_cmd); - - install_element(BTS_NODE, &cfg_bts_is_conn_list_cmd); - install_element(BTS_NODE, &cfg_bts_alt_mode_cmd); - install_element(BTS_NODE, &cfg_om2k_con_group_cmd); - install_element(BTS_NODE, &del_om2k_con_group_cmd); - - return 0; -} diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c deleted file mode 100644 index 66cda8200..000000000 --- a/src/libbsc/abis_rsl.c +++ /dev/null @@ -1,2939 +0,0 @@ -/* GSM Radio Signalling Link messages on the A-bis interface - * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ - -/* (C) 2008-2010 by Harald Welte - * (C) 2012 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 . - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RSL_ALLOC_SIZE 1024 -#define RSL_ALLOC_HEADROOM 128 - -enum sacch_deact { - SACCH_NONE, - SACCH_DEACTIVATE, -}; - -static int rsl_send_imm_assignment(struct gsm_lchan *lchan); -static void error_timeout_cb(void *data); -static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts); -static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc); -static void dyn_ts_switchover_complete(struct gsm_lchan *lchan); - -static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan, - struct gsm_meas_rep *resp) -{ - struct lchan_signal_data sig; - sig.lchan = lchan; - sig.mr = resp; - osmo_signal_dispatch(SS_LCHAN, sig_no, &sig); -} - -static void do_lchan_free(struct gsm_lchan *lchan) -{ - /* We start the error timer to make the channel available again */ - if (lchan->state == LCHAN_S_REL_ERR) { - osmo_timer_setup(&lchan->error_timer, error_timeout_cb, lchan); - osmo_timer_schedule(&lchan->error_timer, - lchan->ts->trx->bts->network->T3111 + 2, 0); - } else { - rsl_lchan_set_state(lchan, LCHAN_S_NONE); - } - lchan_free(lchan); -} - -static void count_codecs(struct gsm_bts *bts, struct gsm_lchan *lchan) -{ - OSMO_ASSERT(bts); - - if (lchan->type == GSM_LCHAN_TCH_H) { - switch (lchan->tch_mode) { - case GSM48_CMODE_SPEECH_AMR: - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_AMR_H]); - break; - case GSM48_CMODE_SPEECH_V1: - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_V1_HR]); - break; - default: - break; - } - } else if (lchan->type == GSM_LCHAN_TCH_F) { - switch (lchan->tch_mode) { - case GSM48_CMODE_SPEECH_AMR: - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_AMR_F]); - break; - case GSM48_CMODE_SPEECH_V1: - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_V1_FR]); - break; - case GSM48_CMODE_SPEECH_EFR: - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_EFR]); - break; - default: - break; - } - } -} - -static uint8_t mdisc_by_msgtype(uint8_t msg_type) -{ - /* mask off the transparent bit ? */ - msg_type &= 0xfe; - - if ((msg_type & 0xf0) == 0x00) - return ABIS_RSL_MDISC_RLL; - if ((msg_type & 0xf0) == 0x10) { - if (msg_type >= 0x19 && msg_type <= 0x22) - return ABIS_RSL_MDISC_TRX; - else - return ABIS_RSL_MDISC_COM_CHAN; - } - if ((msg_type & 0xe0) == 0x20) - return ABIS_RSL_MDISC_DED_CHAN; - - return ABIS_RSL_MDISC_LOC; -} - -static inline void init_dchan_hdr(struct abis_rsl_dchan_hdr *dh, - uint8_t msg_type) -{ - dh->c.msg_discr = mdisc_by_msgtype(msg_type); - dh->c.msg_type = msg_type; - dh->ie_chan = RSL_IE_CHAN_NR; -} - -/* call rsl_lchan_lookup and set the log context */ -static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, - const char *log_name) -{ - int rc; - struct gsm_lchan *lchan = rsl_lchan_lookup(trx, chan_nr, &rc); - - if (!lchan) { - LOGP(DRSL, LOGL_ERROR, "%sunknown chan_nr=0x%02x\n", - log_name, chan_nr); - return NULL; - } - - if (rc < 0) - LOGP(DRSL, LOGL_ERROR, "%s %smismatching chan_nr=0x%02x\n", - gsm_ts_and_pchan_name(lchan->ts), log_name, chan_nr); - - if (lchan->conn) - log_set_context(LOG_CTX_VLR_SUBSCR, lchan->conn->vsub); - - return lchan; -} - -/* As per TS 03.03 Section 2.2, the IMSI has 'not more than 15 digits' */ -uint64_t str_to_imsi(const char *imsi_str) -{ - uint64_t ret; - - ret = strtoull(imsi_str, NULL, 10); - - return ret; -} - -static struct msgb *rsl_msgb_alloc(void) -{ - return msgb_alloc_headroom(RSL_ALLOC_SIZE, RSL_ALLOC_HEADROOM, - "RSL"); -} - -static void pad_macblock(uint8_t *out, const uint8_t *in, int len) -{ - memcpy(out, in, len); - - if (len < GSM_MACBLOCK_LEN) - memset(out+len, 0x2b, GSM_MACBLOCK_LEN - len); -} - -/* Chapter 9.3.7: Encryption Information */ -static int build_encr_info(uint8_t *out, struct gsm_lchan *lchan) -{ - *out++ = lchan->encr.alg_id & 0xff; - if (lchan->encr.key_len) - memcpy(out, lchan->encr.key, lchan->encr.key_len); - return lchan->encr.key_len + 1; -} - -static void print_rsl_cause(int lvl, const uint8_t *cause_v, uint8_t cause_len) -{ - int i; - - LOGPC(DRSL, lvl, "CAUSE=0x%02x(%s) ", - cause_v[0], rsl_err_name(cause_v[0])); - for (i = 1; i < cause_len-1; i++) - LOGPC(DRSL, lvl, "%02x ", cause_v[i]); -} - -static void lchan_act_tmr_cb(void *data) -{ - struct gsm_lchan *lchan = data; - - rsl_lchan_mark_broken(lchan, "activation timeout"); - lchan_free(lchan); -} - -static void lchan_deact_tmr_cb(void *data) -{ - struct gsm_lchan *lchan = data; - - rsl_lchan_mark_broken(lchan, "de-activation timeout"); - lchan_free(lchan); -} - - -/* Send a BCCH_INFO message as per Chapter 8.5.1 */ -int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len) -{ - struct abis_rsl_dchan_hdr *dh; - const struct gsm_bts *bts = trx->bts; - struct msgb *msg = rsl_msgb_alloc(); - uint8_t type = osmo_sitype2rsl(si_type); - - if (bts->c0 != trx) - LOGP(DRR, LOGL_ERROR, "Attempting to set BCCH SI%s on wrong BTS%u/TRX%u\n", - get_value_string(osmo_sitype_strs, si_type), bts->nr, trx->nr); - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof*dh); - init_dchan_hdr(dh, RSL_MT_BCCH_INFO); - dh->chan_nr = RSL_CHAN_BCCH; - - if (trx->bts->type == GSM_BTS_TYPE_RBS2000 - && type == RSL_SYSTEM_INFO_13) { - /* Ericsson proprietary encoding of SI13 */ - msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, RSL_ERIC_SYSTEM_INFO_13); - if (data) - msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); - msgb_tv_put(msg, RSL_IE_ERIC_BCCH_MAPPING, 0x00); - } else { - /* Normal encoding */ - msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); - if (data) - msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); - } - - msg->dst = trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type, - const uint8_t *data, int len) -{ - struct abis_rsl_common_hdr *ch; - struct msgb *msg = rsl_msgb_alloc(); - - ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch)); - ch->msg_discr = ABIS_RSL_MDISC_TRX; - ch->msg_type = RSL_MT_SACCH_FILL; - - msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); - if (data) - msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data); - - msg->dst = trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -int rsl_sacch_info_modify(struct gsm_lchan *lchan, uint8_t type, - const uint8_t *data, int len) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg = rsl_msgb_alloc(); - uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_SACCH_INFO_MODIFY); - dh->chan_nr = chan_nr; - - msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); - if (data) - msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg; - uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - - db = abs(db); - if (db > 30) - return -EINVAL; - - msg = rsl_msgb_alloc(); - - lchan->bs_power = db/2; - if (fpc) - lchan->bs_power |= 0x10; - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_BS_POWER_CONTROL); - dh->chan_nr = chan_nr; - - msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg; - uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - int ctl_lvl; - - ctl_lvl = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, dbm); - if (ctl_lvl < 0) - return ctl_lvl; - - msg = rsl_msgb_alloc(); - - lchan->ms_power = ctl_lvl; - - if (fpc) - lchan->ms_power |= 0x20; - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_MS_POWER_CONTROL); - dh->chan_nr = chan_nr; - - msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, - struct gsm_lchan *lchan) -{ - memset(cm, 0, sizeof(*cm)); - - /* FIXME: what to do with data calls ? */ - cm->dtx_dtu = 0; - if (lchan->ts->trx->bts->dtxu != GSM48_DTX_SHALL_NOT_BE_USED) - cm->dtx_dtu |= RSL_CMOD_DTXu; - if (lchan->ts->trx->bts->dtxd) - cm->dtx_dtu |= RSL_CMOD_DTXd; - - /* set TCH Speech/Data */ - cm->spd_ind = lchan->rsl_cmode; - - if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && - lchan->tch_mode != GSM48_CMODE_SIGN) - LOGP(DRSL, LOGL_ERROR, "unsupported: rsl_mode == signalling, " - "but tch_mode != signalling\n"); - - switch (lchan->type) { - case GSM_LCHAN_SDCCH: - cm->chan_rt = RSL_CMOD_CRT_SDCCH; - break; - case GSM_LCHAN_TCH_F: - cm->chan_rt = RSL_CMOD_CRT_TCH_Bm; - break; - case GSM_LCHAN_TCH_H: - cm->chan_rt = RSL_CMOD_CRT_TCH_Lm; - break; - case GSM_LCHAN_NONE: - case GSM_LCHAN_UNKNOWN: - default: - LOGP(DRSL, LOGL_ERROR, - "unsupported activation lchan->type %u %s\n", - lchan->type, gsm_lchant_name(lchan->type)); - return -EINVAL; - } - - switch (lchan->tch_mode) { - case GSM48_CMODE_SIGN: - cm->chan_rate = 0; - break; - case GSM48_CMODE_SPEECH_V1: - cm->chan_rate = RSL_CMOD_SP_GSM1; - break; - case GSM48_CMODE_SPEECH_EFR: - cm->chan_rate = RSL_CMOD_SP_GSM2; - break; - case GSM48_CMODE_SPEECH_AMR: - cm->chan_rate = RSL_CMOD_SP_GSM3; - break; - case GSM48_CMODE_DATA_14k5: - case GSM48_CMODE_DATA_12k0: - case GSM48_CMODE_DATA_6k0: - switch (lchan->csd_mode) { - case LCHAN_CSD_M_NT: - /* non-transparent CSD with RLP */ - switch (lchan->tch_mode) { - case GSM48_CMODE_DATA_14k5: - cm->chan_rate = RSL_CMOD_SP_NT_14k5; - break; - case GSM48_CMODE_DATA_12k0: - cm->chan_rate = RSL_CMOD_SP_NT_12k0; - break; - case GSM48_CMODE_DATA_6k0: - cm->chan_rate = RSL_CMOD_SP_NT_6k0; - break; - default: - LOGP(DRSL, LOGL_ERROR, - "unsupported lchan->tch_mode %u\n", - lchan->tch_mode); - return -EINVAL; - } - break; - /* transparent data services below */ - case LCHAN_CSD_M_T_1200_75: - cm->chan_rate = RSL_CMOD_CSD_T_1200_75; - break; - case LCHAN_CSD_M_T_600: - cm->chan_rate = RSL_CMOD_CSD_T_600; - break; - case LCHAN_CSD_M_T_1200: - cm->chan_rate = RSL_CMOD_CSD_T_1200; - break; - case LCHAN_CSD_M_T_2400: - cm->chan_rate = RSL_CMOD_CSD_T_2400; - break; - case LCHAN_CSD_M_T_9600: - cm->chan_rate = RSL_CMOD_CSD_T_9600; - break; - case LCHAN_CSD_M_T_14400: - cm->chan_rate = RSL_CMOD_CSD_T_14400; - break; - case LCHAN_CSD_M_T_29000: - cm->chan_rate = RSL_CMOD_CSD_T_29000; - break; - case LCHAN_CSD_M_T_32000: - cm->chan_rate = RSL_CMOD_CSD_T_32000; - break; - default: - LOGP(DRSL, LOGL_ERROR, - "unsupported lchan->csd_mode %u\n", - lchan->csd_mode); - return -EINVAL; - } - break; - default: - LOGP(DRSL, LOGL_ERROR, - "unsupported lchan->tch_mode %u\n", - lchan->tch_mode); - return -EINVAL; - } - - return 0; -} - -static void mr_config_for_bts(struct gsm_lchan *lchan, struct msgb *msg) -{ - if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) - msgb_tlv_put(msg, RSL_IE_MR_CONFIG, lchan->mr_bts_lv[0], - lchan->mr_bts_lv + 1); -} - -static enum gsm_phys_chan_config pchan_for_lchant(enum gsm_chan_t type) -{ - switch (type) { - case GSM_LCHAN_TCH_F: - return GSM_PCHAN_TCH_F; - case GSM_LCHAN_TCH_H: - return GSM_PCHAN_TCH_H; - case GSM_LCHAN_NONE: - case GSM_LCHAN_PDTCH: - /* TODO: so far lchan->type is NONE in PDCH mode. PDTCH is only - * used in osmo-bts. Maybe set PDTCH and drop the NONE case - * here. */ - return GSM_PCHAN_PDCH; - default: - return GSM_PCHAN_UNKNOWN; - } -} - -/*! Tx simplified channel activation message for non-standard PDCH type. */ -static int rsl_chan_activate_lchan_as_pdch(struct gsm_lchan *lchan) -{ - struct msgb *msg; - struct abis_rsl_dchan_hdr *dh; - - /* This might be called after release of the second lchan of a TCH/H, - * but PDCH activation must always happen on the first lchan. Make sure - * the calling code passes the correct lchan. */ - OSMO_ASSERT(lchan == lchan->ts->lchan); - - rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ); - - msg = rsl_msgb_alloc(); - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV); - dh->chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_PDCH); - - msgb_tv_put(msg, RSL_IE_ACT_TYPE, RSL_ACT_OSMO_PDCH); - - if (lchan->ts->trx->bts->type == GSM_BTS_TYPE_RBS2000 && - lchan->ts->trx->bts->rbs2000.use_superchannel) { - const uint8_t eric_pgsl_tmr[] = { 30, 1 }; - msgb_tv_fixed_put(msg, RSL_IE_ERIC_PGSL_TIMERS, - sizeof(eric_pgsl_tmr), eric_pgsl_tmr); - } - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/* Chapter 8.4.1 */ -int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type, - uint8_t ho_ref) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg; - int rc; - uint8_t *len; - uint8_t ta; - - struct rsl_ie_chan_mode cm; - struct gsm48_chan_desc cd; - - /* If a TCH_F/PDCH TS is in PDCH mode, deactivate PDCH first. */ - if (lchan->ts->pchan == GSM_PCHAN_TCH_F_PDCH - && (lchan->ts->flags & TS_F_PDCH_ACTIVE)) { - /* store activation type and handover reference */ - lchan->dyn.act_type = act_type; - lchan->dyn.ho_ref = ho_ref; - return rsl_ipacc_pdch_activate(lchan->ts, 0); - } - - /* - * If necessary, release PDCH on dynamic TS. Note that sending a - * release here is only necessary when in PDCH mode; for TCH types, an - * RSL RF Chan Release is initiated by the BTS when a voice call ends, - * so when we reach this, it will already be released. If a dyn TS is - * in PDCH mode, it is still active and we need to initiate a release - * from the BSC side here. - * - * If pchan_is != pchan_want, the PDCH has already been taken down and - * the switchover now needs to enable the TCH lchan. - * - * To switch a dyn TS between TCH/H and TCH/F, it is sufficient to send - * a chan activ with the new lchan type, because it will already be - * released. - */ - if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH - && lchan->ts->dyn.pchan_is == lchan->ts->dyn.pchan_want) { - enum gsm_phys_chan_config pchan_want; - pchan_want = pchan_for_lchant(lchan->type); - if (lchan->ts->dyn.pchan_is != pchan_want) { - /* - * Make sure to record on lchan[0] so that we'll find - * it after the PDCH release. - */ - struct gsm_lchan *lchan0 = lchan->ts->lchan; - lchan0->dyn.act_type = act_type, - lchan0->dyn.ho_ref = ho_ref; - lchan0->dyn.rqd_ref = lchan->rqd_ref; - lchan0->dyn.rqd_ta = lchan->rqd_ta; - lchan->rqd_ref = NULL; - lchan->rqd_ta = 0; - DEBUGP(DRSL, "%s saved rqd_ref=%p ta=%u\n", - gsm_lchan_name(lchan0), lchan0->rqd_ref, - lchan0->rqd_ta); - return dyn_ts_switchover_start(lchan->ts, pchan_want); - } - } - - DEBUGP(DRSL, "%s Tx RSL Channel Activate with act_type=%s\n", - gsm_ts_and_pchan_name(lchan->ts), - rsl_act_type_name(act_type)); - - if (act_type == RSL_ACT_OSMO_PDCH) { - if (lchan->ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH) { - LOGP(DRSL, LOGL_ERROR, - "%s PDCH channel activation only allowed on %s\n", - gsm_ts_and_pchan_name(lchan->ts), - gsm_pchan_name(GSM_PCHAN_TCH_F_TCH_H_PDCH)); - return -EINVAL; - } - return rsl_chan_activate_lchan_as_pdch(lchan); - } - - if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->ts->dyn.pchan_want == GSM_PCHAN_PDCH) { - LOGP(DRSL, LOGL_ERROR, - "%s Expected PDCH activation kind\n", - gsm_ts_and_pchan_name(lchan->ts)); - return -EINVAL; - } - - rc = channel_mode_from_lchan(&cm, lchan); - if (rc < 0) { - LOGP(DRSL, LOGL_ERROR, - "%s Cannot find channel mode from lchan type\n", - gsm_ts_and_pchan_name(lchan->ts)); - return rc; - } - - rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ); - - ta = lchan->rqd_ta; - - /* BS11 requires TA shifted by 2 bits */ - if (lchan->ts->trx->bts->type == GSM_BTS_TYPE_BS11) - ta <<= 2; - - memset(&cd, 0, sizeof(cd)); - gsm48_lchan2chan_desc(&cd, lchan); - - msg = rsl_msgb_alloc(); - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV); - - if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) - dh->chan_nr = gsm_lchan_as_pchan2chan_nr( - lchan, lchan->ts->dyn.pchan_want); - else - dh->chan_nr = gsm_lchan2chan_nr(lchan); - - msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type); - msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm), - (uint8_t *) &cm); - - /* - * The Channel Identification is needed for Phase1 phones - * and it contains the GSM48 Channel Description and the - * Mobile Allocation. The GSM 08.58 asks for the Mobile - * Allocation to have a length of zero. We are using the - * msgb_l3len to calculate the length of both messages. - */ - msgb_v_put(msg, RSL_IE_CHAN_IDENT); - len = msgb_put(msg, 1); - msgb_tv_fixed_put(msg, GSM48_IE_CHANDESC_2, sizeof(cd), (const uint8_t *) &cd); - - if (lchan->ts->hopping.enabled) - msgb_tlv_put(msg, GSM48_IE_MA_AFTER, lchan->ts->hopping.ma_len, - lchan->ts->hopping.ma_data); - else - msgb_tlv_put(msg, GSM48_IE_MA_AFTER, 0, NULL); - - /* update the calculated size */ - msg->l3h = len + 1; - *len = msgb_l3len(msg); - - if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) { - uint8_t encr_info[MAX_A5_KEY_LEN+2]; - rc = build_encr_info(encr_info, lchan); - if (rc > 0) - msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info); - } - - switch (act_type) { - case RSL_ACT_INTER_ASYNC: - case RSL_ACT_INTER_SYNC: - msgb_tv_put(msg, RSL_IE_HANDO_REF, ho_ref); - break; - default: - break; - } - - msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power); - msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power); - msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); - mr_config_for_bts(lchan, msg); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/* Chapter 8.4.9: Modify channel mode on BTS side */ -int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg; - int rc; - - uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - struct rsl_ie_chan_mode cm; - - rc = channel_mode_from_lchan(&cm, lchan); - if (rc < 0) - return rc; - - msg = rsl_msgb_alloc(); - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_MODE_MODIFY_REQ); - dh->chan_nr = chan_nr; - - msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm), - (uint8_t *) &cm); - - if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) { - uint8_t encr_info[MAX_A5_KEY_LEN+2]; - rc = build_encr_info(encr_info, lchan); - if (rc > 0) - msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info); - } - - mr_config_for_bts(lchan, msg); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/* Chapter 8.4.6: Send the encryption command with given L3 info */ -int rsl_encryption_cmd(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh; - struct gsm_lchan *lchan = msg->lchan; - uint8_t chan_nr = gsm_lchan2chan_nr(lchan); - uint8_t encr_info[MAX_A5_KEY_LEN+2]; - uint8_t l3_len = msg->len; - int rc; - - /* First push the L3 IE tag and length */ - msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); - - /* then the link identifier (SAPI0, main sign link) */ - msgb_tv_push(msg, RSL_IE_LINK_IDENT, 0); - - /* then encryption information */ - rc = build_encr_info(encr_info, lchan); - if (rc <= 0) - return rc; - msgb_tlv_push(msg, RSL_IE_ENCR_INFO, rc, encr_info); - - /* and finally the DCHAN header */ - dh = (struct abis_rsl_dchan_hdr *) msgb_push(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_ENCR_CMD); - dh->chan_nr = chan_nr; - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/* Chapter 8.4.5 / 4.6: Deactivate the SACCH after 04.08 RR CHAN RELEASE */ -int rsl_deact_sacch(struct gsm_lchan *lchan) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg = rsl_msgb_alloc(); - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_DEACTIVATE_SACCH); - dh->chan_nr = gsm_lchan2chan_nr(lchan); - - msg->lchan = lchan; - msg->dst = lchan->ts->trx->rsl_link; - - DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_lchan_name(lchan)); - - return abis_rsl_sendmsg(msg); -} - -static bool dyn_ts_should_switch_to_pdch(struct gsm_bts_trx_ts *ts) -{ - int ss; - - if (ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH) - return false; - - if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) - return false; - - /* Already in PDCH mode? */ - if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) - return false; - - /* See if all lchans are released. */ - for (ss = 0; ss < ts_subslots(ts); ss++) { - struct gsm_lchan *lc = &ts->lchan[ss]; - if (lc->state != LCHAN_S_NONE) { - DEBUGP(DRSL, "%s lchan %u still in use" - " (type=%s,state=%s)\n", - gsm_ts_and_pchan_name(ts), lc->nr, - gsm_lchant_name(lc->type), - gsm_lchans_name(lc->state)); - /* An lchan is still used. */ - return false; - } - } - - /* All channels are released, go to PDCH mode. */ - DEBUGP(DRSL, "%s back to PDCH\n", - gsm_ts_and_pchan_name(ts)); - return true; -} - -static void error_timeout_cb(void *data) -{ - struct gsm_lchan *lchan = data; - if (lchan->state != LCHAN_S_REL_ERR) { - LOGP(DRSL, LOGL_ERROR, "%s error timeout but not in error state: %d\n", - gsm_lchan_name(lchan), lchan->state); - return; - } - - /* go back to the none state */ - LOGP(DRSL, LOGL_INFO, "%s is back in operation.\n", gsm_lchan_name(lchan)); - rsl_lchan_set_state(lchan, LCHAN_S_NONE); - - /* Put PDCH channel back into PDCH mode, if GPRS is enabled */ - if (lchan->ts->pchan == GSM_PCHAN_TCH_F_PDCH - && lchan->ts->trx->bts->gprs.mode != BTS_GPRS_NONE) - rsl_ipacc_pdch_activate(lchan->ts, 1); - - if (dyn_ts_should_switch_to_pdch(lchan->ts)) - dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH); -} - -static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan); - -/* Chapter 8.4.14 / 4.7: Tell BTS to release the radio channel */ -static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error, - enum sacch_deact deact_sacch) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg; - int rc; - - /* Stop timers that should lead to a channel release */ - osmo_timer_del(&lchan->T3109); - - if (lchan->state == LCHAN_S_REL_ERR) { - LOGP(DRSL, LOGL_NOTICE, "%s is in error state, not sending release.\n", - gsm_lchan_name(lchan)); - return -1; - } - - msg = rsl_msgb_alloc(); - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL); - dh->chan_nr = gsm_lchan2chan_nr(lchan); - - msg->lchan = lchan; - msg->dst = lchan->ts->trx->rsl_link; - - if (error) - DEBUGP(DRSL, "%s RF Channel Release due to error: %d\n", - gsm_lchan_name(lchan), error); - else - DEBUGP(DRSL, "%s RF Channel Release\n", gsm_lchan_name(lchan)); - - if (error) { - /* - * FIXME: GSM 04.08 gives us two options for the abnormal - * chanel release. This can be either like in the non-existent - * sub-lcuase 3.5.1 or for the main signalling link deactivate - * the SACCH, start timer T3109 and consider the channel as - * released. - * - * This code is doing the later for all raido links and not - * only the main link. Right now all SAPIs are released on the - * local end, the SACCH will be de-activated and right now the - * T3111 will be started. First T3109 should be started and then - * the T3111. - * - * TODO: Move this out of the function. - */ - - /* - * sacch de-activate and "local end release" - */ - if (deact_sacch == SACCH_DEACTIVATE) - rsl_deact_sacch(lchan); - rsl_release_sapis_from(lchan, 0, RSL_REL_LOCAL_END); - - /* - * TODO: start T3109 now. - */ - rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR); - } - - /* Start another timer or assume the BTS sends a ACK/NACK? */ - osmo_timer_setup(&lchan->act_timer, lchan_deact_tmr_cb, lchan); - osmo_timer_schedule(&lchan->act_timer, 4, 0); - - rc = abis_rsl_sendmsg(msg); - - /* BTS will respond by RF CHAN REL ACK */ - return rc; -} - -/* - * Special handling for channel releases in the error case. - */ -static int rsl_rf_chan_release_err(struct gsm_lchan *lchan) -{ - enum sacch_deact sacch_deact; - if (lchan->state != LCHAN_S_ACTIVE) - return 0; - switch (ts_pchan(lchan->ts)) { - case GSM_PCHAN_TCH_F: - case GSM_PCHAN_TCH_H: - case GSM_PCHAN_CCCH_SDCCH4: - case GSM_PCHAN_CCCH_SDCCH4_CBCH: - case GSM_PCHAN_SDCCH8_SACCH8C: - case GSM_PCHAN_SDCCH8_SACCH8C_CBCH: - sacch_deact = SACCH_DEACTIVATE; - break; - default: - sacch_deact = SACCH_NONE; - break; - } - return rsl_rf_chan_release(lchan, 1, sacch_deact); -} - -static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan) -{ - struct gsm_bts_trx_ts *ts = lchan->ts; - - DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan)); - - /* Stop all pending timers */ - osmo_timer_del(&lchan->act_timer); - osmo_timer_del(&lchan->T3111); - - /* - * The BTS didn't respond within the timeout to our channel - * release request and we have marked the channel as broken. - * Now we do receive an ACK and let's be conservative. If it - * is a sysmoBTS we know that only one RF Channel Release ACK - * will be sent. So let's "repair" the channel. - */ - if (lchan->state == LCHAN_S_BROKEN) { - int do_free = is_sysmobts_v2(ts->trx->bts); - LOGP(DRSL, LOGL_NOTICE, - "%s CHAN REL ACK for broken channel. %s.\n", - gsm_lchan_name(lchan), - do_free ? "Releasing it" : "Keeping it broken"); - if (do_free) - do_lchan_free(lchan); - if (dyn_ts_should_switch_to_pdch(lchan->ts)) - dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH); - return 0; - } - - if (lchan->state != LCHAN_S_REL_REQ && lchan->state != LCHAN_S_REL_ERR) - LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n", - gsm_lchan_name(lchan), - gsm_lchans_name(lchan->state)); - - do_lchan_free(lchan); - - /* - * Check Osmocom RSL CHAN ACT style dynamic TCH/F_TCH/H_PDCH TS for pending - * transitions in these cases: - * - * a) after PDCH was released due to switchover request, activate TCH. - * BSC initiated this switchover, so dyn.pchan_is != pchan_want and - * lchan->type has been set to the desired GSM_LCHAN_*. - * - * b) Voice call ended and a TCH is released. If the TS is now unused, - * switch to PDCH. Here still dyn.pchan_is == dyn.pchan_want because - * we're only just notified and may decide to switch to PDCH now. - */ - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - DEBUGP(DRSL, "%s Rx RSL Channel Release ack for lchan %u\n", - gsm_ts_and_pchan_name(ts), lchan->nr); - - /* (a) */ - if (ts->dyn.pchan_is != ts->dyn.pchan_want) - return dyn_ts_switchover_continue(ts); - - /* (b) */ - if (dyn_ts_should_switch_to_pdch(ts)) - return dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH); - } - - /* - * Put a dynamic TCH/F_PDCH channel back to PDCH mode iff it was - * released successfully. If in error, the PDCH ACT will follow after - * T3111 in error_timeout_cb(). - * - * Any state other than LCHAN_S_REL_ERR became LCHAN_S_NONE after above - * do_lchan_free(). Assert this, because that's what ensures a PDCH ACT - * on a TCH/F_PDCH TS in all cases. - * - * If GPRS is disabled, always skip the PDCH ACT. - */ - OSMO_ASSERT(lchan->state == LCHAN_S_NONE - || lchan->state == LCHAN_S_REL_ERR); - if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) - return 0; - if (ts->pchan == GSM_PCHAN_TCH_F_PDCH - && lchan->state == LCHAN_S_NONE) - return rsl_ipacc_pdch_activate(ts, 1); - return 0; -} - -int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, uint8_t len, - uint8_t *ms_ident, uint8_t chan_needed, bool is_gprs) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *msg = rsl_msgb_alloc(); - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_PAGING_CMD); - dh->chan_nr = RSL_CHAN_PCH_AGCH; - - msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group); - msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2); - msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed); - - /* Ericsson wants to have this IE in case a paging message - * relates to packet paging */ - if (bts->type == GSM_BTS_TYPE_RBS2000 && is_gprs) - msgb_tv_put(msg, RSL_IE_ERIC_PACKET_PAG_IND, 0); - - msg->dst = bts->c0->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -int imsi_str2bcd(uint8_t *bcd_out, const char *str_in) -{ - int i, len = strlen(str_in); - - for (i = 0; i < len; i++) { - int num = str_in[i] - 0x30; - if (num < 0 || num > 9) - return -1; - if (i % 2 == 0) - bcd_out[i/2] = num; - else - bcd_out[i/2] |= (num << 4); - } - - return 0; -} - -/* Chapter 8.5.6 */ -struct msgb *rsl_imm_assign_cmd_common(struct gsm_bts *bts, uint8_t len, uint8_t *val) -{ - struct msgb *msg = rsl_msgb_alloc(); - struct abis_rsl_dchan_hdr *dh; - uint8_t buf[GSM_MACBLOCK_LEN]; - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_IMMEDIATE_ASSIGN_CMD); - dh->chan_nr = RSL_CHAN_PCH_AGCH; - - switch (bts->type) { - case GSM_BTS_TYPE_BS11: - msgb_tlv_put(msg, RSL_IE_IMM_ASS_INFO, len, val); - break; - default: - /* If phase 2, construct a FULL_IMM_ASS_INFO */ - pad_macblock(buf, val, len); - msgb_tlv_put(msg, RSL_IE_FULL_IMM_ASS_INFO, GSM_MACBLOCK_LEN, - buf); - break; - } - - msg->dst = bts->c0->rsl_link; - return msg; -} - -/* Chapter 8.5.6 */ -int rsl_imm_assign_cmd(struct gsm_bts *bts, uint8_t len, uint8_t *val) -{ - struct msgb *msg = rsl_imm_assign_cmd_common(bts, len, val); - if (!msg) - return 1; - return abis_rsl_sendmsg(msg); -} - -/* Chapter 8.5.6 */ -int rsl_ericsson_imm_assign_cmd(struct gsm_bts *bts, uint32_t tlli, uint8_t len, uint8_t *val) -{ - struct msgb *msg = rsl_imm_assign_cmd_common(bts, len, val); - if (!msg) - return 1; - - /* ericsson can handle a reference at the end of the message which is used in - * the confirm message. The confirm message is only sent if the trailer is present */ - msgb_put_u8(msg, RSL_IE_ERIC_MOBILE_ID); - msgb_put_u32(msg, tlli); - - return abis_rsl_sendmsg(msg); -} - -/* Send Siemens specific MS RF Power Capability Indication */ -int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci) -{ - struct msgb *msg = rsl_msgb_alloc(); - struct abis_rsl_dchan_hdr *dh; - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_SIEMENS_MRPCI); - dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN; - dh->chan_nr = gsm_lchan2chan_nr(lchan); - msgb_tv_put(msg, RSL_IE_SIEMENS_MRPCI, *(uint8_t *)mrpci); - - DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n", - gsm_lchan_name(lchan), *(uint8_t *)mrpci); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - - -/* Send "DATA REQUEST" message with given L3 Info payload */ -/* Chapter 8.3.1 */ -int rsl_data_request(struct msgb *msg, uint8_t link_id) -{ - if (msg->lchan == NULL) { - LOGP(DRSL, LOGL_ERROR, "cannot send DATA REQUEST to unknown lchan\n"); - return -EINVAL; - } - - rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, gsm_lchan2chan_nr(msg->lchan), - link_id, 1); - - msg->dst = msg->lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/* Send "ESTABLISH REQUEST" message with given L3 Info payload */ -/* Chapter 8.3.1 */ -int rsl_establish_request(struct gsm_lchan *lchan, uint8_t link_id) -{ - struct msgb *msg; - - msg = rsl_rll_simple(RSL_MT_EST_REQ, gsm_lchan2chan_nr(lchan), - link_id, 0); - msg->dst = lchan->ts->trx->rsl_link; - - DEBUGP(DRLL, "%s RSL RLL ESTABLISH REQ (link_id=0x%02x)\n", - gsm_lchan_name(lchan), link_id); - - return abis_rsl_sendmsg(msg); -} - -static void rsl_handle_release(struct gsm_lchan *lchan); - -/* Special work handler to handle missing RSL_MT_REL_CONF message from - * Nokia InSite BTS */ -static void lchan_rel_work_cb(void *data) -{ - struct gsm_lchan *lchan = data; - int sapi; - - for (sapi = 0; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) { - if (lchan->sapis[sapi] == LCHAN_SAPI_REL) - lchan->sapis[sapi] = LCHAN_SAPI_UNUSED; - } - rsl_handle_release(lchan); -} - -/* Chapter 8.3.7 Request the release of multiframe mode of RLL connection. - This is what higher layers should call. The BTS then responds with - RELEASE CONFIRM, which we in turn use to trigger RSL CHANNEL RELEASE, - which in turn is acknowledged by RSL CHANNEL RELEASE ACK, which calls - lchan_free() */ -int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id, - enum rsl_rel_mode release_mode) -{ - - struct msgb *msg; - - msg = rsl_rll_simple(RSL_MT_REL_REQ, gsm_lchan2chan_nr(lchan), - link_id, 0); - /* 0 is normal release, 1 is local end */ - msgb_tv_put(msg, RSL_IE_RELEASE_MODE, release_mode); - - /* FIXME: start some timer in case we don't receive a REL ACK ? */ - - msg->dst = lchan->ts->trx->rsl_link; - - DEBUGP(DRLL, "%s RSL RLL RELEASE REQ (link_id=0x%02x, reason=%u)\n", - gsm_lchan_name(lchan), link_id, release_mode); - - abis_rsl_sendmsg(msg); - - /* Do not wait for Nokia BTS to send the confirm. */ - if (is_nokia_bts(lchan->ts->trx->bts) - && lchan->ts->trx->bts->nokia.no_loc_rel_cnf - && release_mode == RSL_REL_LOCAL_END) { - DEBUGP(DRLL, "Scheduling release, becasuse Nokia InSite BTS does not send a RELease CONFirm.\n"); - lchan->sapis[link_id & 0x7] = LCHAN_SAPI_REL; - osmo_timer_setup(&lchan->rel_work, lchan_rel_work_cb, lchan); - osmo_timer_schedule(&lchan->rel_work, 0, 0); - } - - return 0; -} - -int rsl_lchan_mark_broken(struct gsm_lchan *lchan, const char *reason) -{ - LOGP(DRSL, LOGL_ERROR, "%s %s lchan broken: %s\n", - gsm_lchan_name(lchan), gsm_lchant_name(lchan->type), reason); - rsl_lchan_set_state(lchan, LCHAN_S_BROKEN); - lchan->broken_reason = reason; - return 0; -} - -int rsl_lchan_set_state(struct gsm_lchan *lchan, int state) -{ - DEBUGP(DRSL, "%s state %s -> %s\n", - gsm_lchan_name(lchan), gsm_lchans_name(lchan->state), - gsm_lchans_name(state)); - lchan->state = state; - return 0; -} - -/* Chapter 8.4.2: Channel Activate Acknowledge */ -static int rsl_rx_chan_act_ack(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); - struct gsm_lchan *lchan = msg->lchan; - struct gsm_bts_trx_ts *ts = lchan->ts; - - /* BTS has confirmed channel activation, we now need - * to assign the activated channel to the MS */ - if (rslh->ie_chan != RSL_IE_CHAN_NR) - return -EINVAL; - - osmo_timer_del(&lchan->act_timer); - - if (lchan->state == LCHAN_S_BROKEN) { - int do_release = is_sysmobts_v2(ts->trx->bts); - LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK for broken channel. %s\n", - gsm_lchan_name(lchan), - do_release ? "Releasing it" : "Keeping it broken"); - if (do_release) { - talloc_free(lchan->rqd_ref); - lchan->rqd_ref = NULL; - lchan->rqd_ta = 0; - rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE); - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - /* - * lchan_act_tmr_cb() already called - * lchan_free() and cleared the lchan->type, so - * calling dyn_ts_switchover_complete() here - * would not have the desired effect of - * mimicking an activated lchan that we can - * release. Instead hack the dyn ts state to - * make sure that rsl_rx_rf_chan_rel_ack() will - * switch back to PDCH, i.e. have pchan_is == - * pchan_want, both != GSM_PCHAN_PDCH: - */ - ts->dyn.pchan_is = GSM_PCHAN_NONE; - ts->dyn.pchan_want = GSM_PCHAN_NONE; - } - rsl_rf_chan_release(msg->lchan, 0, SACCH_NONE); - } - return 0; - } - - if (lchan->state != LCHAN_S_ACT_REQ) - LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n", - gsm_lchan_name(lchan), - gsm_lchans_name(lchan->state)); - rsl_lchan_set_state(lchan, LCHAN_S_ACTIVE); - - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) - dyn_ts_switchover_complete(lchan); - - if (lchan->rqd_ref) { - rsl_send_imm_assignment(lchan); - talloc_free(lchan->rqd_ref); - lchan->rqd_ref = NULL; - lchan->rqd_ta = 0; - } - - send_lchan_signal(S_LCHAN_ACTIVATE_ACK, lchan, NULL); - - /* Update bts attributes inside the PCU */ - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH || - ts->pchan == GSM_PCHAN_TCH_F_PDCH || - ts->pchan == GSM_PCHAN_PDCH) - pcu_info_update(ts->trx->bts); - - return 0; -} - -/* Chapter 8.4.3: Channel Activate NACK */ -static int rsl_rx_chan_act_nack(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - struct tlv_parsed tp; - - osmo_timer_del(&msg->lchan->act_timer); - - if (msg->lchan->state == LCHAN_S_BROKEN) { - LOGP(DRSL, LOGL_ERROR, - "%s CHANNEL ACTIVATE NACK for broken channel.\n", - gsm_lchan_name(msg->lchan)); - return -1; - } - - LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK ", - gsm_lchan_name(msg->lchan)); - - /* BTS has rejected channel activation ?!? */ - if (dh->ie_chan != RSL_IE_CHAN_NR) - return -EINVAL; - - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) { - const uint8_t *cause = TLVP_VAL(&tp, RSL_IE_CAUSE); - print_rsl_cause(LOGL_ERROR, cause, - TLVP_LEN(&tp, RSL_IE_CAUSE)); - msg->lchan->error_cause = *cause; - if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC) { - rsl_lchan_mark_broken(msg->lchan, "NACK on activation"); - } else - rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE); - - } else { - rsl_lchan_mark_broken(msg->lchan, "NACK on activation no IE"); - } - - LOGPC(DRSL, LOGL_ERROR, "\n"); - - send_lchan_signal(S_LCHAN_ACTIVATE_NACK, msg->lchan, NULL); - return 0; -} - -/* Chapter 8.4.4: Connection Failure Indication */ -static int rsl_rx_conn_fail(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - struct tlv_parsed tp; - - LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING state %s ", - gsm_lchan_name(msg->lchan), - gsm_lchans_name(msg->lchan->state)); - - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - - if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) - print_rsl_cause(LOGL_NOTICE, TLVP_VAL(&tp, RSL_IE_CAUSE), - TLVP_LEN(&tp, RSL_IE_CAUSE)); - - LOGPC(DRSL, LOGL_NOTICE, "\n"); - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL]); - return rsl_rf_chan_release_err(msg->lchan); -} - -static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru, - const char *prefix) -{ - DEBUGPC(DMEAS, "RXL-FULL-%s=%3ddBm RXL-SUB-%s=%3ddBm ", - prefix, rxlev2dbm(mru->full.rx_lev), - prefix, rxlev2dbm(mru->sub.rx_lev)); - DEBUGPC(DMEAS, "RXQ-FULL-%s=%d RXQ-SUB-%s=%d ", - prefix, mru->full.rx_qual, prefix, mru->sub.rx_qual); -} - -static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr) -{ - int i; - const char *name = ""; - - if (lchan && lchan->conn) { - if (lchan->conn->bsub) - name = bsc_subscr_name(lchan->conn->bsub); - else - name = lchan->name; - } - - DEBUGP(DMEAS, "[%s] MEASUREMENT RESULT NR=%d ", name, mr->nr); - - if (mr->flags & MEAS_REP_F_DL_DTX) - DEBUGPC(DMEAS, "DTXd "); - - print_meas_rep_uni(&mr->ul, "ul"); - DEBUGPC(DMEAS, "BS_POWER=%d ", mr->bs_power); - - if (mr->flags & MEAS_REP_F_MS_TO) - DEBUGPC(DMEAS, "MS_TO=%d ", mr->ms_timing_offset); - - if (mr->flags & MEAS_REP_F_MS_L1) { - DEBUGPC(DMEAS, "L1_MS_PWR=%3ddBm ", mr->ms_l1.pwr); - DEBUGPC(DMEAS, "L1_FPC=%u ", - mr->flags & MEAS_REP_F_FPC ? 1 : 0); - DEBUGPC(DMEAS, "L1_TA=%u ", mr->ms_l1.ta); - } - - if (mr->flags & MEAS_REP_F_UL_DTX) - DEBUGPC(DMEAS, "DTXu "); - if (mr->flags & MEAS_REP_F_BA1) - DEBUGPC(DMEAS, "BA1 "); - if (!(mr->flags & MEAS_REP_F_DL_VALID)) - DEBUGPC(DMEAS, "NOT VALID "); - else - print_meas_rep_uni(&mr->dl, "dl"); - - DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell); - if (mr->num_cell == 7) - return; - for (i = 0; i < mr->num_cell; i++) { - struct gsm_meas_rep_cell *mrc = &mr->cell[i]; - DEBUGP(DMEAS, "IDX=%u ARFCN=%u BSIC=%u => %d dBm\n", - mrc->neigh_idx, mrc->arfcn, mrc->bsic, rxlev2dbm(mrc->rxlev)); - } -} - -static struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) -{ - struct gsm_meas_rep *meas_rep; - - meas_rep = &lchan->meas_rep[lchan->meas_rep_idx]; - memset(meas_rep, 0, sizeof(*meas_rep)); - meas_rep->lchan = lchan; - lchan->meas_rep_idx = (lchan->meas_rep_idx + 1) - % ARRAY_SIZE(lchan->meas_rep); - - return meas_rep; -} - -static int rsl_rx_meas_res(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - struct tlv_parsed tp; - struct gsm_meas_rep *mr = lchan_next_meas_rep(msg->lchan); - uint8_t len; - const uint8_t *val; - int rc; - - /* check if this channel is actually active */ - /* FIXME: maybe this check should be way more generic/centralized */ - if (msg->lchan->state != LCHAN_S_ACTIVE) { - LOGP(DRSL, LOGL_DEBUG, "%s: MEAS RES for inactive channel\n", - gsm_lchan_name(msg->lchan)); - return 0; - } - - memset(mr, 0, sizeof(*mr)); - mr->lchan = msg->lchan; - - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - - if (!TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR) || - !TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS) || - !TLVP_PRESENT(&tp, RSL_IE_BS_POWER)) - return -EIO; - - /* Mandatory Parts */ - mr->nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR); - - len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS); - val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS); - if (len >= 3) { - if (val[0] & 0x40) - mr->flags |= MEAS_REP_F_DL_DTX; - mr->ul.full.rx_lev = val[0] & 0x3f; - mr->ul.sub.rx_lev = val[1] & 0x3f; - mr->ul.full.rx_qual = val[2]>>3 & 0x7; - mr->ul.sub.rx_qual = val[2] & 0x7; - } - - mr->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER); - - /* Optional Parts */ - if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET)) { - /* According to 3GPP TS 48.058 § MS Timing Offset = Timing Offset field - 63 */ - mr->ms_timing_offset = *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET) - 63; - mr->flags |= MEAS_REP_F_MS_TO; - } - - if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) { - struct e1inp_sign_link *sign_link = msg->dst; - - val = TLVP_VAL(&tp, RSL_IE_L1_INFO); - mr->flags |= MEAS_REP_F_MS_L1; - mr->ms_l1.pwr = ms_pwr_dbm(sign_link->trx->bts->band, val[0] >> 3); - if (val[0] & 0x04) - mr->flags |= MEAS_REP_F_FPC; - mr->ms_l1.ta = val[1]; - /* BS11 and Nokia reports TA shifted by 2 bits */ - if (msg->lchan->ts->trx->bts->type == GSM_BTS_TYPE_BS11 - || msg->lchan->ts->trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) - mr->ms_l1.ta >>= 2; - } - if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { - msg->l3h = (uint8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); - rc = gsm48_parse_meas_rep(mr, msg); - if (rc < 0) - return rc; - } - - print_meas_rep(msg->lchan, mr); - - send_lchan_signal(S_LCHAN_MEAS_REP, msg->lchan, mr); - - return 0; -} - -/* Chapter 8.4.7 */ -static int rsl_rx_hando_det(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - struct tlv_parsed tp; - - DEBUGP(DRSL, "%s HANDOVER DETECT ", gsm_lchan_name(msg->lchan)); - - rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); - - if (TLVP_PRESENT(&tp, RSL_IE_ACCESS_DELAY)) - DEBUGPC(DRSL, "access delay = %u\n", - *TLVP_VAL(&tp, RSL_IE_ACCESS_DELAY)); - else - DEBUGPC(DRSL, "\n"); - - send_lchan_signal(S_LCHAN_HANDOVER_DETECT, msg->lchan, NULL); - - return 0; -} - -static bool lchan_may_change_pdch(struct gsm_lchan *lchan, bool pdch_act) -{ - struct gsm_bts_trx_ts *ts; - - OSMO_ASSERT(lchan); - - ts = lchan->ts; - OSMO_ASSERT(ts); - OSMO_ASSERT(ts->trx); - OSMO_ASSERT(ts->trx->bts); - - if (lchan->ts->pchan != GSM_PCHAN_TCH_F_PDCH) { - LOGP(DRSL, LOGL_ERROR, "%s pchan=%s Rx PDCH %s ACK" - " for channel that is no TCH/F_PDCH\n", - gsm_lchan_name(lchan), - gsm_pchan_name(ts->pchan), - pdch_act? "ACT" : "DEACT"); - return false; - } - - if (lchan->state != LCHAN_S_NONE) { - LOGP(DRSL, LOGL_ERROR, "%s pchan=%s Rx PDCH %s ACK" - " in unexpected state: %s\n", - gsm_lchan_name(lchan), - gsm_pchan_name(ts->pchan), - pdch_act? "ACT" : "DEACT", - gsm_lchans_name(lchan->state)); - return false; - } - return true; -} - -static int rsl_rx_pdch_act_ack(struct msgb *msg) -{ - if (!lchan_may_change_pdch(msg->lchan, true)) - return -EINVAL; - - msg->lchan->ts->flags |= TS_F_PDCH_ACTIVE; - msg->lchan->ts->flags &= ~TS_F_PDCH_ACT_PENDING; - - return 0; -} - -static int rsl_rx_pdch_deact_ack(struct msgb *msg) -{ - if (!lchan_may_change_pdch(msg->lchan, false)) - return -EINVAL; - - msg->lchan->ts->flags &= ~TS_F_PDCH_ACTIVE; - msg->lchan->ts->flags &= ~TS_F_PDCH_DEACT_PENDING; - - rsl_chan_activate_lchan(msg->lchan, msg->lchan->dyn.act_type, - msg->lchan->dyn.ho_ref); - - return 0; -} - -static int abis_rsl_rx_dchan(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); - int rc = 0; - char *ts_name; - struct e1inp_sign_link *sign_link = msg->dst; - - msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr, - "Abis RSL rx DCHAN: "); - if (!msg->lchan) - return -1; - ts_name = gsm_lchan_name(msg->lchan); - - switch (rslh->c.msg_type) { - case RSL_MT_CHAN_ACTIV_ACK: - DEBUGP(DRSL, "%s CHANNEL ACTIVATE ACK\n", ts_name); - rc = rsl_rx_chan_act_ack(msg); - count_codecs(sign_link->trx->bts, msg->lchan); - break; - case RSL_MT_CHAN_ACTIV_NACK: - rc = rsl_rx_chan_act_nack(msg); - break; - case RSL_MT_CONN_FAIL: - rc = rsl_rx_conn_fail(msg); - break; - case RSL_MT_MEAS_RES: - rc = rsl_rx_meas_res(msg); - break; - case RSL_MT_HANDO_DET: - rc = rsl_rx_hando_det(msg); - break; - case RSL_MT_RF_CHAN_REL_ACK: - rc = rsl_rx_rf_chan_rel_ack(msg->lchan); - break; - case RSL_MT_MODE_MODIFY_ACK: - count_codecs(sign_link->trx->bts, msg->lchan); - DEBUGP(DRSL, "%s CHANNEL MODE MODIFY ACK\n", ts_name); - break; - case RSL_MT_MODE_MODIFY_NACK: - LOGP(DRSL, LOGL_ERROR, "%s CHANNEL MODE MODIFY NACK\n", ts_name); - break; - case RSL_MT_IPAC_PDCH_ACT_ACK: - DEBUGP(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name); - rc = rsl_rx_pdch_act_ack(msg); - break; - case RSL_MT_IPAC_PDCH_ACT_NACK: - LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH ACT NACK\n", ts_name); - break; - case RSL_MT_IPAC_PDCH_DEACT_ACK: - DEBUGP(DRSL, "%s IPAC PDCH DEACT ACK\n", ts_name); - rc = rsl_rx_pdch_deact_ack(msg); - break; - case RSL_MT_IPAC_PDCH_DEACT_NACK: - LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH DEACT NACK\n", ts_name); - break; - case RSL_MT_PHY_CONTEXT_CONF: - case RSL_MT_PREPROC_MEAS_RES: - case RSL_MT_TALKER_DET: - case RSL_MT_LISTENER_DET: - case RSL_MT_REMOTE_CODEC_CONF_REP: - case RSL_MT_MR_CODEC_MOD_ACK: - case RSL_MT_MR_CODEC_MOD_NACK: - case RSL_MT_MR_CODEC_MOD_PER: - LOGP(DRSL, LOGL_NOTICE, "%s Unimplemented Abis RSL DChan " - "msg 0x%02x\n", ts_name, rslh->c.msg_type); - break; - default: - LOGP(DRSL, LOGL_NOTICE, "%s unknown Abis RSL DChan msg 0x%02x\n", - ts_name, rslh->c.msg_type); - return -EINVAL; - } - - return rc; -} - -static int rsl_rx_error_rep(struct msgb *msg) -{ - struct abis_rsl_common_hdr *rslh = msgb_l2(msg); - struct tlv_parsed tp; - struct e1inp_sign_link *sign_link = msg->dst; - - LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(sign_link->trx)); - - rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh)); - - if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) - print_rsl_cause(LOGL_ERROR, TLVP_VAL(&tp, RSL_IE_CAUSE), - TLVP_LEN(&tp, RSL_IE_CAUSE)); - - LOGPC(DRSL, LOGL_ERROR, "\n"); - - return 0; -} - -static int abis_rsl_rx_trx(struct msgb *msg) -{ - struct abis_rsl_common_hdr *rslh = msgb_l2(msg); - struct e1inp_sign_link *sign_link = msg->dst; - int rc = 0; - - switch (rslh->msg_type) { - case RSL_MT_ERROR_REPORT: - rc = rsl_rx_error_rep(msg); - break; - case RSL_MT_RF_RES_IND: - /* interference on idle channels of TRX */ - //DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(sign_link->trx)); - break; - case RSL_MT_OVERLOAD: - /* indicate CCCH / ACCH / processor overload */ - LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n", - gsm_trx_name(sign_link->trx)); - break; - case 0x42: /* Nokia specific: SI End ACK */ - LOGP(DRSL, LOGL_INFO, "Nokia SI End ACK\n"); - break; - case 0x43: /* Nokia specific: SI End NACK */ - LOGP(DRSL, LOGL_INFO, "Nokia SI End NACK\n"); - break; - default: - LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message " - "type 0x%02x\n", gsm_trx_name(sign_link->trx), rslh->msg_type); - return -EINVAL; - } - return rc; -} - -/* If T3101 expires, we never received a response to IMMEDIATE ASSIGN */ -static void t3101_expired(void *data) -{ - struct gsm_lchan *lchan = data; - LOGP(DRSL, LOGL_NOTICE, - "%s T3101 expired: no response to IMMEDIATE ASSIGN\n", - gsm_lchan_name(lchan)); - rsl_rf_chan_release(lchan, 1, SACCH_DEACTIVATE); -} - -/* If T3111 expires, we will send the RF Channel Request */ -static void t3111_expired(void *data) -{ - struct gsm_lchan *lchan = data; - LOGP(DRSL, LOGL_NOTICE, - "%s T3111 expired: releasing RF Channel\n", - gsm_lchan_name(lchan)); - rsl_rf_chan_release(lchan, 0, SACCH_NONE); -} - -/* If T3109 expires the MS has not send a UA/UM do the error release */ -static void t3109_expired(void *data) -{ - struct gsm_lchan *lchan = data; - - LOGP(DRSL, LOGL_ERROR, - "%s SACCH deactivation timeout.\n", gsm_lchan_name(lchan)); - rsl_rf_chan_release(lchan, 1, SACCH_NONE); -} - -/* Format an IMM ASS REJ according to 04.08 Chapter 9.1.20 */ -static int rsl_send_imm_ass_rej(struct gsm_bts *bts, - unsigned int num_req_refs, - struct gsm48_req_ref *rqd_refs, - uint8_t wait_ind) -{ - uint8_t buf[GSM_MACBLOCK_LEN]; - struct gsm48_imm_ass_rej *iar = (struct gsm48_imm_ass_rej *)buf; - - /* create IMMEDIATE ASSIGN REJECT 04.08 message */ - memset(iar, 0, sizeof(*iar)); - iar->proto_discr = GSM48_PDISC_RR; - iar->msg_type = GSM48_MT_RR_IMM_ASS_REJ; - iar->page_mode = GSM48_PM_SAME; - - memcpy(&iar->req_ref1, &rqd_refs[0], sizeof(iar->req_ref1)); - iar->wait_ind1 = wait_ind; - - if (num_req_refs >= 2) - memcpy(&iar->req_ref2, &rqd_refs[1], sizeof(iar->req_ref2)); - else - memcpy(&iar->req_ref2, &rqd_refs[0], sizeof(iar->req_ref2)); - iar->wait_ind2 = wait_ind; - - if (num_req_refs >= 3) - memcpy(&iar->req_ref3, &rqd_refs[2], sizeof(iar->req_ref3)); - else - memcpy(&iar->req_ref3, &rqd_refs[0], sizeof(iar->req_ref3)); - iar->wait_ind3 = wait_ind; - - if (num_req_refs >= 4) - memcpy(&iar->req_ref4, &rqd_refs[3], sizeof(iar->req_ref4)); - else - memcpy(&iar->req_ref4, &rqd_refs[0], sizeof(iar->req_ref4)); - iar->wait_ind4 = wait_ind; - - /* we need to subtract 1 byte from sizeof(*iar) since ia includes the l2_plen field */ - iar->l2_plen = GSM48_LEN2PLEN((sizeof(*iar)-1)); - - return rsl_imm_assign_cmd(bts, sizeof(*iar), (uint8_t *) iar); -} - -/* Handle packet channel rach requests */ -static int rsl_rx_pchan_rqd(struct msgb *msg, struct gsm_bts *bts) -{ - struct gsm48_req_ref *rqd_ref; - struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg); - rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1]; - uint8_t ra = rqd_ref->ra; - uint8_t t1, t2, t3; - uint32_t fn; - uint8_t rqd_ta; - uint8_t is_11bit; - - /* Process rach request and forward contained information to PCU */ - if (ra == 0x7F) { - is_11bit = 1; - - /* FIXME: Also handle 11 bit rach requests */ - LOGP(DRSL, LOGL_ERROR, "BTS %d eleven bit access burst not supported yet!\n",bts->nr); - return -EINVAL; - } else { - is_11bit = 0; - t1 = rqd_ref->t1; - t2 = rqd_ref->t2; - t3 = rqd_ref->t3_low | (rqd_ref->t3_high << 3); - fn = (51 * ((t3-t2) % 26) + t3 + 51 * 26 * t1); - - rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2]; - } - - return pcu_tx_rach_ind(bts, rqd_ta, ra, fn, is_11bit, - GSM_L1_BURST_TYPE_ACCESS_0); -} - -/* MS has requested a channel on the RACH */ -static int rsl_rx_chan_rqd(struct msgb *msg) -{ - struct e1inp_sign_link *sign_link = msg->dst; - struct gsm_bts *bts = sign_link->trx->bts; - struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg); - struct gsm48_req_ref *rqd_ref; - enum gsm_chan_t lctype; - enum gsm_chreq_reason_t chreq_reason; - struct gsm_lchan *lchan; - uint8_t rqd_ta; - int is_lu; - - uint16_t arfcn; - uint8_t subch; - - /* parse request reference to be used in immediate assign */ - if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE) - return -EINVAL; - - rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1]; - - /* parse access delay and use as TA */ - if (rqd_hdr->data[sizeof(struct gsm48_req_ref)+1] != RSL_IE_ACCESS_DELAY) - return -EINVAL; - rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2]; - - /* Determine channel request cause code */ - chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci); - LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: reason: %s (ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n", - msg->lchan->ts->trx->bts->nr, - get_value_string(gsm_chreq_descs, chreq_reason), - rqd_ref->ra, bts->network->neci, chreq_reason); - - /* Handle PDCH related rach requests (in case of BSC-co-located-PCU */ - if (chreq_reason == GSM_CHREQ_REASON_PDCH) - return rsl_rx_pchan_rqd(msg, bts); - - /* determine channel type (SDCCH/TCH_F/TCH_H) based on - * request reference RA */ - lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra); - - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL]); - - /* - * We want LOCATION UPDATES to succeed and will assign a TCH - * if we have no SDCCH available. - */ - is_lu = !!(chreq_reason == GSM_CHREQ_REASON_LOCATION_UPD); - - /* check availability / allocate channel */ - lchan = lchan_alloc(bts, lctype, is_lu); - if (!lchan) { - LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n", - msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra); - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL]); - /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */ - if (bts->network->T3122) - rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff); - return 0; - } - - /* - * Expecting lchan state to be NONE, except for dyn TS in PDCH mode. - * Those are expected to be ACTIVE: the PDCH release will be sent from - * rsl_chan_activate_lchan() below. - */ - if (lchan->state != LCHAN_S_NONE - && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH - && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH - && lchan->state == LCHAN_S_ACTIVE)) - LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel " - "in state %s\n", gsm_lchan_name(lchan), - gsm_lchans_name(lchan->state)); - - /* save the RACH data as we need it after the CHAN ACT ACK */ - lchan->rqd_ref = talloc_zero(bts, struct gsm48_req_ref); - if (!lchan->rqd_ref) { - LOGP(DRSL, LOGL_ERROR, "Failed to allocate gsm48_req_ref.\n"); - lchan_free(lchan); - return -ENOMEM; - } - - memcpy(lchan->rqd_ref, rqd_ref, sizeof(*rqd_ref)); - lchan->rqd_ta = rqd_ta; - - arfcn = lchan->ts->trx->arfcn; - subch = lchan->nr; - - lchan->encr.alg_id = RSL_ENC_ALG_A5(0); /* no encryption */ - lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); - lchan->bs_power = 0; /* 0dB reduction, output power = Pn */ - lchan->rsl_cmode = RSL_CMOD_SPD_SIGN; - lchan->tch_mode = GSM48_CMODE_SIGN; - - /* Start another timer or assume the BTS sends a ACK/NACK? */ - osmo_timer_setup(&lchan->act_timer, lchan_act_tmr_cb, lchan); - osmo_timer_schedule(&lchan->act_timer, 4, 0); - - DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s " - "r=%s ra=0x%02x ta=%d\n", gsm_lchan_name(lchan), arfcn, subch, - gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason), - rqd_ref->ra, rqd_ta); - - rsl_chan_activate_lchan(lchan, RSL_ACT_INTRA_IMM_ASS, 0); - - return 0; -} - -static int rsl_send_imm_assignment(struct gsm_lchan *lchan) -{ - struct gsm_bts *bts = lchan->ts->trx->bts; - uint8_t buf[GSM_MACBLOCK_LEN]; - struct gsm48_imm_ass *ia = (struct gsm48_imm_ass *) buf; - - /* create IMMEDIATE ASSIGN 04.08 messge */ - memset(ia, 0, sizeof(*ia)); - /* we set ia->l2_plen once we know the length of the MA below */ - ia->proto_discr = GSM48_PDISC_RR; - ia->msg_type = GSM48_MT_RR_IMM_ASS; - ia->page_mode = GSM48_PM_SAME; - gsm48_lchan2chan_desc(&ia->chan_desc, lchan); - - /* use request reference extracted from CHAN_RQD */ - memcpy(&ia->req_ref, lchan->rqd_ref, sizeof(ia->req_ref)); - ia->timing_advance = lchan->rqd_ta; - if (!lchan->ts->hopping.enabled) { - ia->mob_alloc_len = 0; - } else { - ia->mob_alloc_len = lchan->ts->hopping.ma_len; - memcpy(ia->mob_alloc, lchan->ts->hopping.ma_data, ia->mob_alloc_len); - } - /* we need to subtract 1 byte from sizeof(*ia) since ia includes the l2_plen field */ - ia->l2_plen = GSM48_LEN2PLEN((sizeof(*ia)-1) + ia->mob_alloc_len); - - /* Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */ - osmo_timer_setup(&lchan->T3101, t3101_expired, lchan); - osmo_timer_schedule(&lchan->T3101, bts->network->T3101, 0); - - /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */ - return rsl_imm_assign_cmd(bts, sizeof(*ia)+ia->mob_alloc_len, (uint8_t *) ia); -} - -/* current load on the CCCH */ -static int rsl_rx_ccch_load(struct msgb *msg) -{ - struct e1inp_sign_link *sign_link = msg->dst; - struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); - struct ccch_signal_data sd; - - sd.bts = sign_link->trx->bts; - sd.rach_slot_count = -1; - sd.rach_busy_count = -1; - sd.rach_access_count = -1; - - switch (rslh->data[0]) { - case RSL_IE_PAGING_LOAD: - sd.pg_buf_space = rslh->data[1] << 8 | rslh->data[2]; - if (is_ipaccess_bts(sign_link->trx->bts) && sd.pg_buf_space == 0xffff) { - /* paging load below configured threshold, use 50 as default */ - sd.pg_buf_space = 50; - } - paging_update_buffer_space(sign_link->trx->bts, sd.pg_buf_space); - osmo_signal_dispatch(SS_CCCH, S_CCCH_PAGING_LOAD, &sd); - break; - case RSL_IE_RACH_LOAD: - if (msg->data_len >= 7) { - sd.rach_slot_count = rslh->data[2] << 8 | rslh->data[3]; - sd.rach_busy_count = rslh->data[4] << 8 | rslh->data[5]; - sd.rach_access_count = rslh->data[6] << 8 | rslh->data[7]; - osmo_signal_dispatch(SS_CCCH, S_CCCH_RACH_LOAD, &sd); - } - break; - default: - break; - } - - return 0; -} - -static int abis_rsl_rx_cchan(struct msgb *msg) -{ - struct e1inp_sign_link *sign_link = msg->dst; - struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); - int rc = 0; - uint32_t tlli; - - msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr, - "Abis RSL rx CCHAN: "); - - switch (rslh->c.msg_type) { - case RSL_MT_CHAN_RQD: - /* MS has requested a channel on the RACH */ - rc = rsl_rx_chan_rqd(msg); - break; - case RSL_MT_CCCH_LOAD_IND: - /* current load on the CCCH */ - rc = rsl_rx_ccch_load(msg); - break; - case RSL_MT_DELETE_IND: - /* CCCH overloaded, IMM_ASSIGN was dropped */ - case RSL_MT_CBCH_LOAD_IND: - /* current load on the CBCH */ - LOGP(DRSL, LOGL_NOTICE, "Unimplemented Abis RSL TRX message " - "type 0x%02x\n", rslh->c.msg_type); - break; - case 0x10: /* Ericsson specific: Immediate Assign Sent */ - /* FIXME: Replace the messy message parsing below - * with proper TV parser */ - LOGP(DRSL, LOGL_INFO, "IMM.ass sent\n"); - if(msg->len < 9) - LOGP(DRSL, LOGL_ERROR, "short IMM.ass sent message!\n"); - else if(msg->data[4] != 0xf1) - LOGP(DRSL, LOGL_ERROR, "unsupported IMM.ass message format! (please fix)\n"); - else { - msgb_pull(msg, 5); /* drop previous data to use msg_pull_u32 */ - tlli = msgb_pull_u32(msg); - pcu_tx_imm_ass_sent(sign_link->trx->bts, tlli); - } - break; - default: - LOGP(DRSL, LOGL_NOTICE, "Unknown Abis RSL TRX message type " - "0x%02x\n", rslh->c.msg_type); - return -EINVAL; - } - - return rc; -} - -static int rsl_rx_rll_err_ind(struct msgb *msg) -{ - struct tlv_parsed tp; - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - uint8_t rlm_cause; - - rsl_tlv_parse(&tp, rllh->data, msgb_l2len(msg) - sizeof(*rllh)); - if (!TLVP_PRESENT(&tp, RSL_IE_RLM_CAUSE)) { - LOGP(DRLL, LOGL_ERROR, - "%s ERROR INDICATION without mandantory cause.\n", - gsm_lchan_name(msg->lchan)); - return -1; - } - - rlm_cause = *TLVP_VAL(&tp, RSL_IE_RLM_CAUSE); - LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s in state=%s\n", - gsm_lchan_name(msg->lchan), - rsl_rlm_cause_name(rlm_cause), - gsm_lchans_name(msg->lchan->state)); - - rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); - - if (rlm_cause == RLL_CAUSE_T200_EXPIRED) { - rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR]); - return rsl_rf_chan_release_err(msg->lchan); - } - - return 0; -} - -static void rsl_handle_release(struct gsm_lchan *lchan) -{ - int sapi; - struct gsm_bts *bts; - - /* - * Maybe only one link/SAPI was releasd or the error handling - * was activated. Just return now and let the other code handle - * it. - */ - if (lchan->state != LCHAN_S_REL_REQ) - return; - - for (sapi = 0; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) { - if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) - continue; - LOGP(DRSL, LOGL_DEBUG, "%s waiting for SAPI=%d to be released.\n", - gsm_lchan_name(lchan), sapi); - return; - } - - - /* Stop T3109 and wait for T3111 before re-using the channel */ - osmo_timer_del(&lchan->T3109); - osmo_timer_setup(&lchan->T3111, t3111_expired, lchan); - bts = lchan->ts->trx->bts; - osmo_timer_schedule(&lchan->T3111, bts->network->T3111, 0); -} - -/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST - 0x02, 0x06, - 0x01, 0x20, - 0x02, 0x00, - 0x0b, 0x00, 0x0f, 0x05, 0x08, ... */ - -static int abis_rsl_rx_rll(struct msgb *msg) -{ - struct e1inp_sign_link *sign_link = msg->dst; - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - int rc = 0; - char *ts_name; - uint8_t sapi = rllh->link_id & 7; - - msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr, - "Abis RSL rx RLL: "); - ts_name = gsm_lchan_name(msg->lchan); - DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi); - - switch (rllh->c.msg_type) { - case RSL_MT_DATA_IND: - DEBUGPC(DRLL, "DATA INDICATION\n"); - if (msgb_l2len(msg) > - sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) && - rllh->data[0] == RSL_IE_L3_INFO) { - msg->l3h = &rllh->data[3]; - return gsm0408_rcvmsg(msg, rllh->link_id); - } - break; - case RSL_MT_EST_IND: - DEBUGPC(DRLL, "ESTABLISH INDICATION\n"); - /* lchan is established, stop T3101 */ - msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_MS; - osmo_timer_del(&msg->lchan->T3101); - if (msgb_l2len(msg) > - sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) && - rllh->data[0] == RSL_IE_L3_INFO) { - msg->l3h = &rllh->data[3]; - return gsm0408_rcvmsg(msg, rllh->link_id); - } - break; - case RSL_MT_EST_CONF: - DEBUGPC(DRLL, "ESTABLISH CONFIRM\n"); - msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_NET; - rll_indication(msg->lchan, rllh->link_id, - BSC_RLLR_IND_EST_CONF); - break; - case RSL_MT_REL_IND: - /* BTS informs us of having received DISC from MS */ - DEBUGPC(DRLL, "RELEASE INDICATION\n"); - msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED; - rll_indication(msg->lchan, rllh->link_id, - BSC_RLLR_IND_REL_IND); - rsl_handle_release(msg->lchan); - break; - case RSL_MT_REL_CONF: - /* BTS informs us of having received UA from MS, - * in response to DISC that we've sent earlier */ - DEBUGPC(DRLL, "RELEASE CONFIRMATION\n"); - msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED; - rsl_handle_release(msg->lchan); - break; - case RSL_MT_ERROR_IND: - DEBUGPC(DRLL, "ERROR INDICATION\n"); - rc = rsl_rx_rll_err_ind(msg); - break; - case RSL_MT_UNIT_DATA_IND: - DEBUGPC(DRLL, "UNIT DATA INDICATION\n"); - LOGP(DRLL, LOGL_NOTICE, "unimplemented Abis RLL message " - "type 0x%02x\n", rllh->c.msg_type); - break; - default: - DEBUGPC(DRLL, "UNKNOWN\n"); - LOGP(DRLL, LOGL_NOTICE, "unknown Abis RLL message " - "type 0x%02x\n", rllh->c.msg_type); - } - return rc; -} - -static uint8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) -{ - switch (lchan->tch_mode) { - case GSM48_CMODE_SPEECH_V1: - switch (lchan->type) { - case GSM_LCHAN_TCH_F: - return 0x00; - case GSM_LCHAN_TCH_H: - return 0x03; - default: - break; - } - break; - case GSM48_CMODE_SPEECH_EFR: - switch (lchan->type) { - case GSM_LCHAN_TCH_F: - return 0x01; - /* there's no half-rate EFR */ - default: - break; - } - break; - case GSM48_CMODE_SPEECH_AMR: - switch (lchan->type) { - case GSM_LCHAN_TCH_F: - return 0x02; - case GSM_LCHAN_TCH_H: - return 0x05; - default: - break; - } - break; - default: - break; - } - LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access speech mode for " - "tch_mode == 0x%02x\n", lchan->tch_mode); - return 0; -} - -static uint8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan) -{ - switch (lchan->tch_mode) { - case GSM48_CMODE_SPEECH_V1: - switch (lchan->type) { - case GSM_LCHAN_TCH_F: - return RTP_PT_GSM_FULL; - case GSM_LCHAN_TCH_H: - return RTP_PT_GSM_HALF; - default: - break; - } - break; - case GSM48_CMODE_SPEECH_EFR: - switch (lchan->type) { - case GSM_LCHAN_TCH_F: - return RTP_PT_GSM_EFR; - /* there's no half-rate EFR */ - default: - break; - } - break; - case GSM48_CMODE_SPEECH_AMR: - switch (lchan->type) { - case GSM_LCHAN_TCH_F: - case GSM_LCHAN_TCH_H: - return RTP_PT_AMR; - default: - break; - } - break; - default: - break; - } - LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access rtp payload type for " - "tch_mode == 0x%02x\n & lchan_type == %d", - lchan->tch_mode, lchan->type); - return 0; -} - -/* ip.access specific RSL extensions */ -static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv) -{ - struct in_addr ip; - uint16_t port, conn_id; - - if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_IP)) { - ip.s_addr = tlvp_val32_unal(tv, RSL_IE_IPAC_LOCAL_IP); - DEBUGPC(DRSL, "LOCAL_IP=%s ", inet_ntoa(ip)); - lchan->abis_ip.bound_ip = ntohl(ip.s_addr); - } - - if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_PORT)) { - port = tlvp_val16_unal(tv, RSL_IE_IPAC_LOCAL_PORT); - port = ntohs(port); - DEBUGPC(DRSL, "LOCAL_PORT=%u ", port); - lchan->abis_ip.bound_port = port; - } - - if (TLVP_PRESENT(tv, RSL_IE_IPAC_CONN_ID)) { - conn_id = tlvp_val16_unal(tv, RSL_IE_IPAC_CONN_ID); - conn_id = ntohs(conn_id); - DEBUGPC(DRSL, "CON_ID=%u ", conn_id); - lchan->abis_ip.conn_id = conn_id; - } - - if (TLVP_PRESENT(tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { - lchan->abis_ip.rtp_payload2 = - *TLVP_VAL(tv, RSL_IE_IPAC_RTP_PAYLOAD2); - DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", - lchan->abis_ip.rtp_payload2); - } - - if (TLVP_PRESENT(tv, RSL_IE_IPAC_SPEECH_MODE)) { - lchan->abis_ip.speech_mode = - *TLVP_VAL(tv, RSL_IE_IPAC_SPEECH_MODE); - DEBUGPC(DRSL, "speech_mode=0x%02x ", - lchan->abis_ip.speech_mode); - } - - if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_IP)) { - ip.s_addr = tlvp_val32_unal(tv, RSL_IE_IPAC_REMOTE_IP); - DEBUGPC(DRSL, "REMOTE_IP=%s ", inet_ntoa(ip)); - lchan->abis_ip.connect_ip = ntohl(ip.s_addr); - } - - if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_PORT)) { - port = tlvp_val16_unal(tv, RSL_IE_IPAC_REMOTE_PORT); - port = ntohs(port); - DEBUGPC(DRSL, "REMOTE_PORT=%u ", port); - lchan->abis_ip.connect_port = port; - } - - DEBUGPC(DRSL, "\n"); -} - -/*! \brief Issue IPA RSL CRCX to configure RTP on BTS side - * \param[in] lchan Logical Channel for which we issue CRCX - */ -int rsl_ipacc_crcx(struct gsm_lchan *lchan) -{ - struct msgb *msg = rsl_msgb_alloc(); - struct abis_rsl_dchan_hdr *dh; - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_IPAC_CRCX); - dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; - dh->chan_nr = gsm_lchan2chan_nr(lchan); - - /* 0x1- == receive-only, 0x-1 == EFR codec */ - lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); - lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan); - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); - msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); - - DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x RTP_PAYLOAD=%d\n", - gsm_lchan_name(lchan), lchan->abis_ip.speech_mode, - lchan->abis_ip.rtp_payload); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/*! \brief Issue IPA RSL MDCX to configure MGW-side of RTP - * \param[in] lchan Logical Channel for which we issue MDCX - * \param[in] ip Remote (MGW) IP address for RTP - * \param[in] port Remote (MGW) UDP port number for RTP - * \param[in] rtp_payload2 Contents of RTP PAYLOAD 2 IE - */ -int rsl_ipacc_mdcx(struct gsm_lchan *lchan, uint32_t ip, uint16_t port, - uint8_t rtp_payload2) -{ - struct msgb *msg = rsl_msgb_alloc(); - struct abis_rsl_dchan_hdr *dh; - uint32_t *att_ip; - struct in_addr ia; - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_IPAC_MDCX); - dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; - dh->chan_nr = gsm_lchan2chan_nr(lchan); - - /* we need to store these now as MDCX_ACK does not return them :( */ - lchan->abis_ip.rtp_payload2 = rtp_payload2; - lchan->abis_ip.connect_port = port; - lchan->abis_ip.connect_ip = ip; - - /* 0x0- == both directions, 0x-1 == EFR codec */ - lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); - lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan); - - ia.s_addr = htonl(ip); - DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD=%d RTP_PAYLOAD2=%d " - "CONN_ID=%d speech_mode=0x%02x\n", gsm_lchan_name(lchan), - inet_ntoa(ia), port, lchan->abis_ip.rtp_payload, rtp_payload2, - lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode); - - msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id); - msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP); - att_ip = (uint32_t *) msgb_put(msg, sizeof(ip)); - *att_ip = ia.s_addr; - msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port); - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); - msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); - if (rtp_payload2) - msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2); - - msg->dst = lchan->ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/* tell BTS to connect RTP stream to our local RTP socket */ -int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan) -{ - struct rtp_socket *rs = lchan->abis_ip.rtp_socket; - int rc; - - rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), - ntohs(rs->rtp.sin_local.sin_port), - /* FIXME: use RTP payload of bound socket, not BTS*/ - lchan->abis_ip.rtp_payload2); - - return rc; -} - -int rsl_ipacc_pdch_activate(struct gsm_bts_trx_ts *ts, int act) -{ - struct msgb *msg = rsl_msgb_alloc(); - struct abis_rsl_dchan_hdr *dh; - uint8_t msg_type; - - if (ts->flags & TS_F_PDCH_PENDING_MASK) { - LOGP(DRSL, LOGL_ERROR, - "%s PDCH %s requested, but a PDCH%s%s is still pending\n", - gsm_ts_name(ts), - act ? "ACT" : "DEACT", - ts->flags & TS_F_PDCH_ACT_PENDING? " ACT" : "", - ts->flags & TS_F_PDCH_DEACT_PENDING? " DEACT" : ""); - return -EINVAL; - } - - if (act){ - /* Callers should heed the GPRS mode. */ - OSMO_ASSERT(ts->trx->bts->gprs.mode != BTS_GPRS_NONE); - msg_type = RSL_MT_IPAC_PDCH_ACT; - ts->flags |= TS_F_PDCH_ACT_PENDING; - } else { - msg_type = RSL_MT_IPAC_PDCH_DEACT; - ts->flags |= TS_F_PDCH_DEACT_PENDING; - } - /* TODO add timeout to cancel PDCH DE/ACT */ - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, msg_type); - dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN; - dh->chan_nr = gsm_pchan2chan_nr(GSM_PCHAN_TCH_F, ts->nr, 0); - - DEBUGP(DRSL, "%s IPAC PDCH %sACT\n", gsm_ts_name(ts), - act ? "" : "DE"); - - msg->dst = ts->trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - struct tlv_parsed tv; - struct gsm_lchan *lchan = msg->lchan; - - /* the BTS has acknowledged a local bind, it now tells us the IP - * address and port number to which it has bound the given logical - * channel */ - - rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); - if (!TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_PORT) || - !TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_IP) || - !TLVP_PRESENT(&tv, RSL_IE_IPAC_CONN_ID)) { - LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing"); - return -EINVAL; - } - - ipac_parse_rtp(lchan, &tv); - - osmo_signal_dispatch(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); - - return 0; -} - -static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - struct tlv_parsed tv; - struct gsm_lchan *lchan = msg->lchan; - - /* the BTS has acknowledged a remote connect request and - * it now tells us the IP address and port number to which it has - * connected the given logical channel */ - - rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); - ipac_parse_rtp(lchan, &tv); - osmo_signal_dispatch(SS_ABISIP, S_ABISIP_MDCX_ACK, msg->lchan); - - return 0; -} - -static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) -{ - struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); - struct tlv_parsed tv; - - rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); - - if (TLVP_PRESENT(&tv, RSL_IE_CAUSE)) - print_rsl_cause(LOGL_DEBUG, TLVP_VAL(&tv, RSL_IE_CAUSE), - TLVP_LEN(&tv, RSL_IE_CAUSE)); - - osmo_signal_dispatch(SS_ABISIP, S_ABISIP_DLCX_IND, msg->lchan); - - return 0; -} - -static int abis_rsl_rx_ipacc(struct msgb *msg) -{ - struct e1inp_sign_link *sign_link = msg->dst; - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - char *ts_name; - int rc = 0; - - msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr, - "Abis RSL rx IPACC: "); - ts_name = gsm_lchan_name(msg->lchan); - - switch (rllh->c.msg_type) { - case RSL_MT_IPAC_CRCX_ACK: - DEBUGP(DRSL, "%s IPAC_CRCX_ACK ", ts_name); - rc = abis_rsl_rx_ipacc_crcx_ack(msg); - break; - case RSL_MT_IPAC_CRCX_NACK: - /* somehow the BTS was unable to bind the lchan to its local - * port?!? */ - LOGP(DRSL, LOGL_ERROR, "%s IPAC_CRCX_NACK\n", ts_name); - break; - case RSL_MT_IPAC_MDCX_ACK: - /* the BTS tells us that a connect operation was successful */ - DEBUGP(DRSL, "%s IPAC_MDCX_ACK ", ts_name); - rc = abis_rsl_rx_ipacc_mdcx_ack(msg); - break; - case RSL_MT_IPAC_MDCX_NACK: - /* somehow the BTS was unable to connect the lchan to a remote - * port */ - LOGP(DRSL, LOGL_ERROR, "%s IPAC_MDCX_NACK\n", ts_name); - break; - case RSL_MT_IPAC_DLCX_IND: - DEBUGP(DRSL, "%s IPAC_DLCX_IND ", ts_name); - rc = abis_rsl_rx_ipacc_dlcx_ind(msg); - break; - default: - LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x\n", - rllh->c.msg_type); - break; - } - - return rc; -} - -int dyn_ts_switchover_start(struct gsm_bts_trx_ts *ts, - enum gsm_phys_chan_config to_pchan) -{ - int ss; - int rc = -EIO; - - OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH); - DEBUGP(DRSL, "%s starting switchover to %s\n", - gsm_ts_and_pchan_name(ts), gsm_pchan_name(to_pchan)); - - if (ts->dyn.pchan_is != ts->dyn.pchan_want) { - LOGP(DRSL, LOGL_ERROR, - "%s: Attempt to switch dynamic channel to %s," - " but is already in switchover.\n", - gsm_ts_and_pchan_name(ts), - gsm_pchan_name(to_pchan)); - return ts->dyn.pchan_want == to_pchan? 0 : -EAGAIN; - } - - if (ts->dyn.pchan_is == to_pchan) { - LOGP(DRSL, LOGL_INFO, - "%s %s Already is in %s mode, cannot switchover.\n", - gsm_ts_name(ts), gsm_pchan_name(ts->pchan), - gsm_pchan_name(to_pchan)); - return -EINVAL; - } - - /* Paranoia: let's make sure all is indeed released. */ - for (ss = 0; ss < ts_subslots(ts); ss++) { - struct gsm_lchan *lc = &ts->lchan[ss]; - if (lc->state != LCHAN_S_NONE) { - LOGP(DRSL, LOGL_ERROR, - "%s Attempt to switch dynamic channel to %s," - " but is not fully released.\n", - gsm_ts_and_pchan_name(ts), - gsm_pchan_name(to_pchan)); - return -EAGAIN; - } - } - - /* Record that we're busy switching. */ - ts->dyn.pchan_want = to_pchan; - - /* - * To switch from PDCH, we need to initiate the release from the BSC - * side. dyn_ts_switchover_continue() will be called from - * rsl_rx_rf_chan_rel_ack(). PDCH is always on lchan[0]. - */ - if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) { - rsl_lchan_set_state(ts->lchan, LCHAN_S_REL_REQ); - rc = rsl_rf_chan_release(ts->lchan, 0, SACCH_NONE); - if (rc) { - LOGP(DRSL, LOGL_ERROR, - "%s RSL RF Chan Release failed\n", - gsm_ts_and_pchan_name(ts)); - return dyn_ts_switchover_failed(ts, rc); - } - return 0; - } - - /* - * To switch from TCH/F and TCH/H pchans, this has been called from - * rsl_rx_rf_chan_rel_ack(), i.e. release is complete. Go ahead and - * activate as new type. This will always be PDCH. - */ - return dyn_ts_switchover_continue(ts); -} - -static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts) -{ - int rc; - uint8_t act_type; - uint8_t ho_ref; - int ss; - struct gsm_lchan *lchan; - - OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH); - DEBUGP(DRSL, "%s switchover: release complete," - " activating new pchan type\n", - gsm_ts_and_pchan_name(ts)); - - if (ts->dyn.pchan_is == ts->dyn.pchan_want) { - LOGP(DRSL, LOGL_ERROR, - "%s Requested to switchover dynamic channel to the" - " same type it is already in.\n", - gsm_ts_and_pchan_name(ts)); - return 0; - } - - for (ss = 0; ss < ts_subslots(ts); ss++) { - lchan = &ts->lchan[ss]; - if (lchan->rqd_ref) { - LOGP(DRSL, LOGL_ERROR, - "%s During dyn TS switchover, expecting no" - " Request Reference to be pending. Discarding!\n", - gsm_lchan_name(lchan)); - talloc_free(lchan->rqd_ref); - lchan->rqd_ref = NULL; - } - } - - /* - * When switching pchan modes, all lchans are unused. So always - * activate whatever wants to be activated on the first lchan. (We - * wouldn't remember to use lchan[1] across e.g. a PDCH deact anyway) - */ - lchan = ts->lchan; - - /* - * For TCH/x, the lchan->type has been set in lchan_alloc(), but it may - * have been lost during channel release due to dynamic switchover. - * - * For PDCH, the lchan->type will actually remain NONE. - * TODO: set GSM_LCHAN_PDTCH? - */ - switch (ts->dyn.pchan_want) { - case GSM_PCHAN_TCH_F: - lchan->type = GSM_LCHAN_TCH_F; - break; - case GSM_PCHAN_TCH_H: - lchan->type = GSM_LCHAN_TCH_H; - break; - case GSM_PCHAN_PDCH: - lchan->type = GSM_LCHAN_NONE; - break; - default: - LOGP(DRSL, LOGL_ERROR, - "%s Invalid target pchan for dynamic TS\n", - gsm_ts_and_pchan_name(ts)); - } - - act_type = (ts->dyn.pchan_want == GSM_PCHAN_PDCH) - ? RSL_ACT_OSMO_PDCH - : lchan->dyn.act_type; - ho_ref = (ts->dyn.pchan_want == GSM_PCHAN_PDCH) - ? 0 - : lchan->dyn.ho_ref; - - /* Fetch the rqd_ref back from before switchover started. */ - lchan->rqd_ref = lchan->dyn.rqd_ref; - lchan->rqd_ta = lchan->dyn.rqd_ta; - lchan->dyn.rqd_ref = NULL; - lchan->dyn.rqd_ta = 0; - - /* During switchover, we have received a release ack, which means that - * the act_timer has been stopped. Start the timer again so we mark - * this channel broken if the activation ack comes too late. */ - osmo_timer_setup(&lchan->act_timer, lchan_act_tmr_cb, lchan); - osmo_timer_schedule(&lchan->act_timer, 4, 0); - - rc = rsl_chan_activate_lchan(lchan, act_type, ho_ref); - if (rc) { - LOGP(DRSL, LOGL_ERROR, - "%s RSL Chan Activate failed\n", - gsm_ts_and_pchan_name(ts)); - return dyn_ts_switchover_failed(ts, rc); - } - return 0; -} - -static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc) -{ - ts->dyn.pchan_want = ts->dyn.pchan_is; - LOGP(DRSL, LOGL_ERROR, "%s Error %d during dynamic channel switchover." - " Going back to previous pchan.\n", gsm_ts_and_pchan_name(ts), - rc); - return rc; -} - -static void dyn_ts_switchover_complete(struct gsm_lchan *lchan) -{ - enum gsm_phys_chan_config pchan_act; - enum gsm_phys_chan_config pchan_was; - struct gsm_bts_trx_ts *ts = lchan->ts; - - OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH); - - pchan_act = pchan_for_lchant(lchan->type); - /* - * Paranoia: do the types match? - * In case of errors: we've received an act ack already, so what to do - * about it? Logging the error should suffice for now. - */ - if (pchan_act != ts->dyn.pchan_want) - LOGP(DRSL, LOGL_ERROR, - "%s Requested transition does not match lchan type %s\n", - gsm_ts_and_pchan_name(ts), - gsm_lchant_name(lchan->type)); - - pchan_was = ts->dyn.pchan_is; - ts->dyn.pchan_is = ts->dyn.pchan_want = pchan_act; - - if (pchan_was != ts->dyn.pchan_is) - LOGP(DRSL, LOGL_INFO, "%s switchover from %s complete.\n", - gsm_ts_and_pchan_name(ts), gsm_pchan_name(pchan_was)); -} - -/* Entry-point where L2 RSL from BTS enters */ -int abis_rsl_rcvmsg(struct msgb *msg) -{ - struct abis_rsl_common_hdr *rslh; - int rc = 0; - - if (!msg) { - DEBUGP(DRSL, "Empty RSL msg?..\n"); - return -1; - } - - if (msgb_l2len(msg) < sizeof(*rslh)) { - DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg)); - msgb_free(msg); - return -1; - } - - rslh = msgb_l2(msg); - - switch (rslh->msg_discr & 0xfe) { - case ABIS_RSL_MDISC_RLL: - rc = abis_rsl_rx_rll(msg); - break; - case ABIS_RSL_MDISC_DED_CHAN: - rc = abis_rsl_rx_dchan(msg); - break; - case ABIS_RSL_MDISC_COM_CHAN: - rc = abis_rsl_rx_cchan(msg); - break; - case ABIS_RSL_MDISC_TRX: - rc = abis_rsl_rx_trx(msg); - break; - case ABIS_RSL_MDISC_LOC: - LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL msg disc 0x%02x\n", - rslh->msg_discr); - break; - case ABIS_RSL_MDISC_IPACCESS: - rc = abis_rsl_rx_ipacc(msg); - break; - default: - LOGP(DRSL, LOGL_NOTICE, "unknown RSL message discriminator " - "0x%02x\n", rslh->msg_discr); - rc = -EINVAL; - } - msgb_free(msg); - return rc; -} - -int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number, - struct rsl_ie_cb_cmd_type cb_command, - const uint8_t *data, int len) -{ - struct abis_rsl_dchan_hdr *dh; - struct msgb *cb_cmd; - - cb_cmd = rsl_msgb_alloc(); - if (!cb_cmd) - return -1; - - dh = (struct abis_rsl_dchan_hdr *) msgb_put(cb_cmd, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_SMS_BC_CMD); - dh->c.msg_discr = ABIS_RSL_MDISC_COM_CHAN; - dh->chan_nr = chan_number; /* TODO: check the chan config */ - - msgb_tv_put(cb_cmd, RSL_IE_CB_CMD_TYPE, *(uint8_t*)&cb_command); - msgb_tlv_put(cb_cmd, RSL_IE_SMSCB_MSG, len, data); - - cb_cmd->dst = bts->c0->rsl_link; - - return abis_rsl_sendmsg(cb_cmd); -} - -int rsl_nokia_si_begin(struct gsm_bts_trx *trx) -{ - struct abis_rsl_common_hdr *ch; - struct msgb *msg = rsl_msgb_alloc(); - - ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch)); - ch->msg_discr = ABIS_RSL_MDISC_TRX; - ch->msg_type = 0x40; /* Nokia SI Begin */ - - msg->dst = trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -int rsl_nokia_si_end(struct gsm_bts_trx *trx) -{ - struct abis_rsl_common_hdr *ch; - struct msgb *msg = rsl_msgb_alloc(); - - ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch)); - ch->msg_discr = ABIS_RSL_MDISC_TRX; - ch->msg_type = 0x41; /* Nokia SI End */ - - msgb_tv_put(msg, 0xFD, 0x00); /* Nokia Pagemode Info, No paging reorganisation required */ - - msg->dst = trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -int rsl_bs_power_control(struct gsm_bts_trx *trx, uint8_t channel, uint8_t reduction) -{ - struct abis_rsl_common_hdr *ch; - struct msgb *msg = rsl_msgb_alloc(); - - ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch)); - ch->msg_discr = ABIS_RSL_MDISC_DED_CHAN; - ch->msg_type = RSL_MT_BS_POWER_CONTROL; - - msgb_tv_put(msg, RSL_IE_CHAN_NR, channel); - msgb_tv_put(msg, RSL_IE_BS_POWER, reduction); /* reduction in 2dB steps */ - - msg->dst = trx->rsl_link; - - return abis_rsl_sendmsg(msg); -} - -/** - * Release all allocated SAPIs starting from @param start and - * release them with the given release mode. Once the release - * confirmation arrives it will be attempted to release the - * the RF channel. - */ -int rsl_release_sapis_from(struct gsm_lchan *lchan, int start, - enum rsl_rel_mode release_mode) -{ - int no_sapi = 1; - int sapi; - - for (sapi = start; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) { - uint8_t link_id; - if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) - continue; - - link_id = sapi; - if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H) - link_id |= 0x40; - rsl_release_request(lchan, link_id, release_mode); - no_sapi = 0; - } - - return no_sapi; -} - -int rsl_start_t3109(struct gsm_lchan *lchan) -{ - struct gsm_bts *bts = lchan->ts->trx->bts; - - osmo_timer_setup(&lchan->T3109, t3109_expired, lchan); - osmo_timer_schedule(&lchan->T3109, bts->network->T3109, 0); - return 0; -} - -/** - * \brief directly RF Channel Release the lchan - * - * When no SAPI was allocated, directly release the logical channel. This - * should only be called from chan_alloc.c on channel release handling. In - * case no SAPI was established the RF Channel can be directly released, - */ -int rsl_direct_rf_release(struct gsm_lchan *lchan) -{ - int i; - for (i = 0; i < ARRAY_SIZE(lchan->sapis); ++i) { - if (lchan->sapis[i] != LCHAN_SAPI_UNUSED) { - LOGP(DRSL, LOGL_ERROR, "%s SAPI(%d) still allocated.\n", - gsm_lchan_name(lchan), i); - return -1; - } - } - - /* Now release it */ - return rsl_rf_chan_release(lchan, 0, SACCH_NONE); -} diff --git a/src/libbsc/arfcn_range_encode.c b/src/libbsc/arfcn_range_encode.c deleted file mode 100644 index 9ca48407e..000000000 --- a/src/libbsc/arfcn_range_encode.c +++ /dev/null @@ -1,330 +0,0 @@ -/* gsm 04.08 system information (si) encoding and decoding - * 3gpp ts 04.08 version 7.21.0 release 1998 / etsi ts 100 940 v7.21.0 */ - -/* - * (C) 2012 Holger Hans Peter Freyther - * (C) 2012 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 . - */ - -#include -#include - -#include - -#include - -#include - -static inline int greatest_power_of_2_lesser_or_equal_to(int index) -{ - int power_of_2 = 1; - - do { - power_of_2 *= 2; - } while (power_of_2 <= index); - - /* now go back one step */ - return power_of_2 / 2; -} - -static inline int mod(int data, int range) -{ - int res = data % range; - while (res < 0) - res += range; - return res; -} - -/** - * Determine at which index to split the ARFCNs to create an - * equally size partition for the given range. Return -1 if - * no such partition exists. - */ -int range_enc_find_index(enum gsm48_range range, const int *freqs, const int size) -{ - int i, j, n; - - const int RANGE_DELTA = (range - 1) / 2; - - for (i = 0; i < size; ++i) { - n = 0; - for (j = 0; j < size; ++j) { - if (mod(freqs[j] - freqs[i], range) <= RANGE_DELTA) - n += 1; - } - - if (n - 1 == (size - 1) / 2) - return i; - } - - return -1; -} - -/** - * Range encode the ARFCN list. - * \param range The range to use. - * \param arfcns The list of ARFCNs - * \param size The size of the list of ARFCNs - * \param out Place to store the W(i) output. - */ -int range_enc_arfcns(enum gsm48_range range, - const int *arfcns, int size, int *out, - const int index) -{ - int split_at; - int i; - - /* - * The below is a GNU extension and we can remove it when - * we move to a quicksort like in-situ swap with the pivot. - */ - int arfcns_left[size / 2]; - int arfcns_right[size / 2]; - int l_size; - int r_size; - int l_origin; - int r_origin; - - - /* Test the two recursion anchors and stop processing */ - if (size == 0) - return 0; - - if (size == 1) { - out[index] = 1 + arfcns[0]; - return 0; - } - - /* Now do the processing */ - split_at = range_enc_find_index(range, arfcns, size); - if (split_at < 0) - return -EINVAL; - - /* we now know where to split */ - out[index] = 1 + arfcns[split_at]; - - /* calculate the work that needs to be done for the leafs */ - l_origin = mod(arfcns[split_at] + ((range - 1) / 2) + 1, range); - r_origin = mod(arfcns[split_at] + 1, range); - for (i = 0, l_size = 0, r_size = 0; i < size; ++i) { - if (mod(arfcns[i] - l_origin, range) < range / 2) - arfcns_left[l_size++] = mod(arfcns[i] - l_origin, range); - if (mod(arfcns[i] - r_origin, range) < range / 2) - arfcns_right[r_size++] = mod(arfcns[i] - r_origin, range); - } - - /* - * Now recurse and we need to make this iterative... but as the - * tree is balanced the stack will not be too deep. - */ - if (l_size) - range_enc_arfcns(range / 2, arfcns_left, l_size, - out, index + greatest_power_of_2_lesser_or_equal_to(index + 1)); - if (r_size) - range_enc_arfcns((range - 1) / 2, arfcns_right, r_size, - out, index + (2 * greatest_power_of_2_lesser_or_equal_to(index + 1))); - return 0; -} - -/* - * The easiest is to use f0 == arfcns[0]. This means that under certain - * circumstances we can encode less ARFCNs than possible with an optimal f0. - * - * TODO: Solve the optimisation problem and pick f0 so that the max distance - * is the smallest. Taking into account the modulo operation. I think picking - * size/2 will be the optimal arfcn. - */ -/** - * This implements the range determination as described in GSM 04.08 J4. The - * result will be a base frequency f0 and the range to use. Note that for range - * 1024 encoding f0 always refers to ARFCN 0 even if it is not an element of - * the arfcns list. - * - * \param[in] arfcns The input frequencies, they must be sorted, lowest number first - * \param[in] size The length of the array - * \param[out] f0 The selected F0 base frequency. It might not be inside the list - */ -int range_enc_determine_range(const int *arfcns, const int size, int *f0) -{ - int max = 0; - - /* - * Go for the easiest. And pick arfcns[0] == f0. - */ - max = arfcns[size - 1] - arfcns[0]; - *f0 = arfcns[0]; - - if (max < 128 && size <= 29) - return ARFCN_RANGE_128; - if (max < 256 && size <= 22) - return ARFCN_RANGE_256; - if (max < 512 && size <= 18) - return ARFCN_RANGE_512; - if (max < 1024 && size <= 17) { - *f0 = 0; - return ARFCN_RANGE_1024; - } - - return ARFCN_RANGE_INVALID; -} - -static void write_orig_arfcn(uint8_t *chan_list, int f0) -{ - chan_list[0] |= (f0 >> 9) & 1; - chan_list[1] = (f0 >> 1); - chan_list[2] = (f0 & 1) << 7; -} - -static void write_all_wn(uint8_t *chan_list, int bit_offs, - int *w, int w_size, int w1_len) -{ - int octet_offs = 0; /* offset into chan_list */ - int wk_len = w1_len; /* encoding size in bits of w[k] */ - int k; /* 1 based */ - int level = 0; /* tree level, top level = 0 */ - int lvl_left = 1; /* nodes per tree level */ - - /* W(2^i) to W(2^(i+1)-1) are on w1_len-i bits when present */ - - for (k = 1; k <= w_size; k++) { - int wk_left = wk_len; - DEBUGP(DRR, - "k=%d, wk_len=%d, offs=%d:%d, level=%d, " - "lvl_left=%d\n", - k, wk_len, octet_offs, bit_offs, level, lvl_left); - - while (wk_left > 0) { - int cur_bits = 8 - bit_offs; - int cur_mask; - int wk_slice; - - if (cur_bits > wk_left) - cur_bits = wk_left; - - cur_mask = ((1 << cur_bits) - 1); - - DEBUGP(DRR, - " wk_left=%d, cur_bits=%d, offs=%d:%d\n", - wk_left, cur_bits, octet_offs, bit_offs); - - /* advance */ - wk_left -= cur_bits; - bit_offs += cur_bits; - - /* right aligned wk data for current out octet */ - wk_slice = (w[k-1] >> wk_left) & cur_mask; - - /* cur_bits now contains the number of bits - * that are to be copied from wk to the chan_list. - * wk_left is set to the number of bits that must - * not yet be copied. - * bit_offs points after the bit area that is going to - * be overwritten: - * - * wk_left - * | - * v - * wk: WWWWWWWWWWW - * |||||<-- wk_slice, cur_bits=5 - * --WWWWW- - * ^ - * | - * bit_offs - */ - - DEBUGP(DRR, - " wk=%02x, slice=%02x/%02x, cl=%02x\n", - w[k-1], wk_slice, cur_mask, wk_slice << (8 - bit_offs)); - - chan_list[octet_offs] &= ~(cur_mask << (8 - bit_offs)); - chan_list[octet_offs] |= wk_slice << (8 - bit_offs); - - /* adjust output */ - if (bit_offs == 8) { - bit_offs = 0; - octet_offs += 1; - } - } - - /* adjust bit sizes */ - lvl_left -= 1; - if (!lvl_left) { - /* completed tree level, advance to next */ - level += 1; - lvl_left = 1 << level; - wk_len -= 1; - } - } -} - -int range_enc_range128(uint8_t *chan_list, int f0, int *w) -{ - chan_list[0] = 0x8C; - write_orig_arfcn(chan_list, f0); - - write_all_wn(&chan_list[2], 1, w, 28, 7); - return 0; -} - -int range_enc_range256(uint8_t *chan_list, int f0, int *w) -{ - chan_list[0] = 0x8A; - write_orig_arfcn(chan_list, f0); - - write_all_wn(&chan_list[2], 1, w, 21, 8); - return 0; -} - -int range_enc_range512(uint8_t *chan_list, int f0, int *w) -{ - chan_list[0] = 0x88; - write_orig_arfcn(chan_list, f0); - - write_all_wn(&chan_list[2], 1, w, 17, 9); - return 0; -} - -int range_enc_range1024(uint8_t *chan_list, int f0, int f0_included, int *w) -{ - chan_list[0] = 0x80 | (f0_included << 2); - - write_all_wn(&chan_list[0], 6, w, 16, 10); - return 0; -} - -int range_enc_filter_arfcns(int *arfcns, - const int size, const int f0, int *f0_included) -{ - int i, j = 0; - *f0_included = 0; - - for (i = 0; i < size; ++i) { - /* - * Appendix J.4 says the following: - * All frequencies except F(0), minus F(0) + 1. - * I assume we need to exclude it here. - */ - if (arfcns[i] == f0) { - *f0_included = 1; - continue; - } - - arfcns[j++] = mod(arfcns[i] - (f0 + 1), 1024); - } - - return j; -} diff --git a/src/libbsc/bsc_api.c b/src/libbsc/bsc_api.c deleted file mode 100644 index c60f8182a..000000000 --- a/src/libbsc/bsc_api.c +++ /dev/null @@ -1,897 +0,0 @@ -/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */ - -/* (C) 2010-2011 by Holger Hans Peter Freyther - * (C) 2010-2011 by On-Waves - * (C) 2009 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define GSM0808_T10_VALUE 6, 0 - - -static void rll_ind_cb(struct gsm_lchan *, uint8_t, void *, enum bsc_rllr_ind); -static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id); -static void handle_release(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan); -static void handle_chan_ack(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan); -static void handle_chan_nack(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan); - -/* GSM 08.08 3.2.2.33 */ -static uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan) -{ - uint8_t channel_mode = 0, channel = 0; - - switch (lchan->tch_mode) { - case GSM48_CMODE_SPEECH_V1: - case GSM48_CMODE_SPEECH_EFR: - case GSM48_CMODE_SPEECH_AMR: - channel_mode = 0x9; - break; - case GSM48_CMODE_SIGN: - channel_mode = 0x8; - break; - case GSM48_CMODE_DATA_14k5: - channel_mode = 0xe; - break; - case GSM48_CMODE_DATA_12k0: - channel_mode = 0xb; - break; - case GSM48_CMODE_DATA_6k0: - channel_mode = 0xc; - break; - case GSM48_CMODE_DATA_3k6: - channel_mode = 0xd; - break; - } - - switch (lchan->type) { - case GSM_LCHAN_NONE: - channel = 0x0; - break; - case GSM_LCHAN_SDCCH: - channel = 0x1; - break; - case GSM_LCHAN_TCH_F: - channel = 0x8; - break; - case GSM_LCHAN_TCH_H: - channel = 0x9; - break; - case GSM_LCHAN_UNKNOWN: - default: - LOGP(DMSC, LOGL_ERROR, "Unknown lchan type: %p\n", lchan); - break; - } - - return channel_mode << 4 | channel; -} - -static uint8_t chan_mode_to_speech(struct gsm_lchan *lchan) -{ - int mode = 0; - - switch (lchan->tch_mode) { - case GSM48_CMODE_SPEECH_V1: - mode = 1; - break; - case GSM48_CMODE_SPEECH_EFR: - mode = 0x11; - break; - case GSM48_CMODE_SPEECH_AMR: - mode = 0x21; - break; - case GSM48_CMODE_SIGN: - case GSM48_CMODE_DATA_14k5: - case GSM48_CMODE_DATA_12k0: - case GSM48_CMODE_DATA_6k0: - case GSM48_CMODE_DATA_3k6: - default: - LOGP(DMSC, LOGL_ERROR, "Using non speech mode: %d\n", mode); - return 0; - break; - } - - /* assume to always do AMR HR on any TCH type */ - if (lchan->type == GSM_LCHAN_TCH_H || - lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) - mode |= 0x4; - - return mode; -} - -static void assignment_t10_timeout(void *_conn) -{ - struct bsc_api *api; - struct gsm_subscriber_connection *conn = - (struct gsm_subscriber_connection *) _conn; - - LOGP(DMSC, LOGL_ERROR, "Assignment T10 timeout on %p\n", conn); - - /* - * normal release on the secondary channel but only if the - * secondary_channel has not been released by the handle_chan_nack. - */ - if (conn->secondary_lchan) - lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END); - conn->secondary_lchan = NULL; - - /* inform them about the failure */ - api = conn->network->bsc_api; - api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); -} - -/*! \brief Determine and apply AMR multi-rate configuration to lchan - * Determine which AMR multi-rate configuration to use and apply it to - * the lchan (so it can be communicated to BTS and MS during channel - * activation. - * \param[in] conn subscriber connection (used to resolve bsc_api) - * \param[out] lchan logical channel to which to apply mr config - * \param[in] full_rate whether to use full-rate (1) or half-rate (0) config - */ -static void handle_mr_config(struct gsm_subscriber_connection *conn, - struct gsm_lchan *lchan, int full_rate) -{ - struct bsc_api *api; - api = conn->network->bsc_api; - struct amr_multirate_conf *mr; - struct gsm48_multi_rate_conf *mr_conf; - - /* BSC api override for this method, used in OsmoBSC mode with - * bsc_mr_config() to use MSC-specific/specified configuration */ - if (api->mr_config) - return api->mr_config(conn, lchan, full_rate); - - /* NITB case: use the BTS-specic multi-rate configuration from - * the vty/configuration file */ - if (full_rate) - mr = &lchan->ts->trx->bts->mr_full; - else - mr = &lchan->ts->trx->bts->mr_half; - - mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie; - mr_conf->ver = 1; - - /* default, if no AMR codec defined */ - if (!mr->gsm48_ie[1]) { - mr_conf->icmi = 1; - mr_conf->m5_90 = 1; - } - /* store encoded MR config IE lchan for both MS (uplink) and BTS - * (downlink) directions */ - gsm48_multirate_config(lchan->mr_ms_lv, mr, mr->ms_mode); - gsm48_multirate_config(lchan->mr_bts_lv, mr, mr->bts_mode); -} - -/* - * Start a new assignment and make sure that it is completed within T10 either - * positively, negatively or by the timeout. - * - * 1.) allocate a new lchan - * 2.) copy the encryption key and other data from the - * old to the new channel. - * 3.) RSL Channel Activate this channel and wait - * - * -> Signal handler for the LCHAN - * 4.) Send GSM 04.08 assignment command to the MS - * - * -> Assignment Complete/Assignment Failure - * 5.) Release the SDCCH, continue signalling on the new link - */ -static int handle_new_assignment(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate) -{ - struct gsm_lchan *new_lchan; - int chan_type; - - chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H; - - new_lchan = lchan_alloc(conn->bts, chan_type, 0); - - if (!new_lchan) { - LOGP(DMSC, LOGL_NOTICE, "No free channel.\n"); - return -1; - } - - /* copy old data to the new channel */ - memcpy(&new_lchan->encr, &conn->lchan->encr, sizeof(new_lchan->encr)); - new_lchan->ms_power = conn->lchan->ms_power; - new_lchan->bs_power = conn->lchan->bs_power; - new_lchan->rqd_ta = conn->lchan->rqd_ta; - - /* copy new data to it */ - new_lchan->tch_mode = chan_mode; - new_lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH; - - /* handle AMR correctly */ - if (chan_mode == GSM48_CMODE_SPEECH_AMR) - handle_mr_config(conn, new_lchan, full_rate); - - if (rsl_chan_activate_lchan(new_lchan, 0x1, 0) < 0) { - LOGP(DHO, LOGL_ERROR, "could not activate channel\n"); - lchan_free(new_lchan); - return -1; - } - - /* remember that we have the channel */ - conn->secondary_lchan = new_lchan; - new_lchan->conn = conn; - - rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ); - return 0; -} - -struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lchan) -{ - struct gsm_subscriber_connection *conn; - struct gsm_network *net = lchan->ts->trx->bts->network; - - conn = talloc_zero(net, struct gsm_subscriber_connection); - if (!conn) - return NULL; - - conn->network = net; - conn->lchan = lchan; - conn->bts = lchan->ts->trx->bts; - conn->via_ran = RAN_GERAN_A; - conn->lac = conn->bts->location_area_code; - lchan->conn = conn; - llist_add_tail(&conn->entry, &net->subscr_conns); - return conn; -} - -void bsc_subscr_con_free(struct gsm_subscriber_connection *conn) -{ - if (!conn) - return; - - if (conn->network->bsc_api->conn_cleanup) - conn->network->bsc_api->conn_cleanup(conn); - - if (conn->vsub) { - LOGP(DNM, LOGL_ERROR, "conn->vsub should have been cleared.\n"); - conn->vsub = NULL; - } - - if (conn->ho_lchan) { - LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n"); - conn->ho_lchan->conn = NULL; - } - - if (conn->lchan) { - LOGP(DNM, LOGL_ERROR, "The lchan should have been cleared.\n"); - conn->lchan->conn = NULL; - } - - if (conn->secondary_lchan) { - LOGP(DNM, LOGL_ERROR, "The secondary_lchan should have been cleared.\n"); - conn->secondary_lchan->conn = NULL; - } - - llist_del(&conn->entry); - talloc_free(conn); -} - -int bsc_api_init(struct gsm_network *network, struct bsc_api *api) -{ - network->bsc_api = api; - return 0; -} - -/*! \brief process incoming 08.08 DTAP from MSC (send via BTS to MS) */ -int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, - struct msgb *msg, int link_id, int allow_sacch) -{ - uint8_t sapi; - - - if (!conn->lchan) { - LOGP(DMSC, LOGL_ERROR, - "Called submit dtap without an lchan.\n"); - msgb_free(msg); - return -1; - } - - sapi = link_id & 0x7; - msg->lchan = conn->lchan; - msg->dst = msg->lchan->ts->trx->rsl_link; - - /* If we are on a TCH and need to submit a SMS (on SAPI=3) we need to use the SACH */ - if (allow_sacch && sapi != 0) { - if (conn->lchan->type == GSM_LCHAN_TCH_F || conn->lchan->type == GSM_LCHAN_TCH_H) - link_id |= 0x40; - } - - msg->l3h = msg->data; - /* is requested SAPI already up? */ - if (conn->lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) { - /* Establish L2 for additional SAPI */ - OBSC_LINKID_CB(msg) = link_id; - if (rll_establish(msg->lchan, sapi, rll_ind_cb, msg) != 0) { - msgb_free(msg); - send_sapi_reject(conn, link_id); - return -1; - } - return 0; - } else { - /* Directly forward via RLL/RSL to BTS */ - return rsl_data_request(msg, link_id); - } -} - -/* - * \brief Check if the given channel is compatible with the mode/fullrate - */ -static int chan_compat_with_mode(struct gsm_lchan *lchan, int chan_mode, int full_rate) -{ - switch (chan_mode) { - case GSM48_CMODE_SIGN: - /* signalling is always possible */ - return 1; - case GSM48_CMODE_SPEECH_V1: - case GSM48_CMODE_SPEECH_AMR: - case GSM48_CMODE_DATA_3k6: - case GSM48_CMODE_DATA_6k0: - /* these services can all run on TCH/H, but we may have - * an explicit override by the 'full_rate' argument */ - switch (lchan->type) { - case GSM_LCHAN_TCH_F: - return 1; - case GSM_LCHAN_TCH_H: - if (full_rate) - return 0; - else - return 1; - break; - default: - return 0; - } - break; - case GSM48_CMODE_DATA_12k0: - case GSM48_CMODE_DATA_14k5: - case GSM48_CMODE_SPEECH_EFR: - /* these services all explicitly require a TCH/F */ - if (lchan->type == GSM_LCHAN_TCH_F) - return 1; - else - return 0; - break; - } - - return 0; -} - -/** - * Send a GSM08.08 Assignment Request. Right now this does not contain the - * audio codec type or the allowed rates for the config. It is assumed that - * this is for audio handling only. In case the current channel does not allow - * the selected mode a new one will be allocated. - * - * TODO: Add multirate configuration, make it work for more than audio. - */ -int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate) -{ - struct bsc_api *api; - api = conn->network->bsc_api; - - if (!chan_compat_with_mode(conn->lchan, chan_mode, full_rate)) { - if (handle_new_assignment(conn, chan_mode, full_rate) != 0) - goto error; - } else { - if (chan_mode == GSM48_CMODE_SPEECH_AMR) - handle_mr_config(conn, conn->lchan, full_rate); - - LOGP(DMSC, LOGL_NOTICE, - "Sending %s ChanModify for speech: %s on channel %s\n", - gsm_lchan_name(conn->lchan), - get_value_string(gsm48_chan_mode_names, chan_mode), - get_value_string(gsm_chan_t_names, conn->lchan->type)); - gsm48_lchan_modify(conn->lchan, chan_mode); - } - - /* we will now start the timer to complete the assignment */ - osmo_timer_setup(&conn->T10, assignment_t10_timeout, conn); - osmo_timer_schedule(&conn->T10, GSM0808_T10_VALUE); - return 0; - -error: - api->assign_fail(conn, 0, NULL); - return -1; -} - -int gsm0808_page(struct gsm_bts *bts, unsigned int page_group, unsigned int mi_len, - uint8_t *mi, int chan_type) -{ - return rsl_paging_cmd(bts, page_group, mi_len, mi, chan_type, false); -} - -static void handle_ass_compl(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm48_hdr *gh; - struct bsc_api *api = conn->network->bsc_api; - - if (conn->secondary_lchan != msg->lchan) { - LOGP(DMSC, LOGL_ERROR, "Assignment Compl should occur on second lchan.\n"); - return; - } - - gh = msgb_l3(msg); - if (msgb_l3len(msg) - sizeof(*gh) != 1) { - LOGP(DMSC, LOGL_ERROR, "Assignment Compl invalid: %zu\n", - msgb_l3len(msg) - sizeof(*gh)); - return; - } - - /* switch TRAU muxer for E1 based BTS from one channel to another */ - if (is_e1_bts(conn->bts)) - switch_trau_mux(conn->lchan, conn->secondary_lchan); - - /* swap channels */ - osmo_timer_del(&conn->T10); - - lchan_release(conn->lchan, 0, RSL_REL_LOCAL_END); - conn->lchan = conn->secondary_lchan; - conn->secondary_lchan = NULL; - - if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN) - rsl_ipacc_crcx(conn->lchan); - - api->assign_compl(conn, gh->data[0], - lchan_to_chosen_channel(conn->lchan), - conn->lchan->encr.alg_id, - chan_mode_to_speech(conn->lchan)); -} - -static void handle_ass_fail(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct bsc_api *api = conn->network->bsc_api; - uint8_t *rr_failure; - struct gsm48_hdr *gh; - - - if (conn->lchan != msg->lchan) { - LOGP(DMSC, LOGL_ERROR, "Assignment failure should occur on primary lchan.\n"); - return; - } - - /* stop the timer and release it */ - osmo_timer_del(&conn->T10); - lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END); - conn->secondary_lchan = NULL; - - gh = msgb_l3(msg); - if (msgb_l3len(msg) - sizeof(*gh) != 1) { - LOGP(DMSC, LOGL_ERROR, "assignment failure unhandled: %zu\n", - msgb_l3len(msg) - sizeof(*gh)); - rr_failure = NULL; - } else { - rr_failure = &gh->data[0]; - } - - api->assign_fail(conn, - GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, - rr_failure); -} - -static void handle_classmark_chg(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api; - struct gsm48_hdr *gh = msgb_l3(msg); - unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); - uint8_t cm2_len, cm3_len = 0; - uint8_t *cm2, *cm3 = NULL; - - DEBUGP(DRR, "CLASSMARK CHANGE "); - - /* classmark 2 */ - cm2_len = gh->data[0]; - cm2 = &gh->data[1]; - DEBUGPC(DRR, "CM2(len=%u) ", cm2_len); - - if (payload_len > cm2_len + 1) { - /* we must have a classmark3 */ - if (gh->data[cm2_len+1] != 0x20) { - DEBUGPC(DRR, "ERR CM3 TAG\n"); - return; - } - if (cm2_len > 3) { - DEBUGPC(DRR, "CM2 too long!\n"); - return; - } - - cm3_len = gh->data[cm2_len+2]; - cm3 = &gh->data[cm2_len+3]; - if (cm3_len > 14) { - DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len); - return; - } - DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len); - } - api->classmark_chg(conn, cm2, cm2_len, cm3, cm3_len); -} - -/* Chapter 9.1.16 Handover complete */ -static void handle_rr_ho_compl(struct msgb *msg) -{ - struct lchan_signal_data sig; - struct gsm48_hdr *gh = msgb_l3(msg); - - DEBUGP(DRR, "HANDOVER COMPLETE cause = %s\n", - rr_cause_name(gh->data[0])); - - sig.lchan = msg->lchan; - sig.mr = NULL; - osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, &sig); - /* FIXME: release old channel */ -} - -/* Chapter 9.1.17 Handover Failure */ -static void handle_rr_ho_fail(struct msgb *msg) -{ - struct lchan_signal_data sig; - struct gsm48_hdr *gh = msgb_l3(msg); - - DEBUGP(DRR, "HANDOVER FAILED cause = %s\n", - rr_cause_name(gh->data[0])); - - sig.lchan = msg->lchan; - sig.mr = NULL; - osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, &sig); - /* FIXME: release allocated new channel */ -} - - -static void dispatch_dtap(struct gsm_subscriber_connection *conn, - uint8_t link_id, struct msgb *msg) -{ - struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api; - struct gsm48_hdr *gh; - uint8_t pdisc; - uint8_t msg_type; - int rc; - - if (msgb_l3len(msg) < sizeof(*gh)) { - LOGP(DMSC, LOGL_ERROR, "Message too short for a GSM48 header.\n"); - return; - } - - gh = msgb_l3(msg); - pdisc = gsm48_hdr_pdisc(gh); - msg_type = gsm48_hdr_msg_type(gh); - - /* the idea is to handle all RR messages here, and only hand - * MM/CC/SMS-CP/LCS up to the MSC. Some messages like PAGING - * RESPONSE or CM SERVICE REQUEST will not be covered here, as - * they are only possible in the first L3 message of each L2 - * channel, i.e. 'conn' will not exist and gsm0408_rcvmsg() - * will call api->compl_l3() for it */ - switch (pdisc) { - case GSM48_PDISC_RR: - switch (msg_type) { - case GSM48_MT_RR_GPRS_SUSP_REQ: - DEBUGP(DRR, "%s\n", - gsm48_rr_msg_name(GSM48_MT_RR_GPRS_SUSP_REQ)); - break; - case GSM48_MT_RR_STATUS: - LOGP(DRR, LOGL_NOTICE, "%s (cause: %s)\n", - gsm48_rr_msg_name(GSM48_MT_RR_STATUS), - rr_cause_name(gh->data[0])); - break; - case GSM48_MT_RR_MEAS_REP: - /* This shouldn't actually end up here, as RSL treats - * L3 Info of 08.58 MEASUREMENT REPORT different by calling - * directly into gsm48_parse_meas_rep */ - LOGP(DMEAS, LOGL_ERROR, "DIRECT GSM48 MEASUREMENT REPORT ?!? "); - break; - case GSM48_MT_RR_HANDO_COMPL: - handle_rr_ho_compl(msg); - break; - case GSM48_MT_RR_HANDO_FAIL: - handle_rr_ho_fail(msg); - break; - case GSM48_MT_RR_CIPH_M_COMPL: - if (api->cipher_mode_compl) - api->cipher_mode_compl(conn, msg, - conn->lchan->encr.alg_id); - break; - case GSM48_MT_RR_ASS_COMPL: - handle_ass_compl(conn, msg); - break; - case GSM48_MT_RR_ASS_FAIL: - handle_ass_fail(conn, msg); - break; - case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: - osmo_timer_del(&conn->T10); - rc = gsm48_rx_rr_modif_ack(msg); - if (rc < 0) { - api->assign_fail(conn, - GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, - NULL); - } else if (rc >= 0) { - api->assign_compl(conn, 0, - lchan_to_chosen_channel(conn->lchan), - conn->lchan->encr.alg_id, - chan_mode_to_speech(conn->lchan)); - } - break; - case GSM48_MT_RR_CLSM_CHG: - handle_classmark_chg(conn, msg); - break; - case GSM48_MT_RR_APP_INFO: - /* Passing RR APP INFO to MSC, not quite - * according to spec */ - if (api->dtap) - api->dtap(conn, link_id, msg); - break; - default: - /* Normally, a MSC should never receive RR - * messages, but we'd rather forward what we - * don't know than drop it... */ - LOGP(DRR, LOGL_NOTICE, - "BSC: Passing %s 04.08 RR message to MSC\n", - gsm48_rr_msg_name(msg_type)); - if (api->dtap) - api->dtap(conn, link_id, msg); - } - break; - default: - if (api->dtap) - api->dtap(conn, link_id, msg); - break; - } -} - -/*! \brief RSL has received a DATA INDICATION with L3 from MS */ -int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id) -{ - int rc; - struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api; - struct gsm_lchan *lchan; - - lchan = msg->lchan; - if (lchan->state != LCHAN_S_ACTIVE) { - LOGP(DRSL, LOGL_INFO, "Got data in non active state(%s), " - "discarding.\n", gsm_lchans_name(lchan->state)); - return -1; - } - - - if (lchan->conn) { - /* if we already have a connection, forward via DTAP to - * MSC */ - dispatch_dtap(lchan->conn, link_id, msg); - } else { - /* allocate a new connection */ - rc = BSC_API_CONN_POL_REJECT; - lchan->conn = bsc_subscr_con_allocate(msg->lchan); - if (!lchan->conn) { - lchan_release(lchan, 1, RSL_REL_NORMAL); - return -1; - } - - /* fwd via bsc_api to send COMPLETE L3 INFO to MSC */ - rc = api->compl_l3(lchan->conn, msg, 0); - - if (rc != BSC_API_CONN_POL_ACCEPT) { - lchan->conn->lchan = NULL; - bsc_subscr_con_free(lchan->conn); - lchan_release(lchan, 1, RSL_REL_NORMAL); - } - } - - return 0; -} - -/*! \brief We received a GSM 08.08 CIPHER MODE from the MSC */ -int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher, - const uint8_t *key, int len, int include_imeisv) -{ - if (cipher > 0 && key == NULL) { - LOGP(DRSL, LOGL_ERROR, "Need to have an encrytpion key.\n"); - return -1; - } - - if (len > MAX_A5_KEY_LEN) { - LOGP(DRSL, LOGL_ERROR, "The key is too long: %d\n", len); - return -1; - } - - conn->lchan->encr.alg_id = RSL_ENC_ALG_A5(cipher); - if (key) { - conn->lchan->encr.key_len = len; - memcpy(conn->lchan->encr.key, key, len); - } - - return gsm48_send_rr_ciph_mode(conn->lchan, include_imeisv); -} - -/* - * Release all occupied RF Channels but stay around for more. - */ -int gsm0808_clear(struct gsm_subscriber_connection *conn) -{ - if (conn->ho_lchan) - bsc_clear_handover(conn, 1); - - if (conn->secondary_lchan) - lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END); - - if (conn->lchan) - lchan_release(conn->lchan, 1, RSL_REL_NORMAL); - - conn->lchan = NULL; - conn->secondary_lchan = NULL; - conn->ho_lchan = NULL; - conn->bts = NULL; - - osmo_timer_del(&conn->T10); - - return 0; -} - -static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id) -{ - struct bsc_api *api; - - if (!conn) - return; - - api = conn->network->bsc_api; - if (!api || !api->sapi_n_reject) - return; - - api->sapi_n_reject(conn, link_id); -} - -static void rll_ind_cb(struct gsm_lchan *lchan, uint8_t link_id, void *_data, enum bsc_rllr_ind rllr_ind) -{ - struct msgb *msg = _data; - - /* - * There seems to be a small window that the RLL timer can - * fire after a lchan_release call and before the S_CHALLOC_FREED - * is called. Check if a conn is set before proceeding. - */ - if (!lchan->conn) - return; - - switch (rllr_ind) { - case BSC_RLLR_IND_EST_CONF: - rsl_data_request(msg, OBSC_LINKID_CB(msg)); - break; - case BSC_RLLR_IND_REL_IND: - case BSC_RLLR_IND_ERR_IND: - case BSC_RLLR_IND_TIMEOUT: - send_sapi_reject(lchan->conn, OBSC_LINKID_CB(msg)); - msgb_free(msg); - break; - } -} - -static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct bsc_api *bsc; - struct gsm_lchan *lchan; - struct lchan_signal_data *lchan_data; - - if (subsys != SS_LCHAN) - return 0; - - - lchan_data = signal_data; - if (!lchan_data->lchan || !lchan_data->lchan->conn) - return 0; - - lchan = lchan_data->lchan; - bsc = lchan->ts->trx->bts->network->bsc_api; - if (!bsc) - return 0; - - switch (signal) { - case S_LCHAN_UNEXPECTED_RELEASE: - handle_release(lchan->conn, bsc, lchan); - break; - case S_LCHAN_ACTIVATE_ACK: - handle_chan_ack(lchan->conn, bsc, lchan); - break; - case S_LCHAN_ACTIVATE_NACK: - handle_chan_nack(lchan->conn, bsc, lchan); - break; - } - - return 0; -} - -static void handle_release(struct gsm_subscriber_connection *conn, - struct bsc_api *bsc, struct gsm_lchan *lchan) -{ - int destruct = 1; - - if (conn->secondary_lchan == lchan) { - osmo_timer_del(&conn->T10); - conn->secondary_lchan = NULL; - - bsc->assign_fail(conn, - GSM0808_CAUSE_RADIO_INTERFACE_FAILURE, - NULL); - } - - /* clear the connection now */ - if (bsc->clear_request) - destruct = bsc->clear_request(conn, 0); - - /* now give up all channels */ - if (conn->lchan == lchan) - conn->lchan = NULL; - if (conn->ho_lchan == lchan) { - bsc_clear_handover(conn, 0); - conn->ho_lchan = NULL; - } - lchan->conn = NULL; - - gsm0808_clear(conn); - - if (destruct) - bsc_subscr_con_free(conn); -} - -static void handle_chan_ack(struct gsm_subscriber_connection *conn, - struct bsc_api *api, struct gsm_lchan *lchan) -{ - if (conn->secondary_lchan != lchan) - return; - - LOGP(DMSC, LOGL_NOTICE, "Sending assignment on chan: %p\n", lchan); - gsm48_send_rr_ass_cmd(conn->lchan, lchan, lchan->ms_power); -} - -static void handle_chan_nack(struct gsm_subscriber_connection *conn, - struct bsc_api *api, struct gsm_lchan *lchan) -{ - if (conn->secondary_lchan != lchan) - return; - - LOGP(DMSC, LOGL_ERROR, "Channel activation failed. Waiting for timeout now\n"); - conn->secondary_lchan->conn = NULL; - conn->secondary_lchan = NULL; -} - -static __attribute__((constructor)) void on_dso_load_bsc(void) -{ - osmo_signal_register_handler(SS_LCHAN, bsc_handle_lchan_signal, NULL); -} - diff --git a/src/libbsc/bsc_ctrl_commands.c b/src/libbsc/bsc_ctrl_commands.c deleted file mode 100644 index 641fe2bf6..000000000 --- a/src/libbsc/bsc_ctrl_commands.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * (C) 2013-2015 by Holger Hans Peter Freyther - * (C) 2013-2015 by sysmocom s.f.m.c. GmbH - * - * 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 . - * - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define CTRL_CMD_VTY_STRING(cmdname, cmdstr, dtype, element) \ - CTRL_HELPER_GET_STRING(cmdname, dtype, element) \ - CTRL_HELPER_SET_STRING(cmdname, dtype, element) \ -static struct ctrl_cmd_element cmd_##cmdname = { \ - .name = cmdstr, \ - .get = get_##cmdname, \ - .set = set_##cmdname, \ - .verify = verify_vty_description_string, \ -} - -/** - * Check that there are no newlines or comments or other things - * that could make the VTY configuration unparsable. - */ -static int verify_vty_description_string(struct ctrl_cmd *cmd, - const char *value, void *data) -{ - int i; - const size_t len = strlen(value); - - for (i = 0; i < len; ++i) { - switch(value[i]) { - case '#': - case '\n': - case '\r': - cmd->reply = "String includes illegal character"; - return -1; - default: - break; - } - } - - return 0; -} - -CTRL_CMD_DEFINE_RANGE(net_mnc, "mnc", struct gsm_network, network_code, 0, 999); -CTRL_CMD_DEFINE_RANGE(net_mcc, "mcc", struct gsm_network, country_code, 1, 999); -CTRL_CMD_VTY_STRING(net_short_name, "short-name", struct gsm_network, name_short); -CTRL_CMD_VTY_STRING(net_long_name, "long-name", struct gsm_network, name_long); - -static int set_net_apply_config(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_network *net = cmd->node; - struct gsm_bts *bts; - - llist_for_each_entry(bts, &net->bts_list, list) { - if (!is_ipaccess_bts(bts)) - continue; - - /* - * The ip.access nanoBTS seems to be unrelaible on BSSGP - * so let's us just reboot it. For the sysmoBTS we can just - * restart the process as all state is gone. - */ - if (!is_sysmobts_v2(bts) && strcmp(cmd->value, "restart") == 0) { - struct gsm_bts_trx *trx; - llist_for_each_entry_reverse(trx, &bts->trx_list, list) - abis_nm_ipaccess_restart(trx); - } else - ipaccess_drop_oml(bts); - } - - cmd->reply = "Tried to drop the BTS"; - return CTRL_CMD_REPLY; -} - -CTRL_CMD_DEFINE_WO_NOVRF(net_apply_config, "apply-configuration"); - -static int verify_net_mcc_mnc_apply(struct ctrl_cmd *cmd, const char *value, void *d) -{ - char *tmp, *saveptr, *mcc, *mnc; - - tmp = talloc_strdup(cmd, value); - if (!tmp) - return 1; - - mcc = strtok_r(tmp, ",", &saveptr); - mnc = strtok_r(NULL, ",", &saveptr); - talloc_free(tmp); - - if (!mcc || !mnc) - return 1; - return 0; -} - -static int set_net_mcc_mnc_apply(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_network *net = cmd->node; - char *tmp, *saveptr, *mcc_str, *mnc_str; - int mcc, mnc; - - tmp = talloc_strdup(cmd, cmd->value); - if (!tmp) - goto oom; - - - mcc_str = strtok_r(tmp, ",", &saveptr); - mnc_str = strtok_r(NULL, ",", &saveptr); - - mcc = atoi(mcc_str); - mnc = atoi(mnc_str); - - talloc_free(tmp); - - if (net->network_code == mnc && net->country_code == mcc) { - cmd->reply = "Nothing changed"; - return CTRL_CMD_REPLY; - } - - net->network_code = mnc; - net->country_code = mcc; - - return set_net_apply_config(cmd, data); - -oom: - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; -} -CTRL_CMD_DEFINE_WO(net_mcc_mnc_apply, "mcc-mnc-apply"); - -/* BTS related commands below */ -CTRL_CMD_DEFINE_RANGE(bts_lac, "location-area-code", struct gsm_bts, location_area_code, 0, 65535); -CTRL_CMD_DEFINE_RANGE(bts_ci, "cell-identity", struct gsm_bts, cell_identity, 0, 65535); - -static int set_bts_apply_config(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_bts *bts = cmd->node; - - if (!is_ipaccess_bts(bts)) { - cmd->reply = "BTS is not IP based"; - return CTRL_CMD_ERROR; - } - - ipaccess_drop_oml(bts); - cmd->reply = "Tried to drop the BTS"; - return CTRL_CMD_REPLY; -} - -CTRL_CMD_DEFINE_WO_NOVRF(bts_apply_config, "apply-configuration"); - -static int set_bts_si(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_bts *bts = cmd->node; - int rc; - - rc = gsm_bts_set_system_infos(bts); - if (rc != 0) { - cmd->reply = "Failed to generate SI"; - return CTRL_CMD_ERROR; - } - - cmd->reply = "Generated new System Information"; - return CTRL_CMD_REPLY; -} -CTRL_CMD_DEFINE_WO_NOVRF(bts_si, "send-new-system-informations"); - -static int get_bts_chan_load(struct ctrl_cmd *cmd, void *data) -{ - int i; - struct pchan_load pl; - struct gsm_bts *bts; - const char *space = ""; - - bts = cmd->node; - memset(&pl, 0, sizeof(pl)); - bts_chan_load(&pl, bts); - - cmd->reply = talloc_strdup(cmd, ""); - - for (i = 0; i < ARRAY_SIZE(pl.pchan); ++i) { - const struct load_counter *lc = &pl.pchan[i]; - - /* These can never have user load */ - if (i == GSM_PCHAN_NONE) - continue; - if (i == GSM_PCHAN_CCCH) - continue; - if (i == GSM_PCHAN_PDCH) - continue; - if (i == GSM_PCHAN_UNKNOWN) - continue; - - cmd->reply = talloc_asprintf_append(cmd->reply, - "%s%s,%u,%u", - space, gsm_pchan_name(i), lc->used, lc->total); - if (!cmd->reply) - goto error; - space = " "; - } - - return CTRL_CMD_REPLY; - -error: - cmd->reply = "Memory allocation failure"; - return CTRL_CMD_ERROR; -} - -CTRL_CMD_DEFINE_RO(bts_chan_load, "channel-load"); - -static int get_bts_oml_conn(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_bts *bts = cmd->node; - - cmd->reply = bts->oml_link ? "connected" : "disconnected"; - return CTRL_CMD_REPLY; -} - -CTRL_CMD_DEFINE_RO(bts_oml_conn, "oml-connection-state"); - -static int verify_bts_gprs_mode(struct ctrl_cmd *cmd, const char *value, void *_data) -{ - int valid; - enum bts_gprs_mode mode; - struct gsm_bts *bts = cmd->node; - - mode = bts_gprs_mode_parse(value, &valid); - if (!valid) { - cmd->reply = "Mode is not known"; - return 1; - } - - if (!bts_gprs_mode_is_compat(bts, mode)) { - cmd->reply = "bts does not support this mode"; - return 1; - } - - return 0; -} - -static int get_bts_gprs_mode(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_bts *bts = cmd->node; - - cmd->reply = talloc_strdup(cmd, bts_gprs_mode_name(bts->gprs.mode)); - return CTRL_CMD_REPLY; -} - -static int set_bts_gprs_mode(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_bts *bts = cmd->node; - - bts->gprs.mode = bts_gprs_mode_parse(cmd->value, NULL); - return get_bts_gprs_mode(cmd, data); -} - -CTRL_CMD_DEFINE(bts_gprs_mode, "gprs-mode"); - -static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data) -{ - const char *oper, *admin, *policy; - struct gsm_bts *bts = cmd->node; - - if (!bts) { - cmd->reply = "bts not found."; - return CTRL_CMD_ERROR; - } - - oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts)); - admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts)); - policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts)); - - cmd->reply = talloc_asprintf(cmd, "%s,%s,%s", oper, admin, policy); - if (!cmd->reply) { - cmd->reply = "OOM."; - return CTRL_CMD_ERROR; - } - - return CTRL_CMD_REPLY; -} -CTRL_CMD_DEFINE_RO(bts_rf_state, "rf_state"); - -static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_network *net = cmd->node; - struct gsm_bts *bts; - const char *policy_name; - - policy_name = osmo_bsc_rf_get_policy_name(net->bsc_data->rf_ctrl->policy); - - llist_for_each_entry(bts, &net->bts_list, list) { - struct gsm_bts_trx *trx; - - /* Exclude the BTS from the global lock */ - if (bts->excl_from_rf_lock) - continue; - - llist_for_each_entry(trx, &bts->trx_list, list) { - if (trx->mo.nm_state.availability == NM_AVSTATE_OK && - trx->mo.nm_state.operational != NM_OPSTATE_DISABLED) { - cmd->reply = talloc_asprintf(cmd, - "state=on,policy=%s,bts=%u,trx=%u", - policy_name, bts->nr, trx->nr); - return CTRL_CMD_REPLY; - } - } - } - - cmd->reply = talloc_asprintf(cmd, "state=off,policy=%s", - policy_name); - return CTRL_CMD_REPLY; -} - -#define TIME_FORMAT_RFC2822 "%a, %d %b %Y %T %z" - -static int set_net_rf_lock(struct ctrl_cmd *cmd, void *data) -{ - int locked = atoi(cmd->value); - struct gsm_network *net = cmd->node; - time_t now = time(NULL); - char now_buf[64]; - struct osmo_bsc_rf *rf; - - if (!net) { - cmd->reply = "net not found."; - return CTRL_CMD_ERROR; - } - - rf = net->bsc_data->rf_ctrl; - - if (!rf) { - cmd->reply = "RF Ctrl is not enabled in the BSC Configuration"; - return CTRL_CMD_ERROR; - } - - talloc_free(rf->last_rf_lock_ctrl_command); - strftime(now_buf, sizeof(now_buf), TIME_FORMAT_RFC2822, gmtime(&now)); - rf->last_rf_lock_ctrl_command = - talloc_asprintf(rf, "rf_locked %u (%s)", locked, now_buf); - - osmo_bsc_rf_schedule_lock(rf, locked == 1 ? '0' : '1'); - - cmd->reply = talloc_asprintf(cmd, "%u", locked); - if (!cmd->reply) { - cmd->reply = "OOM."; - return CTRL_CMD_ERROR; - } - - return CTRL_CMD_REPLY; -} - -static int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data) -{ - int locked = atoi(cmd->value); - - if ((locked != 0) && (locked != 1)) - return 1; - - return 0; -} -CTRL_CMD_DEFINE(net_rf_lock, "rf_locked"); - -static int get_net_bts_num(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_network *net = cmd->node; - - cmd->reply = talloc_asprintf(cmd, "%u", net->num_bts); - return CTRL_CMD_REPLY; -} -CTRL_CMD_DEFINE_RO(net_bts_num, "number-of-bts"); - -/* TRX related commands below here */ -CTRL_HELPER_GET_INT(trx_max_power, struct gsm_bts_trx, max_power_red); -static int verify_trx_max_power(struct ctrl_cmd *cmd, const char *value, void *_data) -{ - int tmp = atoi(value); - - if (tmp < 0 || tmp > 22) { - cmd->reply = "Value must be between 0 and 22"; - return -1; - } - - if (tmp & 1) { - cmd->reply = "Value must be even"; - return -1; - } - - return 0; -} -CTRL_CMD_DEFINE_RANGE(trx_arfcn, "arfcn", struct gsm_bts_trx, arfcn, 0, 1023); - -static int set_trx_max_power(struct ctrl_cmd *cmd, void *_data) -{ - struct gsm_bts_trx *trx = cmd->node; - int old_power; - - /* remember the old value, set the new one */ - old_power = trx->max_power_red; - trx->max_power_red = atoi(cmd->value); - - /* Maybe update the value */ - if (old_power != trx->max_power_red) { - LOGP(DCTRL, LOGL_NOTICE, - "%s updating max_pwr_red(%d)\n", - gsm_trx_name(trx), trx->max_power_red); - abis_nm_update_max_power_red(trx); - } - - return get_trx_max_power(cmd, _data); -} -CTRL_CMD_DEFINE(trx_max_power, "max-power-reduction"); - -int bsc_base_ctrl_cmds_install(void) -{ - int rc = 0; - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mnc); - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc); - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_short_name); - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_long_name); - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_apply_config); - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc_mnc_apply); - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_rf_lock); - rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_bts_num); - - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_lac); - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_ci); - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_apply_config); - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_si); - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_chan_load); - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_oml_conn); - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_gprs_mode); - rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_state); - - rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_max_power); - rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_arfcn); - - return rc; -} diff --git a/src/libbsc/bsc_ctrl_lookup.c b/src/libbsc/bsc_ctrl_lookup.c deleted file mode 100644 index a8a8cf526..000000000 --- a/src/libbsc/bsc_ctrl_lookup.c +++ /dev/null @@ -1,107 +0,0 @@ -/* SNMP-like status interface. Look-up of BTS/TRX - * - * (C) 2010-2011 by Daniel Willmann - * (C) 2010-2011 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 General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include - -#include -#include -#include -#include - -extern vector ctrl_node_vec; - -/*! \brief control interface lookup function for bsc/bts gsm_data - * \param[in] data Private data passed to controlif_setup() - * \param[in] vline Vector of the line holding the command string - * \param[out] node_type type (CTRL_NODE_) that was determined - * \param[out] node_data private dta of node that was determined - * \param i Current index into vline, up to which it is parsed - */ -static int bsc_ctrl_node_lookup(void *data, vector vline, int *node_type, - void **node_data, int *i) -{ - struct gsm_network *net = data; - struct gsm_bts *bts = NULL; - struct gsm_bts_trx *trx = NULL; - struct gsm_bts_trx_ts *ts = NULL; - char *token = vector_slot(vline, *i); - long num; - - /* TODO: We need to make sure that the following chars are digits - * and/or use strtol to check if number conversion was successful - * Right now something like net.bts_stats will not work */ - if (!strcmp(token, "bts")) { - if (*node_type != CTRL_NODE_ROOT || !net) - goto err_missing; - (*i)++; - if (!ctrl_parse_get_num(vline, *i, &num)) - goto err_index; - - bts = gsm_bts_num(net, num); - if (!bts) - goto err_missing; - *node_data = bts; - *node_type = CTRL_NODE_BTS; - } else if (!strcmp(token, "trx")) { - if (*node_type != CTRL_NODE_BTS || !*node_data) - goto err_missing; - bts = *node_data; - (*i)++; - if (!ctrl_parse_get_num(vline, *i, &num)) - goto err_index; - - trx = gsm_bts_trx_num(bts, num); - if (!trx) - goto err_missing; - *node_data = trx; - *node_type = CTRL_NODE_TRX; - } else if (!strcmp(token, "ts")) { - if (*node_type != CTRL_NODE_TRX || !*node_data) - goto err_missing; - trx = *node_data; - (*i)++; - if (!ctrl_parse_get_num(vline, *i, &num)) - goto err_index; - - if ((num >= 0) && (num < TRX_NR_TS)) - ts = &trx->ts[num]; - if (!ts) - goto err_missing; - *node_data = ts; - *node_type = CTRL_NODE_TS; - } else - return 0; - - return 1; -err_missing: - return -ENODEV; -err_index: - return -ERANGE; -} - -struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, - const char *bind_addr, uint16_t port) -{ - return ctrl_interface_setup_dynip(net, bind_addr, port, - bsc_ctrl_node_lookup); -} diff --git a/src/libbsc/bsc_dyn_ts.c b/src/libbsc/bsc_dyn_ts.c deleted file mode 100644 index e5422fc5c..000000000 --- a/src/libbsc/bsc_dyn_ts.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Dynamic PDCH initialisation implementation shared across NM and RSL */ - -/* (C) 2016 by sysmocom s.f.m.c. GmbH - * 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 . - * - */ - -#include -#include -#include -#include - -void tchf_pdch_ts_init(struct gsm_bts_trx_ts *ts) -{ - int rc; - - if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) { - LOGP(DRSL, LOGL_NOTICE, "%s: GPRS mode is 'none':" - " not activating PDCH.\n", - gsm_ts_and_pchan_name(ts)); - return; - } - - LOGP(DRSL, LOGL_DEBUG, "%s: trying to PDCH ACT\n", - gsm_ts_and_pchan_name(ts)); - - rc = rsl_ipacc_pdch_activate(ts, 1); - if (rc != 0) - LOGP(DRSL, LOGL_ERROR, "%s %s: PDCH ACT failed\n", - gsm_ts_name(ts), gsm_pchan_name(ts->pchan)); -} - -void tchf_tchh_pdch_ts_init(struct gsm_bts_trx_ts *ts) -{ - if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) { - LOGP(DRSL, LOGL_NOTICE, "%s: GPRS mode is 'none':" - " not activating PDCH.\n", - gsm_ts_and_pchan_name(ts)); - return; - } - - dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH); -} - -void dyn_ts_init(struct gsm_bts_trx_ts *ts) -{ - /* Clear all TCH/F_PDCH flags */ - ts->flags &= ~(TS_F_PDCH_PENDING_MASK | TS_F_PDCH_ACTIVE); - - /* Clear TCH/F_TCH/H_PDCH state */ - ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE; - ts->dyn.pending_chan_activ = NULL; - - switch (ts->pchan) { - case GSM_PCHAN_TCH_F_PDCH: - tchf_pdch_ts_init(ts); - break; - case GSM_PCHAN_TCH_F_TCH_H_PDCH: - tchf_tchh_pdch_ts_init(ts); - break; - default: - break; - } -} diff --git a/src/libbsc/bsc_init.c b/src/libbsc/bsc_init.c deleted file mode 100644 index 78ca2ab4d..000000000 --- a/src/libbsc/bsc_init.c +++ /dev/null @@ -1,567 +0,0 @@ -/* A hackish minimal BSC (+MSC +HLR) implementation */ - -/* (C) 2008-2010 by Harald Welte - * (C) 2009 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* global pointer to the gsm network data structure */ -extern struct gsm_network *bsc_gsmnet; - -/* Callback function for NACK on the OML NM */ -static int oml_msg_nack(struct nm_nack_signal_data *nack) -{ - if (nack->mt == NM_MT_GET_ATTR_NACK) { - LOGP(DNM, LOGL_ERROR, "BTS%u does not support Get Attributes " - "OML message.\n", nack->bts->nr); - return 0; - } - - if (nack->mt == NM_MT_SET_BTS_ATTR_NACK) - LOGP(DNM, LOGL_ERROR, "Failed to set BTS attributes. That is fatal. " - "Was the bts type and frequency properly specified?\n"); - else - LOGP(DNM, LOGL_ERROR, "Got %s NACK going to drop the OML links.\n", - abis_nm_nack_name(nack->mt)); - - if (!nack->bts) { - LOGP(DNM, LOGL_ERROR, "Unknown bts. Can not drop it.\n"); - return 0; - } - - if (is_ipaccess_bts(nack->bts)) - ipaccess_drop_oml(nack->bts); - - return 0; -} - -/* Callback function to be called every time we receive a signal from NM */ -static int nm_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct nm_nack_signal_data *nack; - - switch (signal) { - case S_NM_NACK: - nack = signal_data; - return oml_msg_nack(nack); - default: - break; - } - return 0; -} - -int bsc_shutdown_net(struct gsm_network *net) -{ - struct gsm_bts *bts; - - llist_for_each_entry(bts, &net->bts_list, list) { - LOGP(DNM, LOGL_NOTICE, "shutting down OML for BTS %u\n", bts->nr); - osmo_signal_dispatch(SS_L_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts); - } - - return 0; -} - -static int rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i, int si_len) -{ - struct gsm_bts *bts = trx->bts; - int rc, j; - - if (si_len) { - DEBUGP(DRR, "SI%s: %s\n", get_value_string(osmo_sitype_strs, i), - osmo_hexdump(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN)); - } else - DEBUGP(DRR, "SI%s: OFF\n", get_value_string(osmo_sitype_strs, i)); - - switch (i) { - case SYSINFO_TYPE_5: - case SYSINFO_TYPE_5bis: - case SYSINFO_TYPE_5ter: - case SYSINFO_TYPE_6: - rc = rsl_sacch_filling(trx, osmo_sitype2rsl(i), - si_len ? GSM_BTS_SI(bts, i) : NULL, si_len); - break; - case SYSINFO_TYPE_2quater: - if (si_len == 0) { - rc = rsl_bcch_info(trx, i, NULL, 0); - break; - } - for (j = 0; j <= bts->si2q_count; j++) - rc = rsl_bcch_info(trx, i, (const uint8_t *)GSM_BTS_SI2Q(bts, j), GSM_MACBLOCK_LEN); - break; - default: - rc = rsl_bcch_info(trx, i, si_len ? GSM_BTS_SI(bts, i) : NULL, si_len); - break; - } - - return rc; -} - -/* set all system information types for a TRX */ -int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx) -{ - int i, rc; - struct gsm_bts *bts = trx->bts; - uint8_t gen_si[_MAX_SYSINFO_TYPE], n_si = 0, n; - int si_len[_MAX_SYSINFO_TYPE]; - - bts->si_common.cell_sel_par.ms_txpwr_max_ccch = - ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); - bts->si_common.cell_sel_par.neci = bts->network->neci; - - /* Zero/forget the state of the dynamically computed SIs, leeping the static ones */ - bts->si_valid = bts->si_mode_static; - - /* First, we determine which of the SI messages we actually need */ - - if (trx == bts->c0) { - /* 1...4 are always present on a C0 TRX */ - gen_si[n_si++] = SYSINFO_TYPE_1; - gen_si[n_si++] = SYSINFO_TYPE_2; - gen_si[n_si++] = SYSINFO_TYPE_2bis; - gen_si[n_si++] = SYSINFO_TYPE_2ter; - gen_si[n_si++] = SYSINFO_TYPE_2quater; - gen_si[n_si++] = SYSINFO_TYPE_3; - gen_si[n_si++] = SYSINFO_TYPE_4; - - /* 13 is always present on a C0 TRX of a GPRS BTS */ - if (bts->gprs.mode != BTS_GPRS_NONE) - gen_si[n_si++] = SYSINFO_TYPE_13; - } - - /* 5 and 6 are always present on every TRX */ - gen_si[n_si++] = SYSINFO_TYPE_5; - gen_si[n_si++] = SYSINFO_TYPE_5bis; - gen_si[n_si++] = SYSINFO_TYPE_5ter; - gen_si[n_si++] = SYSINFO_TYPE_6; - - /* Second, we generate the selected SI via RSL */ - - for (n = 0; n < n_si; n++) { - i = gen_si[n]; - /* Only generate SI if this SI is not in "static" (user-defined) mode */ - if (!(bts->si_mode_static & (1 << i))) { - /* Set SI as being valid. gsm_generate_si() might unset - * it, if SI is not required. */ - bts->si_valid |= (1 << i); - rc = gsm_generate_si(bts, i); - if (rc < 0) - goto err_out; - si_len[i] = rc; - } else { - if (i == SYSINFO_TYPE_5 || i == SYSINFO_TYPE_5bis - || i == SYSINFO_TYPE_5ter) - si_len[i] = 18; - else if (i == SYSINFO_TYPE_6) - si_len[i] = 11; - else - si_len[i] = 23; - } - } - - /* Third, we send the selected SI via RSL */ - - for (n = 0; n < n_si; n++) { - i = gen_si[n]; - /* if we don't currently have this SI, we send a zero-length - * RSL BCCH FILLING / SACCH FILLING * in order to deactivate - * the SI, in case it might have previously been active */ - if (!GSM_BTS_HAS_SI(bts, i)) - rc = rsl_si(trx, i, 0); - else - rc = rsl_si(trx, i, si_len[i]); - if (rc < 0) - return rc; - } - - /* Make sure the PCU is aware (in case anything GPRS related has - * changed in SI */ - pcu_info_update(bts); - - return 0; -err_out: - LOGP(DRR, LOGL_ERROR, "Cannot generate SI%s for BTS %u: error <%s>, " - "most likely a problem with neighbor cell list generation\n", - get_value_string(osmo_sitype_strs, i), bts->nr, strerror(-rc)); - return rc; -} - -/* set all system information types for a BTS */ -int gsm_bts_set_system_infos(struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - - /* Generate a new ID */ - bts->bcch_change_mark += 1; - bts->bcch_change_mark %= 0x7; - - llist_for_each_entry(trx, &bts->trx_list, list) { - int rc; - - rc = gsm_bts_trx_set_system_infos(trx); - if (rc != 0) - return rc; - } - - return 0; -} - -/* Produce a MA as specified in 10.5.2.21 */ -static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts) -{ - /* we have three bitvecs: the per-timeslot ARFCNs, the cell chan ARFCNs - * and the MA */ - struct bitvec *cell_chan = &ts->trx->bts->si_common.cell_alloc; - struct bitvec *ts_arfcn = &ts->hopping.arfcns; - struct bitvec *ma = &ts->hopping.ma; - unsigned int num_cell_arfcns, bitnum, n_chan; - int i; - - /* re-set the MA to all-zero */ - ma->cur_bit = 0; - ts->hopping.ma_len = 0; - memset(ma->data, 0, ma->data_len); - - if (!ts->hopping.enabled) - return 0; - - /* count the number of ARFCNs in the cell channel allocation */ - num_cell_arfcns = 0; - for (i = 0; i < 1024; i++) { - if (bitvec_get_bit_pos(cell_chan, i)) - num_cell_arfcns++; - } - - /* pad it to octet-aligned number of bits */ - ts->hopping.ma_len = num_cell_arfcns / 8; - if (num_cell_arfcns % 8) - ts->hopping.ma_len++; - - n_chan = 0; - for (i = 0; i < 1024; i++) { - if (!bitvec_get_bit_pos(cell_chan, i)) - continue; - /* set the corresponding bit in the MA */ - bitnum = (ts->hopping.ma_len * 8) - 1 - n_chan; - if (bitvec_get_bit_pos(ts_arfcn, i)) - bitvec_set_bit_pos(ma, bitnum, 1); - else - bitvec_set_bit_pos(ma, bitnum, 0); - n_chan++; - } - - /* ARFCN 0 is special: It is coded last in the bitmask */ - if (bitvec_get_bit_pos(cell_chan, 0)) { - n_chan++; - /* set the corresponding bit in the MA */ - bitnum = (ts->hopping.ma_len * 8) - 1 - n_chan; - if (bitvec_get_bit_pos(ts_arfcn, 0)) - bitvec_set_bit_pos(ma, bitnum, 1); - else - bitvec_set_bit_pos(ma, bitnum, 0); - } - - return 0; -} - -static void bootstrap_rsl(struct gsm_bts_trx *trx) -{ - unsigned int i; - - LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) " - "on ARFCN %u using MCC=%u MNC=%u LAC=%u CID=%u BSIC=%u\n", - trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code, - bsc_gsmnet->network_code, trx->bts->location_area_code, - trx->bts->cell_identity, trx->bts->bsic); - - if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) { - rsl_nokia_si_begin(trx); - } - - gsm_bts_trx_set_system_infos(trx); - - if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) { - /* channel unspecific, power reduction in 2 dB steps */ - rsl_bs_power_control(trx, 0xFF, trx->max_power_red / 2); - rsl_nokia_si_end(trx); - } - - for (i = 0; i < ARRAY_SIZE(trx->ts); i++) - generate_ma_for_ts(&trx->ts[i]); -} - -/* Callback function to be called every time we receive a signal from INPUT */ -static int inp_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct input_signal_data *isd = signal_data; - struct gsm_bts_trx *trx = isd->trx; - int ts_no, lchan_no; - /* N. B: we rely on attribute order when parsing response in abis_nm_rx_get_attr_resp() */ - const uint8_t bts_attr[] = { NM_ATT_MANUF_ID, NM_ATT_SW_CONFIG, }; - const uint8_t trx_attr[] = { NM_ATT_MANUF_STATE, NM_ATT_SW_CONFIG, }; - - /* we should not request more attributes than we're ready to handle */ - OSMO_ASSERT(sizeof(bts_attr) < MAX_BTS_ATTR); - OSMO_ASSERT(sizeof(trx_attr) < MAX_BTS_ATTR); - - if (subsys != SS_L_INPUT) - return -EINVAL; - - LOGP(DLMI, LOGL_DEBUG, "%s(): Input signal '%s' received\n", __func__, - get_value_string(e1inp_signal_names, signal)); - switch (signal) { - case S_L_INP_TEI_UP: - if (isd->link_type == E1INP_SIGN_OML) { - /* TODO: this is required for the Nokia BTS, hopping is configured - during OML, other MA is not set. */ - struct gsm_bts_trx *cur_trx; - /* was static in system_information.c */ - extern int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts); - uint8_t ca[20]; - /* has to be called before generate_ma_for_ts to - set bts->si_common.cell_alloc */ - generate_cell_chan_list(ca, trx->bts); - - /* Request generic BTS-level attributes */ - abis_nm_get_attr(trx->bts, NM_OC_BTS, 0xFF, 0xFF, 0xFF, bts_attr, sizeof(bts_attr)); - - llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) { - int i; - /* Request TRX-level attributes */ - abis_nm_get_attr(cur_trx->bts, NM_OC_BASEB_TRANSC, 0, cur_trx->nr, 0xFF, - trx_attr, sizeof(trx_attr)); - for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++) - generate_ma_for_ts(&cur_trx->ts[i]); - } - } - if (isd->link_type == E1INP_SIGN_RSL) - bootstrap_rsl(trx); - break; - case S_L_INP_TEI_DN: - LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx); - - if (isd->link_type == E1INP_SIGN_OML) - rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]); - else if (isd->link_type == E1INP_SIGN_RSL) - rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL]); - - /* - * free all allocated channels. change the nm_state so the - * trx and trx_ts becomes unusable and chan_alloc.c can not - * allocate from it. - */ - for (ts_no = 0; ts_no < ARRAY_SIZE(trx->ts); ++ts_no) { - struct gsm_bts_trx_ts *ts = &trx->ts[ts_no]; - - for (lchan_no = 0; lchan_no < ARRAY_SIZE(ts->lchan); ++lchan_no) { - if (ts->lchan[lchan_no].state != LCHAN_S_NONE) - lchan_free(&ts->lchan[lchan_no]); - lchan_reset(&ts->lchan[lchan_no]); - } - } - - gsm_bts_mo_reset(trx->bts); - - abis_nm_clear_queue(trx->bts); - break; - default: - break; - } - - return 0; -} - -static int bootstrap_bts(struct gsm_bts *bts) -{ - int i, n; - - if (!bts->model) - return -EFAULT; - - if (bts->model->start && !bts->model->started) { - int ret = bts->model->start(bts->network); - if (ret < 0) - return ret; - - bts->model->started = true; - } - - /* FIXME: What about secondary TRX of a BTS? What about a BTS that has TRX - * in different bands? Why is 'band' a parameter of the BTS and not of the TRX? */ - switch (bts->band) { - case GSM_BAND_1800: - if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) { - LOGP(DNM, LOGL_ERROR, "GSM1800 channel must be between 512-885.\n"); - return -EINVAL; - } - break; - case GSM_BAND_1900: - if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) { - LOGP(DNM, LOGL_ERROR, "GSM1900 channel must be between 512-810.\n"); - return -EINVAL; - } - break; - case GSM_BAND_900: - if ((bts->c0->arfcn > 124 && bts->c0->arfcn < 955) || - bts->c0->arfcn > 1023) { - LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 0-124, 955-1023.\n"); - return -EINVAL; - } - break; - case GSM_BAND_850: - if (bts->c0->arfcn < 128 || bts->c0->arfcn > 251) { - LOGP(DNM, LOGL_ERROR, "GSM850 channel must be between 128-251.\n"); - return -EINVAL; - } - break; - default: - LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n"); - return -EINVAL; - } - - if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL && - !bts->si_common.rach_control.cell_bar) - LOGP(DNM, LOGL_ERROR, "\nWARNING: You are running an 'accept-all' " - "network on a BTS that is not barred. This " - "configuration is likely to interfere with production " - "GSM networks and should only be used in a RF " - "shielded environment such as a faraday cage!\n\n"); - - /* Control Channel Description is set from vty/config */ - - /* T3212 is set from vty/config */ - - /* Set ccch config by looking at ts config */ - for (n=0, i=0; i<8; i++) - n += bts->c0->ts[i].pchan == GSM_PCHAN_CCCH ? 1 : 0; - - /* Indicate R99 MSC in SI3 */ - bts->si_common.chan_desc.mscr = 1; - - switch (n) { - case 0: - bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; - /* Limit reserved block to 2 on combined channel according to - 3GPP TS 44.018 Table 10.5.2.11.1 */ - if (bts->si_common.chan_desc.bs_ag_blks_res > 2) { - LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, " - "reducing BS-AG-BLKS-RES value %d -> 2\n", - bts->si_common.chan_desc.bs_ag_blks_res); - bts->si_common.chan_desc.bs_ag_blks_res = 2; - } - break; - case 1: - bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_NC; - break; - case 2: - bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_2_NC; - break; - case 3: - bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_3_NC; - break; - case 4: - bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_4_NC; - break; - default: - LOGP(DNM, LOGL_ERROR, "Unsupported CCCH timeslot configuration\n"); - return -EINVAL; - } - - bts->si_common.cell_options.pwrc = 0; /* PWRC not set */ - - bts->si_common.cell_sel_par.acs = 0; - - bts->si_common.ncc_permitted = 0xff; - - /* Initialize the BTS state */ - gsm_bts_mo_reset(bts); - - return 0; -} - -int bsc_network_alloc(mncc_recv_cb_t mncc_recv) -{ - /* initialize our data structures */ - bsc_gsmnet = bsc_network_init(tall_bsc_ctx, 1, 1, mncc_recv); - if (!bsc_gsmnet) - return -ENOMEM; - - bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC"); - bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC"); - - return 0; -} - -int bsc_network_configure(const char *config_file) -{ - struct gsm_bts *bts; - int rc; - - rc = vty_read_config_file(config_file, NULL); - if (rc < 0) { - LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file); - return rc; - } - - /* start telnet after reading config for vty_get_bind_addr() */ - rc = telnet_init_dynif(tall_bsc_ctx, bsc_gsmnet, vty_get_bind_addr(), - OSMO_VTY_PORT_NITB_BSC); - if (rc < 0) - return rc; - - osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL); - osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL); - - llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) { - rc = bootstrap_bts(bts); - if (rc < 0) { - LOGP(DNM, LOGL_FATAL, "Error bootstrapping BTS\n"); - return rc; - } - rc = e1_reconfig_bts(bts); - if (rc < 0) { - LOGP(DNM, LOGL_FATAL, "Error enabling E1 input driver\n"); - return rc; - } - } - - return 0; -} diff --git a/src/libbsc/bsc_msc.c b/src/libbsc/bsc_msc.c deleted file mode 100644 index 82a572dbe..000000000 --- a/src/libbsc/bsc_msc.c +++ /dev/null @@ -1,320 +0,0 @@ -/* Routines to talk to the MSC using the IPA Protocol */ -/* - * (C) 2010 by Holger Hans Peter Freyther - * (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 . - * - */ - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -static void connection_loss(struct bsc_msc_connection *con) -{ - struct osmo_fd *fd; - - fd = &con->write_queue.bfd; - - if (con->pending_msg) { - LOGP(DMSC, LOGL_ERROR, - "MSC(%s) dropping incomplete message.\n", con->name); - msgb_free(con->pending_msg); - con->pending_msg = NULL; - } - - close(fd->fd); - fd->fd = -1; - fd->cb = osmo_wqueue_bfd_cb; - fd->when = 0; - - con->is_connected = 0; - con->first_contact = 0; - con->connection_loss(con); -} - -static void msc_con_timeout(void *_con) -{ - struct bsc_msc_connection *con = _con; - - LOGP(DMSC, LOGL_ERROR, - "MSC(%s) Connection timeout.\n", con->name); - bsc_msc_lost(con); -} - -/* called in the case of a non blocking connect */ -static int msc_connection_connect(struct osmo_fd *fd, unsigned int what) -{ - int rc; - int val; - struct bsc_msc_connection *con; - struct osmo_wqueue *queue; - - socklen_t len = sizeof(val); - - queue = container_of(fd, struct osmo_wqueue, bfd); - con = container_of(queue, struct bsc_msc_connection, write_queue); - - if ((what & BSC_FD_WRITE) == 0) { - LOGP(DMSC, LOGL_ERROR, - "MSC(%s) Callback but not writable.\n", con->name); - return -1; - } - - /* From here on we will either be connected or reconnect */ - osmo_timer_del(&con->timeout_timer); - - /* check the socket state */ - rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len); - if (rc != 0) { - LOGP(DMSC, LOGL_ERROR, - "getsockopt for the MSC(%s) socket failed.\n", con->name); - goto error; - } - if (val != 0) { - LOGP(DMSC, LOGL_ERROR, - "Not connected to the MSC(%s): %d\n", - con->name, val); - goto error; - } - - - /* go to full operation */ - fd->cb = osmo_wqueue_bfd_cb; - fd->when = BSC_FD_READ | BSC_FD_EXCEPT; - - con->is_connected = 1; - LOGP(DMSC, LOGL_NOTICE, - "(Re)Connected to the MSC(%s).\n", con->name); - if (con->connected) - con->connected(con); - return 0; - -error: - osmo_fd_unregister(fd); - connection_loss(con); - return -1; -} -static void setnonblocking(struct osmo_fd *fd) -{ - int flags; - - flags = fcntl(fd->fd, F_GETFL); - if (flags < 0) { - perror("fcntl get failed"); - close(fd->fd); - fd->fd = -1; - return; - } - - flags |= O_NONBLOCK; - flags = fcntl(fd->fd, F_SETFL, flags); - if (flags < 0) { - perror("fcntl get failed"); - close(fd->fd); - fd->fd = -1; - return; - } -} - -int bsc_msc_connect(struct bsc_msc_connection *con) -{ - struct bsc_msc_dest *dest; - struct osmo_fd *fd; - struct sockaddr_in sin; - int on = 1, ret; - - if (llist_empty(con->dests)) { - LOGP(DMSC, LOGL_ERROR, - "No MSC(%s) connections configured.\n", - con->name); - connection_loss(con); - return -1; - } - - /* TODO: Why are we not using the libosmocore soecket - * abstraction, or libosmo-netif? */ - - /* move to the next connection */ - dest = (struct bsc_msc_dest *) con->dests->next; - llist_del(&dest->list); - llist_add_tail(&dest->list, con->dests); - - LOGP(DMSC, LOGL_NOTICE, - "Attempting to connect MSC(%s) at %s:%d\n", - con->name, dest->ip, dest->port); - - con->is_connected = 0; - - msgb_free(con->pending_msg); - con->pending_msg = NULL; - - fd = &con->write_queue.bfd; - fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - fd->priv_nr = 1; - - if (fd->fd < 0) { - perror("Creating TCP socket failed"); - return fd->fd; - } - - /* make it non blocking */ - setnonblocking(fd); - - /* set the socket priority */ - ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS, - &dest->dscp, sizeof(dest->dscp)); - if (ret != 0) - LOGP(DMSC, LOGL_ERROR, - "Failed to set DSCP to %d on MSC(%s). %s\n", - dest->dscp, con->name, strerror(errno)); - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(dest->port); - inet_aton(dest->ip, &sin.sin_addr); - - ret = setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (ret != 0) - LOGP(DMSC, LOGL_ERROR, - "Failed to set SO_REUSEADDR socket option\n"); - ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin)); - - if (ret == -1 && errno == EINPROGRESS) { - LOGP(DMSC, LOGL_ERROR, - "MSC(%s) Connection in progress\n", con->name); - fd->when = BSC_FD_WRITE; - fd->cb = msc_connection_connect; - osmo_timer_setup(&con->timeout_timer, msc_con_timeout, con); - osmo_timer_schedule(&con->timeout_timer, 20, 0); - } else if (ret < 0) { - perror("Connection failed"); - connection_loss(con); - return ret; - } else { - fd->when = BSC_FD_READ | BSC_FD_EXCEPT; - fd->cb = osmo_wqueue_bfd_cb; - con->is_connected = 1; - if (con->connected) - con->connected(con); - } - - ret = osmo_fd_register(fd); - if (ret < 0) { - perror("Registering the fd failed"); - close(fd->fd); - return ret; - } - - return ret; -} - -struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dests) -{ - struct bsc_msc_connection *con; - - con = talloc_zero(NULL, struct bsc_msc_connection); - if (!con) { - LOGP(DMSC, LOGL_FATAL, "Failed to create the MSC connection.\n"); - return NULL; - } - - con->dests = dests; - con->write_queue.bfd.fd = -1; - con->name = ""; - osmo_wqueue_init(&con->write_queue, 100); - return con; -} - -void bsc_msc_lost(struct bsc_msc_connection *con) -{ - osmo_wqueue_clear(&con->write_queue); - osmo_timer_del(&con->timeout_timer); - osmo_timer_del(&con->reconnect_timer); - - if (con->write_queue.bfd.fd >= 0) - osmo_fd_unregister(&con->write_queue.bfd); - connection_loss(con); -} - -static void reconnect_msc(void *_msc) -{ - struct bsc_msc_connection *con = _msc; - - LOGP(DMSC, LOGL_NOTICE, - "Attempting to reconnect to the MSC(%s).\n", con->name); - bsc_msc_connect(con); -} - -void bsc_msc_schedule_connect(struct bsc_msc_connection *con) -{ - LOGP(DMSC, LOGL_NOTICE, - "Attempting to reconnect to the MSC(%s)\n", con->name); - osmo_timer_setup(&con->reconnect_timer, reconnect_msc, con); - osmo_timer_schedule(&con->reconnect_timer, 5, 0); -} - -struct msgb *bsc_msc_id_get_resp(int fixed, const char *token, const uint8_t *res, int len) -{ - struct msgb *msg; - - if (!token) { - LOGP(DMSC, LOGL_ERROR, "No token specified.\n"); - return NULL; - } - - msg = msgb_alloc_headroom(4096, 128, "id resp"); - if (!msg) { - LOGP(DMSC, LOGL_ERROR, "Failed to create the message.\n"); - return NULL; - } - - /* - * The situation is bizarre. The encoding doesn't follow the - * TLV structure. It is more like a LV and old versions had - * it wrong but we want new versions to old servers so we - * introduce the quirk here. - */ - msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP); - if (fixed) { - msgb_put_u8(msg, 0); - msgb_put_u8(msg, strlen(token) + 2); - msgb_tv_fixed_put(msg, IPAC_IDTAG_UNITNAME, strlen(token) + 1, (uint8_t *) token); - if (len > 0) { - msgb_put_u8(msg, 0); - msgb_put_u8(msg, len + 1); - msgb_tv_fixed_put(msg, 0x24, len, res); - } - } else { - msgb_l16tv_put(msg, strlen(token) + 1, - IPAC_IDTAG_UNITNAME, (uint8_t *) token); - } - - return msg; -} diff --git a/src/libbsc/bsc_rf_ctrl.c b/src/libbsc/bsc_rf_ctrl.c deleted file mode 100644 index b7b6fc819..000000000 --- a/src/libbsc/bsc_rf_ctrl.c +++ /dev/null @@ -1,534 +0,0 @@ -/* RF Ctl handling socket */ - -/* (C) 2010 by Harald Welte - * (C) 2010-2014 by Holger Hans Peter Freyther - * (C) 2010-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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include - -#define RF_CMD_QUERY '?' -#define RF_CMD_OFF '0' -#define RF_CMD_ON '1' -#define RF_CMD_D_OFF 'd' -#define RF_CMD_ON_G 'g' - -static const struct value_string opstate_names[] = { - { OSMO_BSC_RF_OPSTATE_INOPERATIONAL, "inoperational" }, - { OSMO_BSC_RF_OPSTATE_OPERATIONAL, "operational" }, - { 0, NULL } -}; - -static const struct value_string adminstate_names[] = { - { OSMO_BSC_RF_ADMINSTATE_UNLOCKED, "unlocked" }, - { OSMO_BSC_RF_ADMINSTATE_LOCKED, "locked" }, - { 0, NULL } -}; - -static const struct value_string policy_names[] = { - { OSMO_BSC_RF_POLICY_OFF, "off" }, - { OSMO_BSC_RF_POLICY_ON, "on" }, - { OSMO_BSC_RF_POLICY_GRACE, "grace" }, - { OSMO_BSC_RF_POLICY_UNKNOWN, "unknown" }, - { 0, NULL } -}; - -const char *osmo_bsc_rf_get_opstate_name(enum osmo_bsc_rf_opstate opstate) -{ - return get_value_string(opstate_names, opstate); -} - -const char *osmo_bsc_rf_get_adminstate_name(enum osmo_bsc_rf_adminstate adminstate) -{ - return get_value_string(adminstate_names, adminstate); -} - -const char *osmo_bsc_rf_get_policy_name(enum osmo_bsc_rf_policy policy) -{ - return get_value_string(policy_names, policy); -} - -enum osmo_bsc_rf_opstate osmo_bsc_rf_get_opstate_by_bts(struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - - llist_for_each_entry(trx, &bts->trx_list, list) { - if (trx->mo.nm_state.operational == NM_OPSTATE_ENABLED) - return OSMO_BSC_RF_OPSTATE_OPERATIONAL; - } - - /* No trx were active, so this bts is disabled */ - return OSMO_BSC_RF_OPSTATE_INOPERATIONAL; -} - -enum osmo_bsc_rf_adminstate osmo_bsc_rf_get_adminstate_by_bts(struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - - llist_for_each_entry(trx, &bts->trx_list, list) { - if (trx->mo.nm_state.administrative == NM_STATE_UNLOCKED) - return OSMO_BSC_RF_ADMINSTATE_UNLOCKED; - } - - /* All trx administrative states were locked */ - return OSMO_BSC_RF_ADMINSTATE_LOCKED; -} - -enum osmo_bsc_rf_policy osmo_bsc_rf_get_policy_by_bts(struct gsm_bts *bts) -{ - struct osmo_bsc_data *bsc_data = bts->network->bsc_data; - - if (!bsc_data) - return OSMO_BSC_RF_POLICY_UNKNOWN; - - switch (bsc_data->rf_ctrl->policy) { - case S_RF_ON: - return OSMO_BSC_RF_POLICY_ON; - case S_RF_OFF: - return OSMO_BSC_RF_POLICY_OFF; - case S_RF_GRACE: - return OSMO_BSC_RF_POLICY_GRACE; - default: - return OSMO_BSC_RF_POLICY_UNKNOWN; - } -} - -static int lock_each_trx(struct gsm_network *net, int lock) -{ - struct gsm_bts *bts; - - llist_for_each_entry(bts, &net->bts_list, list) { - struct gsm_bts_trx *trx; - - /* Exclude the BTS from the global lock */ - if (bts->excl_from_rf_lock) { - LOGP(DLINP, LOGL_DEBUG, - "Excluding BTS(%d) from trx lock.\n", bts->nr); - continue; - } - - llist_for_each_entry(trx, &bts->trx_list, list) { - gsm_trx_lock_rf(trx, lock); - } - } - - return 0; -} - -static void send_resp(struct osmo_bsc_rf_conn *conn, char send) -{ - struct msgb *msg; - - msg = msgb_alloc(10, "RF Query"); - if (!msg) { - LOGP(DLINP, LOGL_ERROR, "Failed to allocate response msg.\n"); - return; - } - - msg->l2h = msgb_put(msg, 1); - msg->l2h[0] = send; - - if (osmo_wqueue_enqueue(&conn->queue, msg) != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the answer.\n"); - msgb_free(msg); - return; - } - - return; -} - - -/* - * Send a - * 'g' when we are in grace mode - * '1' when one TRX is online, - * '0' otherwise - */ -static void handle_query(struct osmo_bsc_rf_conn *conn) -{ - struct gsm_bts *bts; - char send = RF_CMD_OFF; - - if (conn->rf->policy == S_RF_GRACE) - return send_resp(conn, RF_CMD_ON_G); - - llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) { - struct gsm_bts_trx *trx; - - /* Exclude the BTS from the global lock */ - if (bts->excl_from_rf_lock) { - LOGP(DLINP, LOGL_DEBUG, - "Excluding BTS(%d) from query.\n", bts->nr); - continue; - } - llist_for_each_entry(trx, &bts->trx_list, list) { - if (trx->mo.nm_state.availability == NM_AVSTATE_OK && - trx->mo.nm_state.operational != NM_OPSTATE_DISABLED) { - send = RF_CMD_ON; - break; - } - } - } - - send_resp(conn, send); -} - -static void rf_check_cb(void *_data) -{ - struct gsm_bts *bts; - struct osmo_bsc_rf *rf = _data; - - llist_for_each_entry(bts, &rf->gsm_network->bts_list, list) { - struct gsm_bts_trx *trx; - - /* don't bother to check a booting or missing BTS */ - if (!bts->oml_link || !is_ipaccess_bts(bts)) - continue; - - /* Exclude the BTS from the global lock */ - if (bts->excl_from_rf_lock) { - LOGP(DLINP, LOGL_DEBUG, - "Excluding BTS(%d) from query.\n", bts->nr); - continue; - } - - llist_for_each_entry(trx, &bts->trx_list, list) { - if (trx->mo.nm_state.availability != NM_AVSTATE_OK || - trx->mo.nm_state.operational != NM_OPSTATE_ENABLED || - trx->mo.nm_state.administrative != NM_STATE_UNLOCKED) { - LOGP(DNM, LOGL_ERROR, "RF activation failed. Starting again.\n"); - ipaccess_drop_oml(bts); - break; - } - } - } -} - -static void send_signal(struct osmo_bsc_rf *rf, int val) -{ - struct rf_signal_data sig; - sig.net = rf->gsm_network; - - rf->policy = val; - osmo_signal_dispatch(SS_RF, val, &sig); -} - -static int switch_rf_off(struct osmo_bsc_rf *rf) -{ - lock_each_trx(rf->gsm_network, 1); - send_signal(rf, S_RF_OFF); - - return 0; -} - -static void grace_timeout(void *_data) -{ - struct osmo_bsc_rf *rf = (struct osmo_bsc_rf *) _data; - - LOGP(DLINP, LOGL_NOTICE, "Grace timeout. Going to disable all BTS/TRX.\n"); - switch_rf_off(rf); -} - -static int enter_grace(struct osmo_bsc_rf *rf) -{ - if (osmo_timer_pending(&rf->grace_timeout)) { - LOGP(DLINP, LOGL_NOTICE, "RF Grace timer is pending. Not restarting.\n"); - return 0; - } - - osmo_timer_setup(&rf->grace_timeout, grace_timeout, rf); - osmo_timer_schedule(&rf->grace_timeout, rf->gsm_network->bsc_data->mid_call_timeout, 0); - LOGP(DLINP, LOGL_NOTICE, "Going to switch RF off in %d seconds.\n", - rf->gsm_network->bsc_data->mid_call_timeout); - - send_signal(rf, S_RF_GRACE); - return 0; -} - -static void rf_delay_cmd_cb(void *data) -{ - struct osmo_bsc_rf *rf = data; - - switch (rf->last_request) { - case RF_CMD_D_OFF: - rf->last_state_command = "RF Direct Off"; - osmo_timer_del(&rf->rf_check); - osmo_timer_del(&rf->grace_timeout); - switch_rf_off(rf); - break; - case RF_CMD_ON: - rf->last_state_command = "RF Direct On"; - osmo_timer_del(&rf->grace_timeout); - lock_each_trx(rf->gsm_network, 0); - send_signal(rf, S_RF_ON); - osmo_timer_schedule(&rf->rf_check, 3, 0); - break; - case RF_CMD_OFF: - rf->last_state_command = "RF Scheduled Off"; - osmo_timer_del(&rf->rf_check); - enter_grace(rf); - break; - } -} - -static int rf_read_cmd(struct osmo_fd *fd) -{ - struct osmo_bsc_rf_conn *conn = fd->data; - char buf[1]; - int rc; - - rc = read(fd->fd, buf, sizeof(buf)); - if (rc != sizeof(buf)) { - LOGP(DLINP, LOGL_ERROR, "Short read %d/%s\n", errno, strerror(errno)); - osmo_fd_unregister(fd); - close(fd->fd); - osmo_wqueue_clear(&conn->queue); - talloc_free(conn); - return -1; - } - - switch (buf[0]) { - case RF_CMD_QUERY: - handle_query(conn); - break; - case RF_CMD_D_OFF: - case RF_CMD_ON: - case RF_CMD_OFF: - osmo_bsc_rf_schedule_lock(conn->rf, buf[0]); - break; - default: - conn->rf->last_state_command = "Unknown command"; - LOGP(DLINP, LOGL_ERROR, "Unknown command %d\n", buf[0]); - break; - } - - return 0; -} - -static int rf_write_cmd(struct osmo_fd *fd, struct msgb *msg) -{ - int rc; - - rc = write(fd->fd, msg->data, msg->len); - if (rc != msg->len) { - LOGP(DLINP, LOGL_ERROR, "Short write %d/%s\n", errno, strerror(errno)); - return -1; - } - - return 0; -} - -static int rf_ctrl_accept(struct osmo_fd *bfd, unsigned int what) -{ - struct osmo_bsc_rf_conn *conn; - struct osmo_bsc_rf *rf = bfd->data; - struct sockaddr_un addr; - socklen_t len = sizeof(addr); - int fd; - - fd = accept(bfd->fd, (struct sockaddr *) &addr, &len); - if (fd < 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to accept. errno: %d/%s\n", - errno, strerror(errno)); - return -1; - } - - conn = talloc_zero(rf, struct osmo_bsc_rf_conn); - if (!conn) { - LOGP(DLINP, LOGL_ERROR, "Failed to allocate mem.\n"); - close(fd); - return -1; - } - - osmo_wqueue_init(&conn->queue, 10); - conn->queue.bfd.data = conn; - conn->queue.bfd.fd = fd; - conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE; - conn->queue.read_cb = rf_read_cmd; - conn->queue.write_cb = rf_write_cmd; - conn->rf = rf; - - if (osmo_fd_register(&conn->queue.bfd) != 0) { - close(fd); - talloc_free(conn); - return -1; - } - - return 0; -} - -static void rf_auto_off_cb(void *_timer) -{ - struct osmo_bsc_rf *rf = _timer; - - LOGP(DLINP, LOGL_NOTICE, - "Going to switch off RF due lack of a MSC connection.\n"); - osmo_bsc_rf_schedule_lock(rf, RF_CMD_D_OFF); -} - -static int msc_signal_handler(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_network *net; - struct msc_signal_data *msc; - struct osmo_bsc_rf *rf; - - /* check if we want to handle this signal */ - if (subsys != SS_MSC) - return 0; - - net = handler_data; - msc = signal_data; - - /* check if we have the needed information */ - if (!net->bsc_data) - return 0; - if (msc->data->type != MSC_CON_TYPE_NORMAL) - return 0; - - rf = net->bsc_data->rf_ctrl; - switch (signal) { - case S_MSC_LOST: - if (net->bsc_data->auto_off_timeout < 0) - return 0; - if (osmo_timer_pending(&rf->auto_off_timer)) - return 0; - osmo_timer_schedule(&rf->auto_off_timer, - net->bsc_data->auto_off_timeout, 0); - break; - case S_MSC_CONNECTED: - osmo_timer_del(&rf->auto_off_timer); - break; - } - - return 0; -} - -static int rf_create_socket(struct osmo_bsc_rf *rf, const char *path) -{ - unsigned int namelen; - struct sockaddr_un local; - struct osmo_fd *bfd; - int rc; - - bfd = &rf->listen; - bfd->fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (bfd->fd < 0) { - LOGP(DLINP, LOGL_ERROR, "Can not create socket. %d/%s\n", - errno, strerror(errno)); - return -1; - } - - local.sun_family = AF_UNIX; - osmo_strlcpy(local.sun_path, path, sizeof(local.sun_path)); - unlink(local.sun_path); - - /* we use the same magic that X11 uses in Xtranssock.c for - * calculating the proper length of the sockaddr */ -#if defined(BSD44SOCKETS) || defined(__UNIXWARE__) - local.sun_len = strlen(local.sun_path); -#endif -#if defined(BSD44SOCKETS) || defined(SUN_LEN) - namelen = SUN_LEN(&local); -#else - namelen = strlen(local.sun_path) + - offsetof(struct sockaddr_un, sun_path); -#endif - - rc = bind(bfd->fd, (struct sockaddr *) &local, namelen); - if (rc != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to bind '%s' errno: %d/%s\n", - local.sun_path, errno, strerror(errno)); - close(bfd->fd); - return -1; - } - - if (listen(bfd->fd, 0) != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to listen: %d/%s\n", errno, strerror(errno)); - close(bfd->fd); - return -1; - } - - bfd->when = BSC_FD_READ; - bfd->cb = rf_ctrl_accept; - bfd->data = rf; - - if (osmo_fd_register(bfd) != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to register bfd.\n"); - close(bfd->fd); - return -1; - } - - return 0; -} - -struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net) -{ - struct osmo_bsc_rf *rf; - - rf = talloc_zero(NULL, struct osmo_bsc_rf); - if (!rf) { - LOGP(DLINP, LOGL_ERROR, "Failed to create osmo_bsc_rf.\n"); - return NULL; - } - - if (path && rf_create_socket(rf, path) != 0) { - talloc_free(rf); - return NULL; - } - - rf->gsm_network = net; - rf->policy = S_RF_ON; - rf->last_state_command = ""; - rf->last_rf_lock_ctrl_command = talloc_strdup(rf, ""); - - /* check the rf state */ - osmo_timer_setup(&rf->rf_check, rf_check_cb, rf); - - /* delay cmd handling */ - osmo_timer_setup(&rf->delay_cmd, rf_delay_cmd_cb, rf); - - osmo_timer_setup(&rf->auto_off_timer, rf_auto_off_cb, rf); - - /* listen to RF signals */ - osmo_signal_register_handler(SS_MSC, msc_signal_handler, net); - - return rf; -} - -void osmo_bsc_rf_schedule_lock(struct osmo_bsc_rf *rf, char cmd) -{ - rf->last_request = cmd; - if (!osmo_timer_pending(&rf->delay_cmd)) - osmo_timer_schedule(&rf->delay_cmd, 1, 0); -} diff --git a/src/libbsc/bsc_rll.c b/src/libbsc/bsc_rll.c deleted file mode 100644 index bb488da15..000000000 --- a/src/libbsc/bsc_rll.c +++ /dev/null @@ -1,139 +0,0 @@ -/* GSM BSC Radio Link Layer API - * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ - -/* (C) 2009 by Harald Welte - * - * 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 . - * - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct bsc_rll_req { - struct llist_head list; - struct osmo_timer_list timer; - - struct gsm_lchan *lchan; - uint8_t link_id; - - void (*cb)(struct gsm_lchan *lchan, uint8_t link_id, - void *data, enum bsc_rllr_ind); - void *data; -}; - -/* we only compare C1, C2 and SAPI */ -#define LINKID_MASK 0xC7 - -static LLIST_HEAD(bsc_rll_reqs); - -static void complete_rllr(struct bsc_rll_req *rllr, enum bsc_rllr_ind type) -{ - llist_del(&rllr->list); - rllr->cb(rllr->lchan, rllr->link_id, rllr->data, type); - talloc_free(rllr); -} - -static void timer_cb(void *_rllr) -{ - struct bsc_rll_req *rllr = _rllr; - - complete_rllr(rllr, BSC_RLLR_IND_TIMEOUT); -} - -/* establish a RLL connection with given SAPI / priority */ -int rll_establish(struct gsm_lchan *lchan, uint8_t sapi, - void (*cb)(struct gsm_lchan *, uint8_t, void *, - enum bsc_rllr_ind), - void *data) -{ - struct bsc_rll_req *rllr = talloc_zero(tall_bsc_ctx, struct bsc_rll_req); - uint8_t link_id; - if (!rllr) - return -ENOMEM; - - link_id = sapi; - - /* If we are a TCH and not in signalling mode, we need to - * indicate that the new RLL connection is to be made on the SACCH */ - if ((lchan->type == GSM_LCHAN_TCH_F || - lchan->type == GSM_LCHAN_TCH_H) && sapi != 0) - link_id |= 0x40; - - rllr->lchan = lchan; - rllr->link_id = link_id; - rllr->cb = cb; - rllr->data = data; - - llist_add(&rllr->list, &bsc_rll_reqs); - - osmo_timer_setup(&rllr->timer, timer_cb, rllr); - osmo_timer_schedule(&rllr->timer, 7, 0); - - /* send the RSL RLL ESTablish REQuest */ - return rsl_establish_request(rllr->lchan, rllr->link_id); -} - -/* Called from RSL code in case we have received an indication regarding - * any RLL link */ -void rll_indication(struct gsm_lchan *lchan, uint8_t link_id, uint8_t type) -{ - struct bsc_rll_req *rllr, *rllr2; - - llist_for_each_entry_safe(rllr, rllr2, &bsc_rll_reqs, list) { - if (rllr->lchan == lchan && - (rllr->link_id & LINKID_MASK) == (link_id & LINKID_MASK)) { - osmo_timer_del(&rllr->timer); - complete_rllr(rllr, type); - return; - } - } -} - -static int rll_lchan_signal(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct challoc_signal_data *challoc; - struct bsc_rll_req *rllr, *rllr2; - - if (subsys != SS_CHALLOC || signal != S_CHALLOC_FREED) - return 0; - - challoc = (struct challoc_signal_data *) signal_data; - - llist_for_each_entry_safe(rllr, rllr2, &bsc_rll_reqs, list) { - if (rllr->lchan == challoc->lchan) { - osmo_timer_del(&rllr->timer); - complete_rllr(rllr, BSC_RLLR_IND_ERR_IND); - } - } - - return 0; -} - -static __attribute__((constructor)) void on_dso_load_rll(void) -{ - osmo_signal_register_handler(SS_CHALLOC, rll_lchan_signal, NULL); -} diff --git a/src/libbsc/bsc_subscriber.c b/src/libbsc/bsc_subscriber.c deleted file mode 100644 index 73e61e801..000000000 --- a/src/libbsc/bsc_subscriber.c +++ /dev/null @@ -1,168 +0,0 @@ -/* GSM subscriber details for use in BSC land */ - -/* - * (C) 2016 by sysmocom s.f.m.c. GmbH - * - * Author: Neels Hofmeyr - * - * 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 . - * - */ - -#include -#include -#include - -#include -#include - -#include -#include - -static struct bsc_subscr *bsc_subscr_alloc(struct llist_head *list) -{ - struct bsc_subscr *bsub; - - bsub = talloc_zero(list, struct bsc_subscr); - if (!bsub) - return NULL; - - llist_add_tail(&bsub->entry, list); - bsub->use_count = 1; - - return bsub; -} - -struct bsc_subscr *bsc_subscr_find_by_imsi(struct llist_head *list, - const char *imsi) -{ - struct bsc_subscr *bsub; - - if (!imsi || !*imsi) - return NULL; - - llist_for_each_entry(bsub, list, entry) { - if (!strcmp(bsub->imsi, imsi)) - return bsc_subscr_get(bsub); - } - return NULL; -} - -struct bsc_subscr *bsc_subscr_find_by_tmsi(struct llist_head *list, - uint32_t tmsi) -{ - struct bsc_subscr *bsub; - - if (tmsi == GSM_RESERVED_TMSI) - return NULL; - - llist_for_each_entry(bsub, list, entry) { - if (bsub->tmsi == tmsi) - return bsc_subscr_get(bsub); - } - return NULL; -} - -void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi) -{ - if (!bsub) - return; - osmo_strlcpy(bsub->imsi, imsi, sizeof(bsub->imsi)); -} - -struct bsc_subscr *bsc_subscr_find_or_create_by_imsi(struct llist_head *list, - const char *imsi) -{ - struct bsc_subscr *bsub; - bsub = bsc_subscr_find_by_imsi(list, imsi); - if (bsub) - return bsub; - bsub = bsc_subscr_alloc(list); - bsc_subscr_set_imsi(bsub, imsi); - return bsub; -} - -struct bsc_subscr *bsc_subscr_find_or_create_by_tmsi(struct llist_head *list, - uint32_t tmsi) -{ - struct bsc_subscr *bsub; - bsub = bsc_subscr_find_by_tmsi(list, tmsi); - if (bsub) - return bsub; - bsub = bsc_subscr_alloc(list); - bsub->tmsi = tmsi; - return bsub; -} - -const char *bsc_subscr_name(struct bsc_subscr *bsub) -{ - static char buf[32]; - if (!bsub) - return "unknown"; - if (bsub->imsi[0]) - snprintf(buf, sizeof(buf), "IMSI:%s", bsub->imsi); - else - snprintf(buf, sizeof(buf), "TMSI:0x%08x", bsub->tmsi); - return buf; -} - -static void bsc_subscr_free(struct bsc_subscr *bsub) -{ - llist_del(&bsub->entry); - talloc_free(bsub); -} - -struct bsc_subscr *_bsc_subscr_get(struct bsc_subscr *bsub, - const char *file, int line) -{ - OSMO_ASSERT(bsub->use_count < INT_MAX); - bsub->use_count++; - LOGPSRC(DREF, LOGL_DEBUG, file, line, - "BSC subscr %s usage increases to: %d\n", - bsc_subscr_name(bsub), bsub->use_count); - return bsub; -} - -struct bsc_subscr *_bsc_subscr_put(struct bsc_subscr *bsub, - const char *file, int line) -{ - bsub->use_count--; - LOGPSRC(DREF, bsub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR, - file, line, - "BSC subscr %s usage decreases to: %d\n", - bsc_subscr_name(bsub), bsub->use_count); - if (bsub->use_count <= 0) - bsc_subscr_free(bsub); - return NULL; -} - -void log_set_filter_bsc_subscr(struct log_target *target, - struct bsc_subscr *bsc_subscr) -{ - struct bsc_subscr **fsub = (void*)&target->filter_data[LOG_FLT_BSC_SUBSCR]; - - /* free the old data */ - if (*fsub) { - bsc_subscr_put(*fsub); - *fsub = NULL; - } - - if (bsc_subscr) { - target->filter_map |= (1 << LOG_FLT_BSC_SUBSCR); - *fsub = bsc_subscr_get(bsc_subscr); - } else - target->filter_map &= ~(1 << LOG_FLT_BSC_SUBSCR); -} diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c deleted file mode 100644 index d55c6eb30..000000000 --- a/src/libbsc/bsc_vty.c +++ /dev/null @@ -1,4412 +0,0 @@ -/* OpenBSC interface to quagga VTY */ -/* (C) 2009-2010 by Harald Welte - * 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 . - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "../../bscconfig.h" - - -#define LCHAN_NR_STR "Logical Channel Number\n" - - -/* FIXME: this should go to some common file */ -static const struct value_string gprs_ns_timer_strs[] = { - { 0, "tns-block" }, - { 1, "tns-block-retries" }, - { 2, "tns-reset" }, - { 3, "tns-reset-retries" }, - { 4, "tns-test" }, - { 5, "tns-alive" }, - { 6, "tns-alive-retries" }, - { 0, NULL } -}; - -static const struct value_string gprs_bssgp_cfg_strs[] = { - { 0, "blocking-timer" }, - { 1, "blocking-retries" }, - { 2, "unblocking-retries" }, - { 3, "reset-timer" }, - { 4, "reset-retries" }, - { 5, "suspend-timer" }, - { 6, "suspend-retries" }, - { 7, "resume-timer" }, - { 8, "resume-retries" }, - { 9, "capability-update-timer" }, - { 10, "capability-update-retries" }, - { 0, NULL } -}; - -static const struct value_string bts_neigh_mode_strs[] = { - { NL_MODE_AUTOMATIC, "automatic" }, - { NL_MODE_MANUAL, "manual" }, - { NL_MODE_MANUAL_SI5SEP, "manual-si5" }, - { 0, NULL } -}; - -const struct value_string bts_loc_fix_names[] = { - { BTS_LOC_FIX_INVALID, "invalid" }, - { BTS_LOC_FIX_2D, "fix2d" }, - { BTS_LOC_FIX_3D, "fix3d" }, - { 0, NULL } -}; - -struct cmd_node bts_node = { - BTS_NODE, - "%s(config-net-bts)# ", - 1, -}; - -struct cmd_node trx_node = { - TRX_NODE, - "%s(config-net-bts-trx)# ", - 1, -}; - -struct cmd_node ts_node = { - TS_NODE, - "%s(config-net-bts-trx-ts)# ", - 1, -}; - -static int dummy_config_write(struct vty *v) -{ - return CMD_SUCCESS; -} - -static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms) -{ - vty_out(vty,"Oper '%s', Admin '%s', Avail '%s'%s", - abis_nm_opstate_name(nms->operational), - get_value_string(abis_nm_adm_state_names, nms->administrative), - abis_nm_avail_name(nms->availability), VTY_NEWLINE); -} - -static void dump_pchan_load_vty(struct vty *vty, char *prefix, - const struct pchan_load *pl) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(pl->pchan); i++) { - const struct load_counter *lc = &pl->pchan[i]; - unsigned int percent; - - if (lc->total == 0) - continue; - - percent = (lc->used * 100) / lc->total; - - vty_out(vty, "%s%20s: %3u%% (%u/%u)%s", prefix, - gsm_pchan_name(i), percent, lc->used, lc->total, - VTY_NEWLINE); - } -} - -static void net_dump_vty(struct vty *vty, struct gsm_network *net) -{ - struct pchan_load pl; - - vty_out(vty, "BSC is on Country Code %u, Network Code %u " - "and has %u BTS%s", net->country_code, net->network_code, - net->num_bts, VTY_NEWLINE); - vty_out(vty, " Long network name: '%s'%s", - net->name_long, VTY_NEWLINE); - vty_out(vty, " Short network name: '%s'%s", - net->name_short, VTY_NEWLINE); - vty_out(vty, " Authentication policy: %s", - gsm_auth_policy_name(net->auth_policy)); - if (net->authorized_reg_str) - vty_out(vty, ", authorized regexp: %s", net->authorized_reg_str); - vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, " Location updating reject cause: %u%s", - net->reject_cause, VTY_NEWLINE); - vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption, - VTY_NEWLINE); - vty_out(vty, " NECI (TCH/H): %u%s", net->neci, - VTY_NEWLINE); - vty_out(vty, " Use TCH for Paging any: %d%s", net->pag_any_tch, - VTY_NEWLINE); - vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode), - VTY_NEWLINE); - vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off", - VTY_NEWLINE); - vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off", - VTY_NEWLINE); - network_chan_load(&pl, net); - vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE); - dump_pchan_load_vty(vty, " ", &pl); - - /* show rf */ - if (net->bsc_data) - vty_out(vty, " Last RF Command: %s%s", - net->bsc_data->rf_ctrl->last_state_command, - VTY_NEWLINE); - if (net->bsc_data) - vty_out(vty, " Last RF Lock Command: %s%s", - net->bsc_data->rf_ctrl->last_rf_lock_ctrl_command, - VTY_NEWLINE); -} - -DEFUN(bsc_show_net, bsc_show_net_cmd, "show network", - SHOW_STR "Display information about a GSM NETWORK\n") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - net_dump_vty(vty, net); - - return CMD_SUCCESS; -} - -static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l) -{ - struct e1inp_line *line; - - if (!e1l) { - vty_out(vty, " None%s", VTY_NEWLINE); - return; - } - - line = e1l->ts->line; - - vty_out(vty, " E1 Line %u, Type %s: Timeslot %u, Mode %s%s", - line->num, line->driver->name, e1l->ts->num, - e1inp_signtype_name(e1l->type), VTY_NEWLINE); - vty_out(vty, " E1 TEI %u, SAPI %u%s", - e1l->tei, e1l->sapi, VTY_NEWLINE); -} - -static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) -{ - struct pchan_load pl; - - vty_out(vty, "BTS %u is of %s type in band %s, has CI %u LAC %u, " - "BSIC %u (NCC=%u, BCC=%u) and %u TRX%s", - bts->nr, btstype2str(bts->type), gsm_band_name(bts->band), - bts->cell_identity, - bts->location_area_code, bts->bsic, - bts->bsic >> 3, bts->bsic & 7, - bts->num_trx, VTY_NEWLINE); - vty_out(vty, "Description: %s%s", - bts->description ? bts->description : "(null)", VTY_NEWLINE); - if (strnlen(bts->pcu_version, MAX_VERSION_LENGTH)) - vty_out(vty, "PCU version %s connected%s", bts->pcu_version, - VTY_NEWLINE); - vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE); - vty_out(vty, "Minimum Rx Level for Access: %i dBm%s", - rxlev2dbm(bts->si_common.cell_sel_par.rxlev_acc_min), - VTY_NEWLINE); - vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s", - bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); - vty_out(vty, "RACH TX-Integer: %u%s", bts->si_common.rach_control.tx_integer, - VTY_NEWLINE); - vty_out(vty, "RACH Max transmissions: %u%s", - rach_max_trans_raw2val(bts->si_common.rach_control.max_trans), - VTY_NEWLINE); - if (bts->si_common.rach_control.cell_bar) - vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); - if (bts->dtxu != GSM48_DTX_SHALL_NOT_BE_USED) - vty_out(vty, "Uplink DTX: %s%s", - (bts->dtxu != GSM48_DTX_SHALL_BE_USED) ? - "enabled" : "forced", VTY_NEWLINE); - else - vty_out(vty, "Uplink DTX: not enabled%s", VTY_NEWLINE); - vty_out(vty, "Downlink DTX: %senabled%s", bts->dtxd ? "" : "not ", - VTY_NEWLINE); - vty_out(vty, "Channel Description Attachment: %s%s", - (bts->si_common.chan_desc.att) ? "yes" : "no", VTY_NEWLINE); - vty_out(vty, "Channel Description BS-PA-MFRMS: %u%s", - bts->si_common.chan_desc.bs_pa_mfrms + 2, VTY_NEWLINE); - vty_out(vty, "Channel Description BS-AG_BLKS-RES: %u%s", - bts->si_common.chan_desc.bs_ag_blks_res, VTY_NEWLINE); - vty_out(vty, "System Information present: 0x%08x, static: 0x%08x%s", - bts->si_valid, bts->si_mode_static, VTY_NEWLINE); - vty_out(vty, "Early Classmark Sending: %s%s", - bts->early_classmark_allowed ? "allowed" : "forbidden", - VTY_NEWLINE); - if (bts->pcu_sock_path) - vty_out(vty, "PCU Socket Path: %s%s", bts->pcu_sock_path, VTY_NEWLINE); - if (is_ipaccess_bts(bts)) - vty_out(vty, " Unit ID: %u/%u/0, OML Stream ID 0x%02x%s", - bts->ip_access.site_id, bts->ip_access.bts_id, - bts->oml_tei, VTY_NEWLINE); - else if (bts->type == GSM_BTS_TYPE_NOKIA_SITE) - vty_out(vty, " Skip Reset: %d%s", - bts->nokia.skip_reset, VTY_NEWLINE); - vty_out(vty, " NM State: "); - net_dump_nmstate(vty, &bts->mo.nm_state); - vty_out(vty, " Site Mgr NM State: "); - net_dump_nmstate(vty, &bts->site_mgr.mo.nm_state); - vty_out(vty, " GPRS NSE: "); - net_dump_nmstate(vty, &bts->gprs.nse.mo.nm_state); - vty_out(vty, " GPRS CELL: "); - net_dump_nmstate(vty, &bts->gprs.cell.mo.nm_state); - vty_out(vty, " GPRS NSVC0: "); - net_dump_nmstate(vty, &bts->gprs.nsvc[0].mo.nm_state); - vty_out(vty, " GPRS NSVC1: "); - net_dump_nmstate(vty, &bts->gprs.nsvc[1].mo.nm_state); - vty_out(vty, " Paging: %u pending requests, %u free slots%s", - paging_pending_requests_nr(bts), - bts->paging.available_slots, VTY_NEWLINE); - if (is_ipaccess_bts(bts)) { - vty_out(vty, " OML Link state: %s.%s", - bts->oml_link ? "connected" : "disconnected", VTY_NEWLINE); - } else { - vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); - e1isl_dump_vty(vty, bts->oml_link); - } - - /* FIXME: chan_desc */ - memset(&pl, 0, sizeof(pl)); - bts_chan_load(&pl, bts); - vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE); - dump_pchan_load_vty(vty, " ", &pl); -} - -DEFUN(show_bts, show_bts_cmd, "show bts [<0-255>]", - SHOW_STR "Display information about a BTS\n" - "BTS number") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - int bts_nr; - - if (argc != 0) { - /* use the BTS number that the user has specified */ - bts_nr = atoi(argv[0]); - if (bts_nr >= net->num_bts) { - vty_out(vty, "%% can't find BTS '%s'%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - bts_dump_vty(vty, gsm_bts_num(net, bts_nr)); - return CMD_SUCCESS; - } - /* print all BTS's */ - for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) - bts_dump_vty(vty, gsm_bts_num(net, bts_nr)); - - return CMD_SUCCESS; -} - -/* utility functions */ -static void parse_e1_link(struct gsm_e1_subslot *e1_link, const char *line, - const char *ts, const char *ss) -{ - e1_link->e1_nr = atoi(line); - e1_link->e1_ts = atoi(ts); - if (!strcmp(ss, "full")) - e1_link->e1_ts_ss = 255; - else - e1_link->e1_ts_ss = atoi(ss); -} - -static void config_write_e1_link(struct vty *vty, struct gsm_e1_subslot *e1_link, - const char *prefix) -{ - if (!e1_link->e1_ts) - return; - - if (e1_link->e1_ts_ss == 255) - vty_out(vty, "%se1 line %u timeslot %u sub-slot full%s", - prefix, e1_link->e1_nr, e1_link->e1_ts, VTY_NEWLINE); - else - vty_out(vty, "%se1 line %u timeslot %u sub-slot %u%s", - prefix, e1_link->e1_nr, e1_link->e1_ts, - e1_link->e1_ts_ss, VTY_NEWLINE); -} - - -static void config_write_ts_single(struct vty *vty, struct gsm_bts_trx_ts *ts) -{ - vty_out(vty, " timeslot %u%s", ts->nr, VTY_NEWLINE); - if (ts->tsc != -1) - vty_out(vty, " training_sequence_code %u%s", ts->tsc, VTY_NEWLINE); - if (ts->pchan != GSM_PCHAN_NONE) - vty_out(vty, " phys_chan_config %s%s", - gsm_pchan_name(ts->pchan), VTY_NEWLINE); - vty_out(vty, " hopping enabled %u%s", - ts->hopping.enabled, VTY_NEWLINE); - if (ts->hopping.enabled) { - unsigned int i; - vty_out(vty, " hopping sequence-number %u%s", - ts->hopping.hsn, VTY_NEWLINE); - vty_out(vty, " hopping maio %u%s", - ts->hopping.maio, VTY_NEWLINE); - for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) { - if (!bitvec_get_bit_pos(&ts->hopping.arfcns, i)) - continue; - vty_out(vty, " hopping arfcn add %u%s", - i, VTY_NEWLINE); - } - } - config_write_e1_link(vty, &ts->e1_link, " "); - - if (ts->trx->bts->model->config_write_ts) - ts->trx->bts->model->config_write_ts(vty, ts); -} - -static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx) -{ - int i; - - vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE); - if (trx->description) - vty_out(vty, " description %s%s", trx->description, - VTY_NEWLINE); - vty_out(vty, " rf_locked %u%s", - trx->mo.nm_state.administrative == NM_STATE_LOCKED ? 1 : 0, - VTY_NEWLINE); - vty_out(vty, " arfcn %u%s", trx->arfcn, VTY_NEWLINE); - vty_out(vty, " nominal power %u%s", trx->nominal_power, VTY_NEWLINE); - vty_out(vty, " max_power_red %u%s", trx->max_power_red, VTY_NEWLINE); - config_write_e1_link(vty, &trx->rsl_e1_link, " rsl "); - vty_out(vty, " rsl e1 tei %u%s", trx->rsl_tei, VTY_NEWLINE); - - if (trx->bts->model->config_write_trx) - trx->bts->model->config_write_trx(vty, trx); - - for (i = 0; i < TRX_NR_TS; i++) - config_write_ts_single(vty, &trx->ts[i]); -} - -static void config_write_bts_gprs(struct vty *vty, struct gsm_bts *bts) -{ - unsigned int i; - vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode), - VTY_NEWLINE); - if (bts->gprs.mode == BTS_GPRS_NONE) - return; - - vty_out(vty, " gprs 11bit_rach_support_for_egprs %u%s", - bts->gprs.supports_egprs_11bit_rach, VTY_NEWLINE); - - vty_out(vty, " gprs routing area %u%s", bts->gprs.rac, - VTY_NEWLINE); - vty_out(vty, " gprs network-control-order nc%u%s", - bts->gprs.net_ctrl_ord, VTY_NEWLINE); - if (!bts->gprs.ctrl_ack_type_use_block) - vty_out(vty, " gprs control-ack-type-rach%s", VTY_NEWLINE); - vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci, - VTY_NEWLINE); - for (i = 0; i < ARRAY_SIZE(bts->gprs.cell.timer); i++) - vty_out(vty, " gprs cell timer %s %u%s", - get_value_string(gprs_bssgp_cfg_strs, i), - bts->gprs.cell.timer[i], VTY_NEWLINE); - vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei, - VTY_NEWLINE); - for (i = 0; i < ARRAY_SIZE(bts->gprs.nse.timer); i++) - vty_out(vty, " gprs ns timer %s %u%s", - get_value_string(gprs_ns_timer_strs, i), - bts->gprs.nse.timer[i], VTY_NEWLINE); - for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { - struct gsm_bts_gprs_nsvc *nsvc = - &bts->gprs.nsvc[i]; - struct in_addr ia; - - ia.s_addr = htonl(nsvc->remote_ip); - vty_out(vty, " gprs nsvc %u nsvci %u%s", i, - nsvc->nsvci, VTY_NEWLINE); - vty_out(vty, " gprs nsvc %u local udp port %u%s", i, - nsvc->local_port, VTY_NEWLINE); - vty_out(vty, " gprs nsvc %u remote udp port %u%s", i, - nsvc->remote_port, VTY_NEWLINE); - vty_out(vty, " gprs nsvc %u remote ip %s%s", i, - inet_ntoa(ia), VTY_NEWLINE); - } -} - -/* Write the model data if there is one */ -static void config_write_bts_model(struct vty *vty, struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - - if (!bts->model) - return; - - if (bts->model->config_write_bts) - bts->model->config_write_bts(vty, bts); - - llist_for_each_entry(trx, &bts->trx_list, list) - config_write_trx_single(vty, trx); -} - -static void write_amr_modes(struct vty *vty, const char *prefix, - const char *name, struct amr_mode *modes, int num) -{ - int i; - - vty_out(vty, " %s threshold %s", prefix, name); - for (i = 0; i < num - 1; i++) - vty_out(vty, " %d", modes[i].threshold); - vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, " %s hysteresis %s", prefix, name); - for (i = 0; i < num - 1; i++) - vty_out(vty, " %d", modes[i].hysteresis); - vty_out(vty, "%s", VTY_NEWLINE); -} - -static void config_write_bts_amr(struct vty *vty, struct gsm_bts *bts, - struct amr_multirate_conf *mr, int full) -{ - struct gsm48_multi_rate_conf *mr_conf; - const char *prefix = (full) ? "amr tch-f" : "amr tch-h"; - int i, num; - - if (!(mr->gsm48_ie[1])) - return; - - mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie; - - num = 0; - vty_out(vty, " %s modes", prefix); - for (i = 0; i < ((full) ? 8 : 6); i++) { - if ((mr->gsm48_ie[1] & (1 << i))) { - vty_out(vty, " %d", i); - num++; - } - } - vty_out(vty, "%s", VTY_NEWLINE); - if (num > 4) - num = 4; - if (num > 1) { - write_amr_modes(vty, prefix, "ms", mr->ms_mode, num); - write_amr_modes(vty, prefix, "bts", mr->bts_mode, num); - } - vty_out(vty, " %s start-mode ", prefix); - if (mr_conf->icmi) { - num = 0; - for (i = 0; i < ((full) ? 8 : 6) && num < 4; i++) { - if ((mr->gsm48_ie[1] & (1 << i))) - num++; - if (mr_conf->smod == num - 1) { - vty_out(vty, "%d%s", num, VTY_NEWLINE); - break; - } - } - } else - vty_out(vty, "auto%s", VTY_NEWLINE); -} - -static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) -{ - int i; - uint8_t tmp; - - vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE); - vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE); - if (bts->description) - vty_out(vty, " description %s%s", bts->description, VTY_NEWLINE); - vty_out(vty, " band %s%s", gsm_band_name(bts->band), VTY_NEWLINE); - vty_out(vty, " cell_identity %u%s", bts->cell_identity, VTY_NEWLINE); - vty_out(vty, " location_area_code %u%s", bts->location_area_code, - VTY_NEWLINE); - if (bts->dtxu != GSM48_DTX_SHALL_NOT_BE_USED) - vty_out(vty, " dtx uplink%s%s", - (bts->dtxu != GSM48_DTX_SHALL_BE_USED) ? "" : " force", - VTY_NEWLINE); - if (bts->dtxd) - vty_out(vty, " dtx downlink%s", VTY_NEWLINE); - vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE); - vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE); - vty_out(vty, " cell reselection hysteresis %u%s", - bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE); - vty_out(vty, " rxlev access min %u%s", - bts->si_common.cell_sel_par.rxlev_acc_min, VTY_NEWLINE); - - if (bts->si_common.cell_ro_sel_par.present) { - struct gsm48_si_selection_params *sp; - sp = &bts->si_common.cell_ro_sel_par; - - if (sp->cbq) - vty_out(vty, " cell bar qualify %u%s", - sp->cbq, VTY_NEWLINE); - - if (sp->cell_resel_off) - vty_out(vty, " cell reselection offset %u%s", - sp->cell_resel_off*2, VTY_NEWLINE); - - if (sp->temp_offs == 7) - vty_out(vty, " temporary offset infinite%s", - VTY_NEWLINE); - else if (sp->temp_offs) - vty_out(vty, " temporary offset %u%s", - sp->temp_offs*10, VTY_NEWLINE); - - if (sp->penalty_time == 31) - vty_out(vty, " penalty time reserved%s", - VTY_NEWLINE); - else if (sp->penalty_time) - vty_out(vty, " penalty time %u%s", - (sp->penalty_time*20)+20, VTY_NEWLINE); - } - - if (gsm_bts_get_radio_link_timeout(bts) < 0) - vty_out(vty, " radio-link-timeout infinite%s", VTY_NEWLINE); - else - vty_out(vty, " radio-link-timeout %d%s", - gsm_bts_get_radio_link_timeout(bts), VTY_NEWLINE); - - vty_out(vty, " channel allocator %s%s", - bts->chan_alloc_reverse ? "descending" : "ascending", - VTY_NEWLINE); - vty_out(vty, " rach tx integer %u%s", - bts->si_common.rach_control.tx_integer, VTY_NEWLINE); - vty_out(vty, " rach max transmission %u%s", - rach_max_trans_raw2val(bts->si_common.rach_control.max_trans), - VTY_NEWLINE); - - vty_out(vty, " channel-descrption attach %u%s", - bts->si_common.chan_desc.att, VTY_NEWLINE); - vty_out(vty, " channel-descrption bs-pa-mfrms %u%s", - bts->si_common.chan_desc.bs_pa_mfrms + 2, VTY_NEWLINE); - vty_out(vty, " channel-descrption bs-ag-blks-res %u%s", - bts->si_common.chan_desc.bs_ag_blks_res, VTY_NEWLINE); - - if (bts->rach_b_thresh != -1) - vty_out(vty, " rach nm busy threshold %u%s", - bts->rach_b_thresh, VTY_NEWLINE); - if (bts->rach_ldavg_slots != -1) - vty_out(vty, " rach nm load average %u%s", - bts->rach_ldavg_slots, VTY_NEWLINE); - if (bts->si_common.rach_control.cell_bar) - vty_out(vty, " cell barred 1%s", VTY_NEWLINE); - if ((bts->si_common.rach_control.t2 & 0x4) == 0) - vty_out(vty, " rach emergency call allowed 1%s", VTY_NEWLINE); - if ((bts->si_common.rach_control.t3) != 0) - for (i = 0; i < 8; i++) - if (bts->si_common.rach_control.t3 & (0x1 << i)) - vty_out(vty, " rach access-control-class %d barred%s", i, VTY_NEWLINE); - if ((bts->si_common.rach_control.t2 & 0xfb) != 0) - for (i = 0; i < 8; i++) - if ((i != 2) && (bts->si_common.rach_control.t2 & (0x1 << i))) - vty_out(vty, " rach access-control-class %d barred%s", i+8, VTY_NEWLINE); - for (i = SYSINFO_TYPE_1; i < _MAX_SYSINFO_TYPE; i++) { - if (bts->si_mode_static & (1 << i)) { - vty_out(vty, " system-information %s mode static%s", - get_value_string(osmo_sitype_strs, i), VTY_NEWLINE); - vty_out(vty, " system-information %s static %s%s", - get_value_string(osmo_sitype_strs, i), - osmo_hexdump_nospc(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN), - VTY_NEWLINE); - } - } - vty_out(vty, " early-classmark-sending %s%s", - bts->early_classmark_allowed ? "allowed" : "forbidden", VTY_NEWLINE); - switch (bts->type) { - case GSM_BTS_TYPE_NANOBTS: - case GSM_BTS_TYPE_OSMOBTS: - vty_out(vty, " ip.access unit_id %u %u%s", - bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE); - if (bts->ip_access.rsl_ip) { - struct in_addr ia; - ia.s_addr = htonl(bts->ip_access.rsl_ip); - vty_out(vty, " ip.access rsl-ip %s%s", inet_ntoa(ia), - VTY_NEWLINE); - } - vty_out(vty, " oml ip.access stream_id %u line %u%s", - bts->oml_tei, bts->oml_e1_link.e1_nr, VTY_NEWLINE); - break; - case GSM_BTS_TYPE_NOKIA_SITE: - vty_out(vty, " nokia_site skip-reset %d%s", bts->nokia.skip_reset, VTY_NEWLINE); - vty_out(vty, " nokia_site no-local-rel-conf %d%s", - bts->nokia.no_loc_rel_cnf, VTY_NEWLINE); - vty_out(vty, " nokia_site bts-reset-timer %d%s", bts->nokia.bts_reset_timer_cnf, VTY_NEWLINE); - /* fall through: Nokia requires "oml e1" parameters also */ - default: - config_write_e1_link(vty, &bts->oml_e1_link, " oml "); - vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE); - break; - } - - /* if we have a limit, write it */ - if (bts->paging.free_chans_need >= 0) - vty_out(vty, " paging free %d%s", bts->paging.free_chans_need, VTY_NEWLINE); - - vty_out(vty, " neighbor-list mode %s%s", - get_value_string(bts_neigh_mode_strs, bts->neigh_list_manual_mode), VTY_NEWLINE); - if (bts->neigh_list_manual_mode != NL_MODE_AUTOMATIC) { - for (i = 0; i < 1024; i++) { - if (bitvec_get_bit_pos(&bts->si_common.neigh_list, i)) - vty_out(vty, " neighbor-list add arfcn %u%s", - i, VTY_NEWLINE); - } - } - if (bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP) { - for (i = 0; i < 1024; i++) { - if (bitvec_get_bit_pos(&bts->si_common.si5_neigh_list, i)) - vty_out(vty, " si5 neighbor-list add arfcn %u%s", - i, VTY_NEWLINE); - } - } - - for (i = 0; i < MAX_EARFCN_LIST; i++) { - struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; - if (e->arfcn[i] != OSMO_EARFCN_INVALID) { - vty_out(vty, " si2quater neighbor-list add earfcn %u " - "thresh-hi %u", e->arfcn[i], e->thresh_hi); - - vty_out(vty, " thresh-lo %u", - e->thresh_lo_valid ? e->thresh_lo : 32); - - vty_out(vty, " prio %u", - e->prio_valid ? e->prio : 8); - - vty_out(vty, " qrxlv %u", - e->qrxlm_valid ? e->qrxlm : 32); - - tmp = e->meas_bw[i]; - vty_out(vty, " meas %u", - (tmp != OSMO_EARFCN_MEAS_INVALID) ? tmp : 8); - - vty_out(vty, "%s", VTY_NEWLINE); - } - } - - for (i = 0; i < bts->si_common.uarfcn_length; i++) { - vty_out(vty, " si2quater neighbor-list add uarfcn %u %u %u%s", - bts->si_common.data.uarfcn_list[i], - bts->si_common.data.scramble_list[i] & ~(1 << 9), - (bts->si_common.data.scramble_list[i] >> 9) & 1, - VTY_NEWLINE); - } - - vty_out(vty, " codec-support fr"); - if (bts->codec.hr) - vty_out(vty, " hr"); - if (bts->codec.efr) - vty_out(vty, " efr"); - if (bts->codec.amr) - vty_out(vty, " amr"); - vty_out(vty, "%s", VTY_NEWLINE); - - config_write_bts_amr(vty, bts, &bts->mr_full, 1); - config_write_bts_amr(vty, bts, &bts->mr_half, 0); - - config_write_bts_gprs(vty, bts); - - if (bts->excl_from_rf_lock) - vty_out(vty, " rf-lock-exclude%s", VTY_NEWLINE); - - vty_out(vty, " %sforce-combined-si%s", - bts->force_combined_si ? "" : "no ", VTY_NEWLINE); - - for (i = 0; i < ARRAY_SIZE(bts->depends_on); ++i) { - int j; - - if (bts->depends_on[i] == 0) - continue; - - for (j = 0; j < sizeof(bts->depends_on[i]) * 8; ++j) { - int bts_nr; - - if ((bts->depends_on[i] & (1<depends_on[i]) * 8) + j; - vty_out(vty, " depends-on-bts %d%s", bts_nr, VTY_NEWLINE); - } - } - if (bts->pcu_sock_path) - vty_out(vty, " pcu-socket %s%s", bts->pcu_sock_path, VTY_NEWLINE); - - config_write_bts_model(vty, bts); -} - -static int config_write_bts(struct vty *v) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(v); - struct gsm_bts *bts; - - llist_for_each_entry(bts, &gsmnet->bts_list, list) - config_write_bts_single(v, bts); - - return CMD_SUCCESS; -} - -/* small helper macro for conditional dumping of timer */ -#define VTY_OUT_TIMER(number) \ - if (gsmnet->T##number != GSM_T##number##_DEFAULT) \ - vty_out(vty, " timer t"#number" %u%s", gsmnet->T##number, VTY_NEWLINE) - -static int config_write_net(struct vty *vty) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - - vty_out(vty, "network%s", VTY_NEWLINE); - vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE); - vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE); - vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE); - vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE); - vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); - if (gsmnet->authorized_reg_str) - vty_out(vty, " authorized-regexp %s%s", gsmnet->authorized_reg_str, VTY_NEWLINE); - vty_out(vty, " location updating reject cause %u%s", - gsmnet->reject_cause, VTY_NEWLINE); - vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); - vty_out(vty, " authentication %s%s", - gsmnet->authentication_required ? "required" : "optional", - VTY_NEWLINE); - vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); - vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE); - vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), - VTY_NEWLINE); - vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE); - vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE); - vty_out(vty, " handover window rxlev averaging %u%s", - gsmnet->handover.win_rxlev_avg, VTY_NEWLINE); - vty_out(vty, " handover window rxqual averaging %u%s", - gsmnet->handover.win_rxqual_avg, VTY_NEWLINE); - vty_out(vty, " handover window rxlev neighbor averaging %u%s", - gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE); - vty_out(vty, " handover power budget interval %u%s", - gsmnet->handover.pwr_interval, VTY_NEWLINE); - vty_out(vty, " handover power budget hysteresis %u%s", - gsmnet->handover.pwr_hysteresis, VTY_NEWLINE); - vty_out(vty, " handover maximum distance %u%s", - gsmnet->handover.max_distance, VTY_NEWLINE); - VTY_OUT_TIMER(3101); - VTY_OUT_TIMER(3103); - VTY_OUT_TIMER(3105); - VTY_OUT_TIMER(3107); - VTY_OUT_TIMER(3109); - VTY_OUT_TIMER(3111); - VTY_OUT_TIMER(3113); - VTY_OUT_TIMER(3115); - VTY_OUT_TIMER(3117); - VTY_OUT_TIMER(3119); - VTY_OUT_TIMER(3122); - VTY_OUT_TIMER(3141); - vty_out(vty, " dyn_ts_allow_tch_f %d%s", - gsmnet->dyn_ts_allow_tch_f ? 1 : 0, VTY_NEWLINE); - if (gsmnet->tz.override != 0) { - if (gsmnet->tz.dst) - vty_out(vty, " timezone %d %d %d%s", - gsmnet->tz.hr, gsmnet->tz.mn, gsmnet->tz.dst, - VTY_NEWLINE); - else - vty_out(vty, " timezone %d %d%s", - gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE); - } - if (gsmnet->t3212 == 0) - vty_out(vty, " no periodic location update%s", VTY_NEWLINE); - else - vty_out(vty, " periodic location update %u%s", - gsmnet->t3212 * 6, VTY_NEWLINE); - - return CMD_SUCCESS; -} - -static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx) -{ - vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s", - trx->nr, trx->bts->nr, trx->arfcn, VTY_NEWLINE); - vty_out(vty, "Description: %s%s", - trx->description ? trx->description : "(null)", VTY_NEWLINE); - vty_out(vty, " RF Nominal Power: %d dBm, reduced by %u dB, " - "resulting BS power: %d dBm%s", - trx->nominal_power, trx->max_power_red, - trx->nominal_power - trx->max_power_red, VTY_NEWLINE); - vty_out(vty, " NM State: "); - net_dump_nmstate(vty, &trx->mo.nm_state); - vty_out(vty, " Baseband Transceiver NM State: "); - net_dump_nmstate(vty, &trx->bb_transc.mo.nm_state); - if (is_ipaccess_bts(trx->bts)) { - vty_out(vty, " ip.access stream ID: 0x%02x%s", - trx->rsl_tei, VTY_NEWLINE); - } else { - vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); - e1isl_dump_vty(vty, trx->rsl_link); - } -} - -DEFUN(show_trx, - show_trx_cmd, - "show trx [<0-255>] [<0-255>]", - SHOW_STR "Display information about a TRX\n" - "BTS Number\n" - "TRX Number\n") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - struct gsm_bts *bts = NULL; - struct gsm_bts_trx *trx; - int bts_nr, trx_nr; - - if (argc >= 1) { - /* use the BTS number that the user has specified */ - bts_nr = atoi(argv[0]); - if (bts_nr >= net->num_bts) { - vty_out(vty, "%% can't find BTS '%s'%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - bts = gsm_bts_num(net, bts_nr); - } - if (argc >= 2) { - trx_nr = atoi(argv[1]); - if (trx_nr >= bts->num_trx) { - vty_out(vty, "%% can't find TRX '%s'%s", argv[1], - VTY_NEWLINE); - return CMD_WARNING; - } - trx = gsm_bts_trx_num(bts, trx_nr); - trx_dump_vty(vty, trx); - return CMD_SUCCESS; - } - if (bts) { - /* print all TRX in this BTS */ - for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) { - trx = gsm_bts_trx_num(bts, trx_nr); - trx_dump_vty(vty, trx); - } - return CMD_SUCCESS; - } - - for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) { - bts = gsm_bts_num(net, bts_nr); - for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) { - trx = gsm_bts_trx_num(bts, trx_nr); - trx_dump_vty(vty, trx); - } - } - - return CMD_SUCCESS; -} - - -static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts) -{ - vty_out(vty, "BTS %u, TRX %u, Timeslot %u, phys cfg %s, TSC %u", - ts->trx->bts->nr, ts->trx->nr, ts->nr, - gsm_pchan_name(ts->pchan), gsm_ts_tsc(ts)); - if (ts->pchan == GSM_PCHAN_TCH_F_PDCH) - vty_out(vty, " (%s mode)", - ts->flags & TS_F_PDCH_ACTIVE ? "PDCH" : "TCH/F"); - vty_out(vty, "%s", VTY_NEWLINE); - vty_out(vty, " NM State: "); - net_dump_nmstate(vty, &ts->mo.nm_state); - if (!is_ipaccess_bts(ts->trx->bts)) - vty_out(vty, " E1 Line %u, Timeslot %u, Subslot %u%s", - ts->e1_link.e1_nr, ts->e1_link.e1_ts, - ts->e1_link.e1_ts_ss, VTY_NEWLINE); -} - -DEFUN(show_ts, - show_ts_cmd, - "show timeslot [<0-255>] [<0-255>] [<0-7>]", - SHOW_STR "Display information about a TS\n" - "BTS Number\n" "TRX Number\n" "Timeslot Number\n") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - struct gsm_bts *bts = NULL; - struct gsm_bts_trx *trx = NULL; - struct gsm_bts_trx_ts *ts = NULL; - int bts_nr, trx_nr, ts_nr; - - if (argc >= 1) { - /* use the BTS number that the user has specified */ - bts_nr = atoi(argv[0]); - if (bts_nr >= net->num_bts) { - vty_out(vty, "%% can't find BTS '%s'%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - bts = gsm_bts_num(net, bts_nr); - } - if (argc >= 2) { - trx_nr = atoi(argv[1]); - if (trx_nr >= bts->num_trx) { - vty_out(vty, "%% can't find TRX '%s'%s", argv[1], - VTY_NEWLINE); - return CMD_WARNING; - } - trx = gsm_bts_trx_num(bts, trx_nr); - } - if (argc >= 3) { - ts_nr = atoi(argv[2]); - if (ts_nr >= TRX_NR_TS) { - vty_out(vty, "%% can't find TS '%s'%s", argv[2], - VTY_NEWLINE); - return CMD_WARNING; - } - /* Fully Specified: print and exit */ - ts = &trx->ts[ts_nr]; - ts_dump_vty(vty, ts); - return CMD_SUCCESS; - } - - if (bts && trx) { - /* Iterate over all TS in this TRX */ - for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) { - ts = &trx->ts[ts_nr]; - ts_dump_vty(vty, ts); - } - } else if (bts) { - /* Iterate over all TRX in this BTS, TS in each TRX */ - for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) { - trx = gsm_bts_trx_num(bts, trx_nr); - for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) { - ts = &trx->ts[ts_nr]; - ts_dump_vty(vty, ts); - } - } - } else { - /* Iterate over all BTS, TRX in each BTS, TS in each TRX */ - for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) { - bts = gsm_bts_num(net, bts_nr); - for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) { - trx = gsm_bts_trx_num(bts, trx_nr); - for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) { - ts = &trx->ts[ts_nr]; - ts_dump_vty(vty, ts); - } - } - } - } - - return CMD_SUCCESS; -} - -static void subscr_dump_vty(struct vty *vty, struct vlr_subscr *vsub) -{ - OSMO_ASSERT(vsub); - if (strlen(vsub->name)) - vty_out(vty, " Name: '%s'%s", vsub->name, VTY_NEWLINE); - if (strlen(vsub->msisdn)) - vty_out(vty, " Extension: %s%s", vsub->msisdn, - VTY_NEWLINE); - if (strlen(vsub->imsi)) - vty_out(vty, " IMSI: %s%s", vsub->imsi, VTY_NEWLINE); - if (vsub->tmsi != GSM_RESERVED_TMSI) - vty_out(vty, " TMSI: %08X%s", vsub->tmsi, - VTY_NEWLINE); - if (vsub->tmsi_new != GSM_RESERVED_TMSI) - vty_out(vty, " new TMSI: %08X%s", vsub->tmsi_new, - VTY_NEWLINE); - - vty_out(vty, " Use count: %u%s", vsub->use_count, VTY_NEWLINE); -} - -static void bsc_subscr_dump_vty(struct vty *vty, struct bsc_subscr *bsub) -{ - if (strlen(bsub->imsi)) - vty_out(vty, " IMSI: %s%s", bsub->imsi, VTY_NEWLINE); - if (bsub->tmsi != GSM_RESERVED_TMSI) - vty_out(vty, " TMSI: 0x%08x%s", bsub->tmsi, - VTY_NEWLINE); - vty_out(vty, " Use count: %d%s", bsub->use_count, VTY_NEWLINE); -} - -static void meas_rep_dump_uni_vty(struct vty *vty, - struct gsm_meas_rep_unidir *mru, - const char *prefix, - const char *dir) -{ - vty_out(vty, "%s RXL-FULL-%s: %4d dBm, RXL-SUB-%s: %4d dBm ", - prefix, dir, rxlev2dbm(mru->full.rx_lev), - dir, rxlev2dbm(mru->sub.rx_lev)); - vty_out(vty, "RXQ-FULL-%s: %d, RXQ-SUB-%s: %d%s", - dir, mru->full.rx_qual, dir, mru->sub.rx_qual, - VTY_NEWLINE); -} - -static void meas_rep_dump_vty(struct vty *vty, struct gsm_meas_rep *mr, - const char *prefix) -{ - vty_out(vty, "%sMeasurement Report:%s", prefix, VTY_NEWLINE); - vty_out(vty, "%s Flags: %s%s%s%s%s", prefix, - mr->flags & MEAS_REP_F_UL_DTX ? "DTXu " : "", - mr->flags & MEAS_REP_F_DL_DTX ? "DTXd " : "", - mr->flags & MEAS_REP_F_FPC ? "FPC " : "", - mr->flags & MEAS_REP_F_DL_VALID ? " " : "DLinval ", - VTY_NEWLINE); - if (mr->flags & MEAS_REP_F_MS_TO) - vty_out(vty, "%s MS Timing Offset: %d%s", prefix, mr->ms_timing_offset, VTY_NEWLINE); - if (mr->flags & MEAS_REP_F_MS_L1) - vty_out(vty, "%s L1 MS Power: %u dBm, Timing Advance: %u%s", - prefix, mr->ms_l1.pwr, mr->ms_l1.ta, VTY_NEWLINE); - if (mr->flags & MEAS_REP_F_DL_VALID) - meas_rep_dump_uni_vty(vty, &mr->dl, prefix, "dl"); - meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul"); -} - -/* FIXME: move this to libosmogsm */ -static const struct value_string gsm48_cmode_names[] = { - { GSM48_CMODE_SIGN, "signalling" }, - { GSM48_CMODE_SPEECH_V1, "FR or HR" }, - { GSM48_CMODE_SPEECH_EFR, "EFR" }, - { GSM48_CMODE_SPEECH_AMR, "AMR" }, - { GSM48_CMODE_DATA_14k5, "CSD(14k5)" }, - { GSM48_CMODE_DATA_12k0, "CSD(12k0)" }, - { GSM48_CMODE_DATA_6k0, "CSD(6k0)" }, - { GSM48_CMODE_DATA_3k6, "CSD(3k6)" }, - { 0, NULL } -}; - -/* call vty_out() to print a string like " as TCH/H" for dynamic timeslots. - * Don't do anything if the ts is not dynamic. */ -static void vty_out_dyn_ts_status(struct vty *vty, struct gsm_bts_trx_ts *ts) -{ - switch (ts->pchan) { - case GSM_PCHAN_TCH_F_TCH_H_PDCH: - if (ts->dyn.pchan_is == ts->dyn.pchan_want) - vty_out(vty, " as %s", - gsm_pchan_name(ts->dyn.pchan_is)); - else - vty_out(vty, " switching %s -> %s", - gsm_pchan_name(ts->dyn.pchan_is), - gsm_pchan_name(ts->dyn.pchan_want)); - break; - case GSM_PCHAN_TCH_F_PDCH: - if ((ts->flags & TS_F_PDCH_PENDING_MASK) == 0) - vty_out(vty, " as %s", - (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH" - : "TCH/F"); - else - vty_out(vty, " switching %s -> %s", - (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH" - : "TCH/F", - (ts->flags & TS_F_PDCH_ACT_PENDING)? "PDCH" - : "TCH/F"); - break; - default: - /* no dyn ts */ - break; - } -} - -static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan) -{ - int idx; - - vty_out(vty, "BTS %u, TRX %u, Timeslot %u, Lchan %u: Type %s%s", - lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, - lchan->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE); - /* show dyn TS details, if applicable */ - switch (lchan->ts->pchan) { - case GSM_PCHAN_TCH_F_TCH_H_PDCH: - vty_out(vty, " Osmocom Dyn TS:"); - vty_out_dyn_ts_status(vty, lchan->ts); - vty_out(vty, VTY_NEWLINE); - break; - case GSM_PCHAN_TCH_F_PDCH: - vty_out(vty, " IPACC Dyn PDCH TS:"); - vty_out_dyn_ts_status(vty, lchan->ts); - vty_out(vty, VTY_NEWLINE); - break; - default: - /* no dyn ts */ - break; - } - vty_out(vty, " Connection: %u, State: %s%s%s%s", - lchan->conn ? 1: 0, - gsm_lchans_name(lchan->state), - lchan->state == LCHAN_S_BROKEN ? " Error reason: " : "", - lchan->state == LCHAN_S_BROKEN ? lchan->broken_reason : "", - VTY_NEWLINE); - vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s", - lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red - - lchan->bs_power*2, - ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power), - VTY_NEWLINE); - vty_out(vty, " Channel Mode / Codec: %s%s", - get_value_string(gsm48_cmode_names, lchan->tch_mode), - VTY_NEWLINE); - if (lchan->conn && lchan->conn->vsub) { - vty_out(vty, " Subscriber:%s", VTY_NEWLINE); - subscr_dump_vty(vty, lchan->conn->vsub); - } else - vty_out(vty, " No Subscriber%s", VTY_NEWLINE); - if (is_ipaccess_bts(lchan->ts->trx->bts)) { - struct in_addr ia; - ia.s_addr = htonl(lchan->abis_ip.bound_ip); - vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s", - inet_ntoa(ia), lchan->abis_ip.bound_port, - lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id, - VTY_NEWLINE); - } - - /* we want to report the last measurement report */ - idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), - lchan->meas_rep_idx, 1); - meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " "); -} - -static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan) -{ - struct gsm_meas_rep *mr; - int idx; - - /* we want to report the last measurement report */ - idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), - lchan->meas_rep_idx, 1); - mr = &lchan->meas_rep[idx]; - - vty_out(vty, "BTS %u, TRX %u, Timeslot %u %s", - lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, - gsm_pchan_name(lchan->ts->pchan)); - vty_out_dyn_ts_status(vty, lchan->ts); - vty_out(vty, ", Lchan %u, Type %s, State %s - " - "L1 MS Power: %u dBm RXL-FULL-dl: %4d dBm RXL-FULL-ul: %4d dBm%s", - lchan->nr, - gsm_lchant_name(lchan->type), gsm_lchans_name(lchan->state), - mr->ms_l1.pwr, - rxlev2dbm(mr->dl.full.rx_lev), - rxlev2dbm(mr->ul.full.rx_lev), - VTY_NEWLINE); -} - - -static int dump_lchan_trx_ts(struct gsm_bts_trx_ts *ts, struct vty *vty, - void (*dump_cb)(struct vty *, struct gsm_lchan *)) -{ - int lchan_nr; - for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; lchan_nr++) { - struct gsm_lchan *lchan = &ts->lchan[lchan_nr]; - if ((lchan->type == GSM_LCHAN_NONE) && (lchan->state == LCHAN_S_NONE)) - continue; - dump_cb(vty, lchan); - } - - return CMD_SUCCESS; -} - -static int dump_lchan_trx(struct gsm_bts_trx *trx, struct vty *vty, - void (*dump_cb)(struct vty *, struct gsm_lchan *)) -{ - int ts_nr; - - for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) { - struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr]; - dump_lchan_trx_ts(ts, vty, dump_cb); - } - - return CMD_SUCCESS; -} - -static int dump_lchan_bts(struct gsm_bts *bts, struct vty *vty, - void (*dump_cb)(struct vty *, struct gsm_lchan *)) -{ - int trx_nr; - - for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) { - struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_nr); - dump_lchan_trx(trx, vty, dump_cb); - } - - return CMD_SUCCESS; -} - -static int lchan_summary(struct vty *vty, int argc, const char **argv, - void (*dump_cb)(struct vty *, struct gsm_lchan *)) -{ - struct gsm_network *net = gsmnet_from_vty(vty); - struct gsm_bts *bts; - struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - struct gsm_lchan *lchan; - int bts_nr, trx_nr, ts_nr, lchan_nr; - - if (argc >= 1) { - /* use the BTS number that the user has specified */ - bts_nr = atoi(argv[0]); - if (bts_nr >= net->num_bts) { - vty_out(vty, "%% can't find BTS %s%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - bts = gsm_bts_num(net, bts_nr); - - if (argc == 1) - return dump_lchan_bts(bts, vty, dump_cb); - } - if (argc >= 2) { - trx_nr = atoi(argv[1]); - if (trx_nr >= bts->num_trx) { - vty_out(vty, "%% can't find TRX %s%s", argv[1], - VTY_NEWLINE); - return CMD_WARNING; - } - trx = gsm_bts_trx_num(bts, trx_nr); - - if (argc == 2) - return dump_lchan_trx(trx, vty, dump_cb); - } - if (argc >= 3) { - ts_nr = atoi(argv[2]); - if (ts_nr >= TRX_NR_TS) { - vty_out(vty, "%% can't find TS %s%s", argv[2], - VTY_NEWLINE); - return CMD_WARNING; - } - ts = &trx->ts[ts_nr]; - - if (argc == 3) - return dump_lchan_trx_ts(ts, vty, dump_cb); - } - if (argc >= 4) { - lchan_nr = atoi(argv[3]); - if (lchan_nr >= TS_MAX_LCHAN) { - vty_out(vty, "%% can't find LCHAN %s%s", argv[3], - VTY_NEWLINE); - return CMD_WARNING; - } - lchan = &ts->lchan[lchan_nr]; - dump_cb(vty, lchan); - return CMD_SUCCESS; - } - - - for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) { - bts = gsm_bts_num(net, bts_nr); - dump_lchan_bts(bts, vty, dump_cb); - } - - return CMD_SUCCESS; -} - - -DEFUN(show_lchan, - show_lchan_cmd, - "show lchan [<0-255>] [<0-255>] [<0-7>] [lchan_nr]", - SHOW_STR "Display information about a logical channel\n" - "BTS Number\n" "TRX Number\n" "Timeslot Number\n" - LCHAN_NR_STR) - -{ - return lchan_summary(vty, argc, argv, lchan_dump_full_vty); -} - -DEFUN(show_lchan_summary, - show_lchan_summary_cmd, - "show lchan summary [<0-255>] [<0-255>] [<0-7>] [lchan_nr]", - SHOW_STR "Display information about a logical channel\n" - "Short summary\n" - "BTS Number\n" "TRX Number\n" "Timeslot Number\n" - LCHAN_NR_STR) -{ - return lchan_summary(vty, argc, argv, lchan_dump_short_vty); -} - -DEFUN(show_subscr_conn, - show_subscr_conn_cmd, - "show conns", - SHOW_STR "Display currently active subscriber connections\n") -{ - struct gsm_subscriber_connection *conn; - struct gsm_network *net = gsmnet_from_vty(vty); - bool no_conns = true; - unsigned int count = 0; - - vty_out(vty, "Active subscriber connections: %s", VTY_NEWLINE); - - llist_for_each_entry(conn, &net->subscr_conns, entry) { - vty_out(vty, "conn nr #%u:%s", count, VTY_NEWLINE); - lchan_dump_full_vty(vty, conn->lchan); - no_conns = false; - count++; - } - - if (no_conns) - vty_out(vty, "None%s", VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(handover_subscr_conn, - handover_subscr_conn_cmd, - "handover <0-255> <0-255> <0-7> LCHAN_NR <0-255>", - "Handover subscriber connection to other BTS\n" - "BTS Number (current)\n" "TRX Number\n" "Timeslot Number\n" - LCHAN_NR_STR "BTS Number (new)\n") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - struct gsm_subscriber_connection *conn; - struct gsm_bts *bts; - struct gsm_bts *new_bts = NULL; - unsigned int bts_nr = atoi(argv[0]); - unsigned int trx_nr = atoi(argv[1]); - unsigned int ts_nr = atoi(argv[2]); - unsigned int ss_nr = atoi(argv[3]); - unsigned int bts_nr_new = atoi(argv[4]); - - /* Lookup the BTS where we want to handover to */ - llist_for_each_entry(bts, &net->bts_list, list) { - if (bts->nr == bts_nr_new) { - new_bts = bts; - break; - } - } - - if (!new_bts) { - vty_out(vty, "Unable to trigger handover," - "specified bts #%u does not exist %s", bts_nr_new, - VTY_NEWLINE); - return CMD_WARNING; - } - - /* Find the connection/lchan that we want to handover */ - llist_for_each_entry(conn, &net->subscr_conns, entry) { - if (conn->bts->nr == bts_nr && - conn->lchan->ts->trx->nr == trx_nr && - conn->lchan->ts->nr == ts_nr && conn->lchan->nr == ss_nr) { - vty_out(vty, "starting handover for lchan %s...%s", - conn->lchan->name, VTY_NEWLINE); - lchan_dump_full_vty(vty, conn->lchan); - bsc_handover_start(conn->lchan, new_bts); - return CMD_SUCCESS; - } - } - - vty_out(vty, "Unable to trigger handover," - "specified connection (bts=%u,trx=%u,ts=%u,ss=%u) does not exist%s", - bts_nr, trx_nr, ts_nr, ss_nr, VTY_NEWLINE); - - return CMD_WARNING; -} - -static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag) -{ - vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE); - bsc_subscr_dump_vty(vty, pag->bsub); -} - -static void bts_paging_dump_vty(struct vty *vty, struct gsm_bts *bts) -{ - struct gsm_paging_request *pag; - - if (!bts->paging.bts) - return; - - llist_for_each_entry(pag, &bts->paging.pending_requests, entry) - paging_dump_vty(vty, pag); -} - -DEFUN(show_paging, - show_paging_cmd, - "show paging [<0-255>]", - SHOW_STR "Display information about paging reuqests of a BTS\n" - "BTS Number\n") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - struct gsm_bts *bts; - int bts_nr; - - if (argc >= 1) { - /* use the BTS number that the user has specified */ - bts_nr = atoi(argv[0]); - if (bts_nr >= net->num_bts) { - vty_out(vty, "%% can't find BTS %s%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - bts = gsm_bts_num(net, bts_nr); - bts_paging_dump_vty(vty, bts); - - return CMD_SUCCESS; - } - for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) { - bts = gsm_bts_num(net, bts_nr); - bts_paging_dump_vty(vty, bts); - } - - return CMD_SUCCESS; -} - -DEFUN(show_paging_group, - show_paging_group_cmd, - "show paging-group <0-255> IMSI", - SHOW_STR "Display the paging group\n" - "BTS Number\n" "IMSI\n") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - struct gsm_bts *bts; - unsigned int page_group; - int bts_nr = atoi(argv[0]); - - if (bts_nr >= net->num_bts) { - vty_out(vty, "%% can't find BTS %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - bts = gsm_bts_num(net, bts_nr); - if (!bts) { - vty_out(vty, "%% can't find BTS %s%s", argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - page_group = gsm0502_calc_paging_group(&bts->si_common.chan_desc, - str_to_imsi(argv[1])); - vty_out(vty, "%%Paging group for IMSI %" PRIu64 " on BTS #%d is %u%s", - str_to_imsi(argv[1]), bts->nr, - page_group, VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_neci, - cfg_net_neci_cmd, - "neci (0|1)", - "New Establish Cause Indication\n" - "Don't set the NECI bit\n" "Set the NECI bit\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - - gsmnet->neci = atoi(argv[0]); - gsm_net_update_ctype(gsmnet); - return CMD_SUCCESS; -} - -#define HANDOVER_STR "Handover Options\n" - -DEFUN(cfg_net_handover, cfg_net_handover_cmd, - "handover (0|1)", - HANDOVER_STR - "Don't perform in-call handover\n" - "Perform in-call handover\n") -{ - int enable = atoi(argv[0]); - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - - if (enable && ipacc_rtp_direct) { - vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode " - "is enabled by using the -P command line option%s", - VTY_NEWLINE); - return CMD_WARNING; - } - gsmnet->handover.active = enable; - - return CMD_SUCCESS; -} - -#define HO_WIN_STR HANDOVER_STR "Measurement Window\n" -#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n" -#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n" -#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n" -#define HO_AVG_COUNT_STR "Amount to use for Averaging\n" - -DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd, - "handover window rxlev averaging <1-10>", - HO_WIN_RXLEV_STR - "How many RxLev measurements are used for averaging\n" - HO_AVG_COUNT_STR) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.win_rxlev_avg = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd, - "handover window rxqual averaging <1-10>", - HO_WIN_RXQUAL_STR - "How many RxQual measurements are used for averaging\n" - HO_AVG_COUNT_STR) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.win_rxqual_avg = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd, - "handover window rxlev neighbor averaging <1-10>", - HO_WIN_RXLEV_STR "Neighbor\n" - "How many RxQual measurements are used for averaging\n" - HO_AVG_COUNT_STR) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd, - "handover power budget interval <1-99>", - HO_PBUDGET_STR - "How often to check if we have a better cell (SACCH frames)\n" - "Interval\n" "Number\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.pwr_interval = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd, - "handover power budget hysteresis <0-999>", - HO_PBUDGET_STR - "How many dB does a neighbor to be stronger to become a HO candidate\n" - "Hysteresis\n" "Number\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.pwr_hysteresis = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, - "handover maximum distance <0-9999>", - HANDOVER_STR - "How big is the maximum timing advance before HO is forced\n" - "Distance\n" "Number\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->handover.max_distance = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_pag_any_tch, - cfg_net_pag_any_tch_cmd, - "paging any use tch (0|1)", - "Assign a TCH when receiving a Paging Any request\n" - "Any Channel\n" "Use\n" "TCH\n" - "Do not use TCH for Paging Request Any\n" - "Do use TCH for Paging Request Any\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->pag_any_tch = atoi(argv[0]); - gsm_net_update_ctype(gsmnet); - return CMD_SUCCESS; -} - -#define DEFAULT_TIMER(number) GSM_T##number##_DEFAULT -/* Add another expansion so that DEFAULT_TIMER() becomes its value */ -#define EXPAND_AND_STRINGIFY(x) OSMO_STRINGIFY(x) - -#define DECLARE_TIMER(number, doc) \ - DEFUN(cfg_net_T##number, \ - cfg_net_T##number##_cmd, \ - "timer t" #number " (default|<1-65535>)", \ - "Configure GSM Timers\n" \ - doc " (default: " EXPAND_AND_STRINGIFY(DEFAULT_TIMER(number)) " seconds)\n" \ - "Set to default timer value" \ - " (" EXPAND_AND_STRINGIFY(DEFAULT_TIMER(number)) " seconds)\n" \ - "Timer Value in seconds\n") \ -{ \ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); \ - int value; \ - if (strcmp(argv[0], "default") == 0) \ - value = DEFAULT_TIMER(number); \ - else \ - value = atoi(argv[0]); \ - \ - gsmnet->T##number = value; \ - return CMD_SUCCESS; \ -} - -DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT") -DECLARE_TIMER(3103, "Set the timeout value for HANDOVER") -DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION") -DECLARE_TIMER(3107, "Currently not used") -DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout") -DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel") -DECLARE_TIMER(3113, "Set the time to try paging a subscriber") -DECLARE_TIMER(3115, "Currently not used") -DECLARE_TIMER(3117, "Currently not used") -DECLARE_TIMER(3119, "Currently not used") -DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT") -DECLARE_TIMER(3141, "Currently not used") - -DEFUN_DEPRECATED(cfg_net_dtx, - cfg_net_dtx_cmd, - "dtx-used (0|1)", - ".HIDDEN\n""Obsolete\n""Obsolete\n") -{ - vty_out(vty, "%% 'dtx-used' is now deprecated: use dtx * " - "configuration options of BTS instead%s", VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* per-BTS configuration */ -DEFUN(cfg_bts, - cfg_bts_cmd, - "bts <0-255>", - "Select a BTS to configure\n" - "BTS Number\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - int bts_nr = atoi(argv[0]); - struct gsm_bts *bts; - - if (bts_nr > gsmnet->num_bts) { - vty_out(vty, "%% The next unused BTS number is %u%s", - gsmnet->num_bts, VTY_NEWLINE); - return CMD_WARNING; - } else if (bts_nr == gsmnet->num_bts) { - /* allocate a new one */ - bts = gsm_bts_alloc_register(gsmnet, GSM_BTS_TYPE_UNKNOWN, - HARDCODED_BSIC); - } else - bts = gsm_bts_num(gsmnet, bts_nr); - - if (!bts) { - vty_out(vty, "%% Unable to allocate BTS %u%s", - gsmnet->num_bts, VTY_NEWLINE); - return CMD_WARNING; - } - - vty->index = bts; - vty->index_sub = &bts->description; - vty->node = BTS_NODE; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_type, - cfg_bts_type_cmd, - "type TYPE", /* dynamically created */ - "Set the BTS type\n" "Type\n") -{ - struct gsm_bts *bts = vty->index; - int rc; - - rc = gsm_set_bts_type(bts, str2btstype(argv[0])); - if (rc < 0) - return CMD_WARNING; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_band, - cfg_bts_band_cmd, - "band BAND", - "Set the frequency band of this BTS\n" "Frequency band\n") -{ - struct gsm_bts *bts = vty->index; - int band = gsm_band_parse(argv[0]); - - if (band < 0) { - vty_out(vty, "%% BAND %d is not a valid GSM band%s", - band, VTY_NEWLINE); - return CMD_WARNING; - } - - bts->band = band; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_dtxu, cfg_bts_dtxu_cmd, "dtx uplink [force]", - "Configure discontinuous transmission\n" - "Enable Uplink DTX for this BTS\n" - "MS 'shall' use DTXu instead of 'may' use (might not be supported by " - "older phones).\n") -{ - struct gsm_bts *bts = vty->index; - - bts->dtxu = (argc > 0) ? GSM48_DTX_SHALL_BE_USED : GSM48_DTX_MAY_BE_USED; - if (!is_ipaccess_bts(bts)) - vty_out(vty, "%% DTX enabled on non-IP BTS: this configuration " - "neither supported nor tested!%s", VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_no_dtxu, cfg_bts_no_dtxu_cmd, "no dtx uplink", - NO_STR - "Configure discontinuous transmission\n" - "Disable Uplink DTX for this BTS\n") -{ - struct gsm_bts *bts = vty->index; - - bts->dtxu = GSM48_DTX_SHALL_NOT_BE_USED; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_dtxd, cfg_bts_dtxd_cmd, "dtx downlink", - "Configure discontinuous transmission\n" - "Enable Downlink DTX for this BTS\n") -{ - struct gsm_bts *bts = vty->index; - - bts->dtxd = true; - if (!is_ipaccess_bts(bts)) - vty_out(vty, "%% DTX enabled on non-IP BTS: this configuration " - "neither supported nor tested!%s", VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_no_dtxd, cfg_bts_no_dtxd_cmd, "no dtx downlink", - NO_STR - "Configure discontinuous transmission\n" - "Disable Downlink DTX for this BTS\n") -{ - struct gsm_bts *bts = vty->index; - - bts->dtxd = false; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_ci, - cfg_bts_ci_cmd, - "cell_identity <0-65535>", - "Set the Cell identity of this BTS\n" "Cell Identity\n") -{ - struct gsm_bts *bts = vty->index; - int ci = atoi(argv[0]); - - if (ci < 0 || ci > 0xffff) { - vty_out(vty, "%% CI %d is not in the valid range (0-65535)%s", - ci, VTY_NEWLINE); - return CMD_WARNING; - } - bts->cell_identity = ci; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_lac, - cfg_bts_lac_cmd, - "location_area_code <0-65535>", - "Set the Location Area Code (LAC) of this BTS\n" "LAC\n") -{ - struct gsm_bts *bts = vty->index; - int lac = atoi(argv[0]); - - if (lac < 0 || lac > 0xffff) { - vty_out(vty, "%% LAC %d is not in the valid range (0-65535)%s", - lac, VTY_NEWLINE); - return CMD_WARNING; - } - - if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) { - vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s", - lac, VTY_NEWLINE); - return CMD_WARNING; - } - - bts->location_area_code = lac; - - return CMD_SUCCESS; -} - - -/* compatibility wrapper for old config files */ -DEFUN_HIDDEN(cfg_bts_tsc, - cfg_bts_tsc_cmd, - "training_sequence_code <0-7>", - "Set the Training Sequence Code (TSC) of this BTS\n" "TSC\n") -{ - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_bsic, - cfg_bts_bsic_cmd, - "base_station_id_code <0-63>", - "Set the Base Station Identity Code (BSIC) of this BTS\n" - "BSIC of this BTS\n") -{ - struct gsm_bts *bts = vty->index; - int bsic = atoi(argv[0]); - - if (bsic < 0 || bsic > 0x3f) { - vty_out(vty, "%% BSIC %d is not in the valid range (0-255)%s", - bsic, VTY_NEWLINE); - return CMD_WARNING; - } - bts->bsic = bsic; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_unit_id, - cfg_bts_unit_id_cmd, - "ip.access unit_id <0-65534> <0-255>", - "Abis/IP specific options\n" - "Set the IPA BTS Unit ID\n" - "Unit ID (Site)\n" - "Unit ID (BTS)\n") -{ - struct gsm_bts *bts = vty->index; - int site_id = atoi(argv[0]); - int bts_id = atoi(argv[1]); - - if (!is_ipaccess_bts(bts)) { - vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->ip_access.site_id = site_id; - bts->ip_access.bts_id = bts_id; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_rsl_ip, - cfg_bts_rsl_ip_cmd, - "ip.access rsl-ip A.B.C.D", - "Abis/IP specific options\n" - "Set the IPA RSL IP Address of the BSC\n" - "Destination IP address for RSL connection\n") -{ - struct gsm_bts *bts = vty->index; - struct in_addr ia; - - if (!is_ipaccess_bts(bts)) { - vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - inet_aton(argv[0], &ia); - bts->ip_access.rsl_ip = ntohl(ia.s_addr); - - return CMD_SUCCESS; -} - -#define NOKIA_STR "Nokia *Site related commands\n" - -DEFUN(cfg_bts_nokia_site_skip_reset, - cfg_bts_nokia_site_skip_reset_cmd, - "nokia_site skip-reset (0|1)", - NOKIA_STR - "Skip the reset step during bootstrap process of this BTS\n" - "Do NOT skip the reset\n" "Skip the reset\n") -{ - struct gsm_bts *bts = vty->index; - - if (bts->type != GSM_BTS_TYPE_NOKIA_SITE) { - vty_out(vty, "%% BTS is not of Nokia *Site type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->nokia.skip_reset = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_nokia_site_no_loc_rel_cnf, - cfg_bts_nokia_site_no_loc_rel_cnf_cmd, - "nokia_site no-local-rel-conf (0|1)", - NOKIA_STR - "Do not wait for RELease CONFirm message when releasing channel locally\n" - "Wait for RELease CONFirm\n" "Do not wait for RELease CONFirm\n") -{ - struct gsm_bts *bts = vty->index; - - if (!is_nokia_bts(bts)) { - vty_out(vty, "%% BTS is not of Nokia *Site type%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - bts->nokia.no_loc_rel_cnf = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_nokia_site_bts_reset_timer_cnf, - cfg_bts_nokia_site_bts_reset_timer_cnf_cmd, - "nokia_site bts-reset-timer <15-100>", - NOKIA_STR - "The amount of time (in sec.) between BTS_RESET is sent,\n" - "and the BTS is being bootstrapped.\n") -{ - struct gsm_bts *bts = vty->index; - - if (!is_nokia_bts(bts)) { - vty_out(vty, "%% BTS is not of Nokia *Site type%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - bts->nokia.bts_reset_timer_cnf = atoi(argv[0]); - - return CMD_SUCCESS; -} -#define OML_STR "Organization & Maintenance Link\n" -#define IPA_STR "A-bis/IP Specific Options\n" - -DEFUN(cfg_bts_stream_id, - cfg_bts_stream_id_cmd, - "oml ip.access stream_id <0-255> line E1_LINE", - OML_STR IPA_STR - "Set the ip.access Stream ID of the OML link of this BTS\n" - "Stream Identifier\n" "Virtual E1 Line Number\n" "Virtual E1 Line Number\n") -{ - struct gsm_bts *bts = vty->index; - int stream_id = atoi(argv[0]), linenr = atoi(argv[1]); - - if (!is_ipaccess_bts(bts)) { - vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->oml_tei = stream_id; - /* This is used by e1inp_bind_ops callback for each BTS model. */ - bts->oml_e1_link.e1_nr = linenr; - - return CMD_SUCCESS; -} - -#define OML_E1_STR OML_STR "OML E1/T1 Configuration\n" - -DEFUN(cfg_bts_oml_e1, - cfg_bts_oml_e1_cmd, - "oml e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)", - OML_E1_STR - "E1/T1 line number to be used for OML\n" - "E1/T1 line number to be used for OML\n" - "E1/T1 timeslot to be used for OML\n" - "E1/T1 timeslot to be used for OML\n" - "E1/T1 sub-slot to be used for OML\n" - "Use E1/T1 sub-slot 0\n" - "Use E1/T1 sub-slot 1\n" - "Use E1/T1 sub-slot 2\n" - "Use E1/T1 sub-slot 3\n" - "Use full E1 slot 3\n" - ) -{ - struct gsm_bts *bts = vty->index; - - parse_e1_link(&bts->oml_e1_link, argv[0], argv[1], argv[2]); - - return CMD_SUCCESS; -} - - -DEFUN(cfg_bts_oml_e1_tei, - cfg_bts_oml_e1_tei_cmd, - "oml e1 tei <0-63>", - OML_E1_STR - "Set the TEI to be used for OML\n" - "TEI Number\n") -{ - struct gsm_bts *bts = vty->index; - - bts->oml_tei = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_challoc, cfg_bts_challoc_cmd, - "channel allocator (ascending|descending)", - "Channnel Allocator\n" "Channel Allocator\n" - "Allocate Timeslots and Transceivers in ascending order\n" - "Allocate Timeslots and Transceivers in descending order\n") -{ - struct gsm_bts *bts = vty->index; - - if (!strcmp(argv[0], "ascending")) - bts->chan_alloc_reverse = 0; - else - bts->chan_alloc_reverse = 1; - - return CMD_SUCCESS; -} - -#define RACH_STR "Random Access Control Channel\n" - -DEFUN(cfg_bts_rach_tx_integer, - cfg_bts_rach_tx_integer_cmd, - "rach tx integer <0-15>", - RACH_STR - "Set the raw tx integer value in RACH Control parameters IE\n" - "Set the raw tx integer value in RACH Control parameters IE\n" - "Raw tx integer value in RACH Control parameters IE\n") -{ - struct gsm_bts *bts = vty->index; - bts->si_common.rach_control.tx_integer = atoi(argv[0]) & 0xf; - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_rach_max_trans, - cfg_bts_rach_max_trans_cmd, - "rach max transmission (1|2|4|7)", - RACH_STR - "Set the maximum number of RACH burst transmissions\n" - "Set the maximum number of RACH burst transmissions\n" - "Maximum number of 1 RACH burst transmissions\n" - "Maximum number of 2 RACH burst transmissions\n" - "Maximum number of 4 RACH burst transmissions\n" - "Maximum number of 7 RACH burst transmissions\n") -{ - struct gsm_bts *bts = vty->index; - bts->si_common.rach_control.max_trans = rach_max_trans_val2raw(atoi(argv[0])); - return CMD_SUCCESS; -} - -#define CD_STR "Channel Description\n" - -DEFUN(cfg_bts_chan_desc_att, - cfg_bts_chan_desc_att_cmd, - "channel-descrption attach (0|1)", - CD_STR - "Set if attachment is required\n" - "Attachment is NOT required\n" - "Attachment is required (standard)\n") -{ - struct gsm_bts *bts = vty->index; - bts->si_common.chan_desc.att = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_chan_desc_bs_pa_mfrms, - cfg_bts_chan_desc_bs_pa_mfrms_cmd, - "channel-descrption bs-pa-mfrms <2-9>", - CD_STR - "Set number of multiframe periods for paging groups\n" - "Number of multiframe periods for paging groups\n") -{ - struct gsm_bts *bts = vty->index; - int bs_pa_mfrms = atoi(argv[0]); - - bts->si_common.chan_desc.bs_pa_mfrms = bs_pa_mfrms - 2; - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_chan_desc_bs_ag_blks_res, - cfg_bts_chan_desc_bs_ag_blks_res_cmd, - "channel-descrption bs-ag-blks-res <0-7>", - CD_STR - "Set number of blocks reserved for access grant\n" - "Number of blocks reserved for access grant\n") -{ - struct gsm_bts *bts = vty->index; - int bs_ag_blks_res = atoi(argv[0]); - - bts->si_common.chan_desc.bs_ag_blks_res = bs_ag_blks_res; - return CMD_SUCCESS; -} - -#define NM_STR "Network Management\n" - -DEFUN(cfg_bts_rach_nm_b_thresh, - cfg_bts_rach_nm_b_thresh_cmd, - "rach nm busy threshold <0-255>", - RACH_STR NM_STR - "Set the NM Busy Threshold\n" - "Set the NM Busy Threshold\n" - "NM Busy Threshold in dB") -{ - struct gsm_bts *bts = vty->index; - bts->rach_b_thresh = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_rach_nm_ldavg, - cfg_bts_rach_nm_ldavg_cmd, - "rach nm load average <0-65535>", - RACH_STR NM_STR - "Set the NM Loadaverage Slots value\n" - "Set the NM Loadaverage Slots value\n" - "NM Loadaverage Slots value\n") -{ - struct gsm_bts *bts = vty->index; - bts->rach_ldavg_slots = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd, - "cell barred (0|1)", - "Should this cell be barred from access?\n" - "Should this cell be barred from access?\n" - "Cell should NOT be barred\n" - "Cell should be barred\n") - -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.rach_control.cell_bar = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_rach_ec_allowed, cfg_bts_rach_ec_allowed_cmd, - "rach emergency call allowed (0|1)", - RACH_STR - "Should this cell allow emergency calls?\n" - "Should this cell allow emergency calls?\n" - "Should this cell allow emergency calls?\n" - "Do NOT allow emergency calls\n" - "Allow emergency calls\n") -{ - struct gsm_bts *bts = vty->index; - - if (atoi(argv[0]) == 0) - bts->si_common.rach_control.t2 |= 0x4; - else - bts->si_common.rach_control.t2 &= ~0x4; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_rach_ac_class, cfg_bts_rach_ac_class_cmd, - "rach access-control-class (0|1|2|3|4|5|6|7|8|9|11|12|13|14|15) (barred|allowed)", - RACH_STR - "Set access control class\n" - "Access control class 0\n" - "Access control class 1\n" - "Access control class 2\n" - "Access control class 3\n" - "Access control class 4\n" - "Access control class 5\n" - "Access control class 6\n" - "Access control class 7\n" - "Access control class 8\n" - "Access control class 9\n" - "Access control class 11 for PLMN use\n" - "Access control class 12 for security services\n" - "Access control class 13 for public utilities (e.g. water/gas suppliers)\n" - "Access control class 14 for emergency services\n" - "Access control class 15 for PLMN staff\n" - "barred to use access control class\n" - "allowed to use access control class\n") -{ - struct gsm_bts *bts = vty->index; - - uint8_t control_class; - uint8_t allowed = 0; - - if (strcmp(argv[1], "allowed") == 0) - allowed = 1; - - control_class = atoi(argv[0]); - if (control_class < 8) - if (allowed) - bts->si_common.rach_control.t3 &= ~(0x1 << control_class); - else - bts->si_common.rach_control.t3 |= (0x1 << control_class); - else - if (allowed) - bts->si_common.rach_control.t2 &= ~(0x1 << (control_class - 8)); - else - bts->si_common.rach_control.t2 |= (0x1 << (control_class - 8)); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd, - "ms max power <0-40>", - "MS Options\n" - "Maximum transmit power of the MS\n" - "Maximum transmit power of the MS\n" - "Maximum transmit power of the MS in dBm") -{ - struct gsm_bts *bts = vty->index; - - bts->ms_max_power = atoi(argv[0]); - - return CMD_SUCCESS; -} - -#define CELL_STR "Cell Parameters\n" - -DEFUN(cfg_bts_cell_resel_hyst, cfg_bts_cell_resel_hyst_cmd, - "cell reselection hysteresis <0-14>", - CELL_STR "Cell re-selection parameters\n" - "Cell Re-Selection Hysteresis in dB\n" - "Cell Re-Selection Hysteresis in dB") -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_sel_par.cell_resel_hyst = atoi(argv[0])/2; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_rxlev_acc_min, cfg_bts_rxlev_acc_min_cmd, - "rxlev access min <0-63>", - "Minimum RxLev needed for cell access\n" - "Minimum RxLev needed for cell access\n" - "Minimum RxLev needed for cell access\n" - "Minimum RxLev needed for cell access (better than -110dBm)") -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_sel_par.rxlev_acc_min = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_cell_bar_qualify, cfg_bts_cell_bar_qualify_cmd, - "cell bar qualify (0|1)", - CELL_STR "Cell Bar Qualify\n" "Cell Bar Qualify\n" - "Set CBQ to 0\n" "Set CBQ to 1\n") -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_ro_sel_par.present = 1; - bts->si_common.cell_ro_sel_par.cbq = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_cell_resel_ofs, cfg_bts_cell_resel_ofs_cmd, - "cell reselection offset <0-126>", - CELL_STR "Cell Re-Selection Parameters\n" - "Cell Re-Selection Offset (CRO) in dB\n" - "Cell Re-Selection Offset (CRO) in dB\n" - ) -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_ro_sel_par.present = 1; - bts->si_common.cell_ro_sel_par.cell_resel_off = atoi(argv[0])/2; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_temp_ofs, cfg_bts_temp_ofs_cmd, - "temporary offset <0-60>", - "Cell selection temporary negative offset\n" - "Cell selection temporary negative offset\n" - "Cell selection temporary negative offset in dB") -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_ro_sel_par.present = 1; - bts->si_common.cell_ro_sel_par.temp_offs = atoi(argv[0])/10; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_temp_ofs_inf, cfg_bts_temp_ofs_inf_cmd, - "temporary offset infinite", - "Cell selection temporary negative offset\n" - "Cell selection temporary negative offset\n" - "Sets cell selection temporary negative offset to infinity") -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_ro_sel_par.present = 1; - bts->si_common.cell_ro_sel_par.temp_offs = 7; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_penalty_time, cfg_bts_penalty_time_cmd, - "penalty time <20-620>", - "Cell selection penalty time\n" - "Cell selection penalty time\n" - "Cell selection penalty time in seconds (by 20s increments)\n") -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_ro_sel_par.present = 1; - bts->si_common.cell_ro_sel_par.penalty_time = (atoi(argv[0])-20)/20; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_penalty_time_rsvd, cfg_bts_penalty_time_rsvd_cmd, - "penalty time reserved", - "Cell selection penalty time\n" - "Cell selection penalty time\n" - "Set cell selection penalty time to reserved value 31, " - "(indicate that CELL_RESELECT_OFFSET is subtracted from C2 " - "and TEMPORARY_OFFSET is ignored)") -{ - struct gsm_bts *bts = vty->index; - - bts->si_common.cell_ro_sel_par.present = 1; - bts->si_common.cell_ro_sel_par.penalty_time = 31; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_radio_link_timeout, cfg_bts_radio_link_timeout_cmd, - "radio-link-timeout <4-64>", - "Radio link timeout criterion (BTS side)\n" - "Radio link timeout value (lost SACCH block)\n") -{ - struct gsm_bts *bts = vty->index; - - gsm_bts_set_radio_link_timeout(bts, atoi(argv[0])); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_radio_link_timeout_inf, cfg_bts_radio_link_timeout_inf_cmd, - "radio-link-timeout infinite", - "Radio link timeout criterion (BTS side)\n" - "Infinite Radio link timeout value (use only for BTS RF testing)\n") -{ - struct gsm_bts *bts = vty->index; - - if (bts->type != GSM_BTS_TYPE_OSMOBTS) { - vty_out(vty, "%% infinite radio link timeout not supported by this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "%% INFINITE RADIO LINK TIMEOUT, USE ONLY FOR BTS RF TESTING%s", VTY_NEWLINE); - gsm_bts_set_radio_link_timeout(bts, -1); - - return CMD_SUCCESS; -} - -#define GPRS_TEXT "GPRS Packet Network\n" - -DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd, - "gprs cell bvci <2-65535>", - GPRS_TEXT - "GPRS Cell Settings\n" - "GPRS BSSGP VC Identifier\n" - "GPRS BSSGP VC Identifier") -{ - struct gsm_bts *bts = vty->index; - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.cell.bvci = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd, - "gprs nsei <0-65535>", - GPRS_TEXT - "GPRS NS Entity Identifier\n" - "GPRS NS Entity Identifier") -{ - struct gsm_bts *bts = vty->index; - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.nse.nsei = atoi(argv[0]); - - return CMD_SUCCESS; -} - -#define NSVC_TEXT "Network Service Virtual Connection (NS-VC)\n" \ - "NSVC Logical Number\n" - -DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd, - "gprs nsvc <0-1> nsvci <0-65535>", - GPRS_TEXT NSVC_TEXT - "NS Virtual Connection Identifier\n" - "GPRS NS VC Identifier") -{ - struct gsm_bts *bts = vty->index; - int idx = atoi(argv[0]); - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.nsvc[idx].nsvci = atoi(argv[1]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd, - "gprs nsvc <0-1> local udp port <0-65535>", - GPRS_TEXT NSVC_TEXT - "GPRS NS Local UDP Port\n" - "GPRS NS Local UDP Port\n" - "GPRS NS Local UDP Port\n" - "GPRS NS Local UDP Port Number\n") -{ - struct gsm_bts *bts = vty->index; - int idx = atoi(argv[0]); - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.nsvc[idx].local_port = atoi(argv[1]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd, - "gprs nsvc <0-1> remote udp port <0-65535>", - GPRS_TEXT NSVC_TEXT - "GPRS NS Remote UDP Port\n" - "GPRS NS Remote UDP Port\n" - "GPRS NS Remote UDP Port\n" - "GPRS NS Remote UDP Port Number\n") -{ - struct gsm_bts *bts = vty->index; - int idx = atoi(argv[0]); - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.nsvc[idx].remote_port = atoi(argv[1]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd, - "gprs nsvc <0-1> remote ip A.B.C.D", - GPRS_TEXT NSVC_TEXT - "GPRS NS Remote IP Address\n" - "GPRS NS Remote IP Address\n" - "GPRS NS Remote IP Address\n") -{ - struct gsm_bts *bts = vty->index; - int idx = atoi(argv[0]); - struct in_addr ia; - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - inet_aton(argv[1], &ia); - bts->gprs.nsvc[idx].remote_ip = ntohl(ia.s_addr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_pag_free, cfg_bts_pag_free_cmd, - "paging free <-1-1024>", - "Paging options\n" - "Only page when having a certain amount of free slots\n" - "amount of required free paging slots. -1 to disable\n") -{ - struct gsm_bts *bts = vty->index; - - bts->paging.free_chans_need = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_ns_timer, cfg_bts_gprs_ns_timer_cmd, - "gprs ns timer " NS_TIMERS " <0-255>", - GPRS_TEXT "Network Service\n" - "Network Service Timer\n" - NS_TIMERS_HELP "Timer Value\n") -{ - struct gsm_bts *bts = vty->index; - int idx = get_string_value(gprs_ns_timer_strs, argv[0]); - int val = atoi(argv[1]); - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.nse.timer)) - return CMD_WARNING; - - bts->gprs.nse.timer[idx] = val; - - return CMD_SUCCESS; -} - -#define BSSGP_TIMERS "(blocking-timer|blocking-retries|unblocking-retries|reset-timer|reset-retries|suspend-timer|suspend-retries|resume-timer|resume-retries|capability-update-timer|capability-update-retries)" -#define BSSGP_TIMERS_HELP \ - "Tbvc-block timeout\n" \ - "Tbvc-block retries\n" \ - "Tbvc-unblock retries\n" \ - "Tbvcc-reset timeout\n" \ - "Tbvc-reset retries\n" \ - "Tbvc-suspend timeout\n" \ - "Tbvc-suspend retries\n" \ - "Tbvc-resume timeout\n" \ - "Tbvc-resume retries\n" \ - "Tbvc-capa-update timeout\n" \ - "Tbvc-capa-update retries\n" - -DEFUN(cfg_bts_gprs_cell_timer, cfg_bts_gprs_cell_timer_cmd, - "gprs cell timer " BSSGP_TIMERS " <0-255>", - GPRS_TEXT "Cell / BSSGP\n" - "Cell/BSSGP Timer\n" - BSSGP_TIMERS_HELP "Timer Value\n") -{ - struct gsm_bts *bts = vty->index; - int idx = get_string_value(gprs_bssgp_cfg_strs, argv[0]); - int val = atoi(argv[1]); - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.cell.timer)) - return CMD_WARNING; - - bts->gprs.cell.timer[idx] = val; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd, - "gprs routing area <0-255>", - GPRS_TEXT - "GPRS Routing Area Code\n" - "GPRS Routing Area Code\n" - "GPRS Routing Area Code\n") -{ - struct gsm_bts *bts = vty->index; - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.rac = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_ctrl_ack, cfg_bts_gprs_ctrl_ack_cmd, - "gprs control-ack-type-rach", GPRS_TEXT - "Set GPRS Control Ack Type for PACKET CONTROL ACKNOWLEDGMENT message to " - "four access bursts format instead of default RLC/MAC control block\n") -{ - struct gsm_bts *bts = vty->index; - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.ctrl_ack_type_use_block = false; - - return CMD_SUCCESS; -} - -DEFUN(cfg_no_bts_gprs_ctrl_ack, cfg_no_bts_gprs_ctrl_ack_cmd, - "no gprs control-ack-type-rach", NO_STR GPRS_TEXT - "Set GPRS Control Ack Type for PACKET CONTROL ACKNOWLEDGMENT message to " - "four access bursts format instead of default RLC/MAC control block\n") -{ - struct gsm_bts *bts = vty->index; - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.ctrl_ack_type_use_block = true; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_net_ctrl_ord, cfg_bts_gprs_net_ctrl_ord_cmd, - "gprs network-control-order (nc0|nc1|nc2)", - GPRS_TEXT - "GPRS Network Control Order\n" - "MS controlled cell re-selection, no measurement reporting\n" - "MS controlled cell re-selection, MS sends measurement reports\n" - "Network controlled cell re-selection, MS sends measurement reports\n") -{ - struct gsm_bts *bts = vty->index; - - if (bts->gprs.mode == BTS_GPRS_NONE) { - vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.net_ctrl_ord = atoi(argv[0] + 2); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd, - "gprs mode (none|gprs|egprs)", - GPRS_TEXT - "GPRS Mode for this BTS\n" - "GPRS Disabled on this BTS\n" - "GPRS Enabled on this BTS\n" - "EGPRS (EDGE) Enabled on this BTS\n") -{ - struct gsm_bts *bts = vty->index; - enum bts_gprs_mode mode = bts_gprs_mode_parse(argv[0], NULL); - - if (!bts_gprs_mode_is_compat(bts, mode)) { - vty_out(vty, "This BTS type does not support %s%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - - bts->gprs.mode = mode; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_gprs_11bit_rach_support_for_egprs, - cfg_bts_gprs_11bit_rach_support_for_egprs_cmd, - "gprs 11bit_rach_support_for_egprs (0|1)", - GPRS_TEXT "11 bit RACH options\n" - "Disable 11 bit RACH for EGPRS\n" - "Enable 11 bit RACH for EGPRS") -{ - struct gsm_bts *bts = vty->index; - - bts->gprs.supports_egprs_11bit_rach = atoi(argv[0]); - - if (bts->gprs.supports_egprs_11bit_rach > 1) { - vty_out(vty, "Error in RACH type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if ((bts->gprs.mode == BTS_GPRS_NONE) && - (bts->gprs.supports_egprs_11bit_rach == 1)) { - vty_out(vty, "Error:gprs mode is none and 11bit rach is" - " enabled%s", VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -#define SI_TEXT "System Information Messages\n" -#define SI_TYPE_TEXT "(1|2|3|4|5|6|7|8|9|10|13|16|17|18|19|20|2bis|2ter|2quater|5bis|5ter)" -#define SI_TYPE_HELP "System Information Type 1\n" \ - "System Information Type 2\n" \ - "System Information Type 3\n" \ - "System Information Type 4\n" \ - "System Information Type 5\n" \ - "System Information Type 6\n" \ - "System Information Type 7\n" \ - "System Information Type 8\n" \ - "System Information Type 9\n" \ - "System Information Type 10\n" \ - "System Information Type 13\n" \ - "System Information Type 16\n" \ - "System Information Type 17\n" \ - "System Information Type 18\n" \ - "System Information Type 19\n" \ - "System Information Type 20\n" \ - "System Information Type 2bis\n" \ - "System Information Type 2ter\n" \ - "System Information Type 2quater\n" \ - "System Information Type 5bis\n" \ - "System Information Type 5ter\n" - -DEFUN(cfg_bts_si_mode, cfg_bts_si_mode_cmd, - "system-information " SI_TYPE_TEXT " mode (static|computed)", - SI_TEXT SI_TYPE_HELP - "System Information Mode\n" - "Static user-specified\n" - "Dynamic, BSC-computed\n") -{ - struct gsm_bts *bts = vty->index; - int type; - - type = get_string_value(osmo_sitype_strs, argv[0]); - if (type < 0) { - vty_out(vty, "Error SI Type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[1], "static")) - bts->si_mode_static |= (1 << type); - else - bts->si_mode_static &= ~(1 << type); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_si_static, cfg_bts_si_static_cmd, - "system-information " SI_TYPE_TEXT " static HEXSTRING", - SI_TEXT SI_TYPE_HELP - "Static System Information filling\n" - "Static user-specified SI content in HEX notation\n") -{ - struct gsm_bts *bts = vty->index; - int rc, type; - - type = get_string_value(osmo_sitype_strs, argv[0]); - if (type < 0) { - vty_out(vty, "Error SI Type%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (!(bts->si_mode_static & (1 << type))) { - vty_out(vty, "SI Type %s is not configured in static mode%s", - get_value_string(osmo_sitype_strs, type), VTY_NEWLINE); - return CMD_WARNING; - } - - /* Fill buffer with padding pattern */ - memset(GSM_BTS_SI(bts, type), 0x2b, GSM_MACBLOCK_LEN); - - /* Parse the user-specified SI in hex format, [partially] overwriting padding */ - rc = osmo_hexparse(argv[1], GSM_BTS_SI(bts, type), GSM_MACBLOCK_LEN); - if (rc < 0 || rc > GSM_MACBLOCK_LEN) { - vty_out(vty, "Error parsing HEXSTRING%s", VTY_NEWLINE); - return CMD_WARNING; - } - - /* Mark this SI as present */ - bts->si_valid |= (1 << type); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_early_cm, cfg_bts_early_cm_cmd, - "early-classmark-sending (allowed|forbidden)", - "Early Classmark Sending\n" - "Early Classmark Sending is allowed\n" - "Early Classmark Sending is forbidden\n") -{ - struct gsm_bts *bts = vty->index; - - if (!strcmp(argv[0], "allowed")) - bts->early_classmark_allowed = true; - else - bts->early_classmark_allowed = false; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_neigh_mode, cfg_bts_neigh_mode_cmd, - "neighbor-list mode (automatic|manual|manual-si5)", - "Neighbor List\n" "Mode of Neighbor List generation\n" - "Automatically from all BTS in this OpenBSC\n" "Manual\n" - "Manual with different lists for SI2 and SI5\n") -{ - struct gsm_bts *bts = vty->index; - int mode = get_string_value(bts_neigh_mode_strs, argv[0]); - - switch (mode) { - case NL_MODE_MANUAL_SI5SEP: - case NL_MODE_MANUAL: - /* make sure we clear the current list when switching to - * manual mode */ - if (bts->neigh_list_manual_mode == 0) - memset(&bts->si_common.data.neigh_list, 0, - sizeof(bts->si_common.data.neigh_list)); - break; - default: - break; - } - - bts->neigh_list_manual_mode = mode; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_neigh, cfg_bts_neigh_cmd, - "neighbor-list (add|del) arfcn <0-1023>", - "Neighbor List\n" "Add to manual neighbor list\n" - "Delete from manual neighbor list\n" "ARFCN of neighbor\n" - "ARFCN of neighbor\n") -{ - struct gsm_bts *bts = vty->index; - struct bitvec *bv = &bts->si_common.neigh_list; - uint16_t arfcn = atoi(argv[1]); - - if (!bts->neigh_list_manual_mode) { - vty_out(vty, "%% Cannot configure neighbor list in " - "automatic mode%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[0], "add")) - bitvec_set_bit_pos(bv, arfcn, 1); - else - bitvec_set_bit_pos(bv, arfcn, 0); - - return CMD_SUCCESS; -} - -/* help text should be kept in sync with EARFCN_*_INVALID defines */ -DEFUN(cfg_bts_si2quater_neigh_add, cfg_bts_si2quater_neigh_add_cmd, - "si2quater neighbor-list add earfcn <0-65535> thresh-hi <0-31> " - "thresh-lo <0-32> prio <0-8> qrxlv <0-32> meas <0-8>", - "SI2quater Neighbor List\n" "SI2quater Neighbor List\n" - "Add to manual SI2quater neighbor list\n" - "EARFCN of neighbor\n" "EARFCN of neighbor\n" - "threshold high bits\n" "threshold high bits\n" - "threshold low bits\n" "threshold low bits (32 means NA)\n" - "priority\n" "priority (8 means NA)\n" - "QRXLEVMIN\n" "QRXLEVMIN (32 means NA)\n" - "measurement bandwidth\n" "measurement bandwidth (8 means NA)\n") -{ - struct gsm_bts *bts = vty->index; - struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; - uint16_t arfcn = atoi(argv[0]); - uint8_t thresh_hi = atoi(argv[1]), thresh_lo = atoi(argv[2]), - prio = atoi(argv[3]), qrx = atoi(argv[4]), meas = atoi(argv[5]); - int r = bts_earfcn_add(bts, arfcn, thresh_hi, thresh_lo, prio, qrx, meas); - - switch (r) { - case 1: - vty_out(vty, "Warning: multiple threshold-high are not supported, overriding with %u%s", - thresh_hi, VTY_NEWLINE); - break; - case EARFCN_THRESH_LOW_INVALID: - vty_out(vty, "Warning: multiple threshold-low are not supported, overriding with %u%s", - thresh_lo, VTY_NEWLINE); - break; - case EARFCN_QRXLV_INVALID + 1: - vty_out(vty, "Warning: multiple QRXLEVMIN are not supported, overriding with %u%s", - qrx, VTY_NEWLINE); - break; - case EARFCN_PRIO_INVALID: - vty_out(vty, "Warning: multiple priorities are not supported, overriding with %u%s", - prio, VTY_NEWLINE); - break; - default: - if (r < 0) { - vty_out(vty, "Unable to add ARFCN %u: %s%s", arfcn, strerror(-r), VTY_NEWLINE); - return CMD_WARNING; - } - } - - if (si2q_num(bts) <= SI2Q_MAX_NUM) - return CMD_SUCCESS; - - vty_out(vty, "Warning: not enough space in SI2quater (%u/%u used) for a given EARFCN %u%s", - bts->si2q_count, SI2Q_MAX_NUM, arfcn, VTY_NEWLINE); - osmo_earfcn_del(e, arfcn); - - return CMD_WARNING; -} - -DEFUN(cfg_bts_si2quater_neigh_del, cfg_bts_si2quater_neigh_del_cmd, - "si2quater neighbor-list del earfcn <0-65535>", - "SI2quater Neighbor List\n" - "SI2quater Neighbor List\n" - "Delete from SI2quater manual neighbor list\n" - "EARFCN of neighbor\n" - "EARFCN\n") -{ - struct gsm_bts *bts = vty->index; - struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; - uint16_t arfcn = atoi(argv[0]); - int r = osmo_earfcn_del(e, arfcn); - if (r < 0) { - vty_out(vty, "Unable to delete arfcn %u: %s%s", arfcn, - strerror(-r), VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_si2quater_uarfcn_add, cfg_bts_si2quater_uarfcn_add_cmd, - "si2quater neighbor-list add uarfcn <0-16383> <0-511> <0-1>", - "SI2quater Neighbor List\n" - "SI2quater Neighbor List\n" "Add to manual SI2quater neighbor list\n" - "UARFCN of neighbor\n" "UARFCN of neighbor\n" "scrambling code\n" - "diversity bit\n") -{ - struct gsm_bts *bts = vty->index; - uint16_t arfcn = atoi(argv[0]), scramble = atoi(argv[1]); - - switch(bts_uarfcn_add(bts, arfcn, scramble, atoi(argv[2]))) { - case -ENOMEM: - vty_out(vty, "Unable to add UARFCN: max number of UARFCNs (%u) reached%s", MAX_EARFCN_LIST, VTY_NEWLINE); - return CMD_WARNING; - case -ENOSPC: - vty_out(vty, "Warning: not enough space in SI2quater for a given UARFCN (%u, %u)%s", - arfcn, scramble, VTY_NEWLINE); - return CMD_WARNING; - case -EADDRINUSE: - vty_out(vty, "Unable to add UARFCN: (%u, %u) is already added%s", arfcn, scramble, VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_si2quater_uarfcn_del, cfg_bts_si2quater_uarfcn_del_cmd, - "si2quater neighbor-list del uarfcn <0-16383> <0-511>", - "SI2quater Neighbor List\n" - "SI2quater Neighbor List\n" - "Delete from SI2quater manual neighbor list\n" - "UARFCN of neighbor\n" - "UARFCN\n" - "scrambling code\n") -{ - struct gsm_bts *bts = vty->index; - - if (bts_uarfcn_del(bts, atoi(argv[0]), atoi(argv[1])) < 0) { - vty_out(vty, "Unable to delete uarfcn: pair not found%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_si5_neigh, cfg_bts_si5_neigh_cmd, - "si5 neighbor-list (add|del) arfcn <0-1023>", - "SI5 Neighbor List\n" - "SI5 Neighbor List\n" "Add to manual SI5 neighbor list\n" - "Delete from SI5 manual neighbor list\n" "ARFCN of neighbor\n" - "ARFCN of neighbor\n") -{ - struct gsm_bts *bts = vty->index; - struct bitvec *bv = &bts->si_common.si5_neigh_list; - uint16_t arfcn = atoi(argv[1]); - - if (!bts->neigh_list_manual_mode) { - vty_out(vty, "%% Cannot configure neighbor list in " - "automatic mode%s", VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[0], "add")) - bitvec_set_bit_pos(bv, arfcn, 1); - else - bitvec_set_bit_pos(bv, arfcn, 0); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_pcu_sock, cfg_bts_pcu_sock_cmd, - "pcu-socket PATH", - "PCU Socket Path for using OsmoPCU co-located with BSC (legacy BTS)\n" - "Path in the file system for the unix-domain PCU socket\n") -{ - struct gsm_bts *bts = vty->index; - int rc; - - osmo_talloc_replace_string(bts, &bts->pcu_sock_path, argv[0]); - pcu_sock_exit(bts); - rc = pcu_sock_init(bts->pcu_sock_path, bts); - if (rc < 0) { - vty_out(vty, "%% Error creating PCU socket `%s' for BTS %u%s", - bts->pcu_sock_path, bts->nr, VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -#define EXCL_RFLOCK_STR "Exclude this BTS from the global RF Lock\n" - -DEFUN(cfg_bts_excl_rf_lock, - cfg_bts_excl_rf_lock_cmd, - "rf-lock-exclude", - EXCL_RFLOCK_STR) -{ - struct gsm_bts *bts = vty->index; - bts->excl_from_rf_lock = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_no_excl_rf_lock, - cfg_bts_no_excl_rf_lock_cmd, - "no rf-lock-exclude", - NO_STR EXCL_RFLOCK_STR) -{ - struct gsm_bts *bts = vty->index; - bts->excl_from_rf_lock = 0; - return CMD_SUCCESS; -} - -#define FORCE_COMB_SI_STR "Force the generation of a single SI (no ter/bis)\n" - -DEFUN(cfg_bts_force_comb_si, - cfg_bts_force_comb_si_cmd, - "force-combined-si", - FORCE_COMB_SI_STR) -{ - struct gsm_bts *bts = vty->index; - bts->force_combined_si = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_no_force_comb_si, - cfg_bts_no_force_comb_si_cmd, - "no force-combined-si", - NO_STR FORCE_COMB_SI_STR) -{ - struct gsm_bts *bts = vty->index; - bts->force_combined_si = 0; - return CMD_SUCCESS; -} - -static void _get_codec_from_arg(struct vty *vty, int argc, const char *argv[]) -{ - struct gsm_bts *bts = vty->index; - struct bts_codec_conf *codec = &bts->codec; - int i; - - codec->hr = 0; - codec->efr = 0; - codec->amr = 0; - for (i = 0; i < argc; i++) { - if (!strcmp(argv[i], "hr")) - codec->hr = 1; - if (!strcmp(argv[i], "efr")) - codec->efr = 1; - if (!strcmp(argv[i], "amr")) - codec->amr = 1; - } -} - -#define CODEC_PAR_STR " (hr|efr|amr)" -#define CODEC_HELP_STR "Half Rate\n" \ - "Enhanced Full Rate\nAdaptive Multirate\n" - -DEFUN(cfg_bts_codec0, cfg_bts_codec0_cmd, - "codec-support fr", - "Codec Support settings\nFullrate\n") -{ - _get_codec_from_arg(vty, 0, argv); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_codec1, cfg_bts_codec1_cmd, - "codec-support fr" CODEC_PAR_STR, - "Codec Support settings\nFullrate\n" - CODEC_HELP_STR) -{ - _get_codec_from_arg(vty, 1, argv); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_codec2, cfg_bts_codec2_cmd, - "codec-support fr" CODEC_PAR_STR CODEC_PAR_STR, - "Codec Support settings\nFullrate\n" - CODEC_HELP_STR CODEC_HELP_STR) -{ - _get_codec_from_arg(vty, 2, argv); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_codec3, cfg_bts_codec3_cmd, - "codec-support fr" CODEC_PAR_STR CODEC_PAR_STR CODEC_PAR_STR, - "Codec Support settings\nFullrate\n" - CODEC_HELP_STR CODEC_HELP_STR CODEC_HELP_STR) -{ - _get_codec_from_arg(vty, 3, argv); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_codec4, cfg_bts_codec4_cmd, - "codec-support fr" CODEC_PAR_STR CODEC_PAR_STR CODEC_PAR_STR CODEC_PAR_STR, - "Codec Support settings\nFullrate\n" - CODEC_HELP_STR CODEC_HELP_STR CODEC_HELP_STR CODEC_HELP_STR) -{ - _get_codec_from_arg(vty, 4, argv); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_depends_on, cfg_bts_depends_on_cmd, - "depends-on-bts <0-255>", - "This BTS can only be started if another one is up\n" "BTS Number\n") -{ - struct gsm_bts *bts = vty->index; - struct gsm_bts *other_bts; - int dep = atoi(argv[0]); - - - if (!is_ipaccess_bts(bts)) { - vty_out(vty, "This feature is only available for IP systems.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - other_bts = gsm_bts_num(bts->network, dep); - if (!other_bts || !is_ipaccess_bts(other_bts)) { - vty_out(vty, "This feature is only available for IP systems.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (dep >= bts->nr) { - vty_out(vty, "%%Need to depend on an already declared unit.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - bts_depend_mark(bts, dep); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_no_depends_on, cfg_bts_no_depends_on_cmd, - "depeneds-on-bts <0-255>", - NO_STR "This BTS can only be started if another one is up\n" - "BTS Number\n") -{ - struct gsm_bts *bts = vty->index; - int dep = atoi(argv[0]); - - bts_depend_clear(bts, dep); - return CMD_SUCCESS; -} - -#define AMR_TEXT "Adaptive Multi Rate settings\n" -#define AMR_MODE_TEXT "Codec modes to use with AMR codec\n" -#define AMR_START_TEXT "Initial codec to use with AMR\n" \ - "Automatically\nFirst codec\nSecond codec\nThird codec\nFourth codec\n" -#define AMR_TH_TEXT "AMR threshold between codecs\nMS side\nBTS side\n" -#define AMR_HY_TEXT "AMR hysteresis between codecs\nMS side\nBTS side\n" - -static void get_amr_from_arg(struct vty *vty, int argc, const char *argv[], int full) -{ - struct gsm_bts *bts = vty->index; - struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half; - struct gsm48_multi_rate_conf *mr_conf = - (struct gsm48_multi_rate_conf *) mr->gsm48_ie; - int i; - - mr->gsm48_ie[1] = 0; - for (i = 0; i < argc; i++) - mr->gsm48_ie[1] |= 1 << atoi(argv[i]); - mr_conf->icmi = 0; -} - -static void get_amr_th_from_arg(struct vty *vty, int argc, const char *argv[], int full) -{ - struct gsm_bts *bts = vty->index; - struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half; - struct amr_mode *modes; - int i; - - modes = argv[0][0]=='m' ? mr->ms_mode : mr->bts_mode; - for (i = 0; i < argc - 1; i++) - modes[i].threshold = atoi(argv[i + 1]); -} - -static void get_amr_hy_from_arg(struct vty *vty, int argc, const char *argv[], int full) -{ - struct gsm_bts *bts = vty->index; - struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half; - struct amr_mode *modes; - int i; - - modes = argv[0][0]=='m' ? mr->ms_mode : mr->bts_mode; - for (i = 0; i < argc - 1; i++) - modes[i].hysteresis = atoi(argv[i + 1]); -} - -static void get_amr_start_from_arg(struct vty *vty, const char *argv[], int full) -{ - struct gsm_bts *bts = vty->index; - struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half; - struct gsm48_multi_rate_conf *mr_conf = - (struct gsm48_multi_rate_conf *) mr->gsm48_ie; - int num = 0, i; - - for (i = 0; i < ((full) ? 8 : 6); i++) { - if ((mr->gsm48_ie[1] & (1 << i))) { - num++; - } - } - - if (argv[0][0] == 'a' || num == 0) - mr_conf->icmi = 0; - else { - mr_conf->icmi = 1; - if (num < atoi(argv[0])) - mr_conf->smod = num - 1; - else - mr_conf->smod = atoi(argv[0]) - 1; - } -} - -#define AMR_TCHF_PAR_STR " (0|1|2|3|4|5|6|7)" -#define AMR_TCHF_HELP_STR "4,75k\n5,15k\n5,90k\n6,70k\n7,40k\n7,95k\n" \ - "10,2k\n12,2k\n" - -#define AMR_TCHH_PAR_STR " (0|1|2|3|4|5)" -#define AMR_TCHH_HELP_STR "4,75k\n5,15k\n5,90k\n6,70k\n7,40k\n7,95k\n" - -#define AMR_TH_HELP_STR "Threshold between codec 1 and 2\n" -#define AMR_HY_HELP_STR "Hysteresis between codec 1 and 2\n" - -DEFUN(cfg_bts_amr_fr_modes1, cfg_bts_amr_fr_modes1_cmd, - "amr tch-f modes" AMR_TCHF_PAR_STR, - AMR_TEXT "Full Rate\n" AMR_MODE_TEXT - AMR_TCHF_HELP_STR) -{ - get_amr_from_arg(vty, 1, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_modes2, cfg_bts_amr_fr_modes2_cmd, - "amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR, - AMR_TEXT "Full Rate\n" AMR_MODE_TEXT - AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR) -{ - get_amr_from_arg(vty, 2, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_modes3, cfg_bts_amr_fr_modes3_cmd, - "amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR, - AMR_TEXT "Full Rate\n" AMR_MODE_TEXT - AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR) -{ - get_amr_from_arg(vty, 3, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_modes4, cfg_bts_amr_fr_modes4_cmd, - "amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR, - AMR_TEXT "Full Rate\n" AMR_MODE_TEXT - AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR) -{ - get_amr_from_arg(vty, 4, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_start_mode, cfg_bts_amr_fr_start_mode_cmd, - "amr tch-f start-mode (auto|1|2|3|4)", - AMR_TEXT "Full Rate\n" AMR_START_TEXT) -{ - get_amr_start_from_arg(vty, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_thres1, cfg_bts_amr_fr_thres1_cmd, - "amr tch-f threshold (ms|bts) <0-63>", - AMR_TEXT "Full Rate\n" AMR_TH_TEXT - AMR_TH_HELP_STR) -{ - get_amr_th_from_arg(vty, 2, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_thres2, cfg_bts_amr_fr_thres2_cmd, - "amr tch-f threshold (ms|bts) <0-63> <0-63>", - AMR_TEXT "Full Rate\n" AMR_TH_TEXT - AMR_TH_HELP_STR AMR_TH_HELP_STR) -{ - get_amr_th_from_arg(vty, 3, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_thres3, cfg_bts_amr_fr_thres3_cmd, - "amr tch-f threshold (ms|bts) <0-63> <0-63> <0-63>", - AMR_TEXT "Full Rate\n" AMR_TH_TEXT - AMR_TH_HELP_STR AMR_TH_HELP_STR AMR_TH_HELP_STR) -{ - get_amr_th_from_arg(vty, 4, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_hyst1, cfg_bts_amr_fr_hyst1_cmd, - "amr tch-f hysteresis (ms|bts) <0-15>", - AMR_TEXT "Full Rate\n" AMR_HY_TEXT - AMR_HY_HELP_STR) -{ - get_amr_hy_from_arg(vty, 2, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_hyst2, cfg_bts_amr_fr_hyst2_cmd, - "amr tch-f hysteresis (ms|bts) <0-15> <0-15>", - AMR_TEXT "Full Rate\n" AMR_HY_TEXT - AMR_HY_HELP_STR AMR_HY_HELP_STR) -{ - get_amr_hy_from_arg(vty, 3, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_fr_hyst3, cfg_bts_amr_fr_hyst3_cmd, - "amr tch-f hysteresis (ms|bts) <0-15> <0-15> <0-15>", - AMR_TEXT "Full Rate\n" AMR_HY_TEXT - AMR_HY_HELP_STR AMR_HY_HELP_STR AMR_HY_HELP_STR) -{ - get_amr_hy_from_arg(vty, 4, argv, 1); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_modes1, cfg_bts_amr_hr_modes1_cmd, - "amr tch-h modes" AMR_TCHH_PAR_STR, - AMR_TEXT "Half Rate\n" AMR_MODE_TEXT - AMR_TCHH_HELP_STR) -{ - get_amr_from_arg(vty, 1, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_modes2, cfg_bts_amr_hr_modes2_cmd, - "amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR, - AMR_TEXT "Half Rate\n" AMR_MODE_TEXT - AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR) -{ - get_amr_from_arg(vty, 2, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_modes3, cfg_bts_amr_hr_modes3_cmd, - "amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR, - AMR_TEXT "Half Rate\n" AMR_MODE_TEXT - AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR) -{ - get_amr_from_arg(vty, 3, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_modes4, cfg_bts_amr_hr_modes4_cmd, - "amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR, - AMR_TEXT "Half Rate\n" AMR_MODE_TEXT - AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR) -{ - get_amr_from_arg(vty, 4, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_start_mode, cfg_bts_amr_hr_start_mode_cmd, - "amr tch-h start-mode (auto|1|2|3|4)", - AMR_TEXT "Half Rate\n" AMR_START_TEXT) -{ - get_amr_start_from_arg(vty, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_thres1, cfg_bts_amr_hr_thres1_cmd, - "amr tch-h threshold (ms|bts) <0-63>", - AMR_TEXT "Half Rate\n" AMR_TH_TEXT - AMR_TH_HELP_STR) -{ - get_amr_th_from_arg(vty, 2, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_thres2, cfg_bts_amr_hr_thres2_cmd, - "amr tch-h threshold (ms|bts) <0-63> <0-63>", - AMR_TEXT "Half Rate\n" AMR_TH_TEXT - AMR_TH_HELP_STR AMR_TH_HELP_STR) -{ - get_amr_th_from_arg(vty, 3, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_thres3, cfg_bts_amr_hr_thres3_cmd, - "amr tch-h threshold (ms|bts) <0-63> <0-63> <0-63>", - AMR_TEXT "Half Rate\n" AMR_TH_TEXT - AMR_TH_HELP_STR AMR_TH_HELP_STR AMR_TH_HELP_STR) -{ - get_amr_th_from_arg(vty, 4, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_hyst1, cfg_bts_amr_hr_hyst1_cmd, - "amr tch-h hysteresis (ms|bts) <0-15>", - AMR_TEXT "Half Rate\n" AMR_HY_TEXT - AMR_HY_HELP_STR) -{ - get_amr_hy_from_arg(vty, 2, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_hyst2, cfg_bts_amr_hr_hyst2_cmd, - "amr tch-h hysteresis (ms|bts) <0-15> <0-15>", - AMR_TEXT "Half Rate\n" AMR_HY_TEXT - AMR_HY_HELP_STR AMR_HY_HELP_STR) -{ - get_amr_hy_from_arg(vty, 3, argv, 0); - return CMD_SUCCESS; -} - -DEFUN(cfg_bts_amr_hr_hyst3, cfg_bts_amr_hr_hyst3_cmd, - "amr tch-h hysteresis (ms|bts) <0-15> <0-15> <0-15>", - AMR_TEXT "Half Rate\n" AMR_HY_TEXT - AMR_HY_HELP_STR AMR_HY_HELP_STR AMR_HY_HELP_STR) -{ - get_amr_hy_from_arg(vty, 4, argv, 0); - return CMD_SUCCESS; -} - -#define TRX_TEXT "Radio Transceiver\n" - -/* per TRX configuration */ -DEFUN(cfg_trx, - cfg_trx_cmd, - "trx <0-255>", - TRX_TEXT - "Select a TRX to configure") -{ - int trx_nr = atoi(argv[0]); - struct gsm_bts *bts = vty->index; - struct gsm_bts_trx *trx; - - if (trx_nr > bts->num_trx) { - vty_out(vty, "%% The next unused TRX number in this BTS is %u%s", - bts->num_trx, VTY_NEWLINE); - return CMD_WARNING; - } else if (trx_nr == bts->num_trx) { - /* we need to allocate a new one */ - trx = gsm_bts_trx_alloc(bts); - } else - trx = gsm_bts_trx_num(bts, trx_nr); - - if (!trx) - return CMD_WARNING; - - vty->index = trx; - vty->index_sub = &trx->description; - vty->node = TRX_NODE; - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_arfcn, - cfg_trx_arfcn_cmd, - "arfcn <0-1023>", - "Set the ARFCN for this TRX\n" - "Absolute Radio Frequency Channel Number\n") -{ - int arfcn = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - - /* FIXME: check if this ARFCN is supported by this TRX */ - - trx->arfcn = arfcn; - - /* FIXME: patch ARFCN into SYSTEM INFORMATION */ - /* FIXME: use OML layer to update the ARFCN */ - /* FIXME: use RSL layer to update SYSTEM INFORMATION */ - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_nominal_power, - cfg_trx_nominal_power_cmd, - "nominal power <0-100>", - "Nominal TRX RF Power in dBm\n" - "Nominal TRX RF Power in dBm\n" - "Nominal TRX RF Power in dBm\n") -{ - struct gsm_bts_trx *trx = vty->index; - - trx->nominal_power = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_max_power_red, - cfg_trx_max_power_red_cmd, - "max_power_red <0-100>", - "Reduction of maximum BS RF Power (relative to nominal power)\n" - "Reduction of maximum BS RF Power in dB\n") -{ - int maxpwr_r = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - int upper_limit = 24; /* default 12.21 max power red. */ - - /* FIXME: check if our BTS type supports more than 12 */ - if (maxpwr_r < 0 || maxpwr_r > upper_limit) { - vty_out(vty, "%% Power %d dB is not in the valid range%s", - maxpwr_r, VTY_NEWLINE); - return CMD_WARNING; - } - if (maxpwr_r & 1) { - vty_out(vty, "%% Power %d dB is not an even value%s", - maxpwr_r, VTY_NEWLINE); - return CMD_WARNING; - } - - trx->max_power_red = maxpwr_r; - - /* FIXME: make sure we update this using OML */ - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_rsl_e1, - cfg_trx_rsl_e1_cmd, - "rsl e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)", - "RSL Parameters\n" - "E1/T1 interface to be used for RSL\n" - "E1/T1 interface to be used for RSL\n" - "E1/T1 Line Number to be used for RSL\n" - "E1/T1 Timeslot to be used for RSL\n" - "E1/T1 Timeslot to be used for RSL\n" - "E1/T1 Sub-slot to be used for RSL\n" - "E1/T1 Sub-slot 0 is to be used for RSL\n" - "E1/T1 Sub-slot 1 is to be used for RSL\n" - "E1/T1 Sub-slot 2 is to be used for RSL\n" - "E1/T1 Sub-slot 3 is to be used for RSL\n" - "E1/T1 full timeslot is to be used for RSL\n") -{ - struct gsm_bts_trx *trx = vty->index; - - parse_e1_link(&trx->rsl_e1_link, argv[0], argv[1], argv[2]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_rsl_e1_tei, - cfg_trx_rsl_e1_tei_cmd, - "rsl e1 tei <0-63>", - "RSL Parameters\n" - "Set the TEI to be used for RSL\n" - "Set the TEI to be used for RSL\n" - "TEI to be used for RSL\n") -{ - struct gsm_bts_trx *trx = vty->index; - - trx->rsl_tei = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_rf_locked, - cfg_trx_rf_locked_cmd, - "rf_locked (0|1)", - "Set or unset the RF Locking (Turn off RF of the TRX)\n" - "TRX is NOT RF locked (active)\n" - "TRX is RF locked (turned off)\n") -{ - int locked = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - - gsm_trx_lock_rf(trx, locked); - return CMD_SUCCESS; -} - -/* per TS configuration */ -DEFUN(cfg_ts, - cfg_ts_cmd, - "timeslot <0-7>", - "Select a Timeslot to configure\n" - "Timeslot number\n") -{ - int ts_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - struct gsm_bts_trx_ts *ts; - - if (ts_nr >= TRX_NR_TS) { - vty_out(vty, "%% A GSM TRX only has %u Timeslots per TRX%s", - TRX_NR_TS, VTY_NEWLINE); - return CMD_WARNING; - } - - ts = &trx->ts[ts_nr]; - - vty->index = ts; - vty->node = TS_NODE; - - return CMD_SUCCESS; -} - -DEFUN(cfg_ts_pchan, - cfg_ts_pchan_cmd, - "phys_chan_config PCHAN", /* dynamically generated! */ - "Physical Channel configuration (TCH/SDCCH/...)\n" "Physical Channel\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - int pchanc; - - pchanc = gsm_pchan_parse(argv[0]); - if (pchanc < 0) - return CMD_WARNING; - - ts->pchan = pchanc; - - return CMD_SUCCESS; -} - -/* used for backwards compatibility with old config files that still - * have uppercase pchan type names */ -DEFUN_HIDDEN(cfg_ts_pchan_compat, - cfg_ts_pchan_compat_cmd, - "phys_chan_config PCHAN", - "Physical Channel configuration (TCH/SDCCH/...)\n" "Physical Channel\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - int pchanc; - - pchanc = gsm_pchan_parse(argv[0]); - if (pchanc < 0) - return CMD_WARNING; - - ts->pchan = pchanc; - - return CMD_SUCCESS; -} - - - -DEFUN(cfg_ts_tsc, - cfg_ts_tsc_cmd, - "training_sequence_code <0-7>", - "Training Sequence Code of the Timeslot\n" "TSC\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - - if (!gsm_btsmodel_has_feature(ts->trx->bts->model, BTS_FEAT_MULTI_TSC)) { - vty_out(vty, "%% This BTS does not support a TSC != BCC, " - "falling back to BCC%s", VTY_NEWLINE); - ts->tsc = -1; - return CMD_WARNING; - } - - ts->tsc = atoi(argv[0]); - - return CMD_SUCCESS; -} - -#define HOPPING_STR "Configure frequency hopping\n" - -DEFUN(cfg_ts_hopping, - cfg_ts_hopping_cmd, - "hopping enabled (0|1)", - HOPPING_STR "Enable or disable frequency hopping\n" - "Disable frequency hopping\n" "Enable frequency hopping\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - int enabled = atoi(argv[0]); - - if (enabled && !gsm_btsmodel_has_feature(ts->trx->bts->model, BTS_FEAT_HOPPING)) { - vty_out(vty, "BTS model does not support hopping%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - ts->hopping.enabled = enabled; - - return CMD_SUCCESS; -} - -DEFUN(cfg_ts_hsn, - cfg_ts_hsn_cmd, - "hopping sequence-number <0-63>", - HOPPING_STR - "Which hopping sequence to use for this channel\n" - "Hopping Sequence Number (HSN)\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - - ts->hopping.hsn = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ts_maio, - cfg_ts_maio_cmd, - "hopping maio <0-63>", - HOPPING_STR - "Which hopping MAIO to use for this channel\n" - "Mobile Allocation Index Offset (MAIO)\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - - ts->hopping.maio = atoi(argv[0]); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ts_arfcn_add, - cfg_ts_arfcn_add_cmd, - "hopping arfcn add <0-1023>", - HOPPING_STR "Configure hopping ARFCN list\n" - "Add an entry to the hopping ARFCN list\n" "ARFCN\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - int arfcn = atoi(argv[0]); - - bitvec_set_bit_pos(&ts->hopping.arfcns, arfcn, 1); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ts_arfcn_del, - cfg_ts_arfcn_del_cmd, - "hopping arfcn del <0-1023>", - HOPPING_STR "Configure hopping ARFCN list\n" - "Delete an entry to the hopping ARFCN list\n" "ARFCN\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - int arfcn = atoi(argv[0]); - - bitvec_set_bit_pos(&ts->hopping.arfcns, arfcn, 0); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ts_e1_subslot, - cfg_ts_e1_subslot_cmd, - "e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)", - "E1/T1 channel connected to this on-air timeslot\n" - "E1/T1 channel connected to this on-air timeslot\n" - "E1/T1 line connected to this on-air timeslot\n" - "E1/T1 timeslot connected to this on-air timeslot\n" - "E1/T1 timeslot connected to this on-air timeslot\n" - "E1/T1 sub-slot connected to this on-air timeslot\n" - "E1/T1 sub-slot 0 connected to this on-air timeslot\n" - "E1/T1 sub-slot 1 connected to this on-air timeslot\n" - "E1/T1 sub-slot 2 connected to this on-air timeslot\n" - "E1/T1 sub-slot 3 connected to this on-air timeslot\n" - "Full E1/T1 timeslot connected to this on-air timeslot\n") -{ - struct gsm_bts_trx_ts *ts = vty->index; - - parse_e1_link(&ts->e1_link, argv[0], argv[1], argv[2]); - - return CMD_SUCCESS; -} - -void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) -{ - vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - net->bsc_ctrs->ctr[BSC_CTR_CHREQ_TOTAL].current, - net->bsc_ctrs->ctr[BSC_CTR_CHREQ_NO_CHANNEL].current, - VTY_NEWLINE); - vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", - net->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL].current, - net->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR].current, - VTY_NEWLINE); - vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - net->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED].current, - net->bsc_ctrs->ctr[BSC_CTR_PAGING_COMPLETED].current, - net->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED].current, - VTY_NEWLINE); - vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", - net->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL].current, - net->bsc_ctrs->ctr[BSC_CTR_BTS_RSL_FAIL].current, - VTY_NEWLINE); -} - -DEFUN(drop_bts, - drop_bts_cmd, - "drop bts connection <0-65535> (oml|rsl)", - "Debug/Simulation command to drop Abis/IP BTS\n" - "Debug/Simulation command to drop Abis/IP BTS\n" - "Debug/Simulation command to drop Abis/IP BTS\n" - "BTS NR\n" "Drop OML Connection\n" "Drop RSL Connection\n") -{ - struct gsm_network *gsmnet; - struct gsm_bts_trx *trx; - struct gsm_bts *bts; - unsigned int bts_nr; - - gsmnet = gsmnet_from_vty(vty); - - bts_nr = atoi(argv[0]); - if (bts_nr >= gsmnet->num_bts) { - vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s", - gsmnet->num_bts, bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - bts = gsm_bts_num(gsmnet, bts_nr); - if (!bts) { - vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - if (!is_ipaccess_bts(bts)) { - vty_out(vty, "This command only works for ipaccess.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - - /* close all connections */ - if (strcmp(argv[1], "oml") == 0) { - ipaccess_drop_oml(bts); - } else if (strcmp(argv[1], "rsl") == 0) { - /* close all rsl connections */ - llist_for_each_entry(trx, &bts->trx_list, list) { - ipaccess_drop_rsl(trx); - } - } else { - vty_out(vty, "Argument must be 'oml# or 'rsl'.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -DEFUN(restart_bts, restart_bts_cmd, - "restart-bts <0-65535>", - "Restart ip.access nanoBTS through OML\n" - "BTS Number\n") -{ - struct gsm_network *gsmnet; - struct gsm_bts_trx *trx; - struct gsm_bts *bts; - unsigned int bts_nr; - - gsmnet = gsmnet_from_vty(vty); - - bts_nr = atoi(argv[0]); - if (bts_nr >= gsmnet->num_bts) { - vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s", - gsmnet->num_bts, bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - bts = gsm_bts_num(gsmnet, bts_nr); - if (!bts) { - vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - if (!is_ipaccess_bts(bts) || is_sysmobts_v2(bts)) { - vty_out(vty, "This command only works for ipaccess nanoBTS.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - /* go from last TRX to c0 */ - llist_for_each_entry_reverse(trx, &bts->trx_list, list) - abis_nm_ipaccess_restart(trx); - - return CMD_SUCCESS; -} - -DEFUN(bts_resend, bts_resend_cmd, - "bts <0-255> resend-system-information", - "BTS Specific Commands\n" "BTS Number\n" - "Re-generate + re-send BCCH SYSTEM INFORMATION\n") -{ - struct gsm_network *gsmnet; - struct gsm_bts_trx *trx; - struct gsm_bts *bts; - unsigned int bts_nr; - - gsmnet = gsmnet_from_vty(vty); - - bts_nr = atoi(argv[0]); - if (bts_nr >= gsmnet->num_bts) { - vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s", - gsmnet->num_bts, bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - bts = gsm_bts_num(gsmnet, bts_nr); - if (!bts) { - vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - - llist_for_each_entry_reverse(trx, &bts->trx_list, list) - gsm_bts_trx_set_system_infos(trx); - - return CMD_SUCCESS; -} - - -DEFUN(smscb_cmd, smscb_cmd_cmd, - "bts <0-255> smscb-command <1-4> HEXSTRING", - "BTS related commands\n" "BTS Number\n" - "SMS Cell Broadcast\n" "Last Valid Block\n" - "Hex Encoded SMSCB message (up to 88 octets)\n") -{ - struct gsm_bts *bts; - int bts_nr = atoi(argv[0]); - int last_block = atoi(argv[1]); - struct rsl_ie_cb_cmd_type cb_cmd; - uint8_t buf[88]; - int rc; - - bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr); - if (!bts) { - vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE); - return CMD_WARNING; - } - rc = osmo_hexparse(argv[2], buf, sizeof(buf)); - if (rc < 0 || rc > sizeof(buf)) { - vty_out(vty, "Error parsing HEXSTRING%s", VTY_NEWLINE); - return CMD_WARNING; - } - - cb_cmd.spare = 0; - cb_cmd.def_bcast = 0; - cb_cmd.command = RSL_CB_CMD_TYPE_NORMAL; - - switch (last_block) { - case 1: - cb_cmd.last_block = RSL_CB_CMD_LASTBLOCK_1; - break; - case 2: - cb_cmd.last_block = RSL_CB_CMD_LASTBLOCK_2; - break; - case 3: - cb_cmd.last_block = RSL_CB_CMD_LASTBLOCK_3; - break; - case 4: - cb_cmd.last_block = RSL_CB_CMD_LASTBLOCK_4; - break; - } - - rsl_sms_cb_command(bts, RSL_CHAN_SDCCH4_ACCH, cb_cmd, buf, rc); - - return CMD_SUCCESS; -} - -/* resolve a gsm_bts_trx_ts basd on the given numeric identifiers */ -static struct gsm_bts_trx_ts *vty_get_ts(struct vty *vty, const char *bts_str, const char *trx_str, - const char *ts_str) -{ - int bts_nr = atoi(bts_str); - int trx_nr = atoi(trx_str); - int ts_nr = atoi(ts_str); - struct gsm_bts *bts; - struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - - bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr); - if (!bts) { - vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE); - return NULL; - } - - trx = gsm_bts_trx_num(bts, trx_nr); - if (!trx) { - vty_out(vty, "%% No such TRX (%d)%s", trx_nr, VTY_NEWLINE); - return NULL; - } - - ts = &trx->ts[ts_nr]; - - return ts; -} - -DEFUN(pdch_act, pdch_act_cmd, - "bts <0-255> trx <0-255> timeslot <0-7> pdch (activate|deactivate)", - "BTS related commands\n" "BTS Number\n" "Transceiver\n" "Transceiver Number\n" - "TRX Timeslot\n" "Timeslot Number\n" "Packet Data Channel\n" - "Activate Dynamic PDCH/TCH (-> PDCH mode)\n" - "Deactivate Dynamic PDCH/TCH (-> TCH mode)\n") -{ - struct gsm_bts_trx_ts *ts; - int activate; - - ts = vty_get_ts(vty, argv[0], argv[1], argv[2]); - if (!ts) - return CMD_WARNING; - - if (!is_ipaccess_bts(ts->trx->bts)) { - vty_out(vty, "%% This command only works for ipaccess BTS%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - if (ts->pchan != GSM_PCHAN_TCH_F_PDCH) { - vty_out(vty, "%% Timeslot %u is not in dynamic TCH_F/PDCH " - "mode%s", ts->nr, VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[3], "activate")) - activate = 1; - else - activate = 0; - - rsl_ipacc_pdch_activate(ts, activate); - - return CMD_SUCCESS; - -} - -/* determine the logical channel type based on the physical channel type */ -static int lchan_type_by_pchan(enum gsm_phys_chan_config pchan) -{ - switch (pchan) { - case GSM_PCHAN_TCH_F: - return GSM_LCHAN_TCH_F; - case GSM_PCHAN_TCH_H: - return GSM_LCHAN_TCH_H; - case GSM_PCHAN_SDCCH8_SACCH8C: - case GSM_PCHAN_SDCCH8_SACCH8C_CBCH: - case GSM_PCHAN_CCCH_SDCCH4: - case GSM_PCHAN_CCCH_SDCCH4_CBCH: - return GSM_LCHAN_SDCCH; - default: - return -1; - } -} - -/* configure the lchan for a single AMR mode (as specified) */ -static int lchan_set_single_amr_mode(struct gsm_lchan *lchan, uint8_t amr_mode) -{ - struct amr_multirate_conf mr; - struct gsm48_multi_rate_conf *mr_conf; - mr_conf = (struct gsm48_multi_rate_conf *) &mr.gsm48_ie; - - if (amr_mode > 7) - return -1; - - memset(&mr, 0, sizeof(mr)); - mr_conf->ver = 1; - /* bit-mask of supported modes, only one bit is set. Reflects - * Figure 10.5.2.47a where there are no thershold and only a - * single mode */ - mr.gsm48_ie[1] = 1 << amr_mode; - - mr.ms_mode[0].mode = amr_mode; - mr.bts_mode[0].mode = amr_mode; - - /* encode this configuration into the lchan for both uplink and - * downlink direction */ - gsm48_multirate_config(lchan->mr_ms_lv, &mr, mr.ms_mode); - gsm48_multirate_config(lchan->mr_bts_lv, &mr, mr.bts_mode); - - return 0; -} - -/* Debug/Measurement command to activate a given logical channel - * manually in a given mode/codec. This is useful for receiver - * performance testing (FER/RBER/...) */ -DEFUN(lchan_act, lchan_act_cmd, - "bts <0-255> trx <0-255> timeslot <0-7> sub-slot <0-7> (activate|deactivate) (hr|fr|efr|amr) [<0-7>]", - "BTS related commands\n" "BTS Number\n" "Transceiver\n" "Transceiver Number\n" - "TRX Timeslot\n" "Timeslot Number\n" "Sub-Slot Number\n" "Sub-Slot Number\n" - "Manual Channel Activation (e.g. for BER test)\n" - "Manual Channel Deactivation (e.g. for BER test)\n" - "Half-Rate v1\n" "Full-Rate\n" "Enhanced Full Rate\n" "Adaptive Multi-Rate\n" "AMR Mode\n") -{ - struct gsm_bts_trx_ts *ts; - struct gsm_lchan *lchan; - int ss_nr = atoi(argv[3]); - const char *act_str = argv[4]; - const char *codec_str = argv[5]; - int activate; - - ts = vty_get_ts(vty, argv[0], argv[1], argv[2]); - if (!ts) - return CMD_WARNING; - - lchan = &ts->lchan[ss_nr]; - - if (!strcmp(act_str, "activate")) - activate = 1; - else - activate = 0; - - if (ss_nr >= ts_subslots(ts)) { - vty_out(vty, "%% subslot %d >= permitted %d for physical channel %s%s", - ss_nr, ts_subslots(ts), gsm_pchan_name(ts->pchan), VTY_NEWLINE); - return CMD_WARNING; - } - - if (activate) { - int lchan_t; - if (lchan->state != LCHAN_S_NONE) { - vty_out(vty, "%% Cannot activate: Channel busy!%s", VTY_NEWLINE); - return CMD_WARNING; - } - lchan_t = lchan_type_by_pchan(ts->pchan); - if (lchan_t < 0) - return CMD_WARNING; - /* configure the lchan */ - lchan->type = lchan_t; - lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH; - if (!strcmp(codec_str, "hr") || !strcmp(codec_str, "fr")) - lchan->tch_mode = GSM48_CMODE_SPEECH_V1; - else if (!strcmp(codec_str, "efr")) - lchan->tch_mode = GSM48_CMODE_SPEECH_EFR; - else if (!strcmp(codec_str, "amr")) { - int amr_mode; - if (argc < 7) { - vty_out(vty, "%% AMR requires specification of AMR mode%s", VTY_NEWLINE); - return CMD_WARNING; - } - amr_mode = atoi(argv[6]); - lchan->tch_mode = GSM48_CMODE_SPEECH_AMR; - lchan_set_single_amr_mode(lchan, amr_mode); - } - vty_out(vty, "%% activating lchan %s%s", gsm_lchan_name(lchan), VTY_NEWLINE); - rsl_chan_activate_lchan(lchan, RSL_ACT_TYPE_INITIAL, 0); - rsl_ipacc_crcx(lchan); - } else { - rsl_direct_rf_release(lchan); - } - - return CMD_SUCCESS; -} - -DEFUN(lchan_mdcx, lchan_mdcx_cmd, - "bts <0-255> trx <0-255> timeslot <0-7> sub-slot <0-7> mdcx A.B.C.D <0-65535>", - "BTS related commands\n" "BTS Number\n" "Transceiver\n" "Transceiver Number\n" - "TRX Timeslot\n" "Timeslot Number\n" "Sub-Slot\n" "Sub-Slot Number\n" - "Modify RTP Connection\n" "MGW IP Address\n" "MGW UDP Port\n") -{ - struct gsm_bts_trx_ts *ts; - struct gsm_lchan *lchan; - int ss_nr = atoi(argv[3]); - int port = atoi(argv[5]); - struct in_addr ia; - inet_aton(argv[4], &ia); - - ts = vty_get_ts(vty, argv[0], argv[1], argv[2]); - if (!ts) - return CMD_WARNING; - - lchan = &ts->lchan[ss_nr]; - - if (ss_nr >= ts_subslots(ts)) { - vty_out(vty, "%% subslot %d >= permitted %d for physical channel %s%s", - ss_nr, ts_subslots(ts), gsm_pchan_name(ts->pchan), VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "%% connecting RTP of %s to %s:%u%s", gsm_lchan_name(lchan), - inet_ntoa(ia), port, VTY_NEWLINE); - rsl_ipacc_mdcx(lchan, ntohl(ia.s_addr), port, 0); - return CMD_SUCCESS; -} - -DEFUN(ctrl_trap, ctrl_trap_cmd, - "ctrl-interface generate-trap TRAP VALUE", - "Commands related to the CTRL Interface\n" - "Generate a TRAP for test purpose\n" - "Identity/Name of the TRAP variable\n" - "Value of the TRAP variable\n") -{ - struct gsm_network *net = gsmnet_from_vty(vty); - - ctrl_cmd_send_trap(net->ctrl, argv[0], (char *) argv[1]); - return CMD_SUCCESS; -} - -extern int bsc_vty_init_extra(void); - -int bsc_vty_init(struct gsm_network *network) -{ - cfg_ts_pchan_cmd.string = - vty_cmd_string_from_valstr(tall_bsc_ctx, - gsm_pchant_names, - "phys_chan_config (", "|", ")", - VTY_DO_LOWER); - cfg_ts_pchan_cmd.doc = - vty_cmd_string_from_valstr(tall_bsc_ctx, - gsm_pchant_descs, - "Physical Channel Combination\n", - "\n", "", 0); - - cfg_bts_type_cmd.string = - vty_cmd_string_from_valstr(tall_bsc_ctx, - bts_type_names, - "type (", "|", ")", - VTY_DO_LOWER); - cfg_bts_type_cmd.doc = - vty_cmd_string_from_valstr(tall_bsc_ctx, - bts_type_descs, - "BTS Vendor/Type\n", - "\n", "", 0); - - common_cs_vty_init(network, config_write_net); - - install_element_ve(&bsc_show_net_cmd); - install_element_ve(&show_bts_cmd); - install_element_ve(&show_trx_cmd); - install_element_ve(&show_ts_cmd); - install_element_ve(&show_lchan_cmd); - install_element_ve(&show_lchan_summary_cmd); - - install_element_ve(&show_subscr_conn_cmd); - install_element_ve(&handover_subscr_conn_cmd); - - install_element_ve(&show_paging_cmd); - install_element_ve(&show_paging_group_cmd); - - logging_vty_add_cmds(NULL); - - install_element(GSMNET_NODE, &cfg_net_neci_cmd); - install_element(GSMNET_NODE, &cfg_net_handover_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd); - install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd); - install_element(GSMNET_NODE, &cfg_net_T3101_cmd); - install_element(GSMNET_NODE, &cfg_net_T3103_cmd); - install_element(GSMNET_NODE, &cfg_net_T3105_cmd); - install_element(GSMNET_NODE, &cfg_net_T3107_cmd); - install_element(GSMNET_NODE, &cfg_net_T3109_cmd); - install_element(GSMNET_NODE, &cfg_net_T3111_cmd); - install_element(GSMNET_NODE, &cfg_net_T3113_cmd); - install_element(GSMNET_NODE, &cfg_net_T3115_cmd); - install_element(GSMNET_NODE, &cfg_net_T3117_cmd); - install_element(GSMNET_NODE, &cfg_net_T3119_cmd); - install_element(GSMNET_NODE, &cfg_net_T3122_cmd); - install_element(GSMNET_NODE, &cfg_net_T3141_cmd); - install_element(GSMNET_NODE, &cfg_net_dtx_cmd); - install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd); - - install_element(GSMNET_NODE, &cfg_bts_cmd); - install_node(&bts_node, config_write_bts); - vty_install_default(BTS_NODE); - install_element(BTS_NODE, &cfg_bts_type_cmd); - install_element(BTS_NODE, &cfg_description_cmd); - install_element(BTS_NODE, &cfg_no_description_cmd); - install_element(BTS_NODE, &cfg_bts_band_cmd); - install_element(BTS_NODE, &cfg_bts_ci_cmd); - install_element(BTS_NODE, &cfg_bts_dtxu_cmd); - install_element(BTS_NODE, &cfg_bts_dtxd_cmd); - install_element(BTS_NODE, &cfg_bts_no_dtxu_cmd); - install_element(BTS_NODE, &cfg_bts_no_dtxd_cmd); - install_element(BTS_NODE, &cfg_bts_lac_cmd); - install_element(BTS_NODE, &cfg_bts_tsc_cmd); - install_element(BTS_NODE, &cfg_bts_bsic_cmd); - install_element(BTS_NODE, &cfg_bts_unit_id_cmd); - install_element(BTS_NODE, &cfg_bts_rsl_ip_cmd); - install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd); - install_element(BTS_NODE, &cfg_bts_nokia_site_no_loc_rel_cnf_cmd); - install_element(BTS_NODE, &cfg_bts_nokia_site_bts_reset_timer_cnf_cmd); - install_element(BTS_NODE, &cfg_bts_stream_id_cmd); - install_element(BTS_NODE, &cfg_bts_oml_e1_cmd); - install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd); - install_element(BTS_NODE, &cfg_bts_challoc_cmd); - install_element(BTS_NODE, &cfg_bts_rach_tx_integer_cmd); - install_element(BTS_NODE, &cfg_bts_rach_max_trans_cmd); - install_element(BTS_NODE, &cfg_bts_chan_desc_att_cmd); - install_element(BTS_NODE, &cfg_bts_chan_desc_bs_pa_mfrms_cmd); - install_element(BTS_NODE, &cfg_bts_chan_desc_bs_ag_blks_res_cmd); - install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd); - install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd); - install_element(BTS_NODE, &cfg_bts_cell_barred_cmd); - install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd); - install_element(BTS_NODE, &cfg_bts_rach_ac_class_cmd); - install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd); - install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd); - install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd); - install_element(BTS_NODE, &cfg_bts_cell_bar_qualify_cmd); - install_element(BTS_NODE, &cfg_bts_cell_resel_ofs_cmd); - install_element(BTS_NODE, &cfg_bts_temp_ofs_cmd); - install_element(BTS_NODE, &cfg_bts_temp_ofs_inf_cmd); - install_element(BTS_NODE, &cfg_bts_penalty_time_cmd); - install_element(BTS_NODE, &cfg_bts_penalty_time_rsvd_cmd); - install_element(BTS_NODE, &cfg_bts_radio_link_timeout_cmd); - install_element(BTS_NODE, &cfg_bts_radio_link_timeout_inf_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_11bit_rach_support_for_egprs_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_ns_timer_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_net_ctrl_ord_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_ctrl_ack_cmd); - install_element(BTS_NODE, &cfg_no_bts_gprs_ctrl_ack_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_cell_timer_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rport_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rip_cmd); - install_element(BTS_NODE, &cfg_bts_pag_free_cmd); - install_element(BTS_NODE, &cfg_bts_si_mode_cmd); - install_element(BTS_NODE, &cfg_bts_si_static_cmd); - install_element(BTS_NODE, &cfg_bts_early_cm_cmd); - install_element(BTS_NODE, &cfg_bts_neigh_mode_cmd); - install_element(BTS_NODE, &cfg_bts_neigh_cmd); - install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd); - install_element(BTS_NODE, &cfg_bts_si2quater_neigh_add_cmd); - install_element(BTS_NODE, &cfg_bts_si2quater_neigh_del_cmd); - install_element(BTS_NODE, &cfg_bts_si2quater_uarfcn_add_cmd); - install_element(BTS_NODE, &cfg_bts_si2quater_uarfcn_del_cmd); - install_element(BTS_NODE, &cfg_bts_excl_rf_lock_cmd); - install_element(BTS_NODE, &cfg_bts_no_excl_rf_lock_cmd); - install_element(BTS_NODE, &cfg_bts_force_comb_si_cmd); - install_element(BTS_NODE, &cfg_bts_no_force_comb_si_cmd); - install_element(BTS_NODE, &cfg_bts_codec0_cmd); - install_element(BTS_NODE, &cfg_bts_codec1_cmd); - install_element(BTS_NODE, &cfg_bts_codec2_cmd); - install_element(BTS_NODE, &cfg_bts_codec3_cmd); - install_element(BTS_NODE, &cfg_bts_codec4_cmd); - install_element(BTS_NODE, &cfg_bts_depends_on_cmd); - install_element(BTS_NODE, &cfg_bts_no_depends_on_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_modes1_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_modes2_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_modes3_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_modes4_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_thres1_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_thres2_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_thres3_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_hyst1_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_hyst2_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_hyst3_cmd); - install_element(BTS_NODE, &cfg_bts_amr_fr_start_mode_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_modes1_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_modes2_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_modes3_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_modes4_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_thres1_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_thres2_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_thres3_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_hyst1_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_hyst2_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd); - install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd); - install_element(BTS_NODE, &cfg_bts_pcu_sock_cmd); - - install_element(BTS_NODE, &cfg_trx_cmd); - install_node(&trx_node, dummy_config_write); - vty_install_default(TRX_NODE); - install_element(TRX_NODE, &cfg_trx_arfcn_cmd); - install_element(TRX_NODE, &cfg_description_cmd); - install_element(TRX_NODE, &cfg_no_description_cmd); - install_element(TRX_NODE, &cfg_trx_nominal_power_cmd); - install_element(TRX_NODE, &cfg_trx_max_power_red_cmd); - install_element(TRX_NODE, &cfg_trx_rsl_e1_cmd); - install_element(TRX_NODE, &cfg_trx_rsl_e1_tei_cmd); - install_element(TRX_NODE, &cfg_trx_rf_locked_cmd); - - install_element(TRX_NODE, &cfg_ts_cmd); - install_node(&ts_node, dummy_config_write); - vty_install_default(TS_NODE); - install_element(TS_NODE, &cfg_ts_pchan_cmd); - install_element(TS_NODE, &cfg_ts_pchan_compat_cmd); - install_element(TS_NODE, &cfg_ts_tsc_cmd); - install_element(TS_NODE, &cfg_ts_hopping_cmd); - install_element(TS_NODE, &cfg_ts_hsn_cmd); - install_element(TS_NODE, &cfg_ts_maio_cmd); - install_element(TS_NODE, &cfg_ts_arfcn_add_cmd); - install_element(TS_NODE, &cfg_ts_arfcn_del_cmd); - install_element(TS_NODE, &cfg_ts_e1_subslot_cmd); - - install_element(ENABLE_NODE, &drop_bts_cmd); - install_element(ENABLE_NODE, &restart_bts_cmd); - install_element(ENABLE_NODE, &bts_resend_cmd); - install_element(ENABLE_NODE, &pdch_act_cmd); - install_element(ENABLE_NODE, &lchan_act_cmd); - install_element(ENABLE_NODE, &lchan_mdcx_cmd); - install_element(ENABLE_NODE, &smscb_cmd_cmd); - install_element(ENABLE_NODE, &ctrl_trap_cmd); - - abis_nm_vty_init(); - abis_om2k_vty_init(); - e1inp_vty_init(); - osmo_fsm_vty_add_cmds(); - - bsc_vty_init_extra(); - - return 0; -} diff --git a/src/libbsc/bts_ericsson_rbs2000.c b/src/libbsc/bts_ericsson_rbs2000.c deleted file mode 100644 index 99da4e75f..000000000 --- a/src/libbsc/bts_ericsson_rbs2000.c +++ /dev/null @@ -1,204 +0,0 @@ -/* Ericsson RBS-2xxx specific code */ - -/* (C) 2011 by Harald Welte - * - * 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 . - * - */ - - -#include - -#include -#include -#include -#include -#include -#include - -#include - -static void bootstrap_om_bts(struct gsm_bts *bts) -{ - LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr); - - /* FIXME: this is global init, not bootstrapping */ - abis_om2k_bts_init(bts); - abis_om2k_trx_init(bts->c0); - - /* TODO: Should we wait for a Failure report? */ - om2k_bts_fsm_start(bts); -} - -static void bootstrap_om_trx(struct gsm_bts_trx *trx) -{ - LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n", - trx->bts->nr, trx->nr); - /* FIXME */ -} - -static int shutdown_om(struct gsm_bts *bts) -{ - /* FIXME */ - return 0; -} - - -/* Tell LAPD to start start the SAP (send SABM requests) for all signalling - * timeslots in this line */ -static void start_sabm_in_line(struct e1inp_line *line, int start) -{ - struct e1inp_sign_link *link; - int i; - - for (i = 0; i < ARRAY_SIZE(line->ts); i++) { - struct e1inp_ts *ts = &line->ts[i]; - - if (ts->type != E1INP_TS_TYPE_SIGN) - continue; - - llist_for_each_entry(link, &ts->sign.sign_links, list) { - if (!ts->lapd) - continue; - lapd_instance_set_profile(ts->lapd, - &lapd_profile_abis_ericsson); - - if (start) - lapd_sap_start(ts->lapd, link->tei, link->sapi); - else - lapd_sap_stop(ts->lapd, link->tei, link->sapi); - } - } -} - -/* Callback function to be called every time we receive a signal from INPUT */ -static int gbl_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_bts *bts; - - if (subsys != SS_L_GLOBAL) - return 0; - - switch (signal) { - case S_GLOBAL_BTS_CLOSE_OM: - bts = signal_data; - if (bts->type == GSM_BTS_TYPE_RBS2000) - shutdown_om(signal_data); - break; - } - - return 0; -} - -/* Callback function to be called every time we receive a signal from INPUT */ -static int inp_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct input_signal_data *isd = signal_data; - struct e1inp_ts *e1i_ts; - - if (subsys != SS_L_INPUT) - return 0; - - LOGP(DNM, LOGL_DEBUG, "%s(): Input signal '%s' received\n", __func__, - get_value_string(e1inp_signal_names, signal)); - switch (signal) { - case S_L_INP_TEI_UP: - switch (isd->link_type) { - case E1INP_SIGN_OML: - if (isd->trx->bts->type != GSM_BTS_TYPE_RBS2000) - break; - if (isd->tei == isd->trx->bts->oml_tei) - bootstrap_om_bts(isd->trx->bts); - else - bootstrap_om_trx(isd->trx); - break; - } - break; - case S_L_INP_TEI_DN: - if (isd->trx->bts->type != GSM_BTS_TYPE_RBS2000) - break; - LOGP(DNM, LOGL_NOTICE, "Line-%u TS-%u TEI-%u SAPI-%u: Link " - "Lost for Ericsson RBS2000. Re-starting DL Establishment\n", - isd->line->num, isd->ts_nr, isd->tei, isd->sapi); - /* Some datalink for a given TEI/SAPI went down, try to re-start it */ - e1i_ts = &isd->line->ts[isd->ts_nr-1]; - OSMO_ASSERT(e1i_ts->type == E1INP_TS_TYPE_SIGN); - lapd_sap_start(e1i_ts->lapd, isd->tei, isd->sapi); - break; - case S_L_INP_LINE_INIT: - case S_L_INP_LINE_NOALARM: - if (strcasecmp(isd->line->driver->name, "DAHDI") - && strcasecmp(isd->line->driver->name, "MISDN_LAPD") - && strcasecmp(isd->line->driver->name, "UNIXSOCKET")) - break; - start_sabm_in_line(isd->line, 1); - break; - case S_L_INP_LINE_ALARM: - if (strcasecmp(isd->line->driver->name, "DAHDI") - && strcasecmp(isd->line->driver->name, "MISDN_LAPD") - && strcasecmp(isd->line->driver->name, "UNIXSOCKET")) - break; - start_sabm_in_line(isd->line, 0); - break; - } - - return 0; -} - -static void config_write_bts(struct vty *vty, struct gsm_bts *bts) -{ - abis_om2k_config_write_bts(vty, bts); -} - -static int bts_model_rbs2k_start(struct gsm_network *net); - -static void bts_model_rbs2k_e1line_bind_ops(struct e1inp_line *line) -{ - e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops); -} - -static struct gsm_bts_model model_rbs2k = { - .type = GSM_BTS_TYPE_RBS2000, - .name = "rbs2000", - .start = bts_model_rbs2k_start, - .oml_rcvmsg = &abis_om2k_rcvmsg, - .config_write_bts = &config_write_bts, - .e1line_bind_ops = &bts_model_rbs2k_e1line_bind_ops, -}; - -static int bts_model_rbs2k_start(struct gsm_network *net) -{ - model_rbs2k.features.data = &model_rbs2k._features_data[0]; - model_rbs2k.features.data_len = sizeof(model_rbs2k._features_data); - - gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_GPRS); - gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_EGPRS); - gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HOPPING); - gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HSCSD); - gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_MULTI_TSC); - - osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL); - osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL); - - return 0; -} - -int bts_model_rbs2k_init(void) -{ - return gsm_bts_model_register(&model_rbs2k); -} diff --git a/src/libbsc/bts_init.c b/src/libbsc/bts_init.c deleted file mode 100644 index d6b152a79..000000000 --- a/src/libbsc/bts_init.c +++ /dev/null @@ -1,30 +0,0 @@ -/* (C) 2011 by Harald Welte - * - * 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 . - * - */ -#include - -int bts_init(void) -{ - bts_model_bs11_init(); - bts_model_rbs2k_init(); - bts_model_nanobts_init(); - bts_model_nokia_site_init(); - bts_model_sysmobts_init(); - /* Your new BTS here. */ - return 0; -} diff --git a/src/libbsc/bts_ipaccess_nanobts.c b/src/libbsc/bts_ipaccess_nanobts.c deleted file mode 100644 index a1bde778f..000000000 --- a/src/libbsc/bts_ipaccess_nanobts.c +++ /dev/null @@ -1,520 +0,0 @@ -/* ip.access nanoBTS specific code */ - -/* (C) 2009-2010 by Harald Welte - * - * 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 . - * - */ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct gsm_network *bsc_gsmnet; - -static int bts_model_nanobts_start(struct gsm_network *net); -static void bts_model_nanobts_e1line_bind_ops(struct e1inp_line *line); - -struct gsm_bts_model bts_model_nanobts = { - .type = GSM_BTS_TYPE_NANOBTS, - .name = "nanobts", - .start = bts_model_nanobts_start, - .oml_rcvmsg = &abis_nm_rcvmsg, - .e1line_bind_ops = bts_model_nanobts_e1line_bind_ops, - .nm_att_tlvdef = { - .def = { - /* ip.access specifics */ - [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 }, - [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, }, - [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 }, - [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 }, - [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 }, - [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 }, - [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V }, - }, - }, -}; - - -/* Callback function to be called whenever we get a GSM 12.21 state change event */ -static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd) -{ - uint8_t obj_class = nsd->obj_class; - void *obj = nsd->obj; - struct gsm_nm_state *new_state = nsd->new_state; - - struct gsm_bts *bts; - struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - struct gsm_bts_gprs_nsvc *nsvc; - - struct msgb *msgb; - - if (!is_ipaccess_bts(nsd->bts)) - return 0; - - /* This event-driven BTS setup is currently only required on nanoBTS */ - - /* S_NM_STATECHG_ADM is called after we call chg_adm_state() and would create - * endless loop */ - if (evt != S_NM_STATECHG_OPER) - return 0; - - switch (obj_class) { - case NM_OC_SITE_MANAGER: - bts = container_of(obj, struct gsm_bts, site_mgr); - if ((new_state->operational == NM_OPSTATE_ENABLED && - new_state->availability == NM_AVSTATE_OK) || - (new_state->operational == NM_OPSTATE_DISABLED && - new_state->availability == NM_AVSTATE_OFF_LINE)) - abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff); - break; - case NM_OC_BTS: - bts = obj; - if (new_state->availability == NM_AVSTATE_DEPENDENCY) { - msgb = nanobts_attr_bts_get(bts); - abis_nm_set_bts_attr(bts, msgb->data, msgb->len); - msgb_free(msgb); - abis_nm_chg_adm_state(bts, obj_class, - bts->bts_nr, 0xff, 0xff, - NM_STATE_UNLOCKED); - abis_nm_opstart(bts, obj_class, - bts->bts_nr, 0xff, 0xff); - } - break; - case NM_OC_CHANNEL: - ts = obj; - trx = ts->trx; - if (new_state->operational == NM_OPSTATE_DISABLED && - new_state->availability == NM_AVSTATE_DEPENDENCY) { - enum abis_nm_chan_comb ccomb = - abis_nm_chcomb4pchan(ts->pchan); - if (abis_nm_set_channel_attr(ts, ccomb) == -EINVAL) { - ipaccess_drop_oml(trx->bts); - return -1; - } - abis_nm_chg_adm_state(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, ts->nr, - NM_STATE_UNLOCKED); - abis_nm_opstart(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, ts->nr); - } - if (new_state->operational == NM_OPSTATE_ENABLED - && new_state->availability == NM_AVSTATE_OK) - dyn_ts_init(ts); - break; - case NM_OC_RADIO_CARRIER: - trx = obj; - if (new_state->operational == NM_OPSTATE_DISABLED && - new_state->availability == NM_AVSTATE_OK) - abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, - trx->nr, 0xff); - break; - case NM_OC_GPRS_NSE: - bts = container_of(obj, struct gsm_bts, gprs.nse); - if (bts->gprs.mode == BTS_GPRS_NONE) - break; - if (new_state->availability == NM_AVSTATE_DEPENDENCY) { - msgb = nanobts_attr_nse_get(bts); - abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, - 0xff, 0xff, msgb->data, - msgb->len); - msgb_free(msgb); - abis_nm_opstart(bts, obj_class, bts->bts_nr, - 0xff, 0xff); - } - break; - case NM_OC_GPRS_CELL: - bts = container_of(obj, struct gsm_bts, gprs.cell); - if (bts->gprs.mode == BTS_GPRS_NONE) - break; - if (new_state->availability == NM_AVSTATE_DEPENDENCY) { - msgb = nanobts_attr_cell_get(bts); - abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, - 0, 0xff, msgb->data, - msgb->len); - msgb_free(msgb); - abis_nm_opstart(bts, obj_class, bts->bts_nr, - 0, 0xff); - abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr, - 0, 0xff, NM_STATE_UNLOCKED); - abis_nm_chg_adm_state(bts, NM_OC_GPRS_NSE, bts->bts_nr, - 0xff, 0xff, NM_STATE_UNLOCKED); - } - break; - case NM_OC_GPRS_NSVC: - nsvc = obj; - bts = nsvc->bts; - if (bts->gprs.mode == BTS_GPRS_NONE) - break; - /* We skip NSVC1 since we only use NSVC0 */ - if (nsvc->id == 1) - break; - if ((new_state->availability == NM_AVSTATE_OFF_LINE) || - (new_state->availability == NM_AVSTATE_DEPENDENCY)) { - msgb = nanobts_attr_nscv_get(bts); - abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, - nsvc->id, 0xff, - msgb->data, msgb->len); - msgb_free(msgb); - abis_nm_opstart(bts, obj_class, bts->bts_nr, - nsvc->id, 0xff); - abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr, - nsvc->id, 0xff, - NM_STATE_UNLOCKED); - } - default: - break; - } - return 0; -} - -/* Callback function to be called every time we receive a 12.21 SW activated report */ -static int sw_activ_rep(struct msgb *mb) -{ - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct e1inp_sign_link *sign_link = mb->dst; - struct gsm_bts *bts = sign_link->trx->bts; - struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr); - - if (!trx) - return -EINVAL; - - if (!is_ipaccess_bts(trx->bts)) - return 0; - - switch (foh->obj_class) { - case NM_OC_BASEB_TRANSC: - abis_nm_chg_adm_state(trx->bts, foh->obj_class, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - abis_nm_opstart(trx->bts, foh->obj_class, - trx->bts->bts_nr, trx->nr, 0xff); - /* TRX software is active, tell it to initiate RSL Link */ - abis_nm_ipaccess_rsl_connect(trx, trx->bts->ip_access.rsl_ip, - 3003, trx->rsl_tei); - break; - case NM_OC_RADIO_CARRIER: { - /* - * Locking the radio carrier will make it go - * offline again and we would come here. The - * framework should determine that there was - * no change and avoid recursion. - * - * This code is here to make sure that on start - * a TRX remains locked. - */ - int rc_state = trx->mo.nm_state.administrative; - /* Patch ARFCN into radio attribute */ - struct msgb *msgb = nanobts_attr_radio_get(trx->bts, trx); - abis_nm_set_radio_attr(trx, msgb->data, msgb->len); - msgb_free(msgb); - abis_nm_chg_adm_state(trx->bts, foh->obj_class, - trx->bts->bts_nr, trx->nr, 0xff, - rc_state); - abis_nm_opstart(trx->bts, foh->obj_class, trx->bts->bts_nr, - trx->nr, 0xff); - break; - } - } - return 0; -} - -/* Callback function to be called every time we receive a signal from NM */ -static int bts_ipa_nm_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - if (subsys != SS_NM) - return 0; - - switch (signal) { - case S_NM_SW_ACTIV_REP: - return sw_activ_rep(signal_data); - case S_NM_STATECHG_OPER: - case S_NM_STATECHG_ADM: - return nm_statechg_event(signal, signal_data); - default: - break; - } - return 0; -} - -static int bts_model_nanobts_start(struct gsm_network *net) -{ - osmo_signal_unregister_handler(SS_NM, bts_ipa_nm_sig_cb, NULL); - osmo_signal_register_handler(SS_NM, bts_ipa_nm_sig_cb, NULL); - return 0; -} - -int bts_model_nanobts_init(void) -{ - bts_model_nanobts.features.data = &bts_model_nanobts._features_data[0]; - bts_model_nanobts.features.data_len = - sizeof(bts_model_nanobts._features_data); - - gsm_btsmodel_set_feature(&bts_model_nanobts, BTS_FEAT_GPRS); - gsm_btsmodel_set_feature(&bts_model_nanobts, BTS_FEAT_EGPRS); - gsm_btsmodel_set_feature(&bts_model_nanobts, BTS_FEAT_MULTI_TSC); - - return gsm_bts_model_register(&bts_model_nanobts); -} - -#define OML_UP 0x0001 -#define RSL_UP 0x0002 - -static struct gsm_bts * -find_bts_by_unitid(struct gsm_network *net, uint16_t site_id, uint16_t bts_id) -{ - struct gsm_bts *bts; - - llist_for_each_entry(bts, &net->bts_list, list) { - if (!is_ipaccess_bts(bts)) - continue; - - if (bts->ip_access.site_id == site_id && - bts->ip_access.bts_id == bts_id) - return bts; - } - return NULL; -} - -/* These are exported because they are used by the VTY interface. */ -void ipaccess_drop_rsl(struct gsm_bts_trx *trx) -{ - if (!trx->rsl_link) - return; - - e1inp_sign_link_destroy(trx->rsl_link); - trx->rsl_link = NULL; -} - -void ipaccess_drop_oml(struct gsm_bts *bts) -{ - struct gsm_bts *rdep_bts; - struct gsm_bts_trx *trx; - - if (!bts->oml_link) - return; - - e1inp_sign_link_destroy(bts->oml_link); - bts->oml_link = NULL; - - /* we have issues reconnecting RSL, drop everything. */ - llist_for_each_entry(trx, &bts->trx_list, list) - ipaccess_drop_rsl(trx); - - bts->ip_access.flags = 0; - - /* - * Go through the list and see if we are the depndency of a BTS - * and then drop the BTS. This can lead to some recursion but it - * should be fine in userspace. - * The oml_link is serving as recursion anchor for us and - * it is set to NULL some lines above. - */ - llist_for_each_entry(rdep_bts, &bts->network->bts_list, list) { - if (!bts_depend_is_depedency(rdep_bts, bts)) - continue; - LOGP(DLINP, LOGL_NOTICE, "Dropping BTS(%u) due BTS(%u).\n", - rdep_bts->nr, bts->nr); - ipaccess_drop_oml(rdep_bts); - } -} - -/* This function is called once the OML/RSL link becomes up. */ -static struct e1inp_sign_link * -ipaccess_sign_link_up(void *unit_data, struct e1inp_line *line, - enum e1inp_sign_type type) -{ - struct gsm_bts *bts; - struct ipaccess_unit *dev = unit_data; - struct e1inp_sign_link *sign_link = NULL; - - bts = find_bts_by_unitid(bsc_gsmnet, dev->site_id, dev->bts_id); - if (!bts) { - LOGP(DLINP, LOGL_ERROR, "Unable to find BTS configuration for " - " %u/%u/%u, disconnecting\n", dev->site_id, - dev->bts_id, dev->trx_id); - return NULL; - } - DEBUGP(DLINP, "Identified BTS %u/%u/%u\n", - dev->site_id, dev->bts_id, dev->trx_id); - - switch(type) { - case E1INP_SIGN_OML: - /* remove old OML signal link for this BTS. */ - ipaccess_drop_oml(bts); - - if (!bts_depend_check(bts)) { - LOGP(DLINP, LOGL_NOTICE, - "Dependency not full-filled for %u/%u/%u\n", - dev->site_id, dev->bts_id, dev->trx_id); - return NULL; - } - - /* create new OML link. */ - sign_link = bts->oml_link = - e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML - 1], - E1INP_SIGN_OML, bts->c0, - bts->oml_tei, 0); - break; - case E1INP_SIGN_RSL: { - struct e1inp_ts *ts; - struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, dev->trx_id); - - /* no OML link set yet? give up. */ - if (!bts->oml_link || !trx) - return NULL; - - /* remove old RSL link for this TRX. */ - ipaccess_drop_rsl(trx); - - /* set new RSL link for this TRX. */ - line = bts->oml_link->ts->line; - ts = &line->ts[E1INP_SIGN_RSL + dev->trx_id - 1]; - e1inp_ts_config_sign(ts, line); - sign_link = trx->rsl_link = - e1inp_sign_link_create(ts, E1INP_SIGN_RSL, - trx, trx->rsl_tei, 0); - trx->rsl_link->ts->sign.delay = 0; - break; - } - default: - break; - } - return sign_link; -} - -static void ipaccess_sign_link_down(struct e1inp_line *line) -{ - /* No matter what link went down, we close both signal links. */ - struct e1inp_ts *ts = &line->ts[E1INP_SIGN_OML-1]; - struct e1inp_sign_link *link; - - llist_for_each_entry(link, &ts->sign.sign_links, list) { - struct gsm_bts *bts = link->trx->bts; - - ipaccess_drop_oml(bts); - /* Yes, we only use the first element of the list. */ - break; - } -} - -/* This function is called if we receive one OML/RSL message. */ -static int ipaccess_sign_link(struct msgb *msg) -{ - int ret = 0; - struct e1inp_sign_link *link = msg->dst; - struct e1inp_ts *e1i_ts = link->ts; - - switch (link->type) { - case E1INP_SIGN_RSL: - if (!(link->trx->bts->ip_access.flags & - (RSL_UP << link->trx->nr))) { - e1inp_event(e1i_ts, S_L_INP_TEI_UP, - link->tei, link->sapi); - link->trx->bts->ip_access.flags |= - (RSL_UP << link->trx->nr); - } - ret = abis_rsl_rcvmsg(msg); - break; - case E1INP_SIGN_OML: - if (!(link->trx->bts->ip_access.flags & OML_UP)) { - e1inp_event(e1i_ts, S_L_INP_TEI_UP, - link->tei, link->sapi); - link->trx->bts->ip_access.flags |= OML_UP; - } - ret = abis_nm_rcvmsg(msg); - break; - default: - LOGP(DLINP, LOGL_ERROR, "Unknown signal link type %d\n", - link->type); - msgb_free(msg); - break; - } - return ret; -} - -/* not static, ipaccess-config needs it. */ -struct e1inp_line_ops ipaccess_e1inp_line_ops = { - .cfg = { - .ipa = { - .addr = "0.0.0.0", - .role = E1INP_LINE_R_BSC, - }, - }, - .sign_link_up = ipaccess_sign_link_up, - .sign_link_down = ipaccess_sign_link_down, - .sign_link = ipaccess_sign_link, -}; - -static void bts_model_nanobts_e1line_bind_ops(struct e1inp_line *line) -{ - e1inp_line_bind_ops(line, &ipaccess_e1inp_line_ops); -} diff --git a/src/libbsc/bts_ipaccess_nanobts_omlattr.c b/src/libbsc/bts_ipaccess_nanobts_omlattr.c deleted file mode 100644 index 473e1caea..000000000 --- a/src/libbsc/bts_ipaccess_nanobts_omlattr.c +++ /dev/null @@ -1,240 +0,0 @@ -/* ip.access nanoBTS specific code, OML attribute table generator */ - -/* (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 . - */ - -#include -#include -#include -#include - -static void patch_16(uint8_t *data, const uint16_t val) -{ - memcpy(data, &val, sizeof(val)); -} - -static void patch_32(uint8_t *data, const uint32_t val) -{ - memcpy(data, &val, sizeof(val)); -} - -struct msgb *nanobts_attr_bts_get(struct gsm_bts *bts) -{ - struct msgb *msgb; - uint8_t buf[256]; - int rlt; - msgb = msgb_alloc(1024, "nanobts_attr_bts"); - - memcpy(buf, "\x55\x5b\x61\x67\x6d\x73", 6); - msgb_tv_fixed_put(msgb, NM_ATT_INTERF_BOUND, 6, buf); - - /* interference avg. period in numbers of SACCH multifr */ - msgb_tv_put(msgb, NM_ATT_INTAVE_PARAM, 0x06); - - rlt = gsm_bts_get_radio_link_timeout(bts); - if (rlt == -1) { - /* Osmocom extension: Use infinite radio link timeout */ - buf[0] = 0xFF; - buf[1] = 0x00; - } else { - /* conn fail based on SACCH error rate */ - buf[0] = 0x01; - buf[1] = rlt; - } - msgb_tl16v_put(msgb, NM_ATT_CONN_FAIL_CRIT, 2, buf); - - memcpy(buf, "\x1e\x24\x24\xa8\x34\x21\xa8", 7); - msgb_tv_fixed_put(msgb, NM_ATT_T200, 7, buf); - - msgb_tv_put(msgb, NM_ATT_MAX_TA, 0x3f); - - /* seconds */ - memcpy(buf, "\x00\x01\x0a", 3); - msgb_tv_fixed_put(msgb, NM_ATT_OVERL_PERIOD, 3, buf); - - /* percent */ - msgb_tv_put(msgb, NM_ATT_CCCH_L_T, 10); - - /* seconds */ - msgb_tv_put(msgb, NM_ATT_CCCH_L_I_P, 1); - - /* busy threshold in - dBm */ - buf[0] = 10; - if (bts->rach_b_thresh != -1) - buf[0] = bts->rach_b_thresh & 0xff; - msgb_tv_put(msgb, NM_ATT_RACH_B_THRESH, buf[0]); - - /* rach load averaging 1000 slots */ - buf[0] = 0x03; - buf[1] = 0xe8; - if (bts->rach_ldavg_slots != -1) { - buf[0] = (bts->rach_ldavg_slots >> 8) & 0x0f; - buf[1] = bts->rach_ldavg_slots & 0xff; - } - msgb_tv_fixed_put(msgb, NM_ATT_LDAVG_SLOTS, 2, buf); - - /* miliseconds */ - msgb_tv_put(msgb, NM_ATT_BTS_AIR_TIMER, 128); - - /* 10 retransmissions of physical config */ - msgb_tv_put(msgb, NM_ATT_NY1, 10); - - buf[0] = (bts->c0->arfcn >> 8) & 0x0f; - buf[1] = bts->c0->arfcn & 0xff; - msgb_tv_fixed_put(msgb, NM_ATT_BCCH_ARFCN, 2, buf); - - msgb_tv_put(msgb, NM_ATT_BSIC, bts->bsic); - - abis_nm_ipaccess_cgi(buf, bts); - msgb_tl16v_put(msgb, NM_ATT_IPACC_CGI, 7, buf); - - return msgb; -} - -struct msgb *nanobts_attr_nse_get(struct gsm_bts *bts) -{ - struct msgb *msgb; - uint8_t buf[256]; - msgb = msgb_alloc(1024, "nanobts_attr_bts"); - - /* NSEI 925 */ - buf[0] = bts->gprs.nse.nsei >> 8; - buf[1] = bts->gprs.nse.nsei & 0xff; - msgb_tl16v_put(msgb, NM_ATT_IPACC_NSEI, 2, buf); - - /* all timers in seconds */ - OSMO_ASSERT(ARRAY_SIZE(bts->gprs.nse.timer) < sizeof(buf)); - memcpy(buf, bts->gprs.nse.timer, ARRAY_SIZE(bts->gprs.nse.timer)); - msgb_tl16v_put(msgb, NM_ATT_IPACC_NS_CFG, 7, buf); - - /* all timers in seconds */ - buf[0] = 3; /* blockimg timer (T1) */ - buf[1] = 3; /* blocking retries */ - buf[2] = 3; /* unblocking retries */ - buf[3] = 3; /* reset timer (T2) */ - buf[4] = 3; /* reset retries */ - buf[5] = 10; /* suspend timer (T3) in 100ms */ - buf[6] = 3; /* suspend retries */ - buf[7] = 10; /* resume timer (T4) in 100ms */ - buf[8] = 3; /* resume retries */ - buf[9] = 10; /* capability update timer (T5) */ - buf[10] = 3; /* capability update retries */ - - OSMO_ASSERT(ARRAY_SIZE(bts->gprs.cell.timer) < sizeof(buf)); - memcpy(buf, bts->gprs.cell.timer, ARRAY_SIZE(bts->gprs.cell.timer)); - msgb_tl16v_put(msgb, NM_ATT_IPACC_BSSGP_CFG, 11, buf); - - return msgb; -} - -struct msgb *nanobts_attr_cell_get(struct gsm_bts *bts) -{ - struct msgb *msgb; - uint8_t buf[256]; - msgb = msgb_alloc(1024, "nanobts_attr_bts"); - - /* routing area code */ - buf[0] = bts->gprs.rac; - msgb_tl16v_put(msgb, NM_ATT_IPACC_RAC, 1, buf); - - buf[0] = 5; /* repeat time (50ms) */ - buf[1] = 3; /* repeat count */ - msgb_tl16v_put(msgb, NM_ATT_IPACC_GPRS_PAGING_CFG, 2, buf); - - /* BVCI 925 */ - buf[0] = bts->gprs.cell.bvci >> 8; - buf[1] = bts->gprs.cell.bvci & 0xff; - msgb_tl16v_put(msgb, NM_ATT_IPACC_BVCI, 2, buf); - - /* all timers in seconds, unless otherwise stated */ - buf[0] = 20; /* T3142 */ - buf[1] = 5; /* T3169 */ - buf[2] = 5; /* T3191 */ - buf[3] = 160; /* T3193 (units of 10ms) */ - buf[4] = 5; /* T3195 */ - buf[5] = 10; /* N3101 */ - buf[6] = 4; /* N3103 */ - buf[7] = 8; /* N3105 */ - buf[8] = 15; /* RLC CV countdown */ - msgb_tl16v_put(msgb, NM_ATT_IPACC_RLC_CFG, 9, buf); - - if (bts->gprs.mode == BTS_GPRS_EGPRS) { - buf[0] = 0x8f; - buf[1] = 0xff; - } else { - buf[0] = 0x0f; - buf[1] = 0x00; - } - msgb_tl16v_put(msgb, NM_ATT_IPACC_CODING_SCHEMES, 2, buf); - - buf[0] = 0; /* T downlink TBF extension (0..500, high byte) */ - buf[1] = 250; /* T downlink TBF extension (0..500, low byte) */ - buf[2] = 0; /* T uplink TBF extension (0..500, high byte) */ - buf[3] = 250; /* T uplink TBF extension (0..500, low byte) */ - buf[4] = 2; /* CS2 */ - msgb_tl16v_put(msgb, NM_ATT_IPACC_RLC_CFG_2, 5, buf); - -#if 0 - /* EDGE model only, breaks older models. - * Should inquire the BTS capabilities */ - buf[0] = 2; /* MCS2 */ - msgb_tl16v_put(msgb, NM_ATT_IPACC_RLC_CFG_3, 1, buf); -#endif - - return msgb; -} - -struct msgb *nanobts_attr_nscv_get(struct gsm_bts *bts) -{ - struct msgb *msgb; - uint8_t buf[256]; - msgb = msgb_alloc(1024, "nanobts_attr_bts"); - - /* 925 */ - buf[0] = bts->gprs.nsvc[0].nsvci >> 8; - buf[1] = bts->gprs.nsvc[0].nsvci & 0xff; - msgb_tl16v_put(msgb, NM_ATT_IPACC_NSVCI, 2, buf); - - /* remote udp port */ - patch_16(&buf[0], htons(bts->gprs.nsvc[0].remote_port)); - /* remote ip address */ - patch_32(&buf[2], htonl(bts->gprs.nsvc[0].remote_ip)); - /* local udp port */ - patch_16(&buf[6], htons(bts->gprs.nsvc[0].local_port)); - msgb_tl16v_put(msgb, NM_ATT_IPACC_NS_LINK_CFG, 8, buf); - - return msgb; -} - -struct msgb *nanobts_attr_radio_get(struct gsm_bts *bts, - struct gsm_bts_trx *trx) -{ - struct msgb *msgb; - uint8_t buf[256]; - msgb = msgb_alloc(1024, "nanobts_attr_bts"); - - /* number of -2dB reduction steps / Pn */ - msgb_tv_put(msgb, NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2); - - buf[0] = trx->arfcn >> 8; - buf[1] = trx->arfcn & 0xff; - msgb_tl16v_put(msgb, NM_ATT_ARFCN_LIST, 2, buf); - - return msgb; -} diff --git a/src/libbsc/bts_nokia_site.c b/src/libbsc/bts_nokia_site.c deleted file mode 100644 index 3ca76c017..000000000 --- a/src/libbsc/bts_nokia_site.c +++ /dev/null @@ -1,1739 +0,0 @@ -/* Nokia XXXsite family specific code */ - -/* (C) 2011 by Dieter Spaar - * - * 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 . - * - */ - -/* - TODO: Attention: There are some static variables used for states during - configuration. Those variables have to be moved to a BTS specific context, - otherwise there will most certainly be problems if more than one Nokia BTS - is used. -*/ - -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#include - -/* TODO: put in a separate file ? */ - -extern int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg); -/* was static in system_information.c */ -extern int generate_cell_chan_list(uint8_t * chan_list, struct gsm_bts *bts); - -static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts); -static void reset_timer_cb(void *_bts); -static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref); -static int dump_elements(uint8_t * data, int len) __attribute__((unused)); - -static void bootstrap_om_bts(struct gsm_bts *bts) -{ - LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr); - - if (!bts->nokia.skip_reset) { - if (!bts->nokia.did_reset) - abis_nm_reset(bts, 1); - } else - bts->nokia.did_reset = 1; -} - -static void bootstrap_om_trx(struct gsm_bts_trx *trx) -{ - LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n", - trx->bts->nr, trx->nr); -} - -static int shutdown_om(struct gsm_bts *bts) -{ - /* TODO !? */ - return 0; -} - -#define SAPI_OML 62 -#define SAPI_RSL 0 - -/* - - Tell LAPD to start start the SAP (send SABM requests) for all signalling - timeslots in this line - - Attention: this has to be adapted for mISDN -*/ - -static void start_sabm_in_line(struct e1inp_line *line, int start, int sapi) -{ - struct e1inp_sign_link *link; - int i; - - for (i = 0; i < ARRAY_SIZE(line->ts); i++) { - struct e1inp_ts *ts = &line->ts[i]; - - if (ts->type != E1INP_TS_TYPE_SIGN) - continue; - - llist_for_each_entry(link, &ts->sign.sign_links, list) { - if (sapi != -1 && link->sapi != sapi) - continue; - -#if 0 /* debugging */ - printf("sap start/stop (%d): %d tei=%d sapi=%d\n", - start, i + 1, link->tei, link->sapi); -#endif - - if (start) { - ts->lapd->profile.t200_sec = 1; - ts->lapd->profile.t200_usec = 0; - lapd_sap_start(ts->lapd, link->tei, - link->sapi); - } else - lapd_sap_stop(ts->lapd, link->tei, - link->sapi); - } - } -} - -/* Callback function to be called every time we receive a signal from INPUT */ -static int gbl_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_bts *bts; - - if (subsys != SS_L_GLOBAL) - return 0; - - switch (signal) { - case S_GLOBAL_BTS_CLOSE_OM: - bts = signal_data; - if (bts->type == GSM_BTS_TYPE_NOKIA_SITE) - shutdown_om(signal_data); - break; - } - - return 0; -} - -/* Callback function to be called every time we receive a signal from INPUT */ -static int inp_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct input_signal_data *isd = signal_data; - - if (subsys != SS_L_INPUT) - return 0; - - switch (signal) { - case S_L_INP_LINE_INIT: - start_sabm_in_line(isd->line, 1, SAPI_OML); /* start only OML */ - break; - case S_L_INP_TEI_DN: - break; - case S_L_INP_TEI_UP: - switch (isd->link_type) { - case E1INP_SIGN_OML: - if (isd->trx->bts->type != GSM_BTS_TYPE_NOKIA_SITE) - break; - - if (isd->tei == isd->trx->bts->oml_tei) - bootstrap_om_bts(isd->trx->bts); - else - bootstrap_om_trx(isd->trx); - break; - } - break; - case S_L_INP_TEI_UNKNOWN: - /* We are receiving LAPD frames with one TEI that we do not - * seem to know, likely that we (the BSC) stopped working - * and lost our local states. However, the BTS is already - * configured, we try to take over the RSL links. */ - start_sabm_in_line(isd->line, 1, SAPI_RSL); - break; - } - - return 0; -} - -static void nm_statechg_evt(unsigned int signal, - struct nm_statechg_signal_data *nsd) -{ - if (nsd->bts->type != GSM_BTS_TYPE_NOKIA_SITE) - return; -} - -static int nm_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - if (subsys != SS_NM) - return 0; - - switch (signal) { - case S_NM_STATECHG_OPER: - case S_NM_STATECHG_ADM: - nm_statechg_evt(signal, signal_data); - break; - default: - break; - } - - return 0; -} - -/* TODO: put in a separate file ? */ - -static const struct value_string nokia_msgt_name[] = { - { 0x80, "NOKIA_BTS_CONF_DATA" }, - { 0x81, "NOKIA_BTS_ACK" }, - { 0x82, "NOKIA_BTS_OMU_STARTED" }, - { 0x83, "NOKIA_BTS_START_DOWNLOAD_REQ" }, - { 0x84, "NOKIA_BTS_MF_REQ" }, - { 0x85, "NOKIA_BTS_AF_REQ" }, - { 0x86, "NOKIA_BTS_RESET_REQ" }, - { 0x87, "NOKIA_reserved" }, - { 0x88, "NOKIA_BTS_CONF_REQ" }, - { 0x89, "NOKIA_BTS_TEST_REQ" }, - { 0x8A, "NOKIA_BTS_TEST_REPORT" }, - { 0x8B, "NOKIA_reserved" }, - { 0x8C, "NOKIA_reserved" }, - { 0x8D, "NOKIA_reserved" }, - { 0x8E, "NOKIA_BTS_CONF_COMPL" }, - { 0x8F, "NOKIA_reserved" }, - { 0x90, "NOKIA_BTS_STM_TEST_REQ" }, - { 0x91, "NOKIA_BTS_STM_TEST_REPORT" }, - { 0x92, "NOKIA_BTS_TRANSMISSION_COMMAND" }, - { 0x93, "NOKIA_BTS_TRANSMISSION_ANSWER" }, - { 0x94, "NOKIA_BTS_HW_DB_UPLOAD_REQ" }, - { 0x95, "NOKIA_BTS_START_HW_DB_DOWNLOAD_REQ" }, - { 0x96, "NOKIA_BTS_HW_DB_SAVE_REQ" }, - { 0x97, "NOKIA_BTS_FLASH_ERASURE_REQ" }, - { 0x98, "NOKIA_BTS_HW_DB_DOWNLOAD_REQ" }, - { 0x99, "NOKIA_BTS_PWR_SUPPLY_CONTROL" }, - { 0x9A, "NOKIA_BTS_ATTRIBUTE_REQ" }, - { 0x9B, "NOKIA_BTS_ATTRIBUTE_REPORT" }, - { 0x9C, "NOKIA_BTS_HW_REQ" }, - { 0x9D, "NOKIA_BTS_HW_REPORT" }, - { 0x9E, "NOKIA_BTS_RTE_TEST_REQ" }, - { 0x9F, "NOKIA_BTS_RTE_TEST_REPORT" }, - { 0xA0, "NOKIA_BTS_HW_DB_VERIFICATION_REQ" }, - { 0xA1, "NOKIA_BTS_CLOCK_REQ" }, - { 0xA2, "NOKIA_AC_CIRCUIT_REQ_NACK" }, - { 0xA3, "NOKIA_AC_INTERRUPTED" }, - { 0xA4, "NOKIA_BTS_NEW_TRE_INFO" }, - { 0xA5, "NOKIA_AC_BSC_CIRCUITS_ALLOCATED" }, - { 0xA6, "NOKIA_BTS_TRE_POLL_LIST" }, - { 0xA7, "NOKIA_AC_CIRCUIT_REQ" }, - { 0xA8, "NOKIA_BTS_BLOCK_CTRL_REQ" }, - { 0xA9, "NOKIA_BTS_GSM_TIME_REQ" }, - { 0xAA, "NOKIA_BTS_GSM_TIME" }, - { 0xAB, "NOKIA_BTS_OUTPUT_CONTROL" }, - { 0xAC, "NOKIA_BTS_STATE_CHANGED" }, - { 0xAD, "NOKIA_BTS_SW_SAVE_REQ" }, - { 0xAE, "NOKIA_BTS_ALARM" }, - { 0xAF, "NOKIA_BTS_CHA_ADM_STATE" }, - { 0xB0, "NOKIA_AC_POOL_SIZE_REPORT" }, - { 0xB1, "NOKIA_AC_POOL_SIZE_INQUIRY" }, - { 0xB2, "NOKIA_BTS_COMMISS_TEST_COMPLETED" }, - { 0xB3, "NOKIA_BTS_COMMISS_TEST_REQ" }, - { 0xB4, "NOKIA_BTS_TRANSP_BTS_TO_BSC" }, - { 0xB5, "NOKIA_BTS_TRANSP_BSC_TO_BTS" }, - { 0xB6, "NOKIA_BTS_LCS_COMMAND" }, - { 0xB7, "NOKIA_BTS_LCS_ANSWER" }, - { 0xB8, "NOKIA_BTS_LMU_FN_OFFSET_COMMAND" }, - { 0xB9, "NOKIA_BTS_LMU_FN_OFFSET_ANSWER" }, - { 0, NULL } -}; - -static const char *get_msg_type_name_string(uint8_t msg_type) -{ - return get_value_string(nokia_msgt_name, msg_type); -} - -static const struct value_string nokia_element_name[] = { - { 0x01, "Ny1" }, - { 0x02, "T3105_F" }, - { 0x03, "Interference band limits" }, - { 0x04, "Interference report timer in secs" }, - { 0x05, "Channel configuration per TS" }, - { 0x06, "BSIC" }, - { 0x07, "RACH report timer in secs" }, - { 0x08, "Hardware database status" }, - { 0x09, "BTS RX level" }, - { 0x0A, "ARFN" }, - { 0x0B, "STM antenna attenuation" }, - { 0x0C, "Cell allocation bitmap" }, - { 0x0D, "Radio definition per TS" }, - { 0x0E, "Frame number" }, - { 0x0F, "Antenna diversity" }, - { 0x10, "T3105_D" }, - { 0x11, "File format" }, - { 0x12, "Last File" }, - { 0x13, "BTS type" }, - { 0x14, "Erasure mode" }, - { 0x15, "Hopping mode" }, - { 0x16, "Floating TRX" }, - { 0x17, "Power supplies" }, - { 0x18, "Reset type" }, - { 0x19, "Averaging period" }, - { 0x1A, "RBER2" }, - { 0x1B, "LAC" }, - { 0x1C, "CI" }, - { 0x1D, "Failure parameters" }, - { 0x1E, "(RF max power reduction)" }, - { 0x1F, "Measured RX_SENS" }, - { 0x20, "Extended cell radius" }, - { 0x21, "reserved" }, - { 0x22, "Success-Failure" }, - { 0x23, "Ack-Nack" }, - { 0x24, "OMU test results" }, - { 0x25, "File identity" }, - { 0x26, "Generation and version code" }, - { 0x27, "SW description" }, - { 0x28, "BCCH LEV" }, - { 0x29, "Test type" }, - { 0x2A, "Subscriber number" }, - { 0x2B, "reserved" }, - { 0x2C, "HSN" }, - { 0x2D, "reserved" }, - { 0x2E, "MS RXLEV" }, - { 0x2F, "MS TXLEV" }, - { 0x30, "RXQUAL" }, - { 0x31, "RX SENS" }, - { 0x32, "Alarm block" }, - { 0x33, "Neighbouring BCCH levels" }, - { 0x34, "STM report type" }, - { 0x35, "MA" }, - { 0x36, "MAIO" }, - { 0x37, "H_FLAG" }, - { 0x38, "TCH_ARFN" }, - { 0x39, "Clock output" }, - { 0x3A, "Transmitted power" }, - { 0x3B, "Clock sync" }, - { 0x3C, "TMS protocol discriminator" }, - { 0x3D, "TMS protocol data" }, - { 0x3E, "FER" }, - { 0x3F, "SWR result" }, - { 0x40, "Object identity" }, - { 0x41, "STM RX Antenna Test" }, - { 0x42, "reserved" }, - { 0x43, "reserved" }, - { 0x44, "Object current state" }, - { 0x45, "reserved" }, - { 0x46, "FU channel configuration" }, - { 0x47, "reserved" }, - { 0x48, "ARFN of a CU" }, - { 0x49, "FU radio definition" }, - { 0x4A, "reserved" }, - { 0x4B, "Severity" }, - { 0x4C, "Diversity selection" }, - { 0x4D, "RX antenna test" }, - { 0x4E, "RX antenna supervision period" }, - { 0x4F, "RX antenna state" }, - { 0x50, "Sector configuration" }, - { 0x51, "Additional info" }, - { 0x52, "SWR parameters" }, - { 0x53, "HW inquiry mode" }, - { 0x54, "reserved" }, - { 0x55, "Availability status" }, - { 0x56, "reserved" }, - { 0x57, "EAC inputs" }, - { 0x58, "EAC outputs" }, - { 0x59, "reserved" }, - { 0x5A, "Position" }, - { 0x5B, "HW unit identity" }, - { 0x5C, "RF test signal attenuation" }, - { 0x5D, "Operational state" }, - { 0x5E, "Logical object identity" }, - { 0x5F, "reserved" }, - { 0x60, "BS_TXPWR_OM" }, - { 0x61, "Loop_Duration" }, - { 0x62, "LNA_Path_Selection" }, - { 0x63, "Serial number" }, - { 0x64, "HW version" }, - { 0x65, "Obj. identity and obj. state" }, - { 0x66, "reserved" }, - { 0x67, "EAC input definition" }, - { 0x68, "EAC id and text" }, - { 0x69, "HW unit status" }, - { 0x6A, "SW release version" }, - { 0x6B, "FW version" }, - { 0x6C, "Bit_Error_Ratio" }, - { 0x6D, "RXLEV_with_Attenuation" }, - { 0x6E, "RXLEV_without_Attenuation" }, - { 0x6F, "reserved" }, - { 0x70, "CU_Results" }, - { 0x71, "reserved" }, - { 0x72, "LNA_Path_Results" }, - { 0x73, "RTE Results" }, - { 0x74, "Real Time" }, - { 0x75, "RX diversity selection" }, - { 0x76, "EAC input config" }, - { 0x77, "Feature support" }, - { 0x78, "File version" }, - { 0x79, "Outputs" }, - { 0x7A, "FU parameters" }, - { 0x7B, "Diagnostic info" }, - { 0x7C, "FU BSIC" }, - { 0x7D, "TRX Configuration" }, - { 0x7E, "Download status" }, - { 0x7F, "RX difference limit" }, - { 0x80, "TRX HW capability" }, - { 0x81, "Common HW config" }, - { 0x82, "Autoconfiguration pool size" }, - { 0x83, "TRE diagnostic info" }, - { 0x84, "TRE object identity" }, - { 0x85, "New TRE Info" }, - { 0x86, "Acknowledgement period" }, - { 0x87, "Synchronization mode" }, - { 0x88, "reserved" }, - { 0x89, "Block Control Data" }, - { 0x8A, "SW load mode" }, - { 0x8B, "Recommended recovery action" }, - { 0x8C, "BSC BCF id" }, - { 0x8D, "Q1 baud rate" }, - { 0x8E, "Allocation status" }, - { 0x8F, "Functional entity number" }, - { 0x90, "Transmission delay" }, - { 0x91, "Loop Duration ms" }, - { 0x92, "Logical channel" }, - { 0x93, "Q1 address" }, - { 0x94, "Alarm detail" }, - { 0x95, "Cabinet type" }, - { 0x96, "HW unit existence" }, - { 0x97, "RF power parameters" }, - { 0x98, "Message scenario" }, - { 0x99, "HW unit max amount" }, - { 0x9A, "Master TRX" }, - { 0x9B, "Transparent data" }, - { 0x9C, "BSC topology info" }, - { 0x9D, "Air i/f modulation" }, - { 0x9E, "LCS Q1 command data" }, - { 0x9F, "Frame number offset" }, - { 0xA0, "Abis TSL" }, - { 0xA1, "Dynamic pool info" }, - { 0xA2, "LCS LLP data" }, - { 0xA3, "LCS Q1 answer data" }, - { 0xA4, "DFCA FU Radio Definition" }, - { 0xA5, "Antenna hopping" }, - { 0xA6, "Field record sequence number" }, - { 0xA7, "Timeslot offslot" }, - { 0xA8, "EPCR capability" }, - { 0xA9, "Connectsite optional element" }, - { 0xAA, "TSC" }, - { 0xAB, "Special TX Power Setting" }, - { 0xAC, "Optional sync settings" }, - { 0xFA, "Abis If parameters" }, - { 0, NULL } -}; - -static const char *get_element_name_string(uint16_t element) -{ - return get_value_string(nokia_element_name, element); -} - -static const struct value_string nokia_bts_types[] = { - { 0x0a, "MetroSite GSM 900" }, - { 0x0b, "MetroSite GSM 1800" }, - { 0x0c, "MetroSite GSM 1900 (PCS)" }, - { 0x0d, "MetroSite GSM 900 & 1800" }, - { 0x0e, "InSite GSM 900" }, - { 0x0f, "InSite GSM 1800" }, - { 0x10, "InSite GSM 1900" }, - { 0x11, "UltraSite GSM 900" }, - { 0x12, "UltraSite GSM 1800" }, - { 0x13, "UltraSite GSM/US-TDMA 1900" }, - { 0x14, "UltraSite GSM 900 & 1800" }, - { 0x16, "UltraSite GSM/US-TDMA 850" }, - { 0x18, "MetroSite GSM/US-TDMA 850" }, - { 0x19, "UltraSite GSM 800/1900" }, - { 0, NULL } -}; - -static const char *get_bts_type_string(uint8_t type) -{ - return get_value_string(nokia_bts_types, type); -} - -static const struct value_string nokia_severity[] = { - { 0, "indeterminate" }, - { 1, "critical" }, - { 2, "major" }, - { 3, "minor" }, - { 4, "warning" }, - { 0, NULL } -}; - -static const char *get_severity_string(uint8_t severity) -{ - return get_value_string(nokia_severity, severity); -} - -/* TODO: put in a separate file ? */ - -/* some message IDs */ - -#define NOKIA_MSG_CONF_DATA 128 -#define NOKIA_MSG_ACK 129 -#define NOKIA_MSG_OMU_STARTED 130 -#define NOKIA_MSG_START_DOWNLOAD_REQ 131 -#define NOKIA_MSG_MF_REQ 132 -#define NOKIA_MSG_RESET_REQ 134 -#define NOKIA_MSG_CONF_REQ 136 -#define NOKIA_MSG_CONF_COMPLETE 142 -#define NOKIA_MSG_BLOCK_CTRL_REQ 168 -#define NOKIA_MSG_STATE_CHANGED 172 -#define NOKIA_MSG_ALARM 174 - -/* some element IDs */ - -#define NOKIA_EI_BTS_TYPE 0x13 -#define NOKIA_EI_ACK 0x23 -#define NOKIA_EI_ADD_INFO 0x51 -#define NOKIA_EI_SEVERITY 0x4B -#define NOKIA_EI_ALARM_DETAIL 0x94 - -#define OM_ALLOC_SIZE 1024 -#define OM_HEADROOM_SIZE 128 - -static uint8_t fu_config_template[] = { - 0x7F, 0x7A, 0x39, - /* ID = 0x7A (FU parameters) ## constructed ## */ - /* length = 57 */ - /* [3] */ - - 0x5F, 0x40, 0x04, - /* ID = 0x40 (Object identity) */ - /* length = 4 */ - /* [6] */ - 0x00, 0x07, 0x01, 0xFF, - - 0x41, 0x02, - /* ID = 0x01 (Ny1) */ - /* length = 2 */ - /* [12] */ - 0x00, 0x05, - - 0x42, 0x02, - /* ID = 0x02 (T3105_F) */ - /* length = 2 */ - /* [16] */ - 0x00, 0x28, /* FIXME: use net->T3105 */ - - 0x50, 0x02, - /* ID = 0x10 (T3105_D) */ - /* length = 2 */ - /* [20] */ - 0x00, 0x28, /* FIXME: use net->T3105 */ - - 0x43, 0x05, - /* ID = 0x03 (Interference band limits) */ - /* length = 5 */ - /* [24] */ - 0x0F, 0x1B, 0x27, 0x33, 0x3F, - - 0x44, 0x02, - /* ID = 0x04 (Interference report timer in secs) */ - /* length = 2 */ - /* [31] */ - 0x00, 0x10, - - 0x47, 0x01, - /* ID = 0x07 (RACH report timer in secs) */ - /* length = 1 */ - /* [35] */ - 0x1E, - - 0x4C, 0x10, - /* ID = 0x0C (Cell allocation bitmap) ####### */ - /* length = 16 */ - /* [38] */ - 0x8F, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x59, 0x01, - /* ID = 0x19 (Averaging period) */ - /* length = 1 */ - /* [56] */ - 0x01, - - 0x5E, 0x01, - /* ID = 0x1E ((RF max power reduction)) */ - /* length = 1 */ - /* [59] */ - 0x00, - - 0x7F, 0x46, 0x11, - /* ID = 0x46 (FU channel configuration) ## constructed ## */ - /* length = 17 */ - /* [63] */ - - 0x5F, 0x40, 0x04, - /* ID = 0x40 (Object identity) */ - /* length = 4 */ - /* [66] */ - 0x00, 0x07, 0x01, 0xFF, - - 0x45, 0x08, - /* ID = 0x05 (Channel configuration per TS) */ - /* length = 8 */ - /* [72] */ - 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - - 0x7F, 0x65, 0x0B, - /* ID = 0x65 (Obj. identity and obj. state) ## constructed ## */ - /* length = 11 */ - /* [83] */ - - 0x5F, 0x40, 0x04, - /* ID = 0x40 (Object identity) */ - /* length = 4 */ - /* [86] */ - 0x00, 0x04, 0x01, 0xFF, - - 0x5F, 0x44, 0x01, - /* ID = 0x44 (Object current state) */ - /* length = 1 */ - /* [93] */ - 0x03, - - 0x7F, 0x7C, 0x0A, - /* ID = 0x7C (FU BSIC) ## constructed ## */ - /* length = 10 */ - /* [97] */ - - 0x5F, 0x40, 0x04, - /* ID = 0x40 (Object identity) */ - /* length = 4 */ - /* [100] */ - 0x00, 0x07, 0x01, 0xFF, - - 0x46, 0x01, - /* ID = 0x06 (BSIC) */ - /* length = 1 */ - /* [106] */ - 0x00, - - 0x7F, 0x48, 0x0B, - /* ID = 0x48 (ARFN of a CU) ## constructed ## */ - /* length = 11 */ - /* [110] */ - - 0x5F, 0x40, 0x04, - /* ID = 0x40 (Object identity) */ - /* length = 4 */ - /* [113] */ - 0x00, 0x08, 0x01, 0xFF, - - 0x4A, 0x02, - /* ID = 0x0A (ARFN) ####### */ - /* length = 2 */ - /* [119] */ - 0x03, 0x62, - - 0x7F, 0x49, 0x59, - /* ID = 0x49 (FU radio definition) ## constructed ## */ - /* length = 89 */ - /* [124] */ - - 0x5F, 0x40, 0x04, - /* ID = 0x40 (Object identity) */ - /* length = 4 */ - /* [127] */ - 0x00, 0x07, 0x01, 0xFF, - - 0x4D, 0x50, - /* ID = 0x0D (Radio definition per TS) ####### */ - /* length = 80 */ - /* [133] */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MA */ - 0x03, 0x62, /* HSN, MAIO or ARFCN if no hopping */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x62, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x62, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x62, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x62, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x62, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x62, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x62, -}; - -/* TODO: put in a separate file ? */ - -/* - build the configuration for each TRX -*/ - -static int make_fu_config(struct gsm_bts_trx *trx, uint8_t id, - uint8_t * fu_config, int *hopping) -{ - int i; - - *hopping = 0; - - memcpy(fu_config, fu_config_template, sizeof(fu_config_template)); - - /* set ID */ - - fu_config[6 + 2] = id; - fu_config[66 + 2] = id; - fu_config[86 + 2] = id; - fu_config[100 + 2] = id; - fu_config[113 + 2] = id; - fu_config[127 + 2] = id; - - /* set ARFCN */ - - uint16_t arfcn = trx->arfcn; - - fu_config[119] = arfcn >> 8; - fu_config[119 + 1] = arfcn & 0xFF; - - for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { - struct gsm_bts_trx_ts *ts = &trx->ts[i]; - - if (ts->hopping.enabled) { - /* reverse order */ - int j; - for (j = 0; j < ts->hopping.ma_len; j++) - fu_config[133 + (i * 10) + (7 - j)] = - ts->hopping.ma_data[j]; - fu_config[133 + 8 + (i * 10)] = ts->hopping.hsn; - fu_config[133 + 8 + 1 + (i * 10)] = ts->hopping.maio; - *hopping = 1; - } else { - fu_config[133 + 8 + (i * 10)] = arfcn >> 8; - fu_config[133 + 8 + 1 + (i * 10)] = arfcn & 0xFF; - } - } - - /* set BSIC */ - - /* - Attention: all TRX except the first one seem to get the TSC - from the CHANNEL ACTIVATION command (in CHANNEL IDENTIFICATION, - GSM 04.08 CHANNEL DESCRIPTION). - There was a bug in rsl_chan_activate_lchan() setting this parameter. - */ - - uint8_t bsic = trx->bts->bsic; - - fu_config[106] = bsic; - - /* set CA */ - - if (generate_cell_chan_list(&fu_config[38], trx->bts) != 0) { - fprintf(stderr, "generate_cell_chan_list failed\n"); - return 0; - } - - /* set channel configuration */ - - for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { - struct gsm_bts_trx_ts *ts = &trx->ts[i]; - uint8_t chan_config; - - /* - 0 = FCCH + SCH + BCCH + CCCH - 1 = FCCH + SCH + BCCH + CCCH + SDCCH/4 + SACCH/4 - 2 = BCCH + CCCH (This combination is not used in any BTS) - 3 = FCCH + SCH + BCCH + CCCH + SDCCH/4 with SDCCH2 used as CBCH - 4 = SDCCH/8 + SACCH/8 - 5 = SDCCH/8 with SDCCH2 used as CBCH - 6 = TCH/F + FACCH/F + SACCH/F - 7 = E-RACH (Talk family) - 9 = Dual rate (capability for TCH/F and TCH/H) - 10 = reserved for BTS internal use - 11 = PBCCH + PCCCH + PDTCH + PACCH + PTCCH (can be used in GPRS release 2). - 0xFF = spare TS - */ - - if (ts->pchan == GSM_PCHAN_NONE) - chan_config = 0xFF; - else if (ts->pchan == GSM_PCHAN_CCCH) - chan_config = 0; - else if (ts->pchan == GSM_PCHAN_CCCH_SDCCH4) - chan_config = 1; - else if (ts->pchan == GSM_PCHAN_TCH_F) - chan_config = 6; /* 9 should work too */ - else if (ts->pchan == GSM_PCHAN_TCH_H) - chan_config = 9; - else if (ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C) - chan_config = 4; - else if (ts->pchan == GSM_PCHAN_PDCH) - chan_config = 11; - else { - fprintf(stderr, - "unsupported channel config %d for timeslot %d\n", - ts->pchan, i); - return 0; - } - - fu_config[72 + i] = chan_config; - } - return sizeof(fu_config_template); -} - -/* TODO: put in a separate file ? */ - -static uint8_t bts_config_1[] = { - 0x4E, 0x02, - /* ID = 0x0E (Frame number) */ - /* length = 2 */ - /* [2] */ - 0xFF, 0xFF, - - 0x5F, 0x4E, 0x02, - /* ID = 0x4E (RX antenna supervision period) */ - /* length = 2 */ - /* [7] */ - 0xFF, 0xFF, - - 0x5F, 0x50, 0x02, - /* ID = 0x50 (Sector configuration) */ - /* length = 2 */ - /* [12] */ - 0x01, 0x01, -}; - -static uint8_t bts_config_2[] = { - 0x55, 0x02, - /* ID = 0x15 (Hopping mode) */ - /* length = 2 */ - /* [2] */ - 0x01, 0x00, - - 0x5F, 0x75, 0x02, - /* ID = 0x75 (RX diversity selection) */ - /* length = 2 */ - /* [7] */ - 0x01, 0x01, -}; - -static uint8_t bts_config_3[] = { - 0x5F, 0x20, 0x02, - /* ID = 0x20 (Extended cell radius) */ - /* length = 2 */ - /* [3] */ - 0x01, 0x00, -}; - -static uint8_t bts_config_4[] = { - 0x5F, 0x74, 0x09, - /* ID = 0x74 (Real Time) */ - /* length = 9 */ - /* [3] year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */ - 0x07, 0xDB, 0x06, 0x02, 0x0B, 0x20, 0x0C, 0x00, - 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [15] */ - 0x01, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [21] */ - 0x02, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [27] */ - 0x03, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [33] */ - 0x04, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [39] */ - 0x05, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [45] */ - 0x06, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [51] */ - 0x07, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [57] */ - 0x08, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [63] */ - 0x09, 0x01, 0x00, - - 0x5F, 0x76, 0x03, - /* ID = 0x76 (EAC input config) */ - /* length = 3 */ - /* [69] */ - 0x0A, 0x01, 0x00, -}; - -static uint8_t bts_config_insite[] = { - 0x4E, 0x02, - /* ID = 0x0E (Frame number) */ - /* length = 2 */ - /* [2] */ - 0xFF, 0xFF, - - 0x5F, 0x4E, 0x02, - /* ID = 0x4E (RX antenna supervision period) */ - /* length = 2 */ - /* [7] */ - 0xFF, 0xFF, - - 0x5F, 0x50, 0x02, - /* ID = 0x50 (Sector configuration) */ - /* length = 2 */ - /* [12] */ - 0x01, 0x01, - - 0x55, 0x02, - /* ID = 0x15 (Hopping mode) */ - /* length = 2 */ - /* [16] */ - 0x01, 0x00, - - 0x5F, 0x20, 0x02, - /* ID = 0x20 (Extended cell radius) */ - /* length = 2 */ - /* [21] */ - 0x01, 0x00, - - 0x5F, 0x74, 0x09, - /* ID = 0x74 (Real Time) */ - /* length = 9 */ - /* [26] */ - 0x07, 0xDB, 0x07, 0x0A, 0x0F, 0x09, 0x0B, 0x00, - 0x00, -}; - -void set_real_time(uint8_t * real_time) -{ - time_t t; - struct tm *tm; - - t = time(NULL); - tm = localtime(&t); - - /* year-high, year-low, month, day, hour, minute, second, msec-high, msec-low */ - - real_time[0] = (1900 + tm->tm_year) >> 8; - real_time[1] = (1900 + tm->tm_year) & 0xFF; - real_time[2] = tm->tm_mon + 1; - real_time[3] = tm->tm_mday; - real_time[4] = tm->tm_hour; - real_time[5] = tm->tm_min; - real_time[6] = tm->tm_sec; - real_time[7] = 0; - real_time[8] = 0; -} - -/* TODO: put in a separate file ? */ - -/* - build the configuration data -*/ - -static int make_bts_config(uint8_t bts_type, int n_trx, uint8_t * fu_config, - int need_hopping) -{ - /* is it an InSite BTS ? */ - if (bts_type == 0x0E || bts_type == 0x0F || bts_type == 0x10) { /* TODO */ - if (n_trx != 1) { - fprintf(stderr, "InSite has only one TRX\n"); - return 0; - } - if (need_hopping != 0) { - fprintf(stderr, "InSite does not support hopping\n"); - return 0; - } - memcpy(fu_config, bts_config_insite, sizeof(bts_config_insite)); - set_real_time(&fu_config[26]); - return sizeof(bts_config_insite); - } - - int len = 0; - int i; - - memcpy(fu_config + len, bts_config_1, sizeof(bts_config_1)); - - /* set sector configuration */ - fu_config[len + 12 - 1] = 1 + n_trx; /* len */ - for (i = 0; i < n_trx; i++) - fu_config[len + 12 + 1 + i] = ((i + 1) & 0xFF); - - len += (sizeof(bts_config_1) + (n_trx - 1)); - - memcpy(fu_config + len, bts_config_2, sizeof(bts_config_2)); - /* set hopping mode (Baseband and RF hopping work for the MetroSite) */ - if (need_hopping) - fu_config[len + 2 + 1] = 1; /* 0: no hopping, 1: Baseband hopping, 2: RF hopping */ - len += sizeof(bts_config_2); - - /* set extended cell radius for each TRX */ - for (i = 0; i < n_trx; i++) { - memcpy(fu_config + len, bts_config_3, sizeof(bts_config_3)); - fu_config[len + 3] = ((i + 1) & 0xFF); - len += sizeof(bts_config_3); - } - - memcpy(fu_config + len, bts_config_4, sizeof(bts_config_4)); - set_real_time(&fu_config[len + 3]); - len += sizeof(bts_config_4); - - return len; -} - -/* TODO: put in a separate file ? */ - -static struct msgb *nm_msgb_alloc(void) -{ - return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE, "OML"); -} - -/* TODO: put in a separate file ? */ - -struct abis_om_nokia_hdr { - uint8_t msg_type; - uint8_t spare; - uint16_t reference; - uint8_t data[0]; -} __attribute__ ((packed)); - -#define ABIS_OM_NOKIA_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_nokia_hdr)) - -static int abis_nm_send(struct gsm_bts *bts, uint8_t msg_type, uint16_t ref, - uint8_t * data, int len_data) -{ - struct abis_om_hdr *oh; - struct abis_om_nokia_hdr *noh; - struct msgb *msg = nm_msgb_alloc(); - - oh = (struct abis_om_hdr *)msgb_put(msg, - ABIS_OM_NOKIA_HDR_SIZE + len_data); - - oh->mdisc = ABIS_OM_MDISC_FOM; - oh->placement = ABIS_OM_PLACEMENT_ONLY; - oh->sequence = 0; - oh->length = sizeof(struct abis_om_nokia_hdr) + len_data; - - noh = (struct abis_om_nokia_hdr *)oh->data; - - noh->msg_type = msg_type; - noh->spare = 0; - noh->reference = htons(ref); - memcpy(noh->data, data, len_data); - - DEBUGPC(DNM, "Sending %s\n", get_msg_type_name_string(msg_type)); - - return abis_nm_sendmsg(bts, msg); -} - -/* TODO: put in a separate file ? */ - -static uint8_t download_req[] = { - 0x5F, 0x25, 0x0B, - /* ID = 0x25 (File identity) */ - /* length = 11 */ - /* [3] */ - 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, - 0x2A, 0x2A, 0x2A, - - 0x5F, 0x78, 0x03, - /* ID = 0x78 (File version) */ - /* length = 3 */ - /* [17] */ - 0x2A, 0x2A, 0x2A, - - 0x5F, 0x81, 0x0A, 0x01, - /* ID = 0x8A (SW load mode) */ - /* length = 1 */ - /* [24] */ - 0x01, - - 0x5F, 0x81, 0x06, 0x01, - /* ID = 0x86 (Acknowledgement period) */ - /* length = 1 */ - /* [29] */ - 0x01, -}; - -static int abis_nm_download_req(struct gsm_bts *bts, uint16_t ref) -{ - uint8_t *data = download_req; - int len_data = sizeof(download_req); - - return abis_nm_send(bts, NOKIA_MSG_START_DOWNLOAD_REQ, ref, data, - len_data); -} - -/* TODO: put in a separate file ? */ - -static uint8_t ack[] = { - 0x5F, 0x23, 0x01, - /* ID = 0x23 (Ack-Nack) */ - /* length = 1 */ - /* [3] */ - 0x01, -}; - -static int abis_nm_ack(struct gsm_bts *bts, uint16_t ref) -{ - uint8_t *data = ack; - int len_data = sizeof(ack); - - return abis_nm_send(bts, NOKIA_MSG_ACK, ref, data, len_data); -} - -/* TODO: put in a separate file ? */ - -static uint8_t reset[] = { - 0x5F, 0x40, 0x04, - /* ID = 0x40 (Object identity) */ - /* length = 4 */ - /* [3] */ - 0x00, 0x01, 0xFF, 0xFF, -}; - -static int abis_nm_reset(struct gsm_bts *bts, uint16_t ref) -{ - uint8_t *data = reset; - int len_data = sizeof(reset); - LOGP(DLINP, LOGL_INFO, "Nokia BTS reset timer: %d\n", bts->nokia.bts_reset_timer_cnf); - return abis_nm_send(bts, NOKIA_MSG_RESET_REQ, ref, data, len_data); -} - -/* TODO: put in a separate file ? */ - -static int abis_nm_send_multi_segments(struct gsm_bts *bts, uint8_t msg_type, - uint16_t ref, uint8_t * data, int len) -{ - int len_remain, len_to_send, max_send; - int seq = 0; - int ret; - - len_remain = len; - - while (len_remain) { - struct abis_om_hdr *oh; - struct abis_om_nokia_hdr *noh; - struct msgb *msg = nm_msgb_alloc(); - - if (seq == 0) - max_send = 256 - sizeof(struct abis_om_nokia_hdr); - else - max_send = 256; - - if (len_remain > max_send) { - len_to_send = max_send; - - if (seq == 0) { - /* first segment */ - oh = (struct abis_om_hdr *)msgb_put(msg, - ABIS_OM_NOKIA_HDR_SIZE - + - len_to_send); - - oh->mdisc = ABIS_OM_MDISC_FOM; - oh->placement = ABIS_OM_PLACEMENT_FIRST; /* first segment of multi-segment message */ - oh->sequence = seq; - oh->length = 0; /* 256 bytes */ - - noh = (struct abis_om_nokia_hdr *)oh->data; - - noh->msg_type = msg_type; - noh->spare = 0; - noh->reference = htons(ref); - memcpy(noh->data, data, len_to_send); - } else { - /* segment in between */ - oh = (struct abis_om_hdr *)msgb_put(msg, - sizeof - (struct - abis_om_hdr) - + - len_to_send); - - oh->mdisc = ABIS_OM_MDISC_FOM; - oh->placement = ABIS_OM_PLACEMENT_MIDDLE; /* segment of multi-segment message */ - oh->sequence = seq; - oh->length = 0; /* 256 bytes */ - - memcpy(oh->data, data, len_to_send); - } - } else { - - len_to_send = len_remain; - - /* check if message fits in a single segment */ - - if (seq == 0) - return abis_nm_send(bts, msg_type, ref, data, - len_to_send); - - /* last segment */ - - oh = (struct abis_om_hdr *)msgb_put(msg, - sizeof(struct - abis_om_hdr) - + len_to_send); - - oh->mdisc = ABIS_OM_MDISC_FOM; - oh->placement = ABIS_OM_PLACEMENT_LAST; /* last segment of multi-segment message */ - oh->sequence = seq; - oh->length = len_to_send; - - memcpy(oh->data, data, len_to_send); - } - - DEBUGPC(DNM, "Sending multi-segment %d\n", seq); - - ret = abis_nm_sendmsg(bts, msg); - if (ret < 0) - return ret; - - nokia_abis_nm_queue_send_next(bts); - - /* next segment */ - len_remain -= len_to_send; - data += len_to_send; - seq++; - } - return ret; -} - -/* TODO: put in a separate file ? */ - -static int abis_nm_send_config(struct gsm_bts *bts, uint8_t bts_type) -{ - struct gsm_bts_trx *trx; - uint8_t config[2048]; /* TODO: might be too small if lots of TRX are used */ - int len = 0; - int idx = 0; - int ret; - int hopping = 0; - int need_hopping = 0; - - memset(config, 0, sizeof(config)); - - llist_for_each_entry(trx, &bts->trx_list, list) { -#if 0 /* debugging */ - printf("TRX\n"); - printf(" arfcn: %d\n", trx->arfcn); - printf(" bsic: %d\n", trx->bts->bsic); - uint8_t ca[20]; - memset(ca, 0xFF, sizeof(ca)); - ret = generate_cell_chan_list(ca, trx->bts); - printf(" ca (%d): %s\n", ret, osmo_hexdump(ca, sizeof(ca))); - int i; - for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { - struct gsm_bts_trx_ts *ts = &trx->ts[i]; - - printf(" pchan %d: %d\n", i, ts->pchan); - } -#endif - ret = make_fu_config(trx, idx + 1, config + len, &hopping); - need_hopping |= hopping; - len += ret; - - idx++; - } - - ret = make_bts_config(bts_type, idx, config + len, need_hopping); - len += ret; - -#if 0 /* debugging */ - dump_elements(config, len); -#endif - - return abis_nm_send_multi_segments(bts, NOKIA_MSG_CONF_DATA, 1, config, - len); -} - -#define GET_NEXT_BYTE if(idx >= len) return 0; \ - ub = data[idx++]; - -static int find_element(uint8_t * data, int len, uint16_t id, uint8_t * value, - int max_value) -{ - uint8_t ub; - int idx = 0; - int found = 0; - int constructed __attribute__((unused)); - uint16_t id_value; - - for (;;) { - - GET_NEXT_BYTE; - - /* encoding bit, construced means that other elements are contained */ - constructed = ((ub & 0x20) ? 1 : 0); - - if ((ub & 0x1F) == 0x1F) { - /* fixed pattern, ID follows */ - GET_NEXT_BYTE; /* ID */ - id_value = ub & 0x7F; - if (ub & 0x80) { - /* extension bit */ - GET_NEXT_BYTE; /* ID low part */ - id_value = (id_value << 7) | (ub & 0x7F); - } - if (id_value == id) - found = 1; - } else { - id_value = (ub & 0x3F); - if (id_value == id) - found = 1; - } - - GET_NEXT_BYTE; /* length */ - - if (found) { - /* get data */ - uint8_t n = ub; - uint8_t i; - for (i = 0; i < n; i++) { - GET_NEXT_BYTE; - if (max_value <= 0) - return -1; /* buffer too small */ - *value = ub; - value++; - max_value--; - } - return n; /* length */ - } else { - /* skip data */ - uint8_t n = ub; - uint8_t i; - for (i = 0; i < n; i++) { - GET_NEXT_BYTE; - } - } - } - return 0; /* not found */ -} - -static int dump_elements(uint8_t * data, int len) -{ - uint8_t ub; - int idx = 0; - int constructed; - uint16_t id_value; - static char indent[100] = ""; /* TODO: move static to BTS context */ - - for (;;) { - - GET_NEXT_BYTE; - - /* encoding bit, construced means that other elements are contained */ - constructed = ((ub & 0x20) ? 1 : 0); - - if ((ub & 0x1F) == 0x1F) { - /* fixed pattern, ID follows */ - GET_NEXT_BYTE; /* ID */ - id_value = ub & 0x7F; - if (ub & 0x80) { - /* extension bit */ - GET_NEXT_BYTE; /* ID low part */ - id_value = (id_value << 7) | (ub & 0x7F); - } - - } else { - id_value = (ub & 0x3F); - } - - GET_NEXT_BYTE; /* length */ - - printf("%s--ID = 0x%02X (%s) %s\n", indent, id_value, - get_element_name_string(id_value), - constructed ? "** constructed **" : ""); - printf("%s length = %d\n", indent, ub); - printf("%s %s\n", indent, osmo_hexdump(data + idx, ub)); - - if (constructed) { - int indent_len = strlen(indent); - strcat(indent, " "); - - dump_elements(data + idx, ub); - - indent[indent_len] = 0; - } - /* skip data */ - uint8_t n = ub; - uint8_t i; - for (i = 0; i < n; i++) { - GET_NEXT_BYTE; - } - } - return 0; -} - -/* TODO: put in a separate file ? */ - -/* taken from abis_nm.c */ - -static void nokia_abis_nm_queue_send_next(struct gsm_bts *bts) -{ - int wait = 0; - struct msgb *msg; - /* the queue is empty */ - while (!llist_empty(&bts->abis_queue)) { - msg = msgb_dequeue(&bts->abis_queue); - wait = OBSC_NM_W_ACK_CB(msg); - abis_sendmsg(msg); - - if (wait) - break; - } - - bts->abis_nm_pend = wait; -} - -/* TODO: put in a separate file ? */ - -/* timer for restarting OML after BTS reset */ - -static void reset_timer_cb(void *_bts) -{ - struct gsm_bts *bts = _bts; - struct gsm_e1_subslot *e1_link = &bts->oml_e1_link; - struct e1inp_line *line; - - bts->nokia.wait_reset = 0; - - /* OML link */ - line = e1inp_line_find(e1_link->e1_nr); - if (!line) { - LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to " - "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr); - return; - } - - start_sabm_in_line(line, 0, -1); /* stop all first */ - start_sabm_in_line(line, 1, SAPI_OML); /* start only OML */ -} - -/* TODO: put in a separate file ? */ - -/* - This is how the configuration is done: - - start OML link - - reset BTS - - receive ACK, wait some time and restart OML link - - receive OMU STARTED message, send START DOWNLOAD REQ - - receive CNF REQ message, send CONF DATA - - receive ACK, start RSL link(s) - ACK some other messages received from the BTS. - - Probably its also possible to configure the BTS without a reset, this - has not been tested yet. -*/ - -static int abis_nm_rcvmsg_fom(struct msgb *mb) -{ - struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)mb->dst; - struct gsm_bts *bts = sign_link->trx->bts; - struct abis_om_hdr *oh = msgb_l2(mb); - struct abis_om_nokia_hdr *noh = msgb_l3(mb); - uint8_t mt = noh->msg_type; - int ret = 0; - uint16_t ref = ntohs(noh->reference); - uint8_t info[256]; - uint8_t ack = 0xFF; - uint8_t severity = 0xFF; - int str_len; - int len_data; - - if (bts->nokia.wait_reset) { - LOGP(DNM, LOGL_INFO, - "Ignore message while waiting for reset\n"); - return ret; - } - - if (oh->length < sizeof(struct abis_om_nokia_hdr)) { - LOGP(DNM, LOGL_ERROR, "Message too short\n"); - return -EINVAL; - } - - len_data = oh->length - sizeof(struct abis_om_nokia_hdr); - LOGP(DNM, LOGL_INFO, "(0x%02X) %s\n", mt, get_msg_type_name_string(mt)); -#if 0 /* debugging */ - dump_elements(noh->data, len_data); -#endif - - switch (mt) { - case NOKIA_MSG_OMU_STARTED: - if (find_element(noh->data, len_data, - NOKIA_EI_BTS_TYPE, &bts->nokia.bts_type, - sizeof(uint8_t)) == sizeof(uint8_t)) - LOGP(DNM, LOGL_INFO, "BTS type = %d (%s)\n", - bts->nokia.bts_type, - get_bts_type_string(bts->nokia.bts_type)); - else - LOGP(DNM, LOGL_ERROR, "BTS type not found\n"); - /* send START_DOWNLOAD_REQ */ - abis_nm_download_req(bts, ref); - break; - case NOKIA_MSG_MF_REQ: - break; - case NOKIA_MSG_CONF_REQ: - /* send ACK */ - abis_nm_ack(bts, ref); - nokia_abis_nm_queue_send_next(bts); - /* send CONF_DATA */ - abis_nm_send_config(bts, bts->nokia.bts_type); - bts->nokia.configured = 1; - break; - case NOKIA_MSG_ACK: - if (find_element - (noh->data, len_data, NOKIA_EI_ACK, &ack, - sizeof(uint8_t)) == sizeof(uint8_t)) { - LOGP(DNM, LOGL_INFO, "ACK = %d\n", ack); - if (ack != 1) { - LOGP(DNM, LOGL_ERROR, "No ACK received (%d)\n", - ack); - /* TODO: properly handle failures (NACK) */ - } - } else - LOGP(DNM, LOGL_ERROR, "ACK not found\n"); - - /* TODO: the assumption for the following is that no NACK was received */ - - /* ACK for reset message ? */ - if (!bts->nokia.did_reset) { - bts->nokia.did_reset = 1; - - /* - TODO: For the InSite processing the received data is - blocked in the driver during reset. - Otherwise the LAPD module might assert because the InSite - sends garbage on the E1 line during reset. - This is done by looking at "wait_reset" in the driver - (function handle_ts1_read()) and ignoring the received data. - It seems to be necessary for the MetroSite too. - */ - bts->nokia.wait_reset = 1; - - osmo_timer_setup(&bts->nokia.reset_timer, - reset_timer_cb, bts); - osmo_timer_schedule(&bts->nokia.reset_timer, bts->nokia.bts_reset_timer_cnf, 0); - - struct gsm_e1_subslot *e1_link = &bts->oml_e1_link; - struct e1inp_line *line; - /* OML link */ - line = e1inp_line_find(e1_link->e1_nr); - if (!line) { - LOGP(DLINP, LOGL_ERROR, - "BTS %u OML link referring to " - "non-existing E1 line %u\n", bts->nr, - e1_link->e1_nr); - return -ENOMEM; - } - - start_sabm_in_line(line, 0, -1); /* stop all first */ - } - - /* ACK for CONF DATA message ? */ - if (bts->nokia.configured != 0) { - /* start TRX (RSL link) */ - - struct gsm_e1_subslot *e1_link = - &sign_link->trx->rsl_e1_link; - struct e1inp_line *line; - - bts->nokia.configured = 0; - - /* RSL Link */ - line = e1inp_line_find(e1_link->e1_nr); - if (!line) { - LOGP(DLINP, LOGL_ERROR, - "TRX (%u/%u) RSL link referring " - "to non-existing E1 line %u\n", - sign_link->trx->bts->nr, sign_link->trx->nr, - e1_link->e1_nr); - return -ENOMEM; - } - /* start TRX */ - start_sabm_in_line(line, 1, SAPI_RSL); /* start only RSL */ - } - break; - case NOKIA_MSG_STATE_CHANGED: - /* send ACK */ - abis_nm_ack(bts, ref); - break; - case NOKIA_MSG_CONF_COMPLETE: - /* send ACK */ - abis_nm_ack(bts, ref); - break; - case NOKIA_MSG_BLOCK_CTRL_REQ: /* seems to be send when something goes wrong !? */ - /* send ACK (do we have to send an ACK ?) */ - abis_nm_ack(bts, ref); - break; - case NOKIA_MSG_ALARM: - find_element(noh->data, len_data, NOKIA_EI_SEVERITY, &severity, - sizeof(severity)); - /* TODO: there might be alarms with both elements set */ - str_len = - find_element(noh->data, len_data, NOKIA_EI_ADD_INFO, info, - sizeof(info)); - if (str_len > 0) { - info[str_len] = 0; - LOGP(DNM, LOGL_INFO, "ALARM Severity %s (%d) : %s\n", - get_severity_string(severity), severity, info); - } else { /* nothing found, try details */ - str_len = - find_element(noh->data, len_data, - NOKIA_EI_ALARM_DETAIL, info, - sizeof(info)); - if (str_len > 0) { - uint16_t code; - info[str_len] = 0; - code = (info[0] << 8) + info[1]; - LOGP(DNM, LOGL_INFO, - "ALARM Severity %s (%d), code 0x%X : %s\n", - get_severity_string(severity), severity, - code, info + 2); - } - } - /* send ACK */ - abis_nm_ack(bts, ref); - break; - } - - nokia_abis_nm_queue_send_next(bts); - - return ret; -} - -/* TODO: put in a separate file ? */ - -int abis_nokia_rcvmsg(struct msgb *msg) -{ - struct abis_om_hdr *oh = msgb_l2(msg); - int rc = 0; - - /* Various consistency checks */ - if (oh->placement != ABIS_OM_PLACEMENT_ONLY) { - LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n", - oh->placement); - if (oh->placement != ABIS_OM_PLACEMENT_FIRST) - return -EINVAL; - } - if (oh->sequence != 0) { - LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n", - oh->sequence); - return -EINVAL; - } - msg->l3h = (unsigned char *)oh + sizeof(*oh); - - switch (oh->mdisc) { - case ABIS_OM_MDISC_FOM: - LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_FOM\n"); - rc = abis_nm_rcvmsg_fom(msg); - break; - case ABIS_OM_MDISC_MANUF: - LOGP(DNM, LOGL_INFO, "ABIS_OM_MDISC_MANUF\n"); - break; - case ABIS_OM_MDISC_MMI: - case ABIS_OM_MDISC_TRAU: - LOGP(DNM, LOGL_ERROR, - "unimplemented ABIS OML message discriminator 0x%x\n", - oh->mdisc); - break; - default: - LOGP(DNM, LOGL_ERROR, - "unknown ABIS OML message discriminator 0x%x\n", - oh->mdisc); - return -EINVAL; - } - - msgb_free(msg); - return rc; -} - -static int bts_model_nokia_site_start(struct gsm_network *net); - -static void bts_model_nokia_site_e1line_bind_ops(struct e1inp_line *line) -{ - e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops); -} - -static struct gsm_bts_model model_nokia_site = { - .type = GSM_BTS_TYPE_NOKIA_SITE, - .name = "nokia_site", - .start = bts_model_nokia_site_start, - .oml_rcvmsg = &abis_nokia_rcvmsg, - .e1line_bind_ops = &bts_model_nokia_site_e1line_bind_ops, -}; - -static struct gsm_network *my_net; - -static int bts_model_nokia_site_start(struct gsm_network *net) -{ - model_nokia_site.features.data = &model_nokia_site._features_data[0]; - model_nokia_site.features.data_len = - sizeof(model_nokia_site._features_data); - - gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HOPPING); - gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_HSCSD); - gsm_btsmodel_set_feature(&model_nokia_site, BTS_FEAT_MULTI_TSC); - - osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL); - osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL); - osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL); - - my_net = net; - - return 0; -} - -int bts_model_nokia_site_init(void) -{ - return gsm_bts_model_register(&model_nokia_site); -} diff --git a/src/libbsc/bts_siemens_bs11.c b/src/libbsc/bts_siemens_bs11.c deleted file mode 100644 index c083b1e06..000000000 --- a/src/libbsc/bts_siemens_bs11.c +++ /dev/null @@ -1,602 +0,0 @@ -/* Siemens BS-11 specific code */ - -/* (C) 2009-2010 by Harald Welte - * - * 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 . - * - */ - - -#include - -#include -#include -#include -#include -#include - -static int bts_model_bs11_start(struct gsm_network *net); - -static void bts_model_bs11_e1line_bind_ops(struct e1inp_line *line) -{ - e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops); -} - -static struct gsm_bts_model model_bs11 = { - .type = GSM_BTS_TYPE_BS11, - .name = "bs11", - .start = bts_model_bs11_start, - .oml_rcvmsg = &abis_nm_rcvmsg, - .e1line_bind_ops = bts_model_bs11_e1line_bind_ops, - .nm_att_tlvdef = { - .def = { - [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TLV }, - /* BS11 specifics */ - [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV }, - [0xd5] = { TLV_TYPE_TLV }, - [0xa8] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV }, - [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV }, - [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV }, - [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV }, - [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV }, - [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV }, - [0x95] = { TLV_TYPE_FIXED, 2 }, - }, - }, -}; - -/* The following definitions are for OM and NM packets that we cannot yet - * generate by code but we just pass on */ - -// BTS Site Manager, SET ATTRIBUTES - -/* - Object Class: BTS Site Manager - Instance 1: FF - Instance 2: FF - Instance 3: FF -SET ATTRIBUTES - sAbisExternalTime: 2007/09/08 14:36:11 - omLAPDRelTimer: 30sec - shortLAPDIntTimer: 5sec - emergencyTimer1: 10 minutes - emergencyTimer2: 0 minutes -*/ - -unsigned char msg_1[] = -{ - NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER, 0xFF, 0xFF, 0xFF, - NM_ATT_BS11_ABIS_EXT_TIME, 0x07, - 0xD7, 0x09, 0x08, 0x0E, 0x24, 0x0B, 0xCE, - 0x02, - 0x00, 0x1E, - NM_ATT_BS11_SH_LAPD_INT_TIMER, - 0x01, 0x05, - 0x42, 0x02, 0x00, 0x0A, - 0x44, 0x02, 0x00, 0x00 -}; - -// BTS, SET BTS ATTRIBUTES - -/* - Object Class: BTS - BTS relat. Number: 0 - Instance 2: FF - Instance 3: FF -SET BTS ATTRIBUTES - bsIdentityCode / BSIC: - PLMN_colour_code: 7h - BS_colour_code: 7h - BTS Air Timer T3105: 4 ,unit 10 ms - btsIsHopping: FALSE - periodCCCHLoadIndication: 1sec - thresholdCCCHLoadIndication: 0% - cellAllocationNumber: 00h = GSM 900 - enableInterferenceClass: 00h = Disabled - fACCHQual: 6 (FACCH stealing flags minus 1) - intaveParameter: 31 SACCH multiframes - interferenceLevelBoundaries: - Interference Boundary 1: 0Ah - Interference Boundary 2: 0Fh - Interference Boundary 3: 14h - Interference Boundary 4: 19h - Interference Boundary 5: 1Eh - mSTxPwrMax: 11 - GSM range: 2=39dBm, 15=13dBm, stepsize 2 dBm - DCS1800 range: 0=30dBm, 15=0dBm, stepsize 2 dBm - PCS1900 range: 0=30dBm, 15=0dBm, stepsize 2 dBm - 30=33dBm, 31=32dBm - ny1: - Maximum number of repetitions for PHYSICAL INFORMATION message (GSM 04.08): 20 - powerOutputThresholds: - Out Power Fault Threshold: -10 dB - Red Out Power Threshold: - 6 dB - Excessive Out Power Threshold: 5 dB - rACHBusyThreshold: -127 dBm - rACHLoadAveragingSlots: 250 ,number of RACH burst periods - rfResourceIndicationPeriod: 125 SACCH multiframes - T200: - SDCCH: 044 in 5 ms - FACCH/Full rate: 031 in 5 ms - FACCH/Half rate: 041 in 5 ms - SACCH with TCH SAPI0: 090 in 10 ms - SACCH with SDCCH: 090 in 10 ms - SDCCH with SAPI3: 090 in 5 ms - SACCH with TCH SAPI3: 135 in 10 ms - tSync: 9000 units of 10 msec - tTrau: 9000 units of 10 msec - enableUmLoopTest: 00h = disabled - enableExcessiveDistance: 00h = Disabled - excessiveDistance: 64km - hoppingMode: 00h = baseband hopping - cellType: 00h = Standard Cell - BCCH ARFCN / bCCHFrequency: 1 -*/ - -static unsigned char bs11_attr_bts[] = -{ - NM_ATT_BSIC, HARDCODED_BSIC, - NM_ATT_BTS_AIR_TIMER, 0x04, - NM_ATT_BS11_BTSLS_HOPPING, 0x00, - NM_ATT_CCCH_L_I_P, 0x01, - NM_ATT_CCCH_L_T, 0x00, - NM_ATT_BS11_CELL_ALLOC_NR, NM_BS11_CANR_GSM, - NM_ATT_BS11_ENA_INTERF_CLASS, 0x01, - NM_ATT_BS11_FACCH_QUAL, 0x06, - /* interference avg. period in numbers of SACCH multifr */ - NM_ATT_INTAVE_PARAM, 0x1F, - NM_ATT_INTERF_BOUND, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x7B, - NM_ATT_CCCH_L_T, 0x23, - NM_ATT_GSM_TIME, 0x28, 0x00, - NM_ATT_ADM_STATE, 0x03, - NM_ATT_RACH_B_THRESH, 0x7F, - NM_ATT_LDAVG_SLOTS, 0x00, 0xFA, - NM_ATT_BS11_RF_RES_IND_PER, 0x7D, - NM_ATT_T200, 0x2C, 0x1F, 0x29, 0x5A, 0x5A, 0x5A, 0x87, - NM_ATT_BS11_TSYNC, 0x23, 0x28, - NM_ATT_BS11_TTRAU, 0x23, 0x28, - NM_ATT_TEST_DUR, 0x01, 0x00, - NM_ATT_OUTST_ALARM, 0x01, 0x00, - NM_ATT_BS11_EXCESSIVE_DISTANCE, 0x01, 0x40, - NM_ATT_BS11_HOPPING_MODE, 0x01, 0x00, - NM_ATT_BS11_PLL, 0x01, 0x00, - NM_ATT_BCCH_ARFCN, 0x00, HARDCODED_ARFCN/*0x01*/, -}; - -// Handover Recognition, SET ATTRIBUTES - -/* -Illegal Contents GSM Formatted O&M Msg - Object Class: Handover Recognition - BTS relat. Number: 0 - Instance 2: FF - Instance 3: FF -SET ATTRIBUTES - enableDelayPowerBudgetHO: 00h = Disabled - enableDistanceHO: 00h = Disabled - enableInternalInterCellHandover: 00h = Disabled - enableInternalIntraCellHandover: 00h = Disabled - enablePowerBudgetHO: 00h = Disabled - enableRXLEVHO: 00h = Disabled - enableRXQUALHO: 00h = Disabled - hoAveragingDistance: 8 SACCH multiframes - hoAveragingLev: - A_LEV_HO: 8 SACCH multiframes - W_LEV_HO: 1 SACCH multiframes - hoAveragingPowerBudget: 16 SACCH multiframes - hoAveragingQual: - A_QUAL_HO: 8 SACCH multiframes - W_QUAL_HO: 2 SACCH multiframes - hoLowerThresholdLevDL: (10 - 110) dBm - hoLowerThresholdLevUL: (5 - 110) dBm - hoLowerThresholdQualDL: 06h = 6.4% < BER < 12.8% - hoLowerThresholdQualUL: 06h = 6.4% < BER < 12.8% - hoThresholdLevDLintra : (20 - 110) dBm - hoThresholdLevULintra: (20 - 110) dBm - hoThresholdMsRangeMax: 20 km - nCell: 06h - timerHORequest: 3 ,unit 2 SACCH multiframes -*/ - -unsigned char msg_3[] = -{ - NM_MT_BS11_SET_ATTR, NM_OC_BS11_HANDOVER, 0x00, 0xFF, 0xFF, - 0xD0, 0x00, /* enableDelayPowerBudgetHO */ - 0x64, 0x00, /* enableDistanceHO */ - 0x67, 0x00, /* enableInternalInterCellHandover */ - 0x68, 0x00, /* enableInternalInterCellHandover */ - 0x6A, 0x00, /* enablePowerBudgetHO */ - 0x6C, 0x00, /* enableRXLEVHO */ - 0x6D, 0x00, /* enableRXQUALHO */ - 0x6F, 0x08, /* hoAveragingDistance */ - 0x70, 0x08, 0x01, /* hoAveragingLev */ - 0x71, 0x10, 0x10, 0x10, - 0x72, 0x08, 0x02, /* hoAveragingQual */ - 0x73, 0x0A, /* hoLowerThresholdLevDL */ - 0x74, 0x05, /* hoLowerThresholdLevUL */ - 0x75, 0x06, /* hoLowerThresholdQualDL */ - 0x76, 0x06, /* hoLowerThresholdQualUL */ - 0x78, 0x14, /* hoThresholdLevDLintra */ - 0x79, 0x14, /* hoThresholdLevULintra */ - 0x7A, 0x14, /* hoThresholdMsRangeMax */ - 0x7D, 0x06, /* nCell */ - NM_ATT_BS11_TIMER_HO_REQUEST, 0x03, - 0x20, 0x01, 0x00, - 0x45, 0x01, 0x00, - 0x48, 0x01, 0x00, - 0x5A, 0x01, 0x00, - 0x5B, 0x01, 0x05, - 0x5E, 0x01, 0x1A, - 0x5F, 0x01, 0x20, - 0x9D, 0x01, 0x00, - 0x47, 0x01, 0x00, - 0x5C, 0x01, 0x64, - 0x5D, 0x01, 0x1E, - 0x97, 0x01, 0x20, - 0xF7, 0x01, 0x3C, -}; - -// Power Control, SET ATTRIBUTES - -/* - Object Class: Power Control - BTS relat. Number: 0 - Instance 2: FF - Instance 3: FF -SET ATTRIBUTES - enableMsPowerControl: 00h = Disabled - enablePowerControlRLFW: 00h = Disabled - pcAveragingLev: - A_LEV_PC: 4 SACCH multiframes - W_LEV_PC: 1 SACCH multiframes - pcAveragingQual: - A_QUAL_PC: 4 SACCH multiframes - W_QUAL_PC: 2 SACCH multiframes - pcLowerThresholdLevDL: 0Fh - pcLowerThresholdLevUL: 0Ah - pcLowerThresholdQualDL: 05h = 3.2% < BER < 6.4% - pcLowerThresholdQualUL: 05h = 3.2% < BER < 6.4% - pcRLFThreshold: 0Ch - pcUpperThresholdLevDL: 14h - pcUpperThresholdLevUL: 0Fh - pcUpperThresholdQualDL: 04h = 1.6% < BER < 3.2% - pcUpperThresholdQualUL: 04h = 1.6% < BER < 3.2% - powerConfirm: 2 ,unit 2 SACCH multiframes - powerControlInterval: 2 ,unit 2 SACCH multiframes - powerIncrStepSize: 02h = 4 dB - powerRedStepSize: 01h = 2 dB - radioLinkTimeoutBs: 64 SACCH multiframes - enableBSPowerControl: 00h = disabled -*/ - -unsigned char msg_4[] = -{ - NM_MT_BS11_SET_ATTR, NM_OC_BS11_PWR_CTRL, 0x00, 0xFF, 0xFF, - NM_ATT_BS11_ENA_MS_PWR_CTRL, 0x00, - NM_ATT_BS11_ENA_PWR_CTRL_RLFW, 0x00, - 0x7E, 0x04, 0x01, /* pcAveragingLev */ - 0x7F, 0x04, 0x02, /* pcAveragingQual */ - 0x80, 0x0F, /* pcLowerThresholdLevDL */ - 0x81, 0x0A, /* pcLowerThresholdLevUL */ - 0x82, 0x05, /* pcLowerThresholdQualDL */ - 0x83, 0x05, /* pcLowerThresholdQualUL */ - 0x84, 0x0C, /* pcRLFThreshold */ - 0x85, 0x14, /* pcUpperThresholdLevDL */ - 0x86, 0x0F, /* pcUpperThresholdLevUL */ - 0x87, 0x04, /* pcUpperThresholdQualDL */ - 0x88, 0x04, /* pcUpperThresholdQualUL */ - 0x89, 0x02, /* powerConfirm */ - 0x8A, 0x02, /* powerConfirmInterval */ - 0x8B, 0x02, /* powerIncrStepSize */ - 0x8C, 0x01, /* powerRedStepSize */ - 0x8D, 0x40, /* radioLinkTimeoutBs */ - 0x65, 0x01, 0x00 // set to 0x01 to enable BSPowerControl -}; - - -// Transceiver, SET TRX ATTRIBUTES (TRX 0) - -/* - Object Class: Transceiver - BTS relat. Number: 0 - Tranceiver number: 0 - Instance 3: FF -SET TRX ATTRIBUTES - aRFCNList (HEX): 0001 - txPwrMaxReduction: 00h = 30dB - radioMeasGran: 254 SACCH multiframes - radioMeasRep: 01h = enabled - memberOfEmergencyConfig: 01h = TRUE - trxArea: 00h = TRX doesn't belong to a concentric cell -*/ - -static unsigned char bs11_attr_radio[] = -{ - NM_ATT_ARFCN_LIST, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/, - NM_ATT_RF_MAXPOWR_R, 0x00, - NM_ATT_BS11_RADIO_MEAS_GRAN, 0x01, 0x05, - NM_ATT_BS11_RADIO_MEAS_REP, 0x01, 0x01, - NM_ATT_BS11_EMRG_CFG_MEMBER, 0x01, 0x01, - NM_ATT_BS11_TRX_AREA, 0x01, 0x00, -}; - -/* - * Patch the various SYSTEM INFORMATION tables to update - * the LAI - */ -static void patch_nm_tables(struct gsm_bts *bts) -{ - uint8_t arfcn_low = bts->c0->arfcn & 0xff; - uint8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f; - - /* T3105 attribute in units of 10ms */ - bs11_attr_bts[2] = bts->network->T3105 / 10; - - /* patch ARFCN into BTS Attributes */ - bs11_attr_bts[69] &= 0xf0; - bs11_attr_bts[69] |= arfcn_high; - bs11_attr_bts[70] = arfcn_low; - - /* patch ARFCN into TRX Attributes */ - bs11_attr_radio[2] &= 0xf0; - bs11_attr_radio[2] |= arfcn_high; - bs11_attr_radio[3] = arfcn_low; - - /* patch the RACH attributes */ - if (bts->rach_b_thresh != -1) - bs11_attr_bts[33] = bts->rach_b_thresh & 0xff; - - if (bts->rach_ldavg_slots != -1) { - uint8_t avg_high = bts->rach_ldavg_slots & 0xff; - uint8_t avg_low = (bts->rach_ldavg_slots >> 8) & 0x0f; - - bs11_attr_bts[35] = avg_high; - bs11_attr_bts[36] = avg_low; - } - - /* patch BSIC */ - bs11_attr_bts[1] = bts->bsic; - - /* patch the power reduction */ - bs11_attr_radio[5] = bts->c0->max_power_red / 2; -} - - -static void nm_reconfig_ts(struct gsm_bts_trx_ts *ts) -{ - enum abis_nm_chan_comb ccomb = abis_nm_chcomb4pchan(ts->pchan); - struct gsm_e1_subslot *e1l = &ts->e1_link; - - abis_nm_set_channel_attr(ts, ccomb); - - if (is_ipaccess_bts(ts->trx->bts)) - return; - - if (ts_is_tch(ts)) - abis_nm_conn_terr_traf(ts, e1l->e1_nr, e1l->e1_ts, - e1l->e1_ts_ss); -} - -static void nm_reconfig_trx(struct gsm_bts_trx *trx) -{ - struct gsm_e1_subslot *e1l = &trx->rsl_e1_link; - int i; - - patch_nm_tables(trx->bts); - - switch (trx->bts->type) { - case GSM_BTS_TYPE_BS11: - /* FIXME: discover this by fetching an attribute */ -#if 0 - trx->nominal_power = 15; /* 15dBm == 30mW PA configuration */ -#else - trx->nominal_power = 24; /* 24dBm == 250mW PA configuration */ -#endif - abis_nm_conn_terr_sign(trx, e1l->e1_nr, e1l->e1_ts, - e1l->e1_ts_ss); - abis_nm_establish_tei(trx->bts, trx->nr, e1l->e1_nr, - e1l->e1_ts, e1l->e1_ts_ss, trx->rsl_tei); - - /* Set Radio Attributes */ - if (trx == trx->bts->c0) - abis_nm_set_radio_attr(trx, bs11_attr_radio, - sizeof(bs11_attr_radio)); - else { - uint8_t trx1_attr_radio[sizeof(bs11_attr_radio)]; - uint8_t arfcn_low = trx->arfcn & 0xff; - uint8_t arfcn_high = (trx->arfcn >> 8) & 0x0f; - memcpy(trx1_attr_radio, bs11_attr_radio, - sizeof(trx1_attr_radio)); - - /* patch ARFCN into TRX Attributes */ - trx1_attr_radio[2] &= 0xf0; - trx1_attr_radio[2] |= arfcn_high; - trx1_attr_radio[3] = arfcn_low; - - abis_nm_set_radio_attr(trx, trx1_attr_radio, - sizeof(trx1_attr_radio)); - } - break; - case GSM_BTS_TYPE_NANOBTS: - switch (trx->bts->band) { - case GSM_BAND_850: - case GSM_BAND_900: - trx->nominal_power = 20; - break; - case GSM_BAND_1800: - case GSM_BAND_1900: - trx->nominal_power = 23; - break; - default: - LOGP(DNM, LOGL_ERROR, "Unsupported nanoBTS GSM band %s\n", - gsm_band_name(trx->bts->band)); - break; - } - break; - default: - break; - } - - for (i = 0; i < TRX_NR_TS; i++) - nm_reconfig_ts(&trx->ts[i]); -} - -static void nm_reconfig_bts(struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - - switch (bts->type) { - case GSM_BTS_TYPE_BS11: - patch_nm_tables(bts); - abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/ - abis_nm_set_bts_attr(bts, bs11_attr_bts, sizeof(bs11_attr_bts)); - abis_nm_raw_msg(bts, sizeof(msg_3), msg_3); /* set BTS handover attr */ - abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */ - break; - default: - break; - } - - llist_for_each_entry(trx, &bts->trx_list, list) - nm_reconfig_trx(trx); -} - - -static void bootstrap_om_bs11(struct gsm_bts *bts) -{ - LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr); - - /* stop sending event reports */ - abis_nm_event_reports(bts, 0); - - /* begin DB transmission */ - abis_nm_bs11_db_transmission(bts, 1); - - /* end DB transmission */ - abis_nm_bs11_db_transmission(bts, 0); - - /* Reset BTS Site manager resource */ - abis_nm_bs11_reset_resource(bts); - - /* begin DB transmission */ - abis_nm_bs11_db_transmission(bts, 1); - - /* reconfigure BTS with all TRX and all TS */ - nm_reconfig_bts(bts); - - /* end DB transmission */ - abis_nm_bs11_db_transmission(bts, 0); - - /* Reset BTS Site manager resource */ - abis_nm_bs11_reset_resource(bts); - - /* restart sending event reports */ - abis_nm_event_reports(bts, 1); -} - -static int shutdown_om(struct gsm_bts *bts) -{ - /* stop sending event reports */ - abis_nm_event_reports(bts, 0); - - /* begin DB transmission */ - abis_nm_bs11_db_transmission(bts, 1); - - /* end DB transmission */ - abis_nm_bs11_db_transmission(bts, 0); - - /* Reset BTS Site manager resource */ - abis_nm_bs11_reset_resource(bts); - - return 0; -} - -/* Callback function to be called every time we receive a signal from INPUT */ -static int gbl_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_bts *bts; - - if (subsys != SS_L_GLOBAL) - return 0; - - switch (signal) { - case S_GLOBAL_BTS_CLOSE_OM: - bts = signal_data; - if (bts->type == GSM_BTS_TYPE_BS11) - shutdown_om(signal_data); - break; - } - - return 0; -} - -/* Callback function to be called every time we receive a signal from INPUT */ -static int inp_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct input_signal_data *isd = signal_data; - - if (subsys != SS_L_INPUT) - return 0; - - switch (signal) { - case S_L_INP_TEI_UP: - switch (isd->link_type) { - case E1INP_SIGN_OML: - if (isd->trx->bts->type == GSM_BTS_TYPE_BS11) - bootstrap_om_bs11(isd->trx->bts); - break; - } - } - - return 0; -} - -static int bts_model_bs11_start(struct gsm_network *net) -{ - model_bs11.features.data = &model_bs11._features_data[0]; - model_bs11.features.data_len = sizeof(model_bs11._features_data); - - gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HOPPING); - gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HSCSD); - gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_MULTI_TSC); - - osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL); - osmo_signal_register_handler(SS_L_GLOBAL, gbl_sig_cb, NULL); - - return 0; -} - -int bts_model_bs11_init(void) -{ - return gsm_bts_model_register(&model_bs11); -} diff --git a/src/libbsc/bts_sysmobts.c b/src/libbsc/bts_sysmobts.c deleted file mode 100644 index e4b6cdc78..000000000 --- a/src/libbsc/bts_sysmobts.c +++ /dev/null @@ -1,60 +0,0 @@ -/* sysmocom sysmoBTS specific code */ - -/* (C) 2010-2012 by Harald Welte - * - * 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 . - * - */ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct gsm_bts_model bts_model_nanobts; - -static struct gsm_bts_model model_sysmobts; - -int bts_model_sysmobts_init(void) -{ - model_sysmobts = bts_model_nanobts; - model_sysmobts.name = "sysmobts"; - model_sysmobts.type = GSM_BTS_TYPE_OSMOBTS; - - model_sysmobts.features.data = &model_sysmobts._features_data[0]; - model_sysmobts.features.data_len = - sizeof(model_sysmobts._features_data); - memset(model_sysmobts.features.data, 0, sizeof(model_sysmobts.features.data_len)); - - gsm_btsmodel_set_feature(&model_sysmobts, BTS_FEAT_GPRS); - gsm_btsmodel_set_feature(&model_sysmobts, BTS_FEAT_EGPRS); - - return gsm_bts_model_register(&model_sysmobts); -} diff --git a/src/libbsc/bts_unknown.c b/src/libbsc/bts_unknown.c deleted file mode 100644 index f1135294f..000000000 --- a/src/libbsc/bts_unknown.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Generic BTS - VTY code tries to allocate this BTS before type is known */ - -/* (C) 2010 by Daniel Willmann - * - * 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 . - * - */ - - -#include -#include -#include - -static struct gsm_bts_model model_unknown = { - .type = GSM_BTS_TYPE_UNKNOWN, - .name = "unknown", - .oml_rcvmsg = &abis_nm_rcvmsg, - .nm_att_tlvdef = { - .def = { - }, - }, -}; - -int bts_model_unknown_init(void) -{ - return gsm_bts_model_register(&model_unknown); -} diff --git a/src/libbsc/chan_alloc.c b/src/libbsc/chan_alloc.c deleted file mode 100644 index 33b79a0b2..000000000 --- a/src/libbsc/chan_alloc.c +++ /dev/null @@ -1,543 +0,0 @@ -/* GSM Channel allocation routines - * - * (C) 2008 by Harald Welte - * (C) 2008, 2009 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 . - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -static int ts_is_usable(struct gsm_bts_trx_ts *ts) -{ - /* FIXME: How does this behave for BS-11 ? */ - if (is_ipaccess_bts(ts->trx->bts)) { - if (!nm_is_running(&ts->mo.nm_state)) - return 0; - } - - /* If a TCH/F_PDCH TS is busy changing, it is already taken or not - * yet available. */ - if (ts->pchan == GSM_PCHAN_TCH_F_PDCH) { - if (ts->flags & TS_F_PDCH_PENDING_MASK) - return 0; - } - - /* If a dynamic channel is busy changing, it is already taken or not - * yet available. */ - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - if (ts->dyn.pchan_is != ts->dyn.pchan_want) - return 0; - } - - return 1; -} - -int trx_is_usable(struct gsm_bts_trx *trx) -{ - /* FIXME: How does this behave for BS-11 ? */ - if (is_ipaccess_bts(trx->bts)) { - if (!nm_is_running(&trx->mo.nm_state) || - !nm_is_running(&trx->bb_transc.mo.nm_state)) - return 0; - } - - return 1; -} - -static struct gsm_lchan * -_lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan, - enum gsm_phys_chan_config dyn_as_pchan) -{ - struct gsm_bts_trx_ts *ts; - int j, start, stop, dir, ss; - int check_subslots; - - if (!trx_is_usable(trx)) - return NULL; - - if (trx->bts->chan_alloc_reverse) { - /* check TS 7..0 */ - start = 7; - stop = -1; - dir = -1; - } else { - /* check TS 0..7 */ - start = 0; - stop = 8; - dir = 1; - } - - for (j = start; j != stop; j += dir) { - ts = &trx->ts[j]; - if (!ts_is_usable(ts)) - continue; - if (ts->pchan != pchan) - continue; - - /* - * Allocation for fully dynamic timeslots - * (does not apply for ip.access style GSM_PCHAN_TCH_F_PDCH) - * - * Note the special nature of a dynamic timeslot in PDCH mode: - * in PDCH mode, typically, lchan->type is GSM_LCHAN_NONE and - * lchan->state is LCHAN_S_NONE -- an otherwise unused slot - * becomes PDCH implicitly. In the same sense, this channel - * allocator will never be asked to find an available PDCH - * slot; only TCH/F or TCH/H will be requested, and PDCH mode - * means that it is available for switchover. - * - * A dynamic timeslot in PDCH mode may be switched to TCH/F or - * TCH/H. If a dyn TS is already in TCH/F or TCH/H mode, it - * means that it is in use and its mode can't be switched. - * - * The logic concerning channels for TCH/F is trivial: there is - * only one channel, so a dynamic TS in TCH/F mode is already - * taken and not available for allocation. For TCH/H, we need - * to check whether a dynamic timeslot is already in TCH/H mode - * and whether one of the two channels is still available. - */ - switch (pchan) { - case GSM_PCHAN_TCH_F_TCH_H_PDCH: - if (ts->dyn.pchan_is != ts->dyn.pchan_want) { - /* The TS's mode is being switched. Not - * available anymore/yet. */ - DEBUGP(DRLL, "%s already in switchover\n", - gsm_ts_and_pchan_name(ts)); - continue; - } - if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) { - /* This slot is available. Still check for - * error states to be sure; in all cases the - * first lchan will be used. */ - if (ts->lchan->state != LCHAN_S_NONE - && ts->lchan->state != LCHAN_S_ACTIVE) - continue; - return ts->lchan; - } - if (ts->dyn.pchan_is != dyn_as_pchan) - /* not applicable. */ - continue; - /* The requested type matches the dynamic timeslot's - * current mode. A channel may still be available - * (think TCH/H). */ - check_subslots = ts_subslots(ts); - break; - - case GSM_PCHAN_TCH_F_PDCH: - /* Available for voice when in PDCH mode */ - if (ts_pchan(ts) != GSM_PCHAN_PDCH) - continue; - /* Subslots of a PDCH ts don't need to be checked. */ - return ts->lchan; - - default: - /* Not a dynamic channel, there is only one pchan kind: */ - check_subslots = ts_subslots(ts); - break; - } - - /* Is a sub-slot still available? */ - for (ss = 0; ss < check_subslots; ss++) { - struct gsm_lchan *lc = &ts->lchan[ss]; - if (lc->type == GSM_LCHAN_NONE && - lc->state == LCHAN_S_NONE) - return lc; - } - } - - return NULL; -} - -static struct gsm_lchan * -_lc_dyn_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan, - enum gsm_phys_chan_config dyn_as_pchan) -{ - struct gsm_bts_trx *trx; - struct gsm_lchan *lc; - - if (bts->chan_alloc_reverse) { - llist_for_each_entry_reverse(trx, &bts->trx_list, list) { - lc = _lc_find_trx(trx, pchan, dyn_as_pchan); - if (lc) - return lc; - } - } else { - llist_for_each_entry(trx, &bts->trx_list, list) { - lc = _lc_find_trx(trx, pchan, dyn_as_pchan); - if (lc) - return lc; - } - } - - return NULL; -} - -static struct gsm_lchan * -_lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan) -{ - return _lc_dyn_find_bts(bts, pchan, GSM_PCHAN_NONE); -} - -/* Allocate a logical channel. - * - * Dynamic channel types: we always prefer a dedicated TS, and only pick + - * switch a dynamic TS if no pure TS of the requested PCHAN is available. - * - * TCH_F/PDCH: if we pick a PDCH ACT style dynamic TS as TCH/F channel, PDCH - * will be disabled in rsl_chan_activate_lchan(); there is no need to check - * whether PDCH mode is currently active, here. - */ -struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type, - int allow_bigger) -{ - struct gsm_lchan *lchan = NULL; - enum gsm_phys_chan_config first, first_cbch, second, second_cbch; - - switch (type) { - case GSM_LCHAN_SDCCH: - if (bts->chan_alloc_reverse) { - first = GSM_PCHAN_SDCCH8_SACCH8C; - first_cbch = GSM_PCHAN_SDCCH8_SACCH8C_CBCH; - second = GSM_PCHAN_CCCH_SDCCH4; - second_cbch = GSM_PCHAN_CCCH_SDCCH4_CBCH; - } else { - first = GSM_PCHAN_CCCH_SDCCH4; - first_cbch = GSM_PCHAN_CCCH_SDCCH4_CBCH; - second = GSM_PCHAN_SDCCH8_SACCH8C; - second_cbch = GSM_PCHAN_SDCCH8_SACCH8C_CBCH; - } - - lchan = _lc_find_bts(bts, first); - if (lchan == NULL) - lchan = _lc_find_bts(bts, first_cbch); - if (lchan == NULL) - lchan = _lc_find_bts(bts, second); - if (lchan == NULL) - lchan = _lc_find_bts(bts, second_cbch); - - /* allow to assign bigger channels */ - if (allow_bigger) { - if (lchan == NULL) { - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H); - if (lchan) - type = GSM_LCHAN_TCH_H; - } - - if (lchan == NULL) { - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); - if (lchan) - type = GSM_LCHAN_TCH_F; - } - - /* try dynamic TCH/F_PDCH */ - if (lchan == NULL) { - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F_PDCH); - /* TCH/F_PDCH will be used as TCH/F */ - if (lchan) - type = GSM_LCHAN_TCH_F; - } - - /* try fully dynamic TCH/F_TCH/H_PDCH */ - if (lchan == NULL) { - lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_TCH_H_PDCH, - GSM_PCHAN_TCH_H); - if (lchan) - type = GSM_LCHAN_TCH_H; - } - /* - * No need to check fully dynamic channels for TCH/F: - * if no TCH/H was available, neither will be TCH/F. - */ - } - break; - case GSM_LCHAN_TCH_F: - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); - /* If we don't have TCH/F available, fall-back to TCH/H */ - if (!lchan) { - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H); - if (lchan) - type = GSM_LCHAN_TCH_H; - } - /* If we don't have TCH/H either, try dynamic TCH/F_PDCH */ - if (!lchan) { - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F_PDCH); - /* TCH/F_PDCH used as TCH/F -- here, type is already - * set to GSM_LCHAN_TCH_F, but for clarity's sake... */ - if (lchan) - type = GSM_LCHAN_TCH_F; - } - - /* Try fully dynamic TCH/F_TCH/H_PDCH as TCH/F... */ - if (!lchan && bts->network->dyn_ts_allow_tch_f) { - lchan = _lc_dyn_find_bts(bts, - GSM_PCHAN_TCH_F_TCH_H_PDCH, - GSM_PCHAN_TCH_F); - if (lchan) - type = GSM_LCHAN_TCH_F; - } - /* ...and as TCH/H. */ - if (!lchan) { - lchan = _lc_dyn_find_bts(bts, - GSM_PCHAN_TCH_F_TCH_H_PDCH, - GSM_PCHAN_TCH_H); - if (lchan) - type = GSM_LCHAN_TCH_H; - } - break; - case GSM_LCHAN_TCH_H: - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H); - /* If we don't have TCH/H available, fall-back to TCH/F */ - if (!lchan) { - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F); - if (lchan) - type = GSM_LCHAN_TCH_F; - } - /* No dedicated TCH/x available -- try fully dynamic - * TCH/F_TCH/H_PDCH */ - if (!lchan) { - lchan = _lc_dyn_find_bts(bts, - GSM_PCHAN_TCH_F_TCH_H_PDCH, - GSM_PCHAN_TCH_H); - if (lchan) - type = GSM_LCHAN_TCH_H; - } - /* - * No need to check TCH/F_TCH/H_PDCH channels for TCH/F: - * if no TCH/H was available, neither will be TCH/F. - */ - /* If we don't have TCH/F either, try dynamic TCH/F_PDCH */ - if (!lchan) { - lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F_PDCH); - if (lchan) - type = GSM_LCHAN_TCH_F; - } - break; - default: - LOGP(DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type); - } - - if (lchan) { - lchan->type = type; - - LOGP(DRLL, LOGL_INFO, "%s Allocating lchan=%u as %s\n", - gsm_ts_and_pchan_name(lchan->ts), - lchan->nr, gsm_lchant_name(lchan->type)); - - /* clear sapis */ - memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis)); - - /* clear multi rate config */ - memset(&lchan->mr_ms_lv, 0, sizeof(lchan->mr_ms_lv)); - memset(&lchan->mr_bts_lv, 0, sizeof(lchan->mr_bts_lv)); - lchan->broken_reason = ""; - } else { - struct challoc_signal_data sig; - - LOGP(DRLL, LOGL_ERROR, "Failed to allocate %s channel\n", - gsm_lchant_name(type)); - - sig.bts = bts; - sig.type = type; - osmo_signal_dispatch(SS_CHALLOC, S_CHALLOC_ALLOC_FAIL, &sig); - } - - return lchan; -} - -/* Free a logical channel */ -void lchan_free(struct gsm_lchan *lchan) -{ - struct challoc_signal_data sig; - int i; - - sig.type = lchan->type; - lchan->type = GSM_LCHAN_NONE; - - - if (lchan->conn) { - struct lchan_signal_data sig; - - /* We might kill an active channel... */ - sig.lchan = lchan; - sig.mr = NULL; - osmo_signal_dispatch(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, &sig); - } - - if (lchan->abis_ip.rtp_socket) { - LOGP(DRLL, LOGL_ERROR, "%s RTP Proxy Socket remained open.\n", - gsm_lchan_name(lchan)); - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - - /* stop the timer */ - osmo_timer_del(&lchan->T3101); - - /* clear cached measuement reports */ - lchan->meas_rep_idx = 0; - for (i = 0; i < ARRAY_SIZE(lchan->meas_rep); i++) { - lchan->meas_rep[i].flags = 0; - lchan->meas_rep[i].nr = 0; - } - for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) - lchan->neigh_meas[i].arfcn = 0; - - if (lchan->rqd_ref) { - talloc_free(lchan->rqd_ref); - lchan->rqd_ref = NULL; - lchan->rqd_ta = 0; - } - - sig.lchan = lchan; - sig.bts = lchan->ts->trx->bts; - osmo_signal_dispatch(SS_CHALLOC, S_CHALLOC_FREED, &sig); - - if (lchan->conn) { - LOGP(DRLL, LOGL_ERROR, "the subscriber connection should be gone.\n"); - lchan->conn = NULL; - } - - /* FIXME: ts_free() the timeslot, if we're the last logical - * channel using it */ -} - -/* - * There was an error with the TRX and we need to forget - * any state so that a lchan can be allocated again after - * the trx is fully usable. - * - * This should be called after lchan_free to force a channel - * be available for allocation again. This means that this - * method will stop the "delay after error"-timer and set the - * state to LCHAN_S_NONE. - */ -void lchan_reset(struct gsm_lchan *lchan) -{ - osmo_timer_del(&lchan->T3101); - osmo_timer_del(&lchan->T3109); - osmo_timer_del(&lchan->T3111); - osmo_timer_del(&lchan->error_timer); - - lchan->type = GSM_LCHAN_NONE; - lchan->state = LCHAN_S_NONE; - - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } -} - -/* Drive the release process of the lchan */ -static void _lchan_handle_release(struct gsm_lchan *lchan, - int sacch_deact, int mode) -{ - /* Release all SAPIs on the local end and continue */ - rsl_release_sapis_from(lchan, 1, RSL_REL_LOCAL_END); - - /* - * Shall we send a RR Release, start T3109 and wait for the - * release indication from the BTS or just take it down (e.g. - * on assignment requests) - */ - if (sacch_deact) { - gsm48_send_rr_release(lchan); - - /* Deactivate the SACCH on the BTS side */ - rsl_deact_sacch(lchan); - rsl_start_t3109(lchan); - } else if (lchan->sapis[0] == LCHAN_SAPI_UNUSED) { - rsl_direct_rf_release(lchan); - } else { - rsl_release_request(lchan, 0, mode); - } -} - -/* Consider releasing the channel now */ -int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode mode) -{ - DEBUGP(DRLL, "%s starting release sequence\n", gsm_lchan_name(lchan)); - rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); - - lchan->conn = NULL; - _lchan_handle_release(lchan, sacch_deact, mode); - return 1; -} - -void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - - llist_for_each_entry(trx, &bts->trx_list, list) { - int i; - - /* skip administratively deactivated tranxsceivers */ - if (!nm_is_running(&trx->mo.nm_state) || - !nm_is_running(&trx->bb_transc.mo.nm_state)) - continue; - - for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { - struct gsm_bts_trx_ts *ts = &trx->ts[i]; - struct load_counter *pl = &cl->pchan[ts->pchan]; - int j; - int subslots; - - /* skip administratively deactivated timeslots */ - if (!nm_is_running(&ts->mo.nm_state)) - continue; - - subslots = ts_subslots(ts); - for (j = 0; j < subslots; j++) { - struct gsm_lchan *lchan = &ts->lchan[j]; - - pl->total++; - - switch (lchan->state) { - case LCHAN_S_NONE: - break; - default: - pl->used++; - break; - } - } - } - } -} - -void network_chan_load(struct pchan_load *pl, struct gsm_network *net) -{ - struct gsm_bts *bts; - - memset(pl, 0, sizeof(*pl)); - - llist_for_each_entry(bts, &net->bts_list, list) - bts_chan_load(pl, bts); -} - diff --git a/src/libbsc/e1_config.c b/src/libbsc/e1_config.c deleted file mode 100644 index d57dec57e..000000000 --- a/src/libbsc/e1_config.c +++ /dev/null @@ -1,297 +0,0 @@ -/* OpenBSC E1 Input code */ - -/* (C) 2008-2010 by Harald Welte - * 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 . - * - */ - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SAPI_L2ML 0 -#define SAPI_OML 62 -#define SAPI_RSL 0 /* 63 ? */ - -/* The e1_reconfig_*() functions below take the configuration present in the - * bts/trx/ts data structures and ensure the E1 configuration reflects the - * timeslot/subslot/TEI configuration */ - -int e1_reconfig_ts(struct gsm_bts_trx_ts *ts) -{ - struct gsm_e1_subslot *e1_link = &ts->e1_link; - struct e1inp_line *line; - struct e1inp_ts *e1_ts; - - DEBUGP(DLMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr); - - if (!e1_link->e1_ts) { - LOGP(DLINP, LOGL_ERROR, "TS (%u/%u/%u) without E1 timeslot?\n", - ts->nr, ts->trx->nr, ts->trx->bts->nr); - return 0; - } - - line = e1inp_line_find(e1_link->e1_nr); - if (!line) { - LOGP(DLINP, LOGL_ERROR, "TS (%u/%u/%u) referring to " - "non-existing E1 line %u\n", ts->nr, ts->trx->nr, - ts->trx->bts->nr, e1_link->e1_nr); - return -ENOMEM; - } - - if (ts_is_tch(ts)) { - e1_ts = &line->ts[e1_link->e1_ts-1]; - e1inp_ts_config_trau(e1_ts, line, subch_cb); - subch_demux_activate(&e1_ts->trau.demux, e1_link->e1_ts_ss); - } - - return 0; -} - -int e1_reconfig_trx(struct gsm_bts_trx *trx) -{ - struct gsm_e1_subslot *e1_link = &trx->rsl_e1_link; - struct e1inp_ts *sign_ts; - struct e1inp_line *line; - struct e1inp_sign_link *rsl_link; - int i; - - if (!e1_link->e1_ts) { - LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link without " - "timeslot?\n", trx->bts->nr, trx->nr); - return -EINVAL; - } - - /* RSL Link */ - line = e1inp_line_find(e1_link->e1_nr); - if (!line) { - LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link referring " - "to non-existing E1 line %u\n", trx->bts->nr, - trx->nr, e1_link->e1_nr); - return -ENOMEM; - } - sign_ts = &line->ts[e1_link->e1_ts-1]; - e1inp_ts_config_sign(sign_ts, line); - /* Ericsson RBS have a per-TRX OML link in parallel to RSL */ - if (trx->bts->type == GSM_BTS_TYPE_RBS2000) { - struct e1inp_sign_link *oml_link; - oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, trx, - trx->rsl_tei, SAPI_OML); - if (!oml_link) { - LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) OML link creation " - "failed\n", trx->bts->nr, trx->nr); - return -ENOMEM; - } - if (trx->oml_link) - e1inp_sign_link_destroy(trx->oml_link); - trx->oml_link = oml_link; - } - rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, - trx, trx->rsl_tei, SAPI_RSL); - if (!rsl_link) { - LOGP(DLINP, LOGL_ERROR, "TRX (%u/%u) RSL link creation " - "failed\n", trx->bts->nr, trx->nr); - return -ENOMEM; - } - if (trx->rsl_link) - e1inp_sign_link_destroy(trx->rsl_link); - trx->rsl_link = rsl_link; - - for (i = 0; i < TRX_NR_TS; i++) - e1_reconfig_ts(&trx->ts[i]); - - return 0; -} - -/* this is the generic callback for all ISDN-based BTS. */ -static int bts_isdn_sign_link(struct msgb *msg) -{ - int ret = -EINVAL; - struct e1inp_sign_link *link = msg->dst; - struct gsm_bts *bts; - - switch (link->type) { - case E1INP_SIGN_OML: - bts = link->trx->bts; - ret = bts->model->oml_rcvmsg(msg); - break; - case E1INP_SIGN_RSL: - ret = abis_rsl_rcvmsg(msg); - break; - default: - LOGP(DLMI, LOGL_ERROR, "unknown link type %u\n", link->type); - break; - } - return ret; -} - -struct e1inp_line_ops bts_isdn_e1inp_line_ops = { - .sign_link = bts_isdn_sign_link, -}; - -int e1_reconfig_bts(struct gsm_bts *bts) -{ - struct gsm_e1_subslot *e1_link = &bts->oml_e1_link; - struct e1inp_ts *sign_ts; - struct e1inp_line *line; - struct e1inp_sign_link *oml_link; - struct gsm_bts_trx *trx; - - DEBUGP(DLMI, "e1_reconfig_bts(%u)\n", bts->nr); - - line = e1inp_line_find(e1_link->e1_nr); - if (!line) { - LOGP(DLINP, LOGL_ERROR, "BTS %u OML link referring to " - "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr); - return -ENOMEM; - } - - if (!bts->model->e1line_bind_ops) { - LOGP(DLINP, LOGL_ERROR, "no callback to bind E1 line operations\n"); - return -EINVAL; - } - if (!line->ops) - bts->model->e1line_bind_ops(line); - - /* skip signal link initialization, this is done later for these BTS. */ - if (bts->type == GSM_BTS_TYPE_NANOBTS || - bts->type == GSM_BTS_TYPE_OSMOBTS) - return e1inp_line_update(line); - - /* OML link */ - if (!e1_link->e1_ts) { - LOGP(DLINP, LOGL_ERROR, "BTS %u OML link without timeslot?\n", - bts->nr); - return -EINVAL; - } - - sign_ts = &line->ts[e1_link->e1_ts-1]; - e1inp_ts_config_sign(sign_ts, line); - oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, - bts->c0, bts->oml_tei, SAPI_OML); - if (!oml_link) { - LOGP(DLINP, LOGL_ERROR, "BTS %u OML link creation failed\n", - bts->nr); - return -ENOMEM; - } - if (bts->oml_link) - e1inp_sign_link_destroy(bts->oml_link); - bts->oml_link = oml_link; - - llist_for_each_entry(trx, &bts->trx_list, list) - e1_reconfig_trx(trx); - - /* notify E1 input something has changed */ - return e1inp_line_update(line); -} - -#if 0 -/* do some compiled-in configuration for our BTS/E1 setup */ -int e1_config(struct gsm_bts *bts, int cardnr, int release_l2) -{ - struct e1inp_line *line; - struct e1inp_ts *sign_ts; - struct e1inp_sign_link *oml_link, *rsl_link; - struct gsm_bts_trx *trx = bts->c0; - int base_ts; - - switch (bts->nr) { - case 0: - /* First BTS uses E1 TS 01,02,03,04,05 */ - base_ts = HARDCODED_BTS0_TS - 1; - break; - case 1: - /* Second BTS uses E1 TS 06,07,08,09,10 */ - base_ts = HARDCODED_BTS1_TS - 1; - break; - case 2: - /* Third BTS uses E1 TS 11,12,13,14,15 */ - base_ts = HARDCODED_BTS2_TS - 1; - default: - return -EINVAL; - } - - line = talloc_zero(tall_bsc_ctx, struct e1inp_line); - if (!line) - return -ENOMEM; - - /* create E1 timeslots for signalling and TRAU frames */ - e1inp_ts_config(&line->ts[base_ts+1-1], line, E1INP_TS_TYPE_SIGN); - e1inp_ts_config(&line->ts[base_ts+2-1], line, E1INP_TS_TYPE_TRAU); - e1inp_ts_config(&line->ts[base_ts+3-1], line, E1INP_TS_TYPE_TRAU); - - /* create signalling links for TS1 */ - sign_ts = &line->ts[base_ts+1-1]; - oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, - trx, TEI_OML, SAPI_OML); - rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, - trx, TEI_RSL, SAPI_RSL); - - /* create back-links from bts/trx */ - bts->oml_link = oml_link; - trx->rsl_link = rsl_link; - - /* enable subchannel demuxer on TS2 */ - subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 1); - subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 2); - subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 3); - - /* enable subchannel demuxer on TS3 */ - subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 0); - subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 1); - subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 2); - subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 3); - - trx = gsm_bts_trx_num(bts, 1); - if (trx) { - /* create E1 timeslots for TRAU frames of TRX1 */ - e1inp_ts_config(&line->ts[base_ts+4-1], line, E1INP_TS_TYPE_TRAU); - e1inp_ts_config(&line->ts[base_ts+5-1], line, E1INP_TS_TYPE_TRAU); - - /* create RSL signalling link for TRX1 */ - sign_ts = &line->ts[base_ts+1-1]; - rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, - trx, TEI_RSL+1, SAPI_RSL); - /* create back-links from trx */ - trx->rsl_link = rsl_link; - - /* enable subchannel demuxer on TS2 */ - subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 0); - subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 1); - subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 2); - subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 3); - - /* enable subchannel demuxer on TS3 */ - subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 0); - subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 1); - subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 2); - subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 3); - } - - return mi_setup(cardnr, line, release_l2); -} -#endif diff --git a/src/libbsc/gsm_04_08_utils.c b/src/libbsc/gsm_04_08_utils.c deleted file mode 100644 index 7c5e0e97a..000000000 --- a/src/libbsc/gsm_04_08_utils.c +++ /dev/null @@ -1,632 +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 - * utility functions - */ - -/* (C) 2008-2009 by Harald Welte - * (C) 2008, 2009 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 . - * - */ -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* should ip.access BTS use direct RTP streams between each other (1), - * or should OpenBSC always act as RTP relay/proxy in between (0) ? */ -int ipacc_rtp_direct = 1; - -static int gsm48_sendmsg(struct msgb *msg) -{ - if (msg->lchan) - msg->dst = msg->lchan->ts->trx->rsl_link; - - msg->l3h = msg->data; - return rsl_data_request(msg, 0); -} - -/* Section 9.1.8 / Table 9.9 */ -struct chreq { - uint8_t val; - uint8_t mask; - enum chreq_type type; -}; - -/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */ -static const struct chreq chreq_type_neci1[] = { - { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, - { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F }, - { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H }, - { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL }, - { 0xe0, 0xe0, CHREQ_T_TCH_F }, - { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H }, - { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, - { 0x00, 0xf0, CHREQ_T_LOCATION_UPD }, - { 0x10, 0xf0, CHREQ_T_SDCCH }, - { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI1 }, - { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, - { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, - { 0x67, 0xff, CHREQ_T_LMU }, - { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH }, - { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH }, - { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH }, - { 0x70, 0xf8, CHREQ_T_PDCH_TWO_PHASE }, - { 0x78, 0xfc, CHREQ_T_PDCH_ONE_PHASE }, - { 0x78, 0xfa, CHREQ_T_PDCH_ONE_PHASE }, - { 0x78, 0xf9, CHREQ_T_PDCH_ONE_PHASE }, - { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE }, -}; - -/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */ -static const struct chreq chreq_type_neci0[] = { - { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, - { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H }, - { 0xe0, 0xe0, CHREQ_T_TCH_F }, - { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, - { 0x00, 0xe0, CHREQ_T_LOCATION_UPD }, - { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI0 }, - { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, - { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, - { 0x67, 0xff, CHREQ_T_LMU }, - { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH }, - { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH }, - { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH }, - { 0x70, 0xf8, CHREQ_T_PDCH_TWO_PHASE }, - { 0x78, 0xfc, CHREQ_T_PDCH_ONE_PHASE }, - { 0x78, 0xfa, CHREQ_T_PDCH_ONE_PHASE }, - { 0x78, 0xf9, CHREQ_T_PDCH_ONE_PHASE }, - { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE }, -}; - -static const enum gsm_chan_t ctype_by_chreq[] = { - [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F, - [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F, - [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H, - [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H, - [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH, - [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F, - [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H, - [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H, - [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH, - [CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_SDCCH, - [CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH, - [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F, - [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F, - [CHREQ_T_LMU] = GSM_LCHAN_SDCCH, - [CHREQ_T_RESERVED_SDCCH] = GSM_LCHAN_SDCCH, - [CHREQ_T_PDCH_ONE_PHASE] = GSM_LCHAN_PDTCH, - [CHREQ_T_PDCH_TWO_PHASE] = GSM_LCHAN_PDTCH, - [CHREQ_T_RESERVED_IGNORE] = GSM_LCHAN_UNKNOWN, -}; - -static const enum gsm_chreq_reason_t reason_by_chreq[] = { - [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG, - [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL, - [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL, - [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL, - [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_CALL, - [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD, - [CHREQ_T_PAG_R_ANY_NECI1] = GSM_CHREQ_REASON_PAG, - [CHREQ_T_PAG_R_ANY_NECI0] = GSM_CHREQ_REASON_PAG, - [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG, - [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG, - [CHREQ_T_LMU] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_PDCH_ONE_PHASE] = GSM_CHREQ_REASON_PDCH, - [CHREQ_T_PDCH_TWO_PHASE] = GSM_CHREQ_REASON_PDCH, - [CHREQ_T_RESERVED_SDCCH] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_RESERVED_IGNORE] = GSM_CHREQ_REASON_OTHER, -}; - -/* verify that the two tables match */ -osmo_static_assert(sizeof(ctype_by_chreq) == - sizeof(((struct gsm_network *) NULL)->ctype_by_chreq), assert_size); - -/* - * Update channel types for request based on policy. E.g. in the - * case of a TCH/H network/bsc use TCH/H for the emergency calls, - * for early assignment assign a SDCCH and some other options. - */ -void gsm_net_update_ctype(struct gsm_network *network) -{ - /* copy over the data */ - memcpy(network->ctype_by_chreq, ctype_by_chreq, sizeof(ctype_by_chreq)); - - /* - * Use TCH/H for emergency calls when this cell allows TCH/H. Maybe it - * is better to iterate over the BTS/TRX and check if no TCH/F is available - * and then set it to TCH/H. - */ - if (network->neci) - network->ctype_by_chreq[CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_H; - - if (network->pag_any_tch) { - if (network->neci) { - network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_TCH_H; - network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_TCH_H; - } else { - network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_TCH_F; - network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_TCH_F; - } - } -} - -enum gsm_chan_t get_ctype_by_chreq(struct gsm_network *network, uint8_t ra) -{ - int i; - int length; - const struct chreq *chreq; - - if (network->neci) { - chreq = chreq_type_neci1; - length = ARRAY_SIZE(chreq_type_neci1); - } else { - chreq = chreq_type_neci0; - length = ARRAY_SIZE(chreq_type_neci0); - } - - - for (i = 0; i < length; i++) { - const struct chreq *chr = &chreq[i]; - if ((ra & chr->mask) == chr->val) - return network->ctype_by_chreq[chr->type]; - } - LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra); - return GSM_LCHAN_SDCCH; -} - -int get_reason_by_chreq(uint8_t ra, int neci) -{ - int i; - int length; - const struct chreq *chreq; - - if (neci) { - chreq = chreq_type_neci1; - length = ARRAY_SIZE(chreq_type_neci1); - } else { - chreq = chreq_type_neci0; - length = ARRAY_SIZE(chreq_type_neci0); - } - - for (i = 0; i < length; i++) { - const struct chreq *chr = &chreq[i]; - if ((ra & chr->mask) == chr->val) - return reason_by_chreq[chr->type]; - } - LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra); - return GSM_CHREQ_REASON_OTHER; -} - -static void mr_config_for_ms(struct gsm_lchan *lchan, struct msgb *msg) -{ - if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) - msgb_tlv_put(msg, GSM48_IE_MUL_RATE_CFG, lchan->mr_ms_lv[0], - lchan->mr_ms_lv + 1); -} - -/* 7.1.7 and 9.1.7: RR CHANnel RELease */ -int gsm48_send_rr_release(struct gsm_lchan *lchan) -{ - struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 RR REL"); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - uint8_t *cause; - - msg->lchan = lchan; - gh->proto_discr = GSM48_PDISC_RR; - gh->msg_type = GSM48_MT_RR_CHAN_REL; - - cause = msgb_put(msg, 1); - cause[0] = GSM48_RR_CAUSE_NORMAL; - - DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n", - lchan->nr, lchan->type); - - /* Send actual release request to MS */ - return gsm48_sendmsg(msg); -} - -int send_siemens_mrpci(struct gsm_lchan *lchan, - uint8_t *classmark2_lv) -{ - struct rsl_mrpci mrpci; - - if (classmark2_lv[0] < 2) - return -EINVAL; - - mrpci.power_class = classmark2_lv[1] & 0x7; - mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1); - mrpci.vbs_capable = classmark2_lv[2] & (1 <<2); - mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3; - - return rsl_siemens_mrpci(lchan, &mrpci); -} - -/* Chapter 9.1.9: Ciphering Mode Command */ -int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv) -{ - struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 CIPH"); - struct gsm48_hdr *gh; - uint8_t ciph_mod_set; - - msg->lchan = lchan; - - DEBUGP(DRR, "TX CIPHERING MODE CMD\n"); - - if (lchan->encr.alg_id <= RSL_ENC_ALG_A5(0)) - ciph_mod_set = 0; - else - ciph_mod_set = (lchan->encr.alg_id-2)<<1 | 1; - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); - gh->proto_discr = GSM48_PDISC_RR; - gh->msg_type = GSM48_MT_RR_CIPH_M_CMD; - gh->data[0] = (want_imeisv & 0x1) << 4 | (ciph_mod_set & 0xf); - - return rsl_encryption_cmd(msg); -} - -static void gsm48_cell_desc(struct gsm48_cell_desc *cd, - const struct gsm_bts *bts) -{ - cd->ncc = (bts->bsic >> 3 & 0x7); - cd->bcc = (bts->bsic & 0x7); - cd->arfcn_hi = bts->c0->arfcn >> 8; - cd->arfcn_lo = bts->c0->arfcn & 0xff; -} - -void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd, - const struct gsm_lchan *lchan) -{ - uint16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; - - cd->chan_nr = gsm_lchan2chan_nr(lchan); - if (!lchan->ts->hopping.enabled) { - cd->h0.tsc = gsm_ts_tsc(lchan->ts); - cd->h0.h = 0; - cd->h0.arfcn_high = arfcn >> 8; - cd->h0.arfcn_low = arfcn & 0xff; - } else { - cd->h1.tsc = gsm_ts_tsc(lchan->ts); - cd->h1.h = 1; - cd->h1.maio_high = lchan->ts->hopping.maio >> 2; - cd->h1.maio_low = lchan->ts->hopping.maio & 0x03; - cd->h1.hsn = lchan->ts->hopping.hsn; - } -} - -/*! \brief Encode a TS 04.08 multirate config LV according to 10.5.2.21aa - * \param[out] lv caller-allocated buffer of 7 bytes. First octet is IS length - * \param[in] mr multi-rate configuration to encode - * \param[in] modes array describing the AMR modes - * \returns 0 on success */ -int gsm48_multirate_config(uint8_t *lv, const struct amr_multirate_conf *mr, const struct amr_mode *modes) -{ - int num = 0, i; - - for (i = 0; i < 8; i++) { - if (((mr->gsm48_ie[1] >> i) & 1)) - num++; - } - if (num > 4) { - LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec with too " - "many modes in config.\n"); - num = 4; - } - if (num < 1) { - LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec with no " - "mode in config.\n"); - num = 1; - } - - lv[0] = (num == 1) ? 2 : (num + 2); - memcpy(lv + 1, mr->gsm48_ie, 2); - if (num == 1) - return 0; - - lv[3] = modes[0].threshold & 0x3f; - lv[4] = modes[0].hysteresis << 4; - if (num == 2) - return 0; - lv[4] |= (modes[1].threshold & 0x3f) >> 2; - lv[5] = modes[1].threshold << 6; - lv[5] |= (modes[1].hysteresis & 0x0f) << 2; - if (num == 3) - return 0; - lv[5] |= (modes[2].threshold & 0x3f) >> 4; - lv[6] = modes[2].threshold << 4; - lv[6] |= modes[2].hysteresis & 0x0f; - - return 0; -} - -#define GSM48_HOCMD_CCHDESC_LEN 16 - -/* Chapter 9.1.15: Handover Command */ -int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, - uint8_t power_command, uint8_t ho_ref) -{ - struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 HO CMD"); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - struct gsm48_ho_cmd *ho = - (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho)); - - msg->lchan = old_lchan; - gh->proto_discr = GSM48_PDISC_RR; - gh->msg_type = GSM48_MT_RR_HANDO_CMD; - - /* mandatory bits */ - gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts); - gsm48_lchan2chan_desc(&ho->chan_desc, new_lchan); - ho->ho_ref = ho_ref; - ho->power_command = power_command; - - if (new_lchan->ts->hopping.enabled) { - struct gsm_bts *bts = new_lchan->ts->trx->bts; - struct gsm48_system_information_type_1 *si1; - uint8_t *cur; - - si1 = GSM_BTS_SI(bts, SYSINFO_TYPE_1); - /* Copy the Cell Chan Desc (ARFCNS in this cell) */ - msgb_put_u8(msg, GSM48_IE_CELL_CH_DESC); - cur = msgb_put(msg, GSM48_HOCMD_CCHDESC_LEN); - memcpy(cur, si1->cell_channel_description, - GSM48_HOCMD_CCHDESC_LEN); - /* Copy the Mobile Allocation */ - msgb_tlv_put(msg, GSM48_IE_MA_BEFORE, - new_lchan->ts->hopping.ma_len, - new_lchan->ts->hopping.ma_data); - } - /* FIXME: optional bits for type of synchronization? */ - - return gsm48_sendmsg(msg); -} - -/* Chapter 9.1.2: Assignment Command */ -int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, uint8_t power_command) -{ - struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ASS CMD"); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - struct gsm48_ass_cmd *ass = - (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass)); - - DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode); - - msg->lchan = dest_lchan; - gh->proto_discr = GSM48_PDISC_RR; - gh->msg_type = GSM48_MT_RR_ASS_CMD; - - /* - * fill the channel information element, this code - * should probably be shared with rsl_rx_chan_rqd(), - * gsm48_lchan_modify(). But beware that 10.5.2.5 - * 10.5.2.5.a have slightly different semantic for - * the chan_desc. But as long as multi-slot configurations - * are not used we seem to be fine. - */ - gsm48_lchan2chan_desc(&ass->chan_desc, lchan); - ass->power_command = power_command; - - /* optional: cell channel description */ - - msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode); - - /* mobile allocation in case of hopping */ - if (lchan->ts->hopping.enabled) { - msgb_tlv_put(msg, GSM48_IE_MA_BEFORE, lchan->ts->hopping.ma_len, - lchan->ts->hopping.ma_data); - } - - /* in case of multi rate we need to attach a config */ - mr_config_for_ms(lchan, msg); - - return gsm48_sendmsg(msg); -} - -/* 9.1.5 Channel mode modify: Modify the mode on the MS side */ -int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode) -{ - struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 CHN MOD"); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - struct gsm48_chan_mode_modify *cmm = - (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm)); - - DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode); - - lchan->tch_mode = mode; - msg->lchan = lchan; - gh->proto_discr = GSM48_PDISC_RR; - gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF; - - /* fill the channel information element, this code - * should probably be shared with rsl_rx_chan_rqd() */ - gsm48_lchan2chan_desc(&cmm->chan_desc, lchan); - cmm->mode = mode; - - /* in case of multi rate we need to attach a config */ - mr_config_for_ms(lchan, msg); - - return gsm48_sendmsg(msg); -} - -int gsm48_rx_rr_modif_ack(struct msgb *msg) -{ - int rc; - struct gsm48_hdr *gh = msgb_l3(msg); - struct gsm48_chan_mode_modify *mod = - (struct gsm48_chan_mode_modify *) gh->data; - - DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n"); - - if (mod->mode != msg->lchan->tch_mode) { - LOGP(DRR, LOGL_ERROR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n", - msg->lchan->tch_mode, mod->mode); - return -1; - } - - /* update the channel type */ - switch (mod->mode) { - case GSM48_CMODE_SIGN: - msg->lchan->rsl_cmode = RSL_CMOD_SPD_SIGN; - break; - case GSM48_CMODE_SPEECH_V1: - case GSM48_CMODE_SPEECH_EFR: - case GSM48_CMODE_SPEECH_AMR: - msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH; - break; - case GSM48_CMODE_DATA_14k5: - case GSM48_CMODE_DATA_12k0: - case GSM48_CMODE_DATA_6k0: - case GSM48_CMODE_DATA_3k6: - msg->lchan->rsl_cmode = RSL_CMOD_SPD_DATA; - break; - } - - /* We've successfully modified the MS side of the channel, - * now go on to modify the BTS side of the channel */ - rc = rsl_chan_mode_modify_req(msg->lchan); - - /* FIXME: we not only need to do this after mode modify, but - * also after channel activation */ - if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && mod->mode != GSM48_CMODE_SIGN) - rsl_ipacc_crcx(msg->lchan); - return rc; -} - -int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - uint8_t *data = gh->data; - struct gsm_bts *bts = msg->lchan->ts->trx->bts; - struct bitvec *nbv = &bts->si_common.neigh_list; - struct gsm_meas_rep_cell *mrc; - - if (gh->msg_type != GSM48_MT_RR_MEAS_REP) - return -EINVAL; - - if (data[0] & 0x80) - rep->flags |= MEAS_REP_F_BA1; - if (data[0] & 0x40) - rep->flags |= MEAS_REP_F_UL_DTX; - if ((data[1] & 0x40) == 0x00) - rep->flags |= MEAS_REP_F_DL_VALID; - - rep->dl.full.rx_lev = data[0] & 0x3f; - rep->dl.sub.rx_lev = data[1] & 0x3f; - rep->dl.full.rx_qual = (data[2] >> 4) & 0x7; - rep->dl.sub.rx_qual = (data[2] >> 1) & 0x7; - - rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2); - if (rep->num_cell < 1 || rep->num_cell > 6) - return 0; - - /* an encoding nightmare in perfection */ - mrc = &rep->cell[0]; - mrc->rxlev = data[3] & 0x3f; - mrc->neigh_idx = data[4] >> 3; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); - mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5); - if (rep->num_cell < 2) - return 0; - - mrc = &rep->cell[1]; - mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7); - mrc->neigh_idx = (data[6] >> 2) & 0x1f; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); - mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4); - if (rep->num_cell < 3) - return 0; - - mrc = &rep->cell[2]; - mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6); - mrc->neigh_idx = (data[8] >> 1) & 0x1f; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); - mrc->bsic = ((data[8] & 0x01) << 5) | (data[9] >> 3); - if (rep->num_cell < 4) - return 0; - - mrc = &rep->cell[3]; - mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5); - mrc->neigh_idx = data[10] & 0x1f; - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); - mrc->bsic = data[11] >> 2; - if (rep->num_cell < 5) - return 0; - - mrc = &rep->cell[4]; - mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4); - mrc->neigh_idx = ((data[12] & 0xf) << 1) | (data[13] >> 7); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); - mrc->bsic = (data[13] >> 1) & 0x3f; - if (rep->num_cell < 6) - return 0; - - mrc = &rep->cell[5]; - mrc->rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3); - mrc->neigh_idx = ((data[14] & 0x07) << 2) | (data[15] >> 6); - mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1); - mrc->bsic = data[15] & 0x3f; - - return 0; -} - -/* 9.2.5 CM service accept */ -int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn) -{ - struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACK"); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - - msg->lchan = conn->lchan; - - gh->proto_discr = GSM48_PDISC_MM; - gh->msg_type = GSM48_MT_MM_CM_SERV_ACC; - - DEBUGP(DMM, "-> CM SERVICE ACK\n"); - - return gsm0808_submit_dtap(conn, msg, 0, 0); -} - -/* 9.2.6 CM service reject */ -int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, - enum gsm48_reject_value value) -{ - struct msgb *msg; - - msg = gsm48_create_mm_serv_rej(value); - if (!msg) { - LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n"); - return -1; - } - - DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value); - - return gsm0808_submit_dtap(conn, msg, 0, 0); -} diff --git a/src/libbsc/gsm_04_80_utils.c b/src/libbsc/gsm_04_80_utils.c deleted file mode 100644 index e0db81edf..000000000 --- a/src/libbsc/gsm_04_80_utils.c +++ /dev/null @@ -1,40 +0,0 @@ -/* OpenBSC utility functions for 3GPP TS 04.80 */ - -/* (C) 2016 by sysmocom s.m.f.c. GmbH - * - * 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 . - * - */ - -#include -#include - -int bsc_send_ussd_notify(struct gsm_subscriber_connection *conn, int level, - const char *text) -{ - struct msgb *msg = gsm0480_create_ussd_notify(level, text); - if (!msg) - return -1; - return gsm0808_submit_dtap(conn, msg, 0, 0); -} - -int bsc_send_ussd_release_complete(struct gsm_subscriber_connection *conn) -{ - struct msgb *msg = gsm0480_create_ussd_release_complete(); - if (!msg) - return -1; - return gsm0808_submit_dtap(conn, msg, 0, 0); -} diff --git a/src/libbsc/handover_decision.c b/src/libbsc/handover_decision.c deleted file mode 100644 index 8d7e047b7..000000000 --- a/src/libbsc/handover_decision.c +++ /dev/null @@ -1,325 +0,0 @@ -/* Handover Decision making for Inter-BTS (Intra-BSC) Handover. This - * only implements the handover algorithm/decision, but not execution - * of it */ - -/* (C) 2009 by Harald Welte - * - * 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 . - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Get reference to a neighbor cell on a given BCCH ARFCN */ -static struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, - uint16_t arfcn, uint8_t bsic) -{ - struct gsm_bts *neigh; - /* FIXME: use some better heuristics here to determine which cell - * using this ARFCN really is closest to the target cell. For - * now we simply assume that each ARFCN will only be used by one - * cell */ - - llist_for_each_entry(neigh, &bts->network->bts_list, list) { - /* FIXME: this is probably returning the same bts again!? */ - if (neigh->c0->arfcn == arfcn && - neigh->bsic == bsic) - return neigh; - } - - return NULL; -} - - -/* issue handover to a cell identified by ARFCN and BSIC */ -static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, - uint16_t arfcn, uint8_t bsic) -{ - struct gsm_bts *new_bts; - - /* resolve the gsm_bts structure for the best neighbor */ - new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic); - if (!new_bts) { - LOGP(DHO, LOGL_NOTICE, "unable to determine neighbor BTS " - "for ARFCN %u BSIC %u ?!?\n", arfcn, bsic); - return -EINVAL; - } - - /* and actually try to handover to that cell */ - return bsc_handover_start(lchan, new_bts); -} - -/* did we get a RXLEV for a given cell in the given report? */ -static int rxlev_for_cell_in_rep(struct gsm_meas_rep *mr, - uint16_t arfcn, uint8_t bsic) -{ - int i; - - for (i = 0; i < mr->num_cell; i++) { - struct gsm_meas_rep_cell *mrc = &mr->cell[i]; - - /* search for matching report */ - if (!(mrc->arfcn == arfcn && mrc->bsic == bsic)) - continue; - - mrc->flags |= MRC_F_PROCESSED; - return mrc->rxlev; - } - return -ENODEV; -} - -/* obtain averaged rxlev for given neighbor */ -static int neigh_meas_avg(struct neigh_meas_proc *nmp, int window) -{ - unsigned int i, idx; - int avg = 0; - - idx = calc_initial_idx(ARRAY_SIZE(nmp->rxlev), - nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev), - window); - - for (i = 0; i < window; i++) { - int j = (idx+i) % ARRAY_SIZE(nmp->rxlev); - - avg += nmp->rxlev[j]; - } - - return avg / window; -} - -/* find empty or evict bad neighbor */ -static struct neigh_meas_proc *find_evict_neigh(struct gsm_lchan *lchan) -{ - int j, worst = 999999; - struct neigh_meas_proc *nmp_worst = NULL; - - /* first try to find an empty/unused slot */ - for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) { - struct neigh_meas_proc *nmp = &lchan->neigh_meas[j]; - if (!nmp->arfcn) - return nmp; - } - - /* no empty slot found. evict worst neighbor from list */ - for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) { - struct neigh_meas_proc *nmp = &lchan->neigh_meas[j]; - int avg = neigh_meas_avg(nmp, MAX_WIN_NEIGH_AVG); - if (!nmp_worst || avg < worst) { - worst = avg; - nmp_worst = nmp; - } - } - - return nmp_worst; -} - -/* process neighbor cell measurement reports */ -static void process_meas_neigh(struct gsm_meas_rep *mr) -{ - int i, j, idx; - - /* for each reported cell, try to update global state */ - for (j = 0; j < ARRAY_SIZE(mr->lchan->neigh_meas); j++) { - struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[j]; - unsigned int idx; - int rxlev; - - /* skip unused entries */ - if (!nmp->arfcn) - continue; - - rxlev = rxlev_for_cell_in_rep(mr, nmp->arfcn, nmp->bsic); - idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev); - if (rxlev >= 0) { - nmp->rxlev[idx] = rxlev; - nmp->last_seen_nr = mr->nr; - } else - nmp->rxlev[idx] = 0; - nmp->rxlev_cnt++; - } - - /* iterate over list of reported cells, check if we did not - * process all of them */ - for (i = 0; i < mr->num_cell; i++) { - struct gsm_meas_rep_cell *mrc = &mr->cell[i]; - struct neigh_meas_proc *nmp; - - if (mrc->flags & MRC_F_PROCESSED) - continue; - - nmp = find_evict_neigh(mr->lchan); - - nmp->arfcn = mrc->arfcn; - nmp->bsic = mrc->bsic; - - idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev); - nmp->rxlev[idx] = mrc->rxlev; - nmp->rxlev_cnt++; - nmp->last_seen_nr = mr->nr; - - mrc->flags |= MRC_F_PROCESSED; - } -} - -/* attempt to do a handover */ -static int attempt_handover(struct gsm_meas_rep *mr) -{ - struct gsm_network *net = mr->lchan->ts->trx->bts->network; - struct neigh_meas_proc *best_cell = NULL; - unsigned int best_better_db = 0; - int i, rc; - - /* find the best cell in this report that is at least RXLEV_HYST - * better than the current serving cell */ - - for (i = 0; i < ARRAY_SIZE(mr->lchan->neigh_meas); i++) { - struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[i]; - int avg, better; - - /* skip empty slots */ - if (nmp->arfcn == 0) - continue; - - /* caculate average rxlev for this cell over the window */ - avg = neigh_meas_avg(nmp, net->handover.win_rxlev_avg_neigh); - - /* check if hysteresis is fulfilled */ - if (avg < mr->dl.full.rx_lev + net->handover.pwr_hysteresis) - continue; - - better = avg - mr->dl.full.rx_lev; - if (better > best_better_db) { - best_cell = nmp; - best_better_db = better; - } - } - - if (!best_cell) - return 0; - - LOGP(DHO, LOGL_INFO, "%s: Cell on ARFCN %u is better: ", - gsm_ts_name(mr->lchan->ts), best_cell->arfcn); - if (!net->handover.active) { - LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n"); - return 0; - } - - rc = handover_to_arfcn_bsic(mr->lchan, best_cell->arfcn, best_cell->bsic); - switch (rc) { - case 0: - LOGPC(DHO, LOGL_INFO, "Starting handover\n"); - break; - case -ENOSPC: - LOGPC(DHO, LOGL_INFO, "No channel available\n"); - break; - case -EBUSY: - LOGPC(DHO, LOGL_INFO, "Handover already active\n"); - break; - default: - LOGPC(DHO, LOGL_ERROR, "Unknown error\n"); - } - return rc; -} - -/* process an already parsed measurement report and decide if we want to - * attempt a handover */ -static int process_meas_rep(struct gsm_meas_rep *mr) -{ - struct gsm_network *net = mr->lchan->ts->trx->bts->network; - enum meas_rep_field dlev, dqual; - int av_rxlev; - - /* we currently only do handover for TCH channels */ - switch (mr->lchan->type) { - case GSM_LCHAN_TCH_F: - case GSM_LCHAN_TCH_H: - break; - default: - return 0; - } - - if (mr->flags & MEAS_REP_F_DL_DTX) { - dlev = MEAS_REP_DL_RXLEV_SUB; - dqual = MEAS_REP_DL_RXQUAL_SUB; - } else { - dlev = MEAS_REP_DL_RXLEV_FULL; - dqual = MEAS_REP_DL_RXQUAL_FULL; - } - - /* parse actual neighbor cell info */ - if (mr->num_cell > 0 && mr->num_cell < 7) - process_meas_neigh(mr); - - av_rxlev = get_meas_rep_avg(mr->lchan, dlev, - net->handover.win_rxlev_avg); - - /* Interference HO */ - if (rxlev2dbm(av_rxlev) > -85 && - meas_rep_n_out_of_m_be(mr->lchan, dqual, 3, 4, 5)) - return attempt_handover(mr); - - /* Bad Quality */ - if (meas_rep_n_out_of_m_be(mr->lchan, dqual, 3, 4, 5)) - return attempt_handover(mr); - - /* Low Level */ - if (rxlev2dbm(av_rxlev) <= -110) - return attempt_handover(mr); - - /* Distance */ - if (mr->ms_l1.ta > net->handover.max_distance) - return attempt_handover(mr); - - /* Power Budget AKA Better Cell */ - if ((mr->nr % net->handover.pwr_interval) == 0) - return attempt_handover(mr); - - return 0; - -} - -static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct lchan_signal_data *lchan_data; - - if (subsys != SS_LCHAN) - return 0; - - lchan_data = signal_data; - switch (signal) { - case S_LCHAN_MEAS_REP: - process_meas_rep(lchan_data->mr); - break; - } - - return 0; -} - -void on_dso_load_ho_dec(void) -{ - osmo_signal_register_handler(SS_LCHAN, ho_dec_sig_cb, NULL); -} diff --git a/src/libbsc/handover_logic.c b/src/libbsc/handover_logic.c deleted file mode 100644 index 14566cfa1..000000000 --- a/src/libbsc/handover_logic.c +++ /dev/null @@ -1,381 +0,0 @@ -/* Handover Logic for Inter-BTS (Intra-BSC) Handover. This does not - * actually implement the handover algorithm/decision, but executes a - * handover decision */ - -/* (C) 2009 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct bsc_handover { - struct llist_head list; - - struct gsm_lchan *old_lchan; - struct gsm_lchan *new_lchan; - - struct osmo_timer_list T3103; - - uint8_t ho_ref; -}; - -static LLIST_HEAD(bsc_handovers); - -static void handover_free(struct bsc_handover *ho) -{ - osmo_timer_del(&ho->T3103); - llist_del(&ho->list); - talloc_free(ho); -} - -static struct bsc_handover *bsc_ho_by_new_lchan(struct gsm_lchan *new_lchan) -{ - struct bsc_handover *ho; - - llist_for_each_entry(ho, &bsc_handovers, list) { - if (ho->new_lchan == new_lchan) - return ho; - } - - return NULL; -} - -static struct bsc_handover *bsc_ho_by_old_lchan(struct gsm_lchan *old_lchan) -{ - struct bsc_handover *ho; - - llist_for_each_entry(ho, &bsc_handovers, list) { - if (ho->old_lchan == old_lchan) - return ho; - } - - return NULL; -} - -/*! \brief Hand over the specified logical channel to the specified new BTS. - * This is the main entry point for the actual handover algorithm, after the - * decision whether to initiate HO to a specific BTS. */ -int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) -{ - struct gsm_lchan *new_lchan; - struct bsc_handover *ho; - static uint8_t ho_ref; - int rc; - - /* don't attempt multiple handovers for the same lchan at - * the same time */ - if (bsc_ho_by_old_lchan(old_lchan)) - return -EBUSY; - - DEBUGP(DHO, "Beginning with handover operation" - "(old_lchan on BTS %u, new BTS %u) ...\n", - old_lchan->ts->trx->bts->nr, bts->nr); - - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED]); - - if (!old_lchan->conn) { - LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n"); - return -ENOSPC; - } - - new_lchan = lchan_alloc(bts, old_lchan->type, 0); - if (!new_lchan) { - LOGP(DHO, LOGL_NOTICE, "No free channel\n"); - rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL]); - return -ENOSPC; - } - - ho = talloc_zero(tall_bsc_ctx, struct bsc_handover); - if (!ho) { - LOGP(DHO, LOGL_FATAL, "Out of Memory\n"); - lchan_free(new_lchan); - return -ENOMEM; - } - ho->old_lchan = old_lchan; - ho->new_lchan = new_lchan; - ho->ho_ref = ho_ref++; - - /* copy some parameters from old lchan */ - memcpy(&new_lchan->encr, &old_lchan->encr, sizeof(new_lchan->encr)); - new_lchan->ms_power = old_lchan->ms_power; - new_lchan->bs_power = old_lchan->bs_power; - new_lchan->rsl_cmode = old_lchan->rsl_cmode; - new_lchan->tch_mode = old_lchan->tch_mode; - memcpy(&new_lchan->mr_ms_lv, &old_lchan->mr_ms_lv, ARRAY_SIZE(new_lchan->mr_ms_lv)); - memcpy(&new_lchan->mr_bts_lv, &old_lchan->mr_bts_lv, ARRAY_SIZE(new_lchan->mr_bts_lv)); - - new_lchan->conn = old_lchan->conn; - new_lchan->conn->ho_lchan = new_lchan; - - /* FIXME: do we have a better idea of the timing advance? */ - rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, ho->ho_ref); - if (rc < 0) { - LOGP(DHO, LOGL_ERROR, "could not activate channel\n"); - new_lchan->conn->ho_lchan = NULL; - new_lchan->conn = NULL; - talloc_free(ho); - lchan_free(new_lchan); - return rc; - } - - rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ); - llist_add(&ho->list, &bsc_handovers); - /* we continue in the SS_LCHAN handler / ho_chan_activ_ack */ - - return 0; -} - -void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan) -{ - struct bsc_handover *ho; - - ho = bsc_ho_by_new_lchan(conn->ho_lchan); - - - if (!ho && conn->ho_lchan) - LOGP(DHO, LOGL_ERROR, "BUG: We lost some state.\n"); - - if (!ho) { - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); - return; - } - - conn->ho_lchan->conn = NULL; - conn->ho_lchan = NULL; - - if (free_lchan) - lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); - - handover_free(ho); -} - -/* T3103 expired: Handover has failed without HO COMPLETE or HO FAIL */ -static void ho_T3103_cb(void *_ho) -{ - struct bsc_handover *ho = _ho; - struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; - - DEBUGP(DHO, "HO T3103 expired\n"); - rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT]); - - ho->new_lchan->conn->ho_lchan = NULL; - ho->new_lchan->conn = NULL; - lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); - handover_free(ho); -} - -/* RSL has acknowledged activation of the new lchan */ -static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) -{ - struct bsc_handover *ho; - - /* we need to check if this channel activation is related to - * a handover at all (and if, which particular handover) */ - ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) - return -ENODEV; - - DEBUGP(DHO, "handover activate ack, send HO Command\n"); - - /* we can now send the 04.08 HANDOVER COMMAND to the MS - * using the old lchan */ - - gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0, ho->ho_ref); - - /* start T3103. We can continue either with T3103 expiration, - * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ - osmo_timer_setup(&ho->T3103, ho_T3103_cb, ho); - osmo_timer_schedule(&ho->T3103, 10, 0); - - /* create a RTP connection */ - if (is_ipaccess_bts(new_lchan->ts->trx->bts)) - rsl_ipacc_crcx(new_lchan); - - return 0; -} - -/* RSL has not acknowledged activation of the new lchan */ -static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) -{ - struct bsc_handover *ho; - - ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) { - LOGP(DHO, LOGL_INFO, "ACT NACK: unable to find HO record\n"); - return -ENODEV; - } - - new_lchan->conn->ho_lchan = NULL; - new_lchan->conn = NULL; - handover_free(ho); - - /* FIXME: maybe we should try to allocate a new LCHAN here? */ - - return 0; -} - -/* GSM 04.08 HANDOVER COMPLETE has been received on new channel */ -static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) -{ - struct gsm_network *net; - struct bsc_handover *ho; - - ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) { - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); - return -ENODEV; - } - - net = new_lchan->ts->trx->bts->network; - LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN " - "%u->%u\n", vlr_subscr_name(ho->old_lchan->conn->vsub), - ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, - ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); - - rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED]); - - osmo_timer_del(&ho->T3103); - - /* switch TRAU muxer for E1 based BTS from one channel to another */ - if (is_e1_bts(new_lchan->conn->bts)) - switch_trau_mux(ho->old_lchan, new_lchan); - - /* Replace the ho lchan with the primary one */ - if (ho->old_lchan != new_lchan->conn->lchan) - LOGP(DHO, LOGL_ERROR, "Primary lchan changed during handover.\n"); - - if (new_lchan != new_lchan->conn->ho_lchan) - LOGP(DHO, LOGL_ERROR, "Handover channel changed during this handover.\n"); - - new_lchan->conn->ho_lchan = NULL; - new_lchan->conn->lchan = new_lchan; - new_lchan->conn->bts = new_lchan->ts->trx->bts; - ho->old_lchan->conn = NULL; - - lchan_release(ho->old_lchan, 0, RSL_REL_LOCAL_END); - - handover_free(ho); - return 0; -} - -/* GSM 04.08 HANDOVER FAIL has been received */ -static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) -{ - struct gsm_network *net = old_lchan->ts->trx->bts->network; - struct bsc_handover *ho; - struct gsm_lchan *new_lchan; - - ho = bsc_ho_by_old_lchan(old_lchan); - if (!ho) { - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); - return -ENODEV; - } - - rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED]); - - new_lchan = ho->new_lchan; - - /* release the channel and forget about it */ - ho->new_lchan->conn->ho_lchan = NULL; - ho->new_lchan->conn = NULL; - handover_free(ho); - - lchan_release(new_lchan, 0, RSL_REL_LOCAL_END); - - - return 0; -} - -/* GSM 08.58 HANDOVER DETECT has been received */ -static int ho_rsl_detect(struct gsm_lchan *new_lchan) -{ - struct bsc_handover *ho; - - ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) { - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n"); - return -ENODEV; - } - - /* FIXME: do we actually want to do something here ? */ - - return 0; -} - -static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct lchan_signal_data *lchan_data; - struct gsm_lchan *lchan; - - lchan_data = signal_data; - switch (subsys) { - case SS_LCHAN: - lchan = lchan_data->lchan; - switch (signal) { - case S_LCHAN_ACTIVATE_ACK: - return ho_chan_activ_ack(lchan); - case S_LCHAN_ACTIVATE_NACK: - return ho_chan_activ_nack(lchan); - case S_LCHAN_HANDOVER_DETECT: - return ho_rsl_detect(lchan); - case S_LCHAN_HANDOVER_COMPL: - return ho_gsm48_ho_compl(lchan); - case S_LCHAN_HANDOVER_FAIL: - return ho_gsm48_ho_fail(lchan); - } - break; - default: - break; - } - - return 0; -} - -struct gsm_lchan *bsc_handover_pending(struct gsm_lchan *new_lchan) -{ - struct bsc_handover *ho; - ho = bsc_ho_by_new_lchan(new_lchan); - if (!ho) - return NULL; - return ho->old_lchan; -} - -static __attribute__((constructor)) void on_dso_load_ho_logic(void) -{ - osmo_signal_register_handler(SS_LCHAN, ho_logic_sig_cb, NULL); -} diff --git a/src/libbsc/meas_proc.c b/src/libbsc/meas_proc.c deleted file mode 100644 index 5b97e74ee..000000000 --- a/src/libbsc/meas_proc.c +++ /dev/null @@ -1,84 +0,0 @@ -/* Measurement Processing */ - -/* (C) 2009 by Harald Welte - * - * 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 . - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -/* process an already parsed measurement report */ -static int process_meas_rep(struct gsm_meas_rep *mr) -{ - struct gsm_meas_rep_cell *mr_cell = NULL; - unsigned int best_better_db; - int i; - - /* FIXME: implement actual averaging over multiple measurement - * reports */ - - /* find the best cell in this report that is at least RXLEV_HYST - * better than the current serving cell */ - for (i = 0; i < mr->num_cell; i++) { - unsigned int better; - if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST) - continue; - - better = mr->cell[i].rxlev - mr->dl.full.rx_lev; - if (better > best_better_db) { - mr_cell = &mr->cell[i]; - best_better_db = better; - } - } - - if (mr_cell) - return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn, - mr_cell->bsic); - return 0; -} - -static int meas_proc_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_lchan *lchan; - struct gsm_meas_rep *mr; - - if (subsys != SS_LCHAN) - return 0; - - switch (signal) { - case S_LCHAN_MEAS_REP: - mr = signal_data; - process_meas_rep(mr); - break; - } - - return 0; -} - -static __attribute__((constructor)) void on_dso_load_meas(void) -{ - osmo_signal_register_handler(SS_LCHAN, meas_proc_sig_cb, NULL); -} diff --git a/src/libbsc/meas_rep.c b/src/libbsc/meas_rep.c deleted file mode 100644 index 808103d28..000000000 --- a/src/libbsc/meas_rep.c +++ /dev/null @@ -1,115 +0,0 @@ -/* Measurement Report Processing */ - -/* (C) 2009 by Harald Welte - * - * 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 . - * - */ - - -#include -#include - -static int get_field(const struct gsm_meas_rep *rep, - enum meas_rep_field field) -{ - switch (field) { - case MEAS_REP_DL_RXLEV_FULL: - return rep->dl.full.rx_lev; - case MEAS_REP_DL_RXLEV_SUB: - return rep->dl.sub.rx_lev; - case MEAS_REP_DL_RXQUAL_FULL: - return rep->dl.full.rx_qual; - case MEAS_REP_DL_RXQUAL_SUB: - return rep->dl.sub.rx_qual; - case MEAS_REP_UL_RXLEV_FULL: - return rep->ul.full.rx_lev; - case MEAS_REP_UL_RXLEV_SUB: - return rep->ul.sub.rx_lev; - case MEAS_REP_UL_RXQUAL_FULL: - return rep->ul.full.rx_qual; - case MEAS_REP_UL_RXQUAL_SUB: - return rep->ul.sub.rx_qual; - } - - return 0; -} - - -unsigned int calc_initial_idx(unsigned int array_size, - unsigned int meas_rep_idx, - unsigned int num_values) -{ - int offs, idx; - - /* from which element do we need to start if we're interested - * in an average of 'num' elements */ - offs = meas_rep_idx - num_values; - - if (offs < 0) - idx = array_size + offs; - else - idx = offs; - - return idx; -} - -/* obtain an average over the last 'num' fields in the meas reps */ -int get_meas_rep_avg(const struct gsm_lchan *lchan, - enum meas_rep_field field, unsigned int num) -{ - unsigned int i, idx; - int avg = 0; - - if (num < 1) - return 0; - - idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), - lchan->meas_rep_idx, num); - - for (i = 0; i < num; i++) { - int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep); - - avg += get_field(&lchan->meas_rep[j], field); - } - - return avg / num; -} - -/* Check if N out of M last values for FIELD are >= bd */ -int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan, - enum meas_rep_field field, - unsigned int n, unsigned int m, int be) -{ - unsigned int i, idx; - int count = 0; - - idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), - lchan->meas_rep_idx, m); - - for (i = 0; i < m; i++) { - int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep); - int val = get_field(&lchan->meas_rep[j], field); - - if (val >= be) - count++; - - if (count >= n) - return 1; - } - - return 0; -} diff --git a/src/libbsc/net_init.c b/src/libbsc/net_init.c deleted file mode 100644 index 9d5431964..000000000 --- a/src/libbsc/net_init.c +++ /dev/null @@ -1,80 +0,0 @@ -/* (C) 2008-2010 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include - -struct gsm_network *bsc_network_init(void *ctx, - uint16_t country_code, - uint16_t network_code, - mncc_recv_cb_t mncc_recv) -{ - struct gsm_network *net; - - net = gsm_network_init(ctx, country_code, network_code, mncc_recv); - - net->bsc_data = talloc_zero(net, struct osmo_bsc_data); - if (!net->bsc_data) { - talloc_free(net); - return NULL; - } - - /* Init back pointer */ - net->bsc_data->auto_off_timeout = -1; - net->bsc_data->network = net; - INIT_LLIST_HEAD(&net->bsc_data->mscs); - - net->num_bts = 0; - net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED; - net->T3101 = GSM_T3101_DEFAULT; - net->T3103 = GSM_T3103_DEFAULT; - net->T3105 = GSM_T3105_DEFAULT; - net->T3107 = GSM_T3107_DEFAULT; - net->T3109 = GSM_T3109_DEFAULT; - net->T3111 = GSM_T3111_DEFAULT; - net->T3113 = GSM_T3113_DEFAULT; - net->T3115 = GSM_T3115_DEFAULT; - net->T3117 = GSM_T3117_DEFAULT; - net->T3119 = GSM_T3119_DEFAULT; - net->T3122 = GSM_T3122_DEFAULT; - net->T3141 = GSM_T3141_DEFAULT; - - /* default set of handover parameters */ - net->handover.win_rxlev_avg = 10; - net->handover.win_rxqual_avg = 1; - net->handover.win_rxlev_avg_neigh = 10; - net->handover.pwr_interval = 6; - net->handover.pwr_hysteresis = 3; - net->handover.max_distance = 9999; - - INIT_LLIST_HEAD(&net->bts_list); - - /* init statistics */ - net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); - if (!net->bsc_ctrs) { - talloc_free(net); - return NULL; - } - - gsm_net_update_ctype(net); - - return net; -} - diff --git a/src/libbsc/paging.c b/src/libbsc/paging.c deleted file mode 100644 index e19c2d1c4..000000000 --- a/src/libbsc/paging.c +++ /dev/null @@ -1,456 +0,0 @@ -/* Paging helper and manager.... */ -/* (C) 2009,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 . - * - */ - -/* - * Relevant specs: - * 12.21: - * - 9.4.12 for CCCH Local Threshold - * - * 05.58: - * - 8.5.2 CCCH Load indication - * - 9.3.15 Paging Load - * - * Approach: - * - Send paging command to subscriber - * - On Channel Request we will remember the reason - * - After the ACK we will request the identity - * - Then we will send assign the gsm_subscriber and - * - and call a callback - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void *tall_paging_ctx; - -#define PAGING_TIMER 0, 500000 - -/* - * TODO MSCSPLIT: the paging in libbsc is closely tied to MSC land in that the - * MSC realm callback functions used to be invoked from the BSC/BTS level. So - * this entire file needs to be rewired for use with an A interface. - */ - -/* - * Kill one paging request update the internal list... - */ -static void paging_remove_request(struct gsm_bts_paging_state *paging_bts, - struct gsm_paging_request *to_be_deleted) -{ - osmo_timer_del(&to_be_deleted->T3113); - llist_del(&to_be_deleted->entry); - bsc_subscr_put(to_be_deleted->bsub); - talloc_free(to_be_deleted); -} - -static void page_ms(struct gsm_paging_request *request) -{ - uint8_t mi[128]; - unsigned int mi_len; - unsigned int page_group; - struct gsm_bts *bts = request->bts; - - /* the bts is down.. we will just wait for the paging to expire */ - if (!bts->oml_link) - return; - - log_set_context(LOG_CTX_BSC_SUBSCR, request->bsub); - - LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: %s tmsi: " - "0x%08x for ch. type %d (attempt %d)\n", request->bsub->imsi, - request->bsub->tmsi, request->chan_type, request->attempts); - - if (request->bsub->tmsi == GSM_RESERVED_TMSI) - mi_len = gsm48_generate_mid_from_imsi(mi, request->bsub->imsi); - else - mi_len = gsm48_generate_mid_from_tmsi(mi, request->bsub->tmsi); - - page_group = gsm0502_calc_paging_group(&bts->si_common.chan_desc, - str_to_imsi(request->bsub->imsi)); - gsm0808_page(bts, page_group, mi_len, mi, request->chan_type); - log_set_context(LOG_CTX_BSC_SUBSCR, NULL); -} - -static void paging_schedule_if_needed(struct gsm_bts_paging_state *paging_bts) -{ - if (llist_empty(&paging_bts->pending_requests)) - return; - - if (!osmo_timer_pending(&paging_bts->work_timer)) - osmo_timer_schedule(&paging_bts->work_timer, PAGING_TIMER); -} - - -static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_bts); -static void paging_give_credit(void *data) -{ - struct gsm_bts_paging_state *paging_bts = data; - - LOGP(DPAG, LOGL_NOTICE, "No slots available on bts nr %d\n", paging_bts->bts->nr); - paging_bts->available_slots = 20; - paging_handle_pending_requests(paging_bts); -} - -static int can_send_pag_req(struct gsm_bts *bts, int rsl_type) -{ - struct pchan_load pl; - int count; - - memset(&pl, 0, sizeof(pl)); - bts_chan_load(&pl, bts); - - switch (rsl_type) { - case RSL_CHANNEED_TCH_F: - case RSL_CHANNEED_TCH_ForH: - goto count_tch; - break; - case RSL_CHANNEED_SDCCH: - goto count_sdcch; - break; - case RSL_CHANNEED_ANY: - default: - if (bts->network->pag_any_tch) - goto count_tch; - else - goto count_sdcch; - break; - } - - return 0; - - /* could available SDCCH */ -count_sdcch: - count = 0; - count += pl.pchan[GSM_PCHAN_SDCCH8_SACCH8C].total - - pl.pchan[GSM_PCHAN_SDCCH8_SACCH8C].used; - count += pl.pchan[GSM_PCHAN_CCCH_SDCCH4].total - - pl.pchan[GSM_PCHAN_CCCH_SDCCH4].used; - return bts->paging.free_chans_need > count; - -count_tch: - count = 0; - count += pl.pchan[GSM_PCHAN_TCH_F].total - - pl.pchan[GSM_PCHAN_TCH_F].used; - if (bts->network->neci) - count += pl.pchan[GSM_PCHAN_TCH_H].total - - pl.pchan[GSM_PCHAN_TCH_H].used; - return bts->paging.free_chans_need > count; -} - -/* - * This is kicked by the periodic PAGING LOAD Indicator - * coming from abis_rsl.c - * - * We attempt to iterate once over the list of items but - * only upto available_slots. - */ -static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_bts) -{ - struct gsm_paging_request *request = NULL; - - /* - * Determine if the pending_requests list is empty and - * return then. - */ - if (llist_empty(&paging_bts->pending_requests)) { - /* since the list is empty, no need to reschedule the timer */ - return; - } - - /* - * In case the BTS does not provide us with load indication and we - * ran out of slots, call an autofill routine. It might be that the - * BTS did not like our paging messages and then we have counted down - * to zero and we do not get any messages. - */ - if (paging_bts->available_slots == 0) { - osmo_timer_setup(&paging_bts->credit_timer, paging_give_credit, - paging_bts); - osmo_timer_schedule(&paging_bts->credit_timer, 5, 0); - return; - } - - request = llist_entry(paging_bts->pending_requests.next, - struct gsm_paging_request, entry); - - /* we need to determine the number of free channels */ - if (paging_bts->free_chans_need != -1) { - if (can_send_pag_req(request->bts, request->chan_type) != 0) - goto skip_paging; - } - - /* handle the paging request now */ - page_ms(request); - paging_bts->available_slots--; - request->attempts++; - - /* take the current and add it to the back */ - llist_del(&request->entry); - llist_add_tail(&request->entry, &paging_bts->pending_requests); - -skip_paging: - osmo_timer_schedule(&paging_bts->work_timer, PAGING_TIMER); -} - -static void paging_worker(void *data) -{ - struct gsm_bts_paging_state *paging_bts = data; - - paging_handle_pending_requests(paging_bts); -} - -static void paging_init_if_needed(struct gsm_bts *bts) -{ - if (bts->paging.bts) - return; - - bts->paging.bts = bts; - INIT_LLIST_HEAD(&bts->paging.pending_requests); - osmo_timer_setup(&bts->paging.work_timer, paging_worker, - &bts->paging); - - /* Large number, until we get a proper message */ - bts->paging.available_slots = 20; -} - -static int paging_pending_request(struct gsm_bts_paging_state *bts, - struct bsc_subscr *bsub) -{ - struct gsm_paging_request *req; - - llist_for_each_entry(req, &bts->pending_requests, entry) { - if (bsub == req->bsub) - return 1; - } - - return 0; -} - -static void paging_T3113_expired(void *data) -{ - struct gsm_paging_request *req = (struct gsm_paging_request *)data; - void *cbfn_param; - gsm_cbfn *cbfn; - int msg; - - log_set_context(LOG_CTX_BSC_SUBSCR, req->bsub); - - LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n", - req, bsc_subscr_name(req->bsub)); - - /* must be destroyed before calling cbfn, to prevent double free */ - rate_ctr_inc(&req->bts->network->bsc_ctrs->ctr[BSC_CTR_PAGING_EXPIRED]); - cbfn_param = req->cbfn_param; - cbfn = req->cbfn; - - /* did we ever manage to page the subscriber */ - msg = req->attempts > 0 ? GSM_PAGING_EXPIRED : GSM_PAGING_BUSY; - - /* destroy it now. Do not access req afterwards */ - paging_remove_request(&req->bts->paging, req); - - if (cbfn) - cbfn(GSM_HOOK_RR_PAGING, msg, NULL, NULL, - cbfn_param); - -} - -static int _paging_request(struct gsm_bts *bts, struct bsc_subscr *bsub, - int type, gsm_cbfn *cbfn, void *data) -{ - struct gsm_bts_paging_state *bts_entry = &bts->paging; - struct gsm_paging_request *req; - - if (paging_pending_request(bts_entry, bsub)) { - LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", - bsc_subscr_name(bsub)); - return -EEXIST; - } - - LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %s on bts %d.\n", - bsc_subscr_name(bsub), bts->nr); - req = talloc_zero(tall_paging_ctx, struct gsm_paging_request); - req->bsub = bsc_subscr_get(bsub); - req->bts = bts; - req->chan_type = type; - req->cbfn = cbfn; - req->cbfn_param = data; - osmo_timer_setup(&req->T3113, paging_T3113_expired, req); - osmo_timer_schedule(&req->T3113, bts->network->T3113, 0); - llist_add_tail(&req->entry, &bts_entry->pending_requests); - paging_schedule_if_needed(bts_entry); - - return 0; -} - -int paging_request_bts(struct gsm_bts *bts, struct bsc_subscr *bsub, - int type, gsm_cbfn *cbfn, void *data) -{ - int rc; - - /* skip all currently inactive TRX */ - if (!trx_is_usable(bts->c0)) - return 0; - - /* maybe it is the first time we use it */ - paging_init_if_needed(bts); - - /* Trigger paging, pass any error to the caller */ - rc = _paging_request(bts, bsub, type, cbfn, data); - if (rc < 0) - return rc; - return 1; -} - -int paging_request(struct gsm_network *network, struct bsc_subscr *bsub, - int type, gsm_cbfn *cbfn, void *data) -{ - struct gsm_bts *bts = NULL; - int num_pages = 0; - - rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_ATTEMPTED]); - - /* start paging subscriber on all BTS within Location Area */ - do { - int rc; - - bts = gsm_bts_by_lac(network, bsub->lac, bts); - if (!bts) - break; - - rc = paging_request_bts(bts, bsub, type, cbfn, data); - if (rc < 0) { - paging_request_stop(&network->bts_list, NULL, bsub, - NULL, NULL); - return rc; - } - num_pages += rc; - } while (1); - - if (num_pages == 0) - rate_ctr_inc(&network->bsc_ctrs->ctr[BSC_CTR_PAGING_DETACHED]); - - return num_pages; -} - - -/* we consciously ignore the type of the request here */ -static void _paging_request_stop(struct gsm_bts *bts, struct bsc_subscr *bsub, - struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm_bts_paging_state *bts_entry = &bts->paging; - struct gsm_paging_request *req, *req2; - - paging_init_if_needed(bts); - - llist_for_each_entry_safe(req, req2, &bts_entry->pending_requests, - entry) { - if (req->bsub == bsub) { - gsm_cbfn *cbfn = req->cbfn; - void *param = req->cbfn_param; - - /* now give up the data structure */ - paging_remove_request(&bts->paging, req); - req = NULL; - - if (conn && cbfn) { - LOGP(DPAG, LOGL_DEBUG, "Stop paging %s on bts %d, calling cbfn.\n", bsub->imsi, bts->nr); - cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED, - msg, conn, param); - } else - LOGP(DPAG, LOGL_DEBUG, "Stop paging %s on bts %d silently.\n", bsub->imsi, bts->nr); - break; - } - } -} - -/* Stop paging on all other bts' */ -void paging_request_stop(struct llist_head *bts_list, - struct gsm_bts *_bts, struct bsc_subscr *bsub, - struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm_bts *bts; - - log_set_context(LOG_CTX_BSC_SUBSCR, bsub); - - /* Stop this first and dispatch the request */ - if (_bts) - _paging_request_stop(_bts, bsub, conn, msg); - - /* Make sure to cancel this everywhere else */ - llist_for_each_entry(bts, bts_list, list) { - /* Sort of an optimization. */ - if (bts == _bts) - continue; - _paging_request_stop(bts, bsub, NULL, NULL); - } -} - -void paging_update_buffer_space(struct gsm_bts *bts, uint16_t free_slots) -{ - paging_init_if_needed(bts); - - osmo_timer_del(&bts->paging.credit_timer); - bts->paging.available_slots = free_slots; - paging_schedule_if_needed(&bts->paging); -} - -unsigned int paging_pending_requests_nr(struct gsm_bts *bts) -{ - unsigned int requests = 0; - struct gsm_paging_request *req; - - paging_init_if_needed(bts); - - llist_for_each_entry(req, &bts->paging.pending_requests, entry) - ++requests; - - return requests; -} - -/** - * Find any paging data for the given subscriber at the given BTS. - */ -void *paging_get_data(struct gsm_bts *bts, struct bsc_subscr *bsub) -{ - struct gsm_paging_request *req; - - llist_for_each_entry(req, &bts->paging.pending_requests, entry) - if (req->bsub == bsub) - return req->cbfn_param; - - return NULL; -} diff --git a/src/libbsc/pcu_sock.c b/src/libbsc/pcu_sock.c deleted file mode 100644 index 98e12fad4..000000000 --- a/src/libbsc/pcu_sock.c +++ /dev/null @@ -1,742 +0,0 @@ -/* pcu_sock.c: Connect from PCU via unix domain socket */ - -/* (C) 2008-2010 by Harald Welte - * (C) 2009-2012 by Andreas Eversberg - * (C) 2012 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 General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static int pcu_sock_send(struct gsm_bts *bts, struct msgb *msg); -uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx); -int pcu_direct = 1; - -static const char *sapi_string[] = { - [PCU_IF_SAPI_RACH] = "RACH", - [PCU_IF_SAPI_AGCH] = "AGCH", - [PCU_IF_SAPI_PCH] = "PCH", - [PCU_IF_SAPI_BCCH] = "BCCH", - [PCU_IF_SAPI_PDTCH] = "PDTCH", - [PCU_IF_SAPI_PRACH] = "PRACH", - [PCU_IF_SAPI_PTCCH] = "PTCCH", - [PCU_IF_SAPI_AGCH_DT] = "AGCH_DT", -}; - -/* Check if BTS has a PCU connection */ -static bool pcu_connected(struct gsm_bts *bts) -{ - struct pcu_sock_state *state = bts->pcu_state; - - if (!state) - return false; - if (state->conn_bfd.fd <= 0) - return false; - return true; -} - -/* - * PCU messages - */ - -/* Set up an message buffer to package an pcu interface message */ -struct msgb *pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr) -{ - struct msgb *msg; - struct gsm_pcu_if *pcu_prim; - - msg = msgb_alloc(sizeof(struct gsm_pcu_if), "pcu_sock_tx"); - if (!msg) - return NULL; - - msgb_put(msg, sizeof(struct gsm_pcu_if)); - pcu_prim = (struct gsm_pcu_if *) msg->data; - pcu_prim->msg_type = msg_type; - pcu_prim->bts_nr = bts_nr; - - return msg; -} - -/* Helper function exclusivly used by pcu_if_signal_cb() */ -static bool ts_should_be_pdch(struct gsm_bts_trx_ts *ts) { - if (ts->pchan == GSM_PCHAN_PDCH) - return true; - if (ts->pchan == GSM_PCHAN_TCH_F_PDCH) { - /* When we're busy deactivating the PDCH, we first set - * DEACT_PENDING, tell the PCU about it and wait for a - * response. So DEACT_PENDING means "no PDCH" to the PCU. - * Similarly, when we're activating PDCH, we set the - * ACT_PENDING and wait for an activation response from the - * PCU, so ACT_PENDING means "is PDCH". */ - if (ts->flags & TS_F_PDCH_ACTIVE) - return !(ts->flags & TS_F_PDCH_DEACT_PENDING); - else - return (ts->flags & TS_F_PDCH_ACT_PENDING); - } - if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) { - /* - * When we're busy de-/activating the PDCH, we first set - * ts->dyn.pchan_want, tell the PCU about it and wait for a - * response. So only care about dyn.pchan_want here. - */ - return ts->dyn.pchan_want == GSM_PCHAN_PDCH; - } - return false; -} - -/* Send BTS properties to the PCU */ -static int pcu_tx_info_ind(struct gsm_bts *bts) -{ - struct msgb *msg; - struct gsm_pcu_if *pcu_prim; - struct gsm_pcu_if_info_ind *info_ind; - struct gprs_rlc_cfg *rlcc; - struct gsm_bts_gprs_nsvc *nsvc; - struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - int i, j; - - OSMO_ASSERT(bts); - OSMO_ASSERT(bts->network); - - LOGP(DPCU, LOGL_INFO, "Sending info for BTS %d\n",bts->nr); - - rlcc = &bts->gprs.cell.rlc_cfg; - - msg = pcu_msgb_alloc(PCU_IF_MSG_INFO_IND, bts->nr); - if (!msg) - return -ENOMEM; - - pcu_prim = (struct gsm_pcu_if *) msg->data; - info_ind = &pcu_prim->u.info_ind; - info_ind->version = PCU_IF_VERSION; - info_ind->flags |= PCU_IF_FLAG_ACTIVE; - - if (pcu_direct) - info_ind->flags |= PCU_IF_FLAG_SYSMO; - - /* RAI */ - info_ind->mcc = bts->network->country_code; - info_ind->mnc = bts->network->network_code; - info_ind->lac = bts->location_area_code; - info_ind->rac = bts->gprs.rac; - - /* NSE */ - info_ind->nsei = bts->gprs.nse.nsei; - memcpy(info_ind->nse_timer, bts->gprs.nse.timer, 7); - memcpy(info_ind->cell_timer, bts->gprs.cell.timer, 11); - - /* cell attributes */ - info_ind->cell_id = bts->cell_identity; - info_ind->repeat_time = rlcc->paging.repeat_time; - info_ind->repeat_count = rlcc->paging.repeat_count; - info_ind->bvci = bts->gprs.cell.bvci; - info_ind->t3142 = rlcc->parameter[RLC_T3142]; - info_ind->t3169 = rlcc->parameter[RLC_T3169]; - info_ind->t3191 = rlcc->parameter[RLC_T3191]; - info_ind->t3193_10ms = rlcc->parameter[RLC_T3193]; - info_ind->t3195 = rlcc->parameter[RLC_T3195]; - info_ind->n3101 = rlcc->parameter[RLC_N3101]; - info_ind->n3103 = rlcc->parameter[RLC_N3103]; - info_ind->n3105 = rlcc->parameter[RLC_N3105]; - info_ind->cv_countdown = rlcc->parameter[CV_COUNTDOWN]; - if (rlcc->cs_mask & (1 << GPRS_CS1)) - info_ind->flags |= PCU_IF_FLAG_CS1; - if (rlcc->cs_mask & (1 << GPRS_CS2)) - info_ind->flags |= PCU_IF_FLAG_CS2; - if (rlcc->cs_mask & (1 << GPRS_CS3)) - info_ind->flags |= PCU_IF_FLAG_CS3; - if (rlcc->cs_mask & (1 << GPRS_CS4)) - info_ind->flags |= PCU_IF_FLAG_CS4; - if (bts->gprs.mode == BTS_GPRS_EGPRS) { - if (rlcc->cs_mask & (1 << GPRS_MCS1)) - info_ind->flags |= PCU_IF_FLAG_MCS1; - if (rlcc->cs_mask & (1 << GPRS_MCS2)) - info_ind->flags |= PCU_IF_FLAG_MCS2; - if (rlcc->cs_mask & (1 << GPRS_MCS3)) - info_ind->flags |= PCU_IF_FLAG_MCS3; - if (rlcc->cs_mask & (1 << GPRS_MCS4)) - info_ind->flags |= PCU_IF_FLAG_MCS4; - if (rlcc->cs_mask & (1 << GPRS_MCS5)) - info_ind->flags |= PCU_IF_FLAG_MCS5; - if (rlcc->cs_mask & (1 << GPRS_MCS6)) - info_ind->flags |= PCU_IF_FLAG_MCS6; - if (rlcc->cs_mask & (1 << GPRS_MCS7)) - info_ind->flags |= PCU_IF_FLAG_MCS7; - if (rlcc->cs_mask & (1 << GPRS_MCS8)) - info_ind->flags |= PCU_IF_FLAG_MCS8; - if (rlcc->cs_mask & (1 << GPRS_MCS9)) - info_ind->flags |= PCU_IF_FLAG_MCS9; - } -#warning "isn't dl_tbf_ext wrong?: * 10 and no ntohs" - info_ind->dl_tbf_ext = rlcc->parameter[T_DL_TBF_EXT]; -#warning "isn't ul_tbf_ext wrong?: * 10 and no ntohs" - info_ind->ul_tbf_ext = rlcc->parameter[T_UL_TBF_EXT]; - info_ind->initial_cs = rlcc->initial_cs; - info_ind->initial_mcs = rlcc->initial_mcs; - - /* NSVC */ - for (i = 0; i < ARRAY_SIZE(info_ind->nsvci); i++) { - nsvc = &bts->gprs.nsvc[i]; - info_ind->nsvci[i] = nsvc->nsvci; - info_ind->local_port[i] = nsvc->local_port; - info_ind->remote_port[i] = nsvc->remote_port; - info_ind->remote_ip[i] = nsvc->remote_ip; - } - - for (i = 0; i < ARRAY_SIZE(info_ind->trx); i++) { - trx = gsm_bts_trx_num(bts, i); - if (!trx) - continue; - info_ind->trx[i].hlayer1 = 0x2342; - info_ind->trx[i].pdch_mask = 0; - info_ind->trx[i].arfcn = trx->arfcn; - for (j = 0; j < ARRAY_SIZE(trx->ts); j++) { - ts = &trx->ts[j]; - if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED - && ts_should_be_pdch(ts)) { - info_ind->trx[i].pdch_mask |= (1 << j); - info_ind->trx[i].tsc[j] = - (ts->tsc >= 0) ? ts->tsc : bts->bsic & 7; - LOGP(DPCU, LOGL_INFO, "trx=%d ts=%d: " - "available (tsc=%d arfcn=%d)\n", - trx->nr, ts->nr, - info_ind->trx[i].tsc[j], - info_ind->trx[i].arfcn); - } - } - } - - return pcu_sock_send(bts, msg); -} - -void pcu_info_update(struct gsm_bts *bts) -{ - if (pcu_connected(bts)) - pcu_tx_info_ind(bts); -} - -/* Forward rach indication to PCU */ -int pcu_tx_rach_ind(struct gsm_bts *bts, int16_t qta, uint16_t ra, uint32_t fn, - uint8_t is_11bit, enum ph_burst_type burst_type) -{ - struct msgb *msg; - struct gsm_pcu_if *pcu_prim; - struct gsm_pcu_if_rach_ind *rach_ind; - - /* Bail if no PCU is connected */ - if (!pcu_connected(bts)) { - LOGP(DRSL, LOGL_ERROR, "BTS %d CHAN RQD(GPRS) but PCU not " - "connected!\n", bts->nr); - return -ENODEV; - } - - LOGP(DPCU, LOGL_INFO, "Sending RACH indication: qta=%d, ra=%d, " - "fn=%d\n", qta, ra, fn); - - msg = pcu_msgb_alloc(PCU_IF_MSG_RACH_IND, bts->nr); - if (!msg) - return -ENOMEM; - pcu_prim = (struct gsm_pcu_if *) msg->data; - rach_ind = &pcu_prim->u.rach_ind; - - rach_ind->sapi = PCU_IF_SAPI_RACH; - rach_ind->ra = ra; - rach_ind->qta = qta; - rach_ind->fn = fn; - rach_ind->is_11bit = is_11bit; - rach_ind->burst_type = burst_type; - - return pcu_sock_send(bts, msg); -} - -/* Confirm the sending of an immediate assignment to the pcu */ -int pcu_tx_imm_ass_sent(struct gsm_bts *bts, uint32_t tlli) -{ - struct msgb *msg; - struct gsm_pcu_if *pcu_prim; - struct gsm_pcu_if_data_cnf_dt *data_cnf_dt; - - LOGP(DPCU, LOGL_INFO, "Sending PCH confirm with direct TLLI\n"); - - msg = pcu_msgb_alloc(PCU_IF_MSG_DATA_CNF_DT, bts->nr); - if (!msg) - return -ENOMEM; - pcu_prim = (struct gsm_pcu_if *) msg->data; - data_cnf_dt = &pcu_prim->u.data_cnf_dt; - - data_cnf_dt->sapi = PCU_IF_SAPI_PCH; - data_cnf_dt->tlli = tlli; - - return pcu_sock_send(bts, msg); -} - -/* we need to decode the raw RR paging messsage (see PCU code - * Encoding::write_paging_request) and extract the mobile identity - * (P-TMSI) from it */ -static int pcu_rx_rr_paging(struct gsm_bts *bts, uint8_t paging_group, - const uint8_t *raw_rr_msg) -{ - struct gsm48_paging1 *p1 = (struct gsm48_paging1 *) raw_rr_msg; - uint8_t chan_needed; - unsigned int mi_len; - uint8_t *mi; - int rc; - - switch (p1->msg_type) { - case GSM48_MT_RR_PAG_REQ_1: - chan_needed = (p1->cneed2 << 2) | p1->cneed1; - mi_len = p1->data[0]; - mi = p1->data+1; - LOGP(DPCU, LOGL_ERROR, "PCU Sends paging " - "request type %02x (chan_needed=%02x, mi_len=%u, mi=%s)\n", - p1->msg_type, chan_needed, mi_len, - osmo_hexdump_nospc(mi,mi_len)); - /* NOTE: We will have to add 2 to mi_len and subtract 2 from - * the mi pointer because rsl_paging_cmd() will perform the - * reverse operations. This is because rsl_paging_cmd() is - * normally expected to chop off the element identifier (0xC0) - * and the length field. In our parameter, we do not have - * those fields included. */ - rc = rsl_paging_cmd(bts, paging_group, mi_len+2, mi-2, - chan_needed, true); - break; - case GSM48_MT_RR_PAG_REQ_2: - case GSM48_MT_RR_PAG_REQ_3: - LOGP(DPCU, LOGL_ERROR, "PCU Sends unsupported paging " - "request type %02x\n", p1->msg_type); - rc = -EINVAL; - break; - default: - LOGP(DPCU, LOGL_ERROR, "PCU Sends unknown paging " - "request type %02x\n", p1->msg_type); - rc = -EINVAL; - break; - } - - return rc; -} - -static int pcu_rx_data_req(struct gsm_bts *bts, uint8_t msg_type, - struct gsm_pcu_if_data *data_req) -{ - uint8_t is_ptcch; - struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - struct msgb *msg; - char imsi_digit_buf[4]; - uint32_t tlli = -1; - uint8_t pag_grp; - int rc = 0; - - LOGP(DPCU, LOGL_DEBUG, "Data request received: sapi=%s arfcn=%d " - "block=%d data=%s\n", sapi_string[data_req->sapi], - data_req->arfcn, data_req->block_nr, - osmo_hexdump(data_req->data, data_req->len)); - - switch (data_req->sapi) { - case PCU_IF_SAPI_PCH: - /* the first three bytes are the last three digits of - * the IMSI, which we need to compute the paging group */ - imsi_digit_buf[0] = data_req->data[0]; - imsi_digit_buf[1] = data_req->data[1]; - imsi_digit_buf[2] = data_req->data[2]; - imsi_digit_buf[3] = '\0'; - LOGP(DPCU, LOGL_DEBUG, "SAPI PCH imsi %s\n", imsi_digit_buf); - pag_grp = gsm0502_calc_paging_group(&bts->si_common.chan_desc, - str_to_imsi(imsi_digit_buf)); - pcu_rx_rr_paging(bts, pag_grp, data_req->data+3); - break; - case PCU_IF_SAPI_AGCH: - msg = msgb_alloc(data_req->len, "pcu_agch"); - if (!msg) { - rc = -ENOMEM; - break; - } - msg->l3h = msgb_put(msg, data_req->len); - memcpy(msg->l3h, data_req->data, data_req->len); - - if (rsl_imm_assign_cmd(bts, msg->len, msg->data)) { - msgb_free(msg); - rc = -EIO; - } - break; - case PCU_IF_SAPI_AGCH_DT: - /* DT = direct tlli. A tlli is prefixed */ - - if (data_req->len < 5) { - LOGP(DPCU, LOGL_ERROR, "Received PCU data request with " - "invalid/small length %d\n", data_req->len); - break; - } - tlli = *((uint32_t *)data_req->data); - - msg = msgb_alloc(data_req->len - 4, "pcu_agch"); - if (!msg) { - rc = -ENOMEM; - break; - } - msg->l3h = msgb_put(msg, data_req->len - 4); - memcpy(msg->l3h, data_req->data + 4, data_req->len - 4); - - if (bts->type == GSM_BTS_TYPE_RBS2000) - rc = rsl_ericsson_imm_assign_cmd(bts, tlli, msg->len, msg->data); - else - rc = rsl_imm_assign_cmd(bts, msg->len, msg->data); - - if (rc) { - msgb_free(msg); - rc = -EIO; - } - break; - default: - LOGP(DPCU, LOGL_ERROR, "Received PCU data request with " - "unsupported sapi %d\n", data_req->sapi); - rc = -EINVAL; - } - - return rc; -} - -static int pcu_rx(struct gsm_network *net, uint8_t msg_type, - struct gsm_pcu_if *pcu_prim) -{ - int rc = 0; - struct gsm_bts *bts; - - /* FIXME: allow multiple BTS */ - bts = llist_entry(net->bts_list.next, struct gsm_bts, list); - - switch (msg_type) { - case PCU_IF_MSG_DATA_REQ: - case PCU_IF_MSG_PAG_REQ: - rc = pcu_rx_data_req(bts, msg_type, &pcu_prim->u.data_req); - break; - default: - LOGP(DPCU, LOGL_ERROR, "Received unknwon PCU msg type %d\n", - msg_type); - rc = -EINVAL; - } - - return rc; -} - -/* - * PCU socket interface - */ - -static int pcu_sock_send(struct gsm_bts *bts, struct msgb *msg) -{ - struct pcu_sock_state *state = bts->pcu_state; - struct osmo_fd *conn_bfd; - struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *) msg->data; - - if (!state) { - if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND) - LOGP(DPCU, LOGL_INFO, "PCU socket not created, " - "dropping message\n"); - msgb_free(msg); - return -EINVAL; - } - conn_bfd = &state->conn_bfd; - if (conn_bfd->fd <= 0) { - if (pcu_prim->msg_type != PCU_IF_MSG_TIME_IND) - LOGP(DPCU, LOGL_NOTICE, "PCU socket not connected, " - "dropping message\n"); - msgb_free(msg); - return -EIO; - } - msgb_enqueue(&state->upqueue, msg); - conn_bfd->when |= BSC_FD_WRITE; - - return 0; -} - -static void pcu_sock_close(struct pcu_sock_state *state) -{ - struct osmo_fd *bfd = &state->conn_bfd; - struct gsm_bts *bts; - struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - int i, j; - - /* FIXME: allow multiple BTS */ - bts = llist_entry(state->net->bts_list.next, struct gsm_bts, list); - - LOGP(DPCU, LOGL_NOTICE, "PCU socket has LOST connection\n"); - - close(bfd->fd); - bfd->fd = -1; - osmo_fd_unregister(bfd); - - /* re-enable the generation of ACCEPT for new connections */ - state->listen_bfd.when |= BSC_FD_READ; - -#if 0 - /* remove si13, ... */ - bts->si_valid &= ~(1 << SYSINFO_TYPE_13); - osmo_signal_dispatch(SS_GLOBAL, S_NEW_SYSINFO, bts); -#endif - - /* release PDCH */ - for (i = 0; i < 8; i++) { - trx = gsm_bts_trx_num(bts, i); - if (!trx) - break; - for (j = 0; j < 8; j++) { - ts = &trx->ts[j]; - if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED - && ts->pchan == GSM_PCHAN_PDCH) { - printf("l1sap_chan_rel(trx,gsm_lchan2chan_nr(ts->lchan));\n"); - } - } - } - - /* flush the queue */ - while (!llist_empty(&state->upqueue)) { - struct msgb *msg = msgb_dequeue(&state->upqueue); - msgb_free(msg); - } -} - -static int pcu_sock_read(struct osmo_fd *bfd) -{ - struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data; - struct gsm_pcu_if *pcu_prim; - struct msgb *msg; - int rc; - - msg = msgb_alloc(sizeof(*pcu_prim), "pcu_sock_rx"); - if (!msg) - return -ENOMEM; - - pcu_prim = (struct gsm_pcu_if *) msg->tail; - - rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0); - if (rc == 0) - goto close; - - if (rc < 0) { - if (errno == EAGAIN) - return 0; - goto close; - } - - rc = pcu_rx(state->net, pcu_prim->msg_type, pcu_prim); - - /* as we always synchronously process the message in pcu_rx() and - * its callbacks, we can free the message here. */ - msgb_free(msg); - - return rc; - -close: - msgb_free(msg); - pcu_sock_close(state); - return -1; -} - -static int pcu_sock_write(struct osmo_fd *bfd) -{ - struct pcu_sock_state *state = bfd->data; - int rc; - - while (!llist_empty(&state->upqueue)) { - struct msgb *msg, *msg2; - struct gsm_pcu_if *pcu_prim; - - /* peek at the beginning of the queue */ - msg = llist_entry(state->upqueue.next, struct msgb, list); - pcu_prim = (struct gsm_pcu_if *)msg->data; - - bfd->when &= ~BSC_FD_WRITE; - - /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */ - if (!msgb_length(msg)) { - LOGP(DPCU, LOGL_ERROR, "message type (%d) with ZERO " - "bytes!\n", pcu_prim->msg_type); - goto dontsend; - } - - /* try to send it over the socket */ - rc = write(bfd->fd, msgb_data(msg), msgb_length(msg)); - if (rc == 0) - goto close; - if (rc < 0) { - if (errno == EAGAIN) { - bfd->when |= BSC_FD_WRITE; - break; - } - goto close; - } - -dontsend: - /* _after_ we send it, we can deueue */ - msg2 = msgb_dequeue(&state->upqueue); - assert(msg == msg2); - msgb_free(msg); - } - return 0; - -close: - pcu_sock_close(state); - - return -1; -} - -static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags) -{ - int rc = 0; - - if (flags & BSC_FD_READ) - rc = pcu_sock_read(bfd); - if (rc < 0) - return rc; - - if (flags & BSC_FD_WRITE) - rc = pcu_sock_write(bfd); - - return rc; -} - -/* accept connection comming from PCU */ -static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags) -{ - struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data; - struct osmo_fd *conn_bfd = &state->conn_bfd; - struct sockaddr_un un_addr; - socklen_t len; - int rc; - - len = sizeof(un_addr); - rc = accept(bfd->fd, (struct sockaddr *) &un_addr, &len); - if (rc < 0) { - LOGP(DPCU, LOGL_ERROR, "Failed to accept a new connection\n"); - return -1; - } - - if (conn_bfd->fd >= 0) { - LOGP(DPCU, LOGL_NOTICE, "PCU connects but we already have " - "another active connection ?!?\n"); - /* We already have one PCU connected, this is all we support */ - state->listen_bfd.when &= ~BSC_FD_READ; - close(rc); - return 0; - } - - conn_bfd->fd = rc; - conn_bfd->when = BSC_FD_READ; - conn_bfd->cb = pcu_sock_cb; - conn_bfd->data = state; - - if (osmo_fd_register(conn_bfd) != 0) { - LOGP(DPCU, LOGL_ERROR, "Failed to register new connection " - "fd\n"); - close(conn_bfd->fd); - conn_bfd->fd = -1; - return -1; - } - - LOGP(DPCU, LOGL_NOTICE, "PCU socket connected to external PCU\n"); - - return 0; -} - -/* Open connection to PCU */ -int pcu_sock_init(const char *path, struct gsm_bts *bts) -{ - struct pcu_sock_state *state; - struct osmo_fd *bfd; - int rc; - - state = talloc_zero(NULL, struct pcu_sock_state); - if (!state) - return -ENOMEM; - - INIT_LLIST_HEAD(&state->upqueue); - state->net = bts->network; - state->conn_bfd.fd = -1; - - bfd = &state->listen_bfd; - - bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path, - OSMO_SOCK_F_BIND); - if (bfd->fd < 0) { - LOGP(DPCU, LOGL_ERROR, "Could not create unix socket: %s\n", - strerror(errno)); - talloc_free(state); - return -1; - } - - bfd->when = BSC_FD_READ; - bfd->cb = pcu_sock_accept; - bfd->data = state; - - rc = osmo_fd_register(bfd); - if (rc < 0) { - LOGP(DPCU, LOGL_ERROR, "Could not register listen fd: %d\n", - rc); - close(bfd->fd); - talloc_free(state); - return rc; - } - - bts->pcu_state = state; - return 0; -} - -/* Close connection to PCU */ -void pcu_sock_exit(struct gsm_bts *bts) -{ - struct pcu_sock_state *state = bts->pcu_state; - struct osmo_fd *bfd, *conn_bfd; - - if (!state) - return; - - conn_bfd = &state->conn_bfd; - if (conn_bfd->fd > 0) - pcu_sock_close(state); - bfd = &state->listen_bfd; - close(bfd->fd); - osmo_fd_unregister(bfd); - talloc_free(state); - bts->pcu_state = NULL; -} - diff --git a/src/libbsc/rest_octets.c b/src/libbsc/rest_octets.c deleted file mode 100644 index fdab70a0c..000000000 --- a/src/libbsc/rest_octets.c +++ /dev/null @@ -1,860 +0,0 @@ -/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface, - * rest octet handling according to - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2009 by Harald Welte - * - * 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 . - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* generate SI1 rest octets */ -int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net) -{ - struct bitvec bv; - - memset(&bv, 0, sizeof(bv)); - bv.data = data; - bv.data_len = 1; - - if (nch_pos) { - bitvec_set_bit(&bv, H); - bitvec_set_uint(&bv, *nch_pos, 5); - } else - bitvec_set_bit(&bv, L); - - if (is1800_net) - bitvec_set_bit(&bv, L); - else - bitvec_set_bit(&bv, H); - - bitvec_spare_padding(&bv, 6); - return bv.data_len; -} - -/* Append Repeated E-UTRAN Neighbour Cell to bitvec: see 3GPP TS 44.018 Table 10.5.2.33b.1 */ -static inline void append_eutran_neib_cell(struct bitvec *bv, struct gsm_bts *bts, uint8_t budget) -{ - const struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; - unsigned i, skip = 0; - size_t offset = bts->e_offset; - uint8_t rem = budget - 6, earfcn_budget; /* account for mandatory stop bit and THRESH_E-UTRAN_high */ - - if (budget <= 6) - return; - - OSMO_ASSERT(budget <= SI2Q_MAX_LEN); - - /* first we have to properly adjust budget requirements */ - if (e->prio_valid) /* E-UTRAN_PRIORITY: 3GPP TS 45.008*/ - rem -= 4; - else - rem--; - - if (e->thresh_lo_valid) /* THRESH_E-UTRAN_low: */ - rem -= 6; - else - rem--; - - if (e->qrxlm_valid) /* E-UTRAN_QRXLEVMIN: */ - rem -= 6; - else - rem--; - - /* now we can proceed with actually adding EARFCNs within adjusted budget limit */ - for (i = 0; i < e->length; i++) { - if (e->arfcn[i] != OSMO_EARFCN_INVALID) { - if (skip < offset) { - skip++; /* ignore EARFCNs added on previous calls */ - } else { - earfcn_budget = 17; /* compute budget per-EARFCN */ - if (OSMO_EARFCN_MEAS_INVALID == e->meas_bw[i]) - earfcn_budget++; - else - earfcn_budget += 4; - - if (rem - earfcn_budget < 0) - break; - else { - bts->e_offset++; - rem -= earfcn_budget; - bitvec_set_bit(bv, 1); /* EARFCN: */ - bitvec_set_uint(bv, e->arfcn[i], 16); - - if (OSMO_EARFCN_MEAS_INVALID == e->meas_bw[i]) - bitvec_set_bit(bv, 0); - else { /* Measurement Bandwidth: 9.1.54 */ - bitvec_set_bit(bv, 1); - bitvec_set_uint(bv, e->meas_bw[i], 3); - } - } - } - } - } - - /* stop bit - end of EARFCN + Measurement Bandwidth sequence */ - bitvec_set_bit(bv, 0); - - /* Note: we don't support different EARFCN arrays each with different priority, threshold etc. */ - - if (e->prio_valid) { - /* E-UTRAN_PRIORITY: 3GPP TS 45.008*/ - bitvec_set_bit(bv, 1); - bitvec_set_uint(bv, e->prio, 3); - } else - bitvec_set_bit(bv, 0); - - /* THRESH_E-UTRAN_high */ - bitvec_set_uint(bv, e->thresh_hi, 5); - - if (e->thresh_lo_valid) { - /* THRESH_E-UTRAN_low: */ - bitvec_set_bit(bv, 1); - bitvec_set_uint(bv, e->thresh_lo, 5); - } else - bitvec_set_bit(bv, 0); - - if (e->qrxlm_valid) { - /* E-UTRAN_QRXLEVMIN: */ - bitvec_set_bit(bv, 1); - bitvec_set_uint(bv, e->qrxlm, 5); - } else - bitvec_set_bit(bv, 0); -} - -static inline void append_earfcn(struct bitvec *bv, struct gsm_bts *bts, uint8_t budget) -{ - int rem = budget - 25; - if (rem <= 0) - return; - - OSMO_ASSERT(budget <= SI2Q_MAX_LEN); - - /* Additions in Rel-5: */ - bitvec_set_bit(bv, H); - /* No 3G Additional Measurement Param. Descr. */ - bitvec_set_bit(bv, 0); - /* No 3G ADDITIONAL MEASUREMENT Param. Descr. 2 */ - bitvec_set_bit(bv, 0); - /* Additions in Rel-6: */ - bitvec_set_bit(bv, H); - /* 3G_CCN_ACTIVE */ - bitvec_set_bit(bv, 0); - /* Additions in Rel-7: */ - bitvec_set_bit(bv, H); - /* No 700_REPORTING_OFFSET */ - bitvec_set_bit(bv, 0); - /* No 810_REPORTING_OFFSET */ - bitvec_set_bit(bv, 0); - /* Additions in Rel-8: */ - bitvec_set_bit(bv, H); - - /* Priority and E-UTRAN Parameters Description */ - bitvec_set_bit(bv, 1); - - /* No Serving Cell Priority Parameters Descr. */ - bitvec_set_bit(bv, 0); - /* No 3G Priority Parameters Description */ - bitvec_set_bit(bv, 0); - /* E-UTRAN Parameters Description */ - bitvec_set_bit(bv, 1); - - /* E-UTRAN_CCN_ACTIVE */ - bitvec_set_bit(bv, 0); - /* E-UTRAN_Start: 9.1.54 */ - bitvec_set_bit(bv, 1); - /* E-UTRAN_Stop: 9.1.54 */ - bitvec_set_bit(bv, 1); - - /* No E-UTRAN Measurement Parameters Descr. */ - bitvec_set_bit(bv, 0); - /* No GPRS E-UTRAN Measurement Param. Descr. */ - bitvec_set_bit(bv, 0); - - /* Note: each of next 3 "repeated" structures might be repeated any - (0, 1, 2...) times - we only support 1 and 0 */ - - /* Repeated E-UTRAN Neighbour Cells */ - bitvec_set_bit(bv, 1); - - /* N. B: 25 bits are set in append_earfcn() - keep it in sync with budget adjustment below: */ - append_eutran_neib_cell(bv, bts, rem); - - /* stop bit - end of Repeated E-UTRAN Neighbour Cells sequence: */ - bitvec_set_bit(bv, 0); - - /* Note: following 2 repeated structs are not supported ATM */ - /* stop bit - end of Repeated E-UTRAN Not Allowed Cells sequence: */ - bitvec_set_bit(bv, 0); - /* stop bit - end of Repeated E-UTRAN PCID to TA mapping sequence: */ - bitvec_set_bit(bv, 0); - - /* Priority and E-UTRAN Parameters Description ends here */ - /* No 3G CSG Description */ - bitvec_set_bit(bv, 0); - /* No E-UTRAN CSG Description */ - bitvec_set_bit(bv, 0); - /* No Additions in Rel-9: */ - bitvec_set_bit(bv, L); -} - -static inline int f0_helper(int *sc, size_t length, uint8_t *chan_list) -{ - int w[RANGE_ENC_MAX_ARFCNS] = { 0 }; - - return range_encode(ARFCN_RANGE_1024, sc, length, w, 0, chan_list); -} - -/* Estimate how many bits it'll take to append single FDD UARFCN */ -static inline int append_utran_fdd_length(uint16_t u, int *sc, size_t sc_len, size_t length) -{ - uint8_t chan_list[16] = { 0 }; - int tmp[sc_len], f0; - - memcpy(tmp, sc, sizeof(tmp)); - - f0 = f0_helper(tmp, length, chan_list); - if (f0 < 0) - return f0; - - return 21 + range1024_p(length); -} - -/* Append single FDD UARFCN */ -static inline int append_utran_fdd(struct bitvec *bv, uint16_t u, int *sc, size_t length) -{ - uint8_t chan_list[16] = { 0 }; - int f0 = f0_helper(sc, length, chan_list); - - if (f0 < 0) - return f0; - - /* Repeated UTRAN FDD Neighbour Cells */ - bitvec_set_bit(bv, 1); - - /* FDD-ARFCN */ - bitvec_set_bit(bv, 0); - bitvec_set_uint(bv, u, 14); - - /* FDD_Indic0: parameter value '0000000000' is a member of the set? */ - bitvec_set_bit(bv, f0); - /* NR_OF_FDD_CELLS */ - bitvec_set_uint(bv, length, 5); - - f0 = bv->cur_bit; - bitvec_add_range1024(bv, (struct gsm48_range_1024 *)chan_list); - bv->cur_bit = f0 + range1024_p(length); - - return 21 + range1024_p(length); -} - -/* Append multiple FDD UARFCNs */ -static inline int append_uarfcns(struct bitvec *bv, struct gsm_bts *bts, uint8_t budget) -{ - const uint16_t *u = bts->si_common.data.uarfcn_list, *sc = bts->si_common.data.scramble_list; - int i, j, k, rc, st = 0, a[bts->si_common.uarfcn_length]; - uint16_t cu = u[bts->u_offset]; /* caller ensures that length is positive */ - uint8_t rem = budget - 7, offset_diff; /* account for constant bits right away */ - - OSMO_ASSERT(budget <= SI2Q_MAX_LEN); - - if (budget <= 7) - return -ENOMEM; - - /* 3G Neighbour Cell Description */ - bitvec_set_bit(bv, 1); - /* No Index_Start_3G */ - bitvec_set_bit(bv, 0); - /* No Absolute_Index_Start_EMR */ - bitvec_set_bit(bv, 0); - - /* UTRAN FDD Description */ - bitvec_set_bit(bv, 1); - /* No Bandwidth_FDD */ - bitvec_set_bit(bv, 0); - - for (i = bts->u_offset; i < bts->si_common.uarfcn_length; i++) { - offset_diff = 0; - for (j = st, k = 0; j < i; j++) { - a[k++] = sc[j]; /* copy corresponding SCs */ - offset_diff++; /* compute proper offset step */ - } - if (u[i] != cu) { /* we've reached new UARFCN */ - rc = append_utran_fdd_length(cu, a, bts->si_common.uarfcn_length, k); - if (rc < 0) { /* estimate bit length requirements */ - return rc; - } - - if (rem - rc <= 0) - break; /* we have ran out of budget in current SI2q */ - else { - rem -= append_utran_fdd(bv, cu, a, k); - bts->u_offset += offset_diff; - } - cu = u[i]; - st = i; /* update start position */ - } - } - - if (rem > 22) { /* add last UARFCN not covered by previous cycle if it could possibly fit into budget */ - offset_diff = 0; - for (i = st, k = 0; i < bts->si_common.uarfcn_length; i++) { - a[k++] = sc[i]; - offset_diff++; - } - rc = append_utran_fdd_length(cu, a, bts->si_common.uarfcn_length, k); - if (rc < 0) { - return rc; - } - - if (rem - rc >= 0) { - rem -= append_utran_fdd(bv, cu, a, k); - bts->u_offset += offset_diff; - } - } - - /* stop bit - end of Repeated UTRAN FDD Neighbour Cells */ - bitvec_set_bit(bv, 0); - - /* UTRAN TDD Description */ - bitvec_set_bit(bv, 0); - - return 0; -} - -/* generate SI2quater rest octets: 3GPP TS 44.018 § 10.5.2.33b */ -int rest_octets_si2quater(uint8_t *data, struct gsm_bts *bts) -{ - int rc; - struct bitvec bv; - - if (bts->si2q_count < bts->si2q_index) - return -EINVAL; - - bv.data = data; - bv.data_len = 20; - bitvec_zero(&bv); - - /* BA_IND */ - bitvec_set_bit(&bv, 1); - /* 3G_BA_IND */ - bitvec_set_bit(&bv, 1); - /* MP_CHANGE_MARK */ - bitvec_set_bit(&bv, 0); - - /* SI2quater_INDEX */ - bitvec_set_uint(&bv, bts->si2q_index, 4); - /* SI2quater_COUNT */ - bitvec_set_uint(&bv, bts->si2q_count, 4); - - /* No Measurement_Parameters Description */ - bitvec_set_bit(&bv, 0); - /* No GPRS_Real Time Difference Description */ - bitvec_set_bit(&bv, 0); - /* No GPRS_BSIC Description */ - bitvec_set_bit(&bv, 0); - /* No GPRS_REPORT PRIORITY Description */ - bitvec_set_bit(&bv, 0); - /* No GPRS_MEASUREMENT_Parameters Description */ - bitvec_set_bit(&bv, 0); - /* No NC Measurement Parameters */ - bitvec_set_bit(&bv, 0); - /* No extension (length) */ - bitvec_set_bit(&bv, 0); - - rc = SI2Q_MAX_LEN - (bv.cur_bit + 3); - if (rc > 0 && bts->si_common.uarfcn_length - bts->u_offset > 0) { - rc = append_uarfcns(&bv, bts, rc); - if (rc < 0) { - LOGP(DRR, LOGL_ERROR, "SI2quater [%u/%u]: failed to append %zu UARFCNs due to range encoding " - "failure: %s\n", - bts->si2q_index, bts->si2q_count, bts->si_common.uarfcn_length, strerror(-rc)); - return rc; - } - } else /* No 3G Neighbour Cell Description */ - bitvec_set_bit(&bv, 0); - - /* No 3G Measurement Parameters Description */ - bitvec_set_bit(&bv, 0); - /* No GPRS_3G_MEASUREMENT Parameters Descr. */ - bitvec_set_bit(&bv, 0); - - rc = SI2Q_MAX_LEN - bv.cur_bit; - if (rc > 0 && si2q_earfcn_count(&bts->si_common.si2quater_neigh_list) - bts->e_offset > 0) - append_earfcn(&bv, bts, rc); - else /* No Additions in Rel-5: */ - bitvec_set_bit(&bv, L); - - bitvec_spare_padding(&bv, (bv.data_len * 8) - 1); - return bv.data_len; -} - -/* Append selection parameters to bitvec */ -static void append_selection_params(struct bitvec *bv, - const struct gsm48_si_selection_params *sp) -{ - if (sp->present) { - bitvec_set_bit(bv, H); - bitvec_set_bit(bv, sp->cbq); - bitvec_set_uint(bv, sp->cell_resel_off, 6); - bitvec_set_uint(bv, sp->temp_offs, 3); - bitvec_set_uint(bv, sp->penalty_time, 5); - } else - bitvec_set_bit(bv, L); -} - -/* Append power offset to bitvec */ -static void append_power_offset(struct bitvec *bv, - const struct gsm48_si_power_offset *po) -{ - if (po->present) { - bitvec_set_bit(bv, H); - bitvec_set_uint(bv, po->power_offset, 2); - } else - bitvec_set_bit(bv, L); -} - -/* Append GPRS indicator to bitvec */ -static void append_gprs_ind(struct bitvec *bv, - const struct gsm48_si3_gprs_ind *gi) -{ - if (gi->present) { - bitvec_set_bit(bv, H); - bitvec_set_uint(bv, gi->ra_colour, 3); - /* 0 == SI13 in BCCH Norm, 1 == SI13 sent on BCCH Ext */ - bitvec_set_bit(bv, gi->si13_position); - } else - bitvec_set_bit(bv, L); -} - - -/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */ -int rest_octets_si3(uint8_t *data, const struct gsm48_si_ro_info *si3) -{ - struct bitvec bv; - - memset(&bv, 0, sizeof(bv)); - bv.data = data; - bv.data_len = 4; - - /* Optional Selection Parameters */ - append_selection_params(&bv, &si3->selection_params); - - /* Optional Power Offset */ - append_power_offset(&bv, &si3->power_offset); - - /* Do we have a SI2ter on the BCCH? */ - if (si3->si2ter_indicator) - bitvec_set_bit(&bv, H); - else - bitvec_set_bit(&bv, L); - - /* Early Classmark Sending Control */ - if (si3->early_cm_ctrl) - bitvec_set_bit(&bv, H); - else - bitvec_set_bit(&bv, L); - - /* Do we have a SI Type 9 on the BCCH? */ - if (si3->scheduling.present) { - bitvec_set_bit(&bv, H); - bitvec_set_uint(&bv, si3->scheduling.where, 3); - } else - bitvec_set_bit(&bv, L); - - /* GPRS Indicator */ - append_gprs_ind(&bv, &si3->gprs_ind); - - /* 3G Early Classmark Sending Restriction controlled by - * early_cm_ctrl above */ - bitvec_set_bit(&bv, H); - - if (si3->si2quater_indicator) { - bitvec_set_bit(&bv, H); /* indicator struct present */ - bitvec_set_uint(&bv, 0, 1); /* message is sent on BCCH Norm */ - } - - bitvec_spare_padding(&bv, (bv.data_len*8)-1); - return bv.data_len; -} - -static int append_lsa_params(struct bitvec *bv, - const struct gsm48_lsa_params *lsa_params) -{ - /* FIXME */ - return -1; -} - -/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */ -int rest_octets_si4(uint8_t *data, const struct gsm48_si_ro_info *si4, int len) -{ - struct bitvec bv; - - memset(&bv, 0, sizeof(bv)); - bv.data = data; - bv.data_len = len; - - /* SI4 Rest Octets O */ - append_selection_params(&bv, &si4->selection_params); - append_power_offset(&bv, &si4->power_offset); - append_gprs_ind(&bv, &si4->gprs_ind); - - if (0 /* FIXME */) { - /* H and SI4 Rest Octets S */ - bitvec_set_bit(&bv, H); - - /* LSA Parameters */ - if (si4->lsa_params.present) { - bitvec_set_bit(&bv, H); - append_lsa_params(&bv, &si4->lsa_params); - } else - bitvec_set_bit(&bv, L); - - /* Cell Identity */ - if (1) { - bitvec_set_bit(&bv, H); - bitvec_set_uint(&bv, si4->cell_id, 16); - } else - bitvec_set_bit(&bv, L); - - /* LSA ID Information */ - if (0) { - bitvec_set_bit(&bv, H); - /* FIXME */ - } else - bitvec_set_bit(&bv, L); - } else { - /* L and break indicator */ - bitvec_set_bit(&bv, L); - bitvec_set_bit(&bv, si4->break_ind ? H : L); - } - - return bv.data_len; -} - - -/* GSM 04.18 ETSI TS 101 503 V8.27.0 (2006-05) - - ::= -{L | H } -{L | H } -{ < DTM_support : bit == L > I < DTM_support : bit == H > -< RAC : bit (8) > -< MAX_LAPDm : bit (3) > } -< Band indicator > -{ L | H < GPRS_MS_TXPWR_MAX_CCH : bit (5) > } -; -*/ -int rest_octets_si6(uint8_t *data, bool is1800_net) -{ - struct bitvec bv; - - memset(&bv, 0, sizeof(bv)); - bv.data = data; - bv.data_len = 1; - - /* no PCH/NCH info */ - bitvec_set_bit(&bv, L); - /* no VBS/VGCS options */ - bitvec_set_bit(&bv, L); - /* no DTM_support */ - bitvec_set_bit(&bv, L); - /* band indicator */ - if (is1800_net) - bitvec_set_bit(&bv, L); - else - bitvec_set_bit(&bv, H); - /* no GPRS_MS_TXPWR_MAX_CCH */ - bitvec_set_bit(&bv, L); - - bitvec_spare_padding(&bv, (bv.data_len * 8) - 1); - return bv.data_len; -} - -/* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a: - < GPRS Mobile Allocation IE > ::= - < HSN : bit (6) > - { 0 | 1 < RFL number list : < RFL number list struct > > } - { 0 < MA_LENGTH : bit (6) > - < MA_BITMAP: bit (val(MA_LENGTH) + 1) > - | 1 { 0 | 1 > } } ; - - < RFL number list struct > :: = - < RFL_NUMBER : bit (4) > - { 0 | 1 < RFL number list struct > } ; - < ARFCN index list struct > ::= - < ARFCN_INDEX : bit(6) > - { 0 | 1 < ARFCN index list struct > } ; - */ -static int append_gprs_mobile_alloc(struct bitvec *bv) -{ - /* Hopping Sequence Number */ - bitvec_set_uint(bv, 0, 6); - - if (0) { - /* We want to use a RFL number list */ - bitvec_set_bit(bv, 1); - /* FIXME: RFL number list */ - } else - bitvec_set_bit(bv, 0); - - if (0) { - /* We want to use a MA_BITMAP */ - bitvec_set_bit(bv, 0); - /* FIXME: MA_LENGTH, MA_BITMAP, ... */ - } else { - bitvec_set_bit(bv, 1); - if (0) { - /* We want to provide an ARFCN index list */ - bitvec_set_bit(bv, 1); - /* FIXME */ - } else - bitvec_set_bit(bv, 0); - } - return 0; -} - -static int encode_t3192(unsigned int t3192) -{ - /* See also 3GPP TS 44.060 - Table 12.24.2: GPRS Cell Options information element details */ - if (t3192 == 0) - return 3; - else if (t3192 <= 80) - return 4; - else if (t3192 <= 120) - return 5; - else if (t3192 <= 160) - return 6; - else if (t3192 <= 200) - return 7; - else if (t3192 <= 500) - return 0; - else if (t3192 <= 1000) - return 1; - else if (t3192 <= 1500) - return 2; - else - return -EINVAL; -} - -static int encode_drx_timer(unsigned int drx) -{ - if (drx == 0) - return 0; - else if (drx == 1) - return 1; - else if (drx == 2) - return 2; - else if (drx <= 4) - return 3; - else if (drx <= 8) - return 4; - else if (drx <= 16) - return 5; - else if (drx <= 32) - return 6; - else if (drx <= 64) - return 7; - else - return -EINVAL; -} - -/* GPRS Cell Options as per TS 04.60 Chapter 12.24 - < GPRS Cell Options IE > ::= - < NMO : bit(2) > - < T3168 : bit(3) > - < T3192 : bit(3) > - < DRX_TIMER_MAX: bit(3) > - < ACCESS_BURST_TYPE: bit > - < CONTROL_ACK_TYPE : bit > - < BS_CV_MAX: bit(4) > - { 0 | 1 < PAN_DEC : bit(3) > - < PAN_INC : bit(3) > - < PAN_MAX : bit(3) > - { 0 | 1 < Extension Length : bit(6) > - < bit (val(Extension Length) + 1 - & { < Extension Information > ! { bit ** = } } ; - < Extension Information > ::= - { 0 | 1 < EGPRS_PACKET_CHANNEL_REQUEST : bit > - < BEP_PERIOD : bit(4) > } - < PFC_FEATURE_MODE : bit > - < DTM_SUPPORT : bit > - - ** ; - */ -static int append_gprs_cell_opt(struct bitvec *bv, - const struct gprs_cell_options *gco) -{ - int t3192, drx_timer_max; - - t3192 = encode_t3192(gco->t3192); - if (t3192 < 0) - return t3192; - - drx_timer_max = encode_drx_timer(gco->drx_timer_max); - if (drx_timer_max < 0) - return drx_timer_max; - - bitvec_set_uint(bv, gco->nmo, 2); - - /* See also 3GPP TS 44.060 - Table 12.24.2: GPRS Cell Options information element details */ - bitvec_set_uint(bv, gco->t3168 / 500 - 1, 3); - - bitvec_set_uint(bv, t3192, 3); - bitvec_set_uint(bv, drx_timer_max, 3); - /* ACCESS_BURST_TYPE: Hard-code 8bit */ - bitvec_set_bit(bv, 0); - /* CONTROL_ACK_TYPE: */ - bitvec_set_bit(bv, gco->ctrl_ack_type_use_block); - bitvec_set_uint(bv, gco->bs_cv_max, 4); - - if (0) { - /* hard-code no PAN_{DEC,INC,MAX} */ - bitvec_set_bit(bv, 0); - } else { - /* copied from ip.access BSC protocol trace */ - bitvec_set_bit(bv, 1); - bitvec_set_uint(bv, 1, 3); /* DEC */ - bitvec_set_uint(bv, 1, 3); /* INC */ - bitvec_set_uint(bv, 15, 3); /* MAX */ - } - - if (!gco->ext_info_present) { - /* no extension information */ - bitvec_set_bit(bv, 0); - } else { - /* extension information */ - bitvec_set_bit(bv, 1); - if (!gco->ext_info.egprs_supported) { - /* 6bit length of extension */ - bitvec_set_uint(bv, (1 + 3)-1, 6); - /* EGPRS supported in the cell */ - bitvec_set_bit(bv, 0); - } else { - /* 6bit length of extension */ - bitvec_set_uint(bv, (1 + 5 + 3)-1, 6); - /* EGPRS supported in the cell */ - bitvec_set_bit(bv, 1); - - /* 1bit EGPRS PACKET CHANNEL REQUEST */ - if (gco->supports_egprs_11bit_rach == 0) { - bitvec_set_bit(bv, - gco->ext_info.use_egprs_p_ch_req); - } else { - bitvec_set_bit(bv, 0); - } - - /* 4bit BEP PERIOD */ - bitvec_set_uint(bv, gco->ext_info.bep_period, 4); - } - bitvec_set_bit(bv, gco->ext_info.pfc_supported); - bitvec_set_bit(bv, gco->ext_info.dtm_supported); - bitvec_set_bit(bv, gco->ext_info.bss_paging_coordination); - } - - return 0; -} - -static void append_gprs_pwr_ctrl_pars(struct bitvec *bv, - const struct gprs_power_ctrl_pars *pcp) -{ - bitvec_set_uint(bv, pcp->alpha, 4); - bitvec_set_uint(bv, pcp->t_avg_w, 5); - bitvec_set_uint(bv, pcp->t_avg_t, 5); - bitvec_set_uint(bv, pcp->pc_meas_chan, 1); - bitvec_set_uint(bv, pcp->n_avg_i, 4); -} - -/* Generate SI13 Rest Octests (04.08 Chapter 10.5.2.37b) */ -int rest_octets_si13(uint8_t *data, const struct gsm48_si13_info *si13) -{ - struct bitvec bv; - - memset(&bv, 0, sizeof(bv)); - bv.data = data; - bv.data_len = 20; - - if (0) { - /* No rest octets */ - bitvec_set_bit(&bv, L); - } else { - bitvec_set_bit(&bv, H); - bitvec_set_uint(&bv, si13->bcch_change_mark, 3); - bitvec_set_uint(&bv, si13->si_change_field, 4); - if (1) { - bitvec_set_bit(&bv, 0); - } else { - bitvec_set_bit(&bv, 1); - bitvec_set_uint(&bv, si13->bcch_change_mark, 2); - append_gprs_mobile_alloc(&bv); - } - if (!si13->pbcch_present) { - /* PBCCH not present in cell */ - bitvec_set_bit(&bv, 0); - bitvec_set_uint(&bv, si13->no_pbcch.rac, 8); - bitvec_set_bit(&bv, si13->no_pbcch.spgc_ccch_sup); - bitvec_set_uint(&bv, si13->no_pbcch.prio_acc_thr, 3); - bitvec_set_uint(&bv, si13->no_pbcch.net_ctrl_ord, 2); - append_gprs_cell_opt(&bv, &si13->cell_opts); - append_gprs_pwr_ctrl_pars(&bv, &si13->pwr_ctrl_pars); - } else { - /* PBCCH present in cell */ - bitvec_set_bit(&bv, 1); - bitvec_set_uint(&bv, si13->pbcch.psi1_rep_per, 4); - /* PBCCH Descripiton */ - bitvec_set_uint(&bv, si13->pbcch.pb, 4); - bitvec_set_uint(&bv, si13->pbcch.tsc, 3); - bitvec_set_uint(&bv, si13->pbcch.tn, 3); - switch (si13->pbcch.carrier_type) { - case PBCCH_BCCH: - bitvec_set_bit(&bv, 0); - bitvec_set_bit(&bv, 0); - break; - case PBCCH_ARFCN: - bitvec_set_bit(&bv, 0); - bitvec_set_bit(&bv, 1); - bitvec_set_uint(&bv, si13->pbcch.arfcn, 10); - break; - case PBCCH_MAIO: - bitvec_set_bit(&bv, 1); - bitvec_set_uint(&bv, si13->pbcch.maio, 6); - break; - } - } - /* 3GPP TS 44.018 Release 6 / 10.5.2.37b */ - bitvec_set_bit(&bv, H); /* added Release 99 */ - /* claim our SGSN is compatible with Release 99, as EDGE and EGPRS - * was only added in this Release */ - bitvec_set_bit(&bv, 1); - } - bitvec_spare_padding(&bv, (bv.data_len*8)-1); - return bv.data_len; -} diff --git a/src/libbsc/system_information.c b/src/libbsc/system_information.c deleted file mode 100644 index dcabbbdd1..000000000 --- a/src/libbsc/system_information.c +++ /dev/null @@ -1,1169 +0,0 @@ -/* GSM 04.08 System Information (SI) encoding and decoding - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2008-2010 by Harald Welte - * (C) 2012 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 . - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* - * DCS1800 and PCS1900 have overlapping ARFCNs. We would need to set the - * ARFCN_PCS flag on the 1900 ARFCNs but this would increase cell_alloc - * and other arrays to make sure (ARFCN_PCS + 1024)/8 ARFCNs fit into the - * array. DCS1800 and PCS1900 can not be used at the same time so conserve - * memory and do the below. - */ -static int band_compatible(const struct gsm_bts *bts, int arfcn) -{ - enum gsm_band band = gsm_arfcn2band(arfcn); - - /* normal case */ - if (band == bts->band) - return 1; - /* deal with ARFCN_PCS not set */ - if (band == GSM_BAND_1800 && bts->band == GSM_BAND_1900) - return 1; - - return 0; -} - -static int is_dcs_net(const struct gsm_bts *bts) -{ - if (bts->band == GSM_BAND_850) - return 0; - if (bts->band == GSM_BAND_1900) - return 0; - return 1; -} - -/* Return p(n) for given NR_OF_TDD_CELLS - see Table 9.1.54.1a, 3GPP TS 44.018 */ -unsigned range1024_p(unsigned n) -{ - switch (n) { - case 0: return 0; - case 1: return 10; - case 2: return 19; - case 3: return 28; - case 4: return 36; - case 5: return 44; - case 6: return 52; - case 7: return 60; - case 8: return 67; - case 9: return 74; - case 10: return 81; - case 11: return 88; - case 12: return 95; - case 13: return 102; - case 14: return 109; - case 15: return 116; - case 16: return 122; - default: return 0; - } -} - -/* Return q(m) for given NR_OF_TDD_CELLS - see Table 9.1.54.1b, 3GPP TS 44.018 */ -unsigned range512_q(unsigned m) -{ - switch (m) { - case 0: return 0; - case 1: return 9; - case 2: return 17; - case 3: return 25; - case 4: return 32; - case 5: return 39; - case 6: return 46; - case 7: return 53; - case 8: return 59; - case 9: return 65; - case 10: return 71; - case 11: return 77; - case 12: return 83; - case 13: return 89; - case 14: return 95; - case 15: return 101; - case 16: return 106; - case 17: return 111; - case 18: return 116; - case 19: return 121; - case 20: return 126; - default: return 0; - } -} - -size_t si2q_earfcn_count(const struct osmo_earfcn_si2q *e) -{ - unsigned i, ret = 0; - - if (!e) - return 0; - - for (i = 0; i < e->length; i++) - if (e->arfcn[i] != OSMO_EARFCN_INVALID) - ret++; - - return ret; -} - -/* generate SI2quater messages, return rest octets length of last generated message or negative error code */ -static int make_si2quaters(struct gsm_bts *bts, bool counting) -{ - int rc; - bool memory_exceeded = true; - struct gsm48_system_information_type_2quater *si2q; - - for (bts->si2q_index = 0; bts->si2q_index < SI2Q_MAX_NUM; bts->si2q_index++) { - si2q = GSM_BTS_SI2Q(bts, bts->si2q_index); - if (counting) { /* that's legitimate if we're called for counting purpose: */ - if (bts->si2q_count < bts->si2q_index) - bts->si2q_count = bts->si2q_index; - } else { - memset(si2q, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si2q->header.l2_plen = GSM48_LEN2PLEN(22); - si2q->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si2q->header.skip_indicator = 0; - si2q->header.system_information = GSM48_MT_RR_SYSINFO_2quater; - } - - rc = rest_octets_si2quater(si2q->rest_octets, bts); - if (rc < 0) - return rc; - - if (bts->u_offset >= bts->si_common.uarfcn_length && - bts->e_offset >= si2q_earfcn_count(&bts->si_common.si2quater_neigh_list)) { - memory_exceeded = false; - break; - } - } - - if (memory_exceeded) - return -ENOMEM; - - return rc; -} - -/* we generate SI2q rest octets twice to get proper estimation but it's one time cost anyway */ -uint8_t si2q_num(struct gsm_bts *bts) -{ - int rc = make_si2quaters(bts, true); - uint8_t num = bts->si2q_index + 1; /* number of SI2quater messages */ - - /* N. B: si2q_num() should NEVER be called during actualSI2q rest octets generation - we're not re-entrant because of the following code: */ - bts->u_offset = 0; - bts->e_offset = 0; - - if (rc < 0) - return 0xFF; /* return impossible index as an indicator of error in generating SI2quater */ - - return num; -} - -/* 3GPP TS 44.018, Table 9.1.54.1 - prepend diversity bit to scrambling code */ -static inline uint16_t encode_fdd(uint16_t scramble, bool diversity) -{ - if (diversity) - return scramble | (1 << 9); - return scramble; -} - -int bts_earfcn_add(struct gsm_bts *bts, uint16_t earfcn, uint8_t thresh_hi, uint8_t thresh_lo, uint8_t prio, - uint8_t qrx, uint8_t meas_bw) -{ - struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; - int r = osmo_earfcn_add(e, earfcn, (meas_bw < EARFCN_MEAS_BW_INVALID) ? meas_bw : OSMO_EARFCN_MEAS_INVALID); - - if (r < 0) - return r; - - if (e->thresh_hi && thresh_hi != e->thresh_hi) - r = 1; - - e->thresh_hi = thresh_hi; - - if (thresh_lo != EARFCN_THRESH_LOW_INVALID) { - if (e->thresh_lo_valid && e->thresh_lo != thresh_lo) - r = EARFCN_THRESH_LOW_INVALID; - e->thresh_lo = thresh_lo; - e->thresh_lo_valid = true; - } - - if (qrx != EARFCN_QRXLV_INVALID) { - if (e->qrxlm_valid && e->qrxlm != qrx) - r = EARFCN_QRXLV_INVALID + 1; - e->qrxlm = qrx; - e->qrxlm_valid = true; - } - - if (prio != EARFCN_PRIO_INVALID) { - if (e->prio_valid && e->prio != prio) - r = EARFCN_PRIO_INVALID; - e->prio = prio; - e->prio_valid = true; - } - - return r; -} - -int bts_uarfcn_del(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble) -{ - uint16_t sc0 = encode_fdd(scramble, false), sc1 = encode_fdd(scramble, true), - *ual = bts->si_common.data.uarfcn_list, - *scl = bts->si_common.data.scramble_list; - size_t len = bts->si_common.uarfcn_length, i; - for (i = 0; i < len; i++) { - if (arfcn == ual[i] && (sc0 == scl[i] || sc1 == scl[i])) { - /* we rely on the assumption that (uarfcn, scramble) - tuple is unique in the lists */ - if (i != len - 1) { /* move the tail if necessary */ - memmove(ual + i, ual + i + 1, 2 * (len - i + 1)); - memmove(scl + i, scl + i + 1, 2 * (len - i + 1)); - } - break; - } - } - - if (i == len) - return -EINVAL; - - bts->si_common.uarfcn_length--; - return 0; -} - -int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, bool diversity) -{ - size_t len = bts->si_common.uarfcn_length, i, k = 0; - uint16_t scr, chk, - *ual = bts->si_common.data.uarfcn_list, - *scl = bts->si_common.data.scramble_list, - scramble1 = encode_fdd(scramble, true), - scramble0 = encode_fdd(scramble, false); - - scr = diversity ? scramble1 : scramble0; - chk = diversity ? scramble0 : scramble1; - - if (len == MAX_EARFCN_LIST) - return -ENOMEM; - - for (i = 0; i < len; i++) /* find the position of arfcn if any */ - if (arfcn == ual[i]) - break; - - for (k = 0; i < len; i++) { - if (arfcn == ual[i] && (scr == scl[i] || chk == scl[i])) - return -EADDRINUSE; - if (scr > scl[i]) - k = i + 1; - } - /* we keep lists sorted by scramble code: - insert into appropriate position and move the tail */ - if (len - k) { - memmove(ual + k + 1, ual + k, (len - k) * 2); - memmove(scl + k + 1, scl + k, (len - k) * 2); - } - - ual[k] = arfcn; - scl[k] = scr; - bts->si_common.uarfcn_length++; - - if (si2q_num(bts) <= SI2Q_MAX_NUM) { - bts->si2q_count = si2q_num(bts) - 1; - return 0; - } - - bts_uarfcn_del(bts, arfcn, scramble); - return -ENOSPC; -} - -static inline int use_arfcn(const struct gsm_bts *bts, const bool bis, const bool ter, - const bool pgsm, const int arfcn) -{ - if (bts->force_combined_si) - return !bis && !ter; - if (!bis && !ter && band_compatible(bts, arfcn)) - return 1; - /* Correct but somehow broken with either the nanoBTS or the iPhone5 */ - if (bis && pgsm && band_compatible(bts, arfcn) && (arfcn < 1 || arfcn > 124)) - return 1; - if (ter && !band_compatible(bts, arfcn)) - return 1; - return 0; -} - -/* Frequency Lists as per TS 04.08 10.5.2.13 */ - -/* 10.5.2.13.2: Bit map 0 format */ -static int freq_list_bm0_set_arfcn(uint8_t *chan_list, unsigned int arfcn) -{ - unsigned int byte, bit; - - if (arfcn > 124 || arfcn < 1) { - LOGP(DRR, LOGL_ERROR, "Bitmap 0 only supports ARFCN 1...124\n"); - return -EINVAL; - } - - /* the bitmask is from 1..124, not from 0..123 */ - arfcn--; - - byte = arfcn / 8; - bit = arfcn % 8; - - chan_list[GSM48_CELL_CHAN_DESC_SIZE-1-byte] |= (1 << bit); - - return 0; -} - -/* 10.5.2.13.7: Variable bit map format */ -static int freq_list_bmrel_set_arfcn(uint8_t *chan_list, unsigned int arfcn) -{ - unsigned int byte, bit; - unsigned int min_arfcn; - unsigned int bitno; - - min_arfcn = (chan_list[0] & 1) << 9; - min_arfcn |= chan_list[1] << 1; - min_arfcn |= (chan_list[2] >> 7) & 1; - - /* The lower end of our bitmaks is always implicitly included */ - if (arfcn == min_arfcn) - return 0; - - if (((arfcn - min_arfcn) & 1023) > 111) { - LOGP(DRR, LOGL_ERROR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn); - return -EINVAL; - } - - bitno = (arfcn - min_arfcn) & 1023; - byte = bitno / 8; - bit = bitno % 8; - - chan_list[2 + byte] |= 1 << (7 - bit); - - return 0; -} - -/* generate a variable bitmap */ -static inline int enc_freq_lst_var_bitmap(uint8_t *chan_list, - struct bitvec *bv, const struct gsm_bts *bts, - bool bis, bool ter, int min, bool pgsm) -{ - int i; - - /* set it to 'Variable bitmap format' */ - chan_list[0] = 0x8e; - - chan_list[0] |= (min >> 9) & 1; - chan_list[1] = (min >> 1); - chan_list[2] = (min & 1) << 7; - - for (i = 0; i < bv->data_len*8; i++) { - /* see notes in bitvec2freq_list */ - if (bitvec_get_bit_pos(bv, i) - && ((!bis && !ter && band_compatible(bts,i)) - || (bis && pgsm && band_compatible(bts,i) && (i < 1 || i > 124)) - || (ter && !band_compatible(bts, i)))) { - int rc = freq_list_bmrel_set_arfcn(chan_list, i); - if (rc < 0) - return rc; - } - } - - return 0; -} - -int range_encode(enum gsm48_range r, int *arfcns, int arfcns_used, int *w, - int f0, uint8_t *chan_list) -{ - /* - * Manipulate the ARFCN list according to the rules in J4 depending - * on the selected range. - */ - int rc, f0_included; - - range_enc_filter_arfcns(arfcns, arfcns_used, f0, &f0_included); - - rc = range_enc_arfcns(r, arfcns, arfcns_used, w, 0); - if (rc < 0) - return rc; - - /* Select the range and the amount of bits needed */ - switch (r) { - case ARFCN_RANGE_128: - return range_enc_range128(chan_list, f0, w); - case ARFCN_RANGE_256: - return range_enc_range256(chan_list, f0, w); - case ARFCN_RANGE_512: - return range_enc_range512(chan_list, f0, w); - case ARFCN_RANGE_1024: - return range_enc_range1024(chan_list, f0, f0_included, w); - default: - return -ERANGE; - }; - - return f0_included; -} - -/* generate a frequency list with the range 512 format */ -static inline int enc_freq_lst_range(uint8_t *chan_list, - struct bitvec *bv, const struct gsm_bts *bts, - bool bis, bool ter, bool pgsm) -{ - int arfcns[RANGE_ENC_MAX_ARFCNS]; - int w[RANGE_ENC_MAX_ARFCNS]; - int arfcns_used = 0; - int i, range, f0; - - /* - * Select ARFCNs according to the rules in bitvec2freq_list - */ - for (i = 0; i < bv->data_len * 8; ++i) { - /* More ARFCNs than the maximum */ - if (arfcns_used > ARRAY_SIZE(arfcns)) - return -1; - /* Check if we can select it? */ - if (bitvec_get_bit_pos(bv, i) && use_arfcn(bts, bis, ter, pgsm, i)) - arfcns[arfcns_used++] = i; - } - - /* - * Check if the given list of ARFCNs can be encoded. - */ - range = range_enc_determine_range(arfcns, arfcns_used, &f0); - if (range == ARFCN_RANGE_INVALID) - return -2; - - memset(w, 0, sizeof(w)); - return range_encode(range, arfcns, arfcns_used, w, f0, chan_list); -} - -/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ -static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, - const struct gsm_bts *bts, bool bis, bool ter) -{ - int i, rc, min = -1, max = -1, arfcns = 0; - bool pgsm = false; - memset(chan_list, 0, 16); - - if (bts->band == GSM_BAND_900 - && bts->c0->arfcn >= 1 && bts->c0->arfcn <= 124) - pgsm = true; - /* P-GSM-only handsets only support 'bit map 0 format' */ - if (!bis && !ter && pgsm) { - chan_list[0] = 0; - - for (i = 0; i < bv->data_len*8; i++) { - if (i >= 1 && i <= 124 - && bitvec_get_bit_pos(bv, i)) { - rc = freq_list_bm0_set_arfcn(chan_list, i); - if (rc < 0) - return rc; - } - } - return 0; - } - - for (i = 0; i < bv->data_len*8; i++) { - /* in case of SI2 or SI5 allow all neighbours in same band - * in case of SI*bis, allow neighbours in same band ouside pgsm - * in case of SI*ter, allow neighbours in different bands - */ - if (!bitvec_get_bit_pos(bv, i)) - continue; - if (!use_arfcn(bts, bis, ter, pgsm, i)) - continue; - /* count the arfcns we want to carry */ - arfcns += 1; - - /* 955..1023 < 0..885 */ - if (min < 0) - min = i; - if (i >= 955 && min < 955) - min = i; - if (i >= 955 && min >= 955 && i < min) - min = i; - if (i < 955 && min < 955 && i < min) - min = i; - if (max < 0) - max = i; - if (i < 955 && max >= 955) - max = i; - if (i >= 955 && max >= 955 && i > max) - max = i; - if (i < 955 && max < 955 && i > max) - max = i; - } - - if (max == -1) { - /* Empty set, use 'bit map 0 format' */ - chan_list[0] = 0; - return 0; - } - - /* Now find the best encoding */ - if (((max - min) & 1023) <= 111) - return enc_freq_lst_var_bitmap(chan_list, bv, bts, bis, - ter, min, pgsm); - - /* Attempt to do the range encoding */ - rc = enc_freq_lst_range(chan_list, bv, bts, bis, ter, pgsm); - if (rc >= 0) - return 0; - - LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, arfcns=%d " - "can not generate ARFCN list", min, max, arfcns); - return -EINVAL; -} - -/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ -/* static*/ int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - struct bitvec *bv = &bts->si_common.cell_alloc; - - /* Zero-initialize the bit-vector */ - memset(bv->data, 0, bv->data_len); - - /* first we generate a bitvec of all TRX ARFCN's in our BTS */ - llist_for_each_entry(trx, &bts->trx_list, list) { - unsigned int i, j; - /* Always add the TRX's ARFCN */ - bitvec_set_bit_pos(bv, trx->arfcn, 1); - for (i = 0; i < ARRAY_SIZE(trx->ts); i++) { - struct gsm_bts_trx_ts *ts = &trx->ts[i]; - /* Add any ARFCNs present in hopping channels */ - for (j = 0; j < 1024; j++) { - if (bitvec_get_bit_pos(&ts->hopping.arfcns, j)) - bitvec_set_bit_pos(bv, j, 1); - } - } - } - - /* then we generate a GSM 04.08 frequency list from the bitvec */ - return bitvec2freq_list(chan_list, bv, bts, false, false); -} - -/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ -static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts, - bool si5, bool bis, bool ter) -{ - struct gsm_bts *cur_bts; - struct bitvec *bv; - - if (si5 && bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP) - bv = &bts->si_common.si5_neigh_list; - else - bv = &bts->si_common.neigh_list; - - /* Generate list of neighbor cells if we are in automatic mode */ - if (bts->neigh_list_manual_mode == NL_MODE_AUTOMATIC) { - /* Zero-initialize the bit-vector */ - memset(bv->data, 0, bv->data_len); - - /* first we generate a bitvec of the BCCH ARFCN's in our BSC */ - llist_for_each_entry(cur_bts, &bts->network->bts_list, list) { - if (cur_bts == bts) - continue; - bitvec_set_bit_pos(bv, cur_bts->c0->arfcn, 1); - } - } - - /* then we generate a GSM 04.08 frequency list from the bitvec */ - return bitvec2freq_list(chan_list, bv, bts, bis, ter); -} - -static int list_arfcn(uint8_t *chan_list, uint8_t mask, char *text) -{ - int n = 0, i; - struct gsm_sysinfo_freq freq[1024]; - - memset(freq, 0, sizeof(freq)); - gsm48_decode_freq_list(freq, chan_list, 16, 0xce, 1); - for (i = 0; i < 1024; i++) { - if (freq[i].mask) { - if (!n) - LOGP(DRR, LOGL_INFO, "%s", text); - LOGPC(DRR, LOGL_INFO, " %d", i); - n++; - } - } - if (n) - LOGPC(DRR, LOGL_INFO, "\n"); - - return n; -} - -static int generate_si1(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - int rc; - struct gsm48_system_information_type_1 *si1 = (struct gsm48_system_information_type_1 *) GSM_BTS_SI(bts, t); - - memset(si1, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si1->header.l2_plen = GSM48_LEN2PLEN(21); - si1->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si1->header.skip_indicator = 0; - si1->header.system_information = GSM48_MT_RR_SYSINFO_1; - - rc = generate_cell_chan_list(si1->cell_channel_description, bts); - if (rc < 0) - return rc; - list_arfcn(si1->cell_channel_description, 0xce, "Serving cell:"); - - si1->rach_control = bts->si_common.rach_control; - - /* - * SI1 Rest Octets (10.5.2.32), contains NCH position and band - * indicator but that is not in the 04.08. - */ - rc = rest_octets_si1(si1->rest_octets, NULL, is_dcs_net(bts)); - - return sizeof(*si1) + rc; -} - -static int generate_si2(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - int rc; - struct gsm48_system_information_type_2 *si2 = (struct gsm48_system_information_type_2 *) GSM_BTS_SI(bts, t); - - memset(si2, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si2->header.l2_plen = GSM48_LEN2PLEN(22); - si2->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si2->header.skip_indicator = 0; - si2->header.system_information = GSM48_MT_RR_SYSINFO_2; - - rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, false, false, false); - if (rc < 0) - return rc; - list_arfcn(si2->bcch_frequency_list, 0xce, - "SI2 Neighbour cells in same band:"); - - si2->ncc_permitted = bts->si_common.ncc_permitted; - si2->rach_control = bts->si_common.rach_control; - - return sizeof(*si2); -} - -static int generate_si2bis(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - int rc; - struct gsm48_system_information_type_2bis *si2b = - (struct gsm48_system_information_type_2bis *) GSM_BTS_SI(bts, t); - int n; - - memset(si2b, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si2b->header.l2_plen = GSM48_LEN2PLEN(22); - si2b->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si2b->header.skip_indicator = 0; - si2b->header.system_information = GSM48_MT_RR_SYSINFO_2bis; - - rc = generate_bcch_chan_list(si2b->bcch_frequency_list, bts, false, true, false); - if (rc < 0) - return rc; - n = list_arfcn(si2b->bcch_frequency_list, 0xce, - "Neighbour cells in same band, but outside P-GSM:"); - if (n) { - /* indicate in SI2 and SI2bis: there is an extension */ - struct gsm48_system_information_type_2 *si2 = - (struct gsm48_system_information_type_2 *) GSM_BTS_SI(bts, SYSINFO_TYPE_2); - si2->bcch_frequency_list[0] |= 0x20; - si2b->bcch_frequency_list[0] |= 0x20; - } else - bts->si_valid &= ~(1 << SYSINFO_TYPE_2bis); - - si2b->rach_control = bts->si_common.rach_control; - - return sizeof(*si2b); -} - -static int generate_si2ter(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - int rc; - struct gsm48_system_information_type_2ter *si2t = - (struct gsm48_system_information_type_2ter *) GSM_BTS_SI(bts, t); - int n; - - memset(si2t, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si2t->header.l2_plen = GSM48_LEN2PLEN(22); - si2t->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si2t->header.skip_indicator = 0; - si2t->header.system_information = GSM48_MT_RR_SYSINFO_2ter; - - rc = generate_bcch_chan_list(si2t->ext_bcch_frequency_list, bts, false, false, true); - if (rc < 0) - return rc; - n = list_arfcn(si2t->ext_bcch_frequency_list, 0x8e, - "Neighbour cells in different band:"); - if (!n) - bts->si_valid &= ~(1 << SYSINFO_TYPE_2ter); - - return sizeof(*si2t); -} - -/* SI2quater messages are optional - we only generate them when neighbor UARFCNs or EARFCNs are configured */ -static inline bool si2quater_not_needed(struct gsm_bts *bts) -{ - unsigned i = MAX_EARFCN_LIST; - - if (bts->si_common.si2quater_neigh_list.arfcn) - for (i = 0; i < MAX_EARFCN_LIST; i++) - if (bts->si_common.si2quater_neigh_list.arfcn[i] != OSMO_EARFCN_INVALID) - break; - - if (!bts->si_common.uarfcn_length && i == MAX_EARFCN_LIST) { - bts->si_valid &= ~(1 << SYSINFO_TYPE_2quater); /* mark SI2q as invalid if no (E|U)ARFCNs are present */ - return true; - } - - return false; -} - -static int generate_si2quater(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - int rc; - struct gsm48_system_information_type_2quater *si2q; - - if (si2quater_not_needed(bts)) /* generate rest_octets for SI2q only when necessary */ - return GSM_MACBLOCK_LEN; - - bts->u_offset = 0; - bts->e_offset = 0; - bts->si2q_index = 0; - bts->si2q_count = si2q_num(bts) - 1; - - rc = make_si2quaters(bts, false); - if (rc < 0) - return rc; - - OSMO_ASSERT(bts->si2q_count == bts->si2q_index); - OSMO_ASSERT(bts->si2q_count <= SI2Q_MAX_NUM); - - return sizeof(*si2q) + rc; -} - -static struct gsm48_si_ro_info si_info = { - .selection_params = { - .present = 0, - }, - .power_offset = { - .present = 0, - }, - .si2ter_indicator = 0, - .early_cm_ctrl = 1, - .scheduling = { - .present = 0, - }, - .gprs_ind = { - .si13_position = 0, - .ra_colour = 0, - .present = 1, - }, - .si2quater_indicator = 0, - .lsa_params = { - .present = 0, - }, - .cell_id = 0, /* FIXME: doesn't the bts have this? */ - .break_ind = 0, -}; - -static int generate_si3(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - int rc; - struct gsm48_system_information_type_3 *si3 = (struct gsm48_system_information_type_3 *) GSM_BTS_SI(bts, t); - - memset(si3, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si3->header.l2_plen = GSM48_LEN2PLEN(18); - si3->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si3->header.skip_indicator = 0; - si3->header.system_information = GSM48_MT_RR_SYSINFO_3; - - si3->cell_identity = htons(bts->cell_identity); - gsm48_generate_lai(&si3->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); - si3->control_channel_desc = bts->si_common.chan_desc; - si3->cell_options = bts->si_common.cell_options; - si3->cell_sel_par = bts->si_common.cell_sel_par; - si3->rach_control = bts->si_common.rach_control; - - /* allow/disallow DTXu */ - gsm48_set_dtx(&si3->cell_options, bts->dtxu, bts->dtxu, true); - - if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_2ter)) { - LOGP(DRR, LOGL_INFO, "SI 2ter is included.\n"); - si_info.si2ter_indicator = 1; - } else { - si_info.si2ter_indicator = 0; - } - if (GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_2quater)) { - LOGP(DRR, LOGL_INFO, "SI 2quater is included, based on %zu EARFCNs and %zu UARFCNs.\n", - si2q_earfcn_count(&bts->si_common.si2quater_neigh_list), bts->si_common.uarfcn_length); - si_info.si2quater_indicator = 1; - } else { - si_info.si2quater_indicator = 0; - } - si_info.early_cm_ctrl = bts->early_classmark_allowed; - - /* SI3 Rest Octets (10.5.2.34), containing - CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME - Power Offset, 2ter Indicator, Early Classmark Sending, - Scheduling if and WHERE, GPRS Indicator, SI13 position */ - rc = rest_octets_si3(si3->rest_octets, &si_info); - - return sizeof(*si3) + rc; -} - -static int generate_si4(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - int rc; - struct gsm48_system_information_type_4 *si4 = (struct gsm48_system_information_type_4 *) GSM_BTS_SI(bts, t); - struct gsm_lchan *cbch_lchan; - uint8_t *restoct = si4->data; - - /* length of all IEs present except SI4 rest octets and l2_plen */ - int l2_plen = sizeof(*si4) - 1; - - memset(si4, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si4->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si4->header.skip_indicator = 0; - si4->header.system_information = GSM48_MT_RR_SYSINFO_4; - - gsm48_generate_lai(&si4->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); - si4->cell_sel_par = bts->si_common.cell_sel_par; - si4->rach_control = bts->si_common.rach_control; - - /* Optional: CBCH Channel Description + CBCH Mobile Allocation */ - cbch_lchan = gsm_bts_get_cbch(bts); - if (cbch_lchan) { - struct gsm48_chan_desc cd; - gsm48_lchan2chan_desc(&cd, cbch_lchan); - tv_fixed_put(si4->data, GSM48_IE_CBCH_CHAN_DESC, 3, - (uint8_t *) &cd); - l2_plen += 3 + 1; - restoct += 3 + 1; - /* we don't use hopping and thus don't need a CBCH MA */ - } - - si4->header.l2_plen = GSM48_LEN2PLEN(l2_plen); - - /* SI4 Rest Octets (10.5.2.35), containing - Optional Power offset, GPRS Indicator, - Cell Identity, LSA ID, Selection Parameter */ - rc = rest_octets_si4(restoct, &si_info, (uint8_t *)GSM_BTS_SI(bts, t) + GSM_MACBLOCK_LEN - restoct); - - return l2_plen + 1 + rc; -} - -static int generate_si5(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - struct gsm48_system_information_type_5 *si5; - uint8_t *output = GSM_BTS_SI(bts, t); - int rc, l2_plen = 18; - - memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - /* ip.access nanoBTS needs l2_plen!! */ - switch (bts->type) { - case GSM_BTS_TYPE_NANOBTS: - case GSM_BTS_TYPE_OSMOBTS: - *output++ = GSM48_LEN2PLEN(l2_plen); - l2_plen++; - break; - default: - break; - } - - si5 = (struct gsm48_system_information_type_5 *) GSM_BTS_SI(bts, t); - - /* l2 pseudo length, not part of msg: 18 */ - si5->rr_protocol_discriminator = GSM48_PDISC_RR; - si5->skip_indicator = 0; - si5->system_information = GSM48_MT_RR_SYSINFO_5; - rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, true, false, false); - if (rc < 0) - return rc; - list_arfcn(si5->bcch_frequency_list, 0xce, - "SI5 Neighbour cells in same band:"); - - /* 04.08 9.1.37: L2 Pseudo Length of 18 */ - return l2_plen; -} - -static int generate_si5bis(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - struct gsm48_system_information_type_5bis *si5b; - uint8_t *output = GSM_BTS_SI(bts, t); - int rc, l2_plen = 18; - int n; - - memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - /* ip.access nanoBTS needs l2_plen!! */ - switch (bts->type) { - case GSM_BTS_TYPE_NANOBTS: - case GSM_BTS_TYPE_OSMOBTS: - *output++ = GSM48_LEN2PLEN(l2_plen); - l2_plen++; - break; - default: - break; - } - - si5b = (struct gsm48_system_information_type_5bis *) GSM_BTS_SI(bts, t); - - /* l2 pseudo length, not part of msg: 18 */ - si5b->rr_protocol_discriminator = GSM48_PDISC_RR; - si5b->skip_indicator = 0; - si5b->system_information = GSM48_MT_RR_SYSINFO_5bis; - rc = generate_bcch_chan_list(si5b->bcch_frequency_list, bts, true, true, false); - if (rc < 0) - return rc; - n = list_arfcn(si5b->bcch_frequency_list, 0xce, - "Neighbour cells in same band, but outside P-GSM:"); - if (n) { - /* indicate in SI5 and SI5bis: there is an extension */ - struct gsm48_system_information_type_5 *si5 = - (struct gsm48_system_information_type_5 *) GSM_BTS_SI(bts, SYSINFO_TYPE_5); - si5->bcch_frequency_list[0] |= 0x20; - si5b->bcch_frequency_list[0] |= 0x20; - } else - bts->si_valid &= ~(1 << SYSINFO_TYPE_5bis); - - /* 04.08 9.1.37: L2 Pseudo Length of 18 */ - return l2_plen; -} - -static int generate_si5ter(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - struct gsm48_system_information_type_5ter *si5t; - uint8_t *output = GSM_BTS_SI(bts, t); - int rc, l2_plen = 18; - int n; - - memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - /* ip.access nanoBTS needs l2_plen!! */ - switch (bts->type) { - case GSM_BTS_TYPE_NANOBTS: - case GSM_BTS_TYPE_OSMOBTS: - *output++ = GSM48_LEN2PLEN(l2_plen); - l2_plen++; - break; - default: - break; - } - - si5t = (struct gsm48_system_information_type_5ter *) GSM_BTS_SI(bts, t); - - /* l2 pseudo length, not part of msg: 18 */ - si5t->rr_protocol_discriminator = GSM48_PDISC_RR; - si5t->skip_indicator = 0; - si5t->system_information = GSM48_MT_RR_SYSINFO_5ter; - rc = generate_bcch_chan_list(si5t->bcch_frequency_list, bts, true, false, true); - if (rc < 0) - return rc; - n = list_arfcn(si5t->bcch_frequency_list, 0x8e, - "Neighbour cells in different band:"); - if (!n) - bts->si_valid &= ~(1 << SYSINFO_TYPE_5ter); - - /* 04.08 9.1.37: L2 Pseudo Length of 18 */ - return l2_plen; -} - -static int generate_si6(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - struct gsm48_system_information_type_6 *si6; - uint8_t *output = GSM_BTS_SI(bts, t); - int l2_plen = 11; - int rc; - - memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - /* ip.access nanoBTS needs l2_plen!! */ - switch (bts->type) { - case GSM_BTS_TYPE_NANOBTS: - case GSM_BTS_TYPE_OSMOBTS: - *output++ = GSM48_LEN2PLEN(l2_plen); - l2_plen++; - break; - default: - break; - } - - si6 = (struct gsm48_system_information_type_6 *) GSM_BTS_SI(bts, t); - - /* l2 pseudo length, not part of msg: 11 */ - si6->rr_protocol_discriminator = GSM48_PDISC_RR; - si6->skip_indicator = 0; - si6->system_information = GSM48_MT_RR_SYSINFO_6; - si6->cell_identity = htons(bts->cell_identity); - gsm48_generate_lai(&si6->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); - si6->cell_options = bts->si_common.cell_options; - si6->ncc_permitted = bts->si_common.ncc_permitted; - /* allow/disallow DTXu */ - gsm48_set_dtx(&si6->cell_options, bts->dtxu, bts->dtxu, false); - - /* SI6 Rest Octets: 10.5.2.35a: PCH / NCH info, VBS/VGCS options */ - rc = rest_octets_si6(si6->rest_octets, is_dcs_net(bts)); - - return l2_plen + rc; -} - -static struct gsm48_si13_info si13_default = { - .cell_opts = { - .nmo = GPRS_NMO_II, - .t3168 = 2000, - .t3192 = 1500, - .drx_timer_max = 3, - .bs_cv_max = 15, - .ctrl_ack_type_use_block = true, - .ext_info_present = 0, - .supports_egprs_11bit_rach = 0, - .ext_info = { - /* The values below are just guesses ! */ - .egprs_supported = 0, - .use_egprs_p_ch_req = 1, - .bep_period = 5, - .pfc_supported = 0, - .dtm_supported = 0, - .bss_paging_coordination = 0, - }, - }, - .pwr_ctrl_pars = { - .alpha = 0, /* a = 0.0 */ - .t_avg_w = 16, - .t_avg_t = 16, - .pc_meas_chan = 0, /* downling measured on CCCH */ - .n_avg_i = 8, - }, - .bcch_change_mark = 1, - .si_change_field = 0, - .pbcch_present = 0, - { - .no_pbcch = { - .rac = 0, /* needs to be patched */ - .spgc_ccch_sup = 0, - .net_ctrl_ord = 0, - .prio_acc_thr = 6, - }, - }, -}; - -static int generate_si13(enum osmo_sysinfo_type t, struct gsm_bts *bts) -{ - struct gsm48_system_information_type_13 *si13 = - (struct gsm48_system_information_type_13 *) GSM_BTS_SI(bts, t); - int ret; - - memset(si13, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); - - si13->header.rr_protocol_discriminator = GSM48_PDISC_RR; - si13->header.skip_indicator = 0; - si13->header.system_information = GSM48_MT_RR_SYSINFO_13; - - si13_default.no_pbcch.rac = bts->gprs.rac; - si13_default.no_pbcch.net_ctrl_ord = bts->gprs.net_ctrl_ord; - - si13_default.cell_opts.ctrl_ack_type_use_block = - bts->gprs.ctrl_ack_type_use_block; - - /* Information about the other SIs */ - si13_default.bcch_change_mark = bts->bcch_change_mark; - si13_default.cell_opts.supports_egprs_11bit_rach = - bts->gprs.supports_egprs_11bit_rach; - - ret = rest_octets_si13(si13->rest_octets, &si13_default); - if (ret < 0) - return ret; - - /* length is coded in bit 2 an up */ - si13->header.l2_plen = 0x01; - - return sizeof (*si13) + ret; -} - -typedef int (*gen_si_fn_t)(enum osmo_sysinfo_type t, struct gsm_bts *bts); - -static const gen_si_fn_t gen_si_fn[_MAX_SYSINFO_TYPE] = { - [SYSINFO_TYPE_1] = &generate_si1, - [SYSINFO_TYPE_2] = &generate_si2, - [SYSINFO_TYPE_2bis] = &generate_si2bis, - [SYSINFO_TYPE_2ter] = &generate_si2ter, - [SYSINFO_TYPE_2quater] = &generate_si2quater, - [SYSINFO_TYPE_3] = &generate_si3, - [SYSINFO_TYPE_4] = &generate_si4, - [SYSINFO_TYPE_5] = &generate_si5, - [SYSINFO_TYPE_5bis] = &generate_si5bis, - [SYSINFO_TYPE_5ter] = &generate_si5ter, - [SYSINFO_TYPE_6] = &generate_si6, - [SYSINFO_TYPE_13] = &generate_si13, -}; - -int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type) -{ - gen_si_fn_t gen_si; - - switch (bts->gprs.mode) { - case BTS_GPRS_EGPRS: - si13_default.cell_opts.ext_info_present = 1; - si13_default.cell_opts.ext_info.egprs_supported = 1; - /* fallthrough */ - case BTS_GPRS_GPRS: - si_info.gprs_ind.present = 1; - break; - case BTS_GPRS_NONE: - si_info.gprs_ind.present = 0; - break; - } - - memcpy(&si_info.selection_params, - &bts->si_common.cell_ro_sel_par, - sizeof(struct gsm48_si_selection_params)); - - gen_si = gen_si_fn[si_type]; - if (!gen_si) - return -EINVAL; - - return gen_si(si_type, bts); -} diff --git a/src/libcommon/common_vty.c b/src/libcommon/common_vty.c index 1443791f0..7157e0070 100644 --- a/src/libcommon/common_vty.c +++ b/src/libcommon/common_vty.c @@ -27,8 +27,6 @@ #include #include #include -#include -#include #include #include @@ -44,24 +42,6 @@ int bsc_vty_go_parent(struct vty *vty) vty->node = CONFIG_NODE; vty->index = NULL; break; - case BTS_NODE: - vty->node = GSMNET_NODE; - { - /* set vty->index correctly ! */ - struct gsm_bts *bts = vty->index; - vty->index = bts->network; - vty->index_sub = NULL; - } - break; - case TRX_NODE: - vty->node = BTS_NODE; - { - /* set vty->index correctly ! */ - struct gsm_bts_trx *trx = vty->index; - vty->index = trx->bts; - vty->index_sub = &trx->bts->description; - } - break; case TS_NODE: vty->node = TRX_NODE; { @@ -71,36 +51,6 @@ int bsc_vty_go_parent(struct vty *vty) vty->index_sub = &ts->trx->description; } break; - case OML_NODE: - case OM2K_NODE: - vty->node = ENABLE_NODE; - /* NOTE: this only works because it's not part of the config - * tree, where outer commands are searched via vty_go_parent() - * and only (!) executed when a matching one is found. - */ - talloc_free(vty->index); - vty->index = NULL; - break; - case OM2K_CON_GROUP_NODE: - vty->node = BTS_NODE; - { - struct con_group *cg = vty->index; - struct gsm_bts *bts = cg->bts; - vty->index = bts; - vty->index_sub = &bts->description; - } - break; - case NAT_BSC_NODE: - vty->node = NAT_NODE; - { - struct bsc_config *bsc_config = vty->index; - vty->index = bsc_config->nat; - } - break; - case PGROUP_NODE: - vty->node = NAT_NODE; - vty->index = NULL; - break; case TRUNK_NODE: vty->node = MGCP_NODE; vty->index = NULL; @@ -111,13 +61,8 @@ int bsc_vty_go_parent(struct vty *vty) break; case SMPP_NODE: case MGCP_NODE: - case GBPROXY_NODE: - case SGSN_NODE: - case NAT_NODE: - case BSC_NODE: case MSC_NODE: case MNCC_INT_NODE: - case NITB_NODE: vty->node = CONFIG_NODE; vty->index = NULL; break; @@ -141,8 +86,6 @@ int bsc_vty_is_config_node(struct vty *vty, int node) switch (node) { /* add items that are not config */ - case OML_NODE: - case OM2K_NODE: case SUBSCR_NODE: case CONFIG_NODE: return 0; diff --git a/src/libfilter/Makefile.am b/src/libfilter/Makefile.am deleted file mode 100644 index 6d3db0b90..000000000 --- a/src/libfilter/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - -I$(top_builddir) \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMOSCCP_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -noinst_LIBRARIES = \ - libfilter.a \ - $(NULL) - -libfilter_a_SOURCES = \ - bsc_msg_filter.c \ - bsc_msg_acc.c \ - bsc_msg_vty.c \ - $(NULL) - diff --git a/src/libfilter/bsc_msg_acc.c b/src/libfilter/bsc_msg_acc.c deleted file mode 100644 index a42206db8..000000000 --- a/src/libfilter/bsc_msg_acc.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * (C) 2010-2015 by Holger Hans Peter Freyther - * (C) 2010-2011 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 . - * - */ - -#include -#include -#include - -#include -#include - -#include - -static const struct rate_ctr_desc acc_list_ctr_description[] = { - [ACC_LIST_LOCAL_FILTER] = { "access-list.local-filter", "Rejected by rule for local"}, - [ACC_LIST_GLOBAL_FILTER]= { "access-list.global-filter", "Rejected by rule for global"}, -}; - -static const struct rate_ctr_group_desc bsc_cfg_acc_list_desc = { - .group_name_prefix = "nat.filter", - .group_description = "NAT Access-List Statistics", - .num_ctr = ARRAY_SIZE(acc_list_ctr_description), - .ctr_desc = acc_list_ctr_description, - .class_id = OSMO_STATS_CLASS_GLOBAL, -}; - - -int bsc_msg_acc_lst_check_allow(struct bsc_msg_acc_lst *lst, const char *mi_string) -{ - struct bsc_msg_acc_lst_entry *entry; - - llist_for_each_entry(entry, &lst->fltr_list, list) { - if (!entry->imsi_allow) - continue; - if (regexec(&entry->imsi_allow_re, mi_string, 0, NULL, 0) == 0) - return 0; - } - - return 1; -} - -struct bsc_msg_acc_lst *bsc_msg_acc_lst_find(struct llist_head *head, const char *name) -{ - struct bsc_msg_acc_lst *lst; - - if (!name) - return NULL; - - llist_for_each_entry(lst, head, list) - if (strcmp(lst->name, name) == 0) - return lst; - - return NULL; -} - -struct bsc_msg_acc_lst *bsc_msg_acc_lst_get(void *ctx, struct llist_head *head, const char *name) -{ - struct bsc_msg_acc_lst *lst; - - lst = bsc_msg_acc_lst_find(head, name); - if (lst) - return lst; - - lst = talloc_zero(ctx, struct bsc_msg_acc_lst); - if (!lst) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate access list"); - return NULL; - } - - /* TODO: get the index right */ - lst->stats = rate_ctr_group_alloc(lst, &bsc_cfg_acc_list_desc, 0); - if (!lst->stats) { - talloc_free(lst); - return NULL; - } - - INIT_LLIST_HEAD(&lst->fltr_list); - lst->name = talloc_strdup(lst, name); - llist_add_tail(&lst->list, head); - return lst; -} - -void bsc_msg_acc_lst_delete(struct bsc_msg_acc_lst *lst) -{ - llist_del(&lst->list); - rate_ctr_group_free(lst->stats); - talloc_free(lst); -} - -struct bsc_msg_acc_lst_entry *bsc_msg_acc_lst_entry_create(struct bsc_msg_acc_lst *lst) -{ - struct bsc_msg_acc_lst_entry *entry; - - entry = talloc_zero(lst, struct bsc_msg_acc_lst_entry); - if (!entry) - return NULL; - - entry->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - entry->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - llist_add_tail(&entry->list, &lst->fltr_list); - return entry; -} - diff --git a/src/libfilter/bsc_msg_filter.c b/src/libfilter/bsc_msg_filter.c deleted file mode 100644 index 115d376cb..000000000 --- a/src/libfilter/bsc_msg_filter.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Access filtering - */ -/* - * (C) 2010-2015 by Holger Hans Peter Freyther - * (C) 2010-2012 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 . - * - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -int bsc_filter_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu) -{ - struct bsc_filter_barr_entry *n; - n = rb_entry(root->rb_node, struct bsc_filter_barr_entry, node); - - while (n) { - int rc = strcmp(imsi, n->imsi); - if (rc == 0) { - *cm = n->cm_reject_cause; - *lu = n->lu_reject_cause; - return 1; - } - - n = rb_entry( - (rc < 0) ? n->node.rb_left : n->node.rb_right, - struct bsc_filter_barr_entry, node); - }; - - return 0; -} - -static int insert_barr_node(struct bsc_filter_barr_entry *entry, struct rb_root *root) -{ - struct rb_node **new = &root->rb_node, *parent = NULL; - - while (*new) { - int rc; - struct bsc_filter_barr_entry *this; - this = rb_entry(*new, struct bsc_filter_barr_entry, node); - parent = *new; - - rc = strcmp(entry->imsi, this->imsi); - if (rc < 0) - new = &((*new)->rb_left); - else if (rc > 0) - new = &((*new)->rb_right); - else { - LOGP(DFILTER, LOGL_ERROR, - "Duplicate entry for IMSI(%s)\n", entry->imsi); - talloc_free(entry); - return -1; - } - } - - rb_link_node(&entry->node, parent, new); - rb_insert_color(&entry->node, root); - return 0; -} - -int bsc_filter_barr_adapt(void *ctx, struct rb_root *root, - const struct osmo_config_list *list) -{ - struct osmo_config_entry *cfg_entry; - int err = 0; - - /* free the old data */ - while (!RB_EMPTY_ROOT(root)) { - struct rb_node *node = rb_first(root); - rb_erase(node, root); - talloc_free(node); - } - - if (!list) - return 0; - - /* now adapt the new list */ - llist_for_each_entry(cfg_entry, &list->entry, list) { - struct bsc_filter_barr_entry *entry; - entry = talloc_zero(ctx, struct bsc_filter_barr_entry); - if (!entry) { - LOGP(DFILTER, LOGL_ERROR, - "Allocation of the barr entry failed.\n"); - continue; - } - - entry->imsi = talloc_strdup(entry, cfg_entry->mcc); - entry->cm_reject_cause = atoi(cfg_entry->mnc); - entry->lu_reject_cause = atoi(cfg_entry->option); - err |= insert_barr_node(entry, root); - } - - return err; -} - - -static int lst_check_deny(struct bsc_msg_acc_lst *lst, const char *mi_string, - int *cm_cause, int *lu_cause) -{ - struct bsc_msg_acc_lst_entry *entry; - - llist_for_each_entry(entry, &lst->fltr_list, list) { - if (!entry->imsi_deny) - continue; - if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { - *cm_cause = entry->cm_reject_cause; - *lu_cause = entry->lu_reject_cause; - return 0; - } - } - - return 1; -} - -/* apply white/black list */ -static int auth_imsi(struct bsc_filter_request *req, - const char *imsi, - struct bsc_filter_reject_cause *cause) -{ - /* - * Now apply blacklist/whitelist of the BSC and the NAT. - * 1.) Check the global IMSI barr list - * 2.) Allow directly if the IMSI is allowed at the BSC - * 3.) Reject if the IMSI is not allowed at the BSC - * 4.) Reject if the IMSI not allowed at the global level. - * 5.) Allow directly if the IMSI is allowed at the global level - */ - int cm, lu; - struct bsc_msg_acc_lst *nat_lst = NULL; - struct bsc_msg_acc_lst *bsc_lst = NULL; - - /* 1. global check for barred imsis */ - if (req->black_list && bsc_filter_barr_find(req->black_list, imsi, &cm, &lu)) { - cause->cm_reject_cause = cm; - cause->lu_reject_cause = lu; - LOGP(DFILTER, LOGL_DEBUG, - "Blocking subscriber IMSI %s with CM: %d LU: %d\n", - imsi, cm, lu); - return -4; - } - - - bsc_lst = bsc_msg_acc_lst_find(req->access_lists, req->local_lst_name); - nat_lst = bsc_msg_acc_lst_find(req->access_lists, req->global_lst_name); - - - if (bsc_lst) { - /* 2. BSC allow */ - if (bsc_msg_acc_lst_check_allow(bsc_lst, imsi) == 0) - return 1; - - /* 3. BSC deny */ - if (lst_check_deny(bsc_lst, imsi, &cm, &lu) == 0) { - LOGP(DFILTER, LOGL_ERROR, - "Filtering %s by imsi_deny on config nr: %d.\n", imsi, req->bsc_nr); - rate_ctr_inc(&bsc_lst->stats->ctr[ACC_LIST_LOCAL_FILTER]); - cause->cm_reject_cause = cm; - cause->lu_reject_cause = lu; - return -2; - } - - } - - /* 4. NAT deny */ - if (nat_lst) { - if (lst_check_deny(nat_lst, imsi, &cm, &lu) == 0) { - LOGP(DFILTER, LOGL_ERROR, - "Filtering %s global imsi_deny on bsc nr: %d.\n", imsi, req->bsc_nr); - rate_ctr_inc(&nat_lst->stats->ctr[ACC_LIST_GLOBAL_FILTER]); - cause->cm_reject_cause = cm; - cause->lu_reject_cause = lu; - return -3; - } - } - - return 1; -} - -static int _cr_check_loc_upd(void *ctx, - uint8_t *data, unsigned int length, - char **imsi) -{ - uint8_t mi_type; - struct gsm48_loc_upd_req *lu; - char mi_string[GSM48_MI_SIZE]; - - if (length < sizeof(*lu)) { - LOGP(DFILTER, LOGL_ERROR, - "LU does not fit. Length is %d \n", length); - return -1; - } - - lu = (struct gsm48_loc_upd_req *) data; - mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; - - /* - * We can only deal with the IMSI. This will fail for a phone that - * will send the TMSI of a previous network to us. - */ - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len); - *imsi = talloc_strdup(ctx, mi_string); - return 1; -} - -static int _cr_check_cm_serv_req(void *ctx, - uint8_t *data, unsigned int length, - int *con_type, char **imsi) -{ - static const uint32_t classmark_offset = - offsetof(struct gsm48_service_request, classmark); - - char mi_string[GSM48_MI_SIZE]; - uint8_t mi_type; - int rc; - struct gsm48_service_request *req; - - /* unfortunately in Phase1 the classmark2 length is variable */ - - if (length < sizeof(*req)) { - LOGP(DFILTER, LOGL_ERROR, - "CM Serv Req does not fit. Length is %d\n", length); - return -1; - } - - req = (struct gsm48_service_request *) data; - if (req->cm_service_type == 0x8) - *con_type = FLT_CON_TYPE_SSA; - rc = gsm48_extract_mi((uint8_t *) &req->classmark, - length - classmark_offset, mi_string, &mi_type); - if (rc < 0) { - LOGP(DFILTER, LOGL_ERROR, "Failed to parse the classmark2/mi. error: %d\n", rc); - return -1; - } - - /* we have to let the TMSI or such pass */ - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - *imsi = talloc_strdup(ctx, mi_string); - return 1; -} - -static int _cr_check_pag_resp(void *ctx, - uint8_t *data, unsigned int length, char **imsi) -{ - struct gsm48_pag_resp *resp; - char mi_string[GSM48_MI_SIZE]; - uint8_t mi_type; - - if (length < sizeof(*resp)) { - LOGP(DFILTER, LOGL_ERROR, "PAG RESP does not fit. Length was %d.\n", length); - return -1; - } - - resp = (struct gsm48_pag_resp *) data; - if (gsm48_paging_extract_mi(resp, length, mi_string, &mi_type) < 0) { - LOGP(DFILTER, LOGL_ERROR, "Failed to extract the MI.\n"); - return -1; - } - - /* we need to let it pass for now */ - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - *imsi = talloc_strdup(ctx, mi_string); - return 1; -} - -static int _dt_check_id_resp(struct bsc_filter_request *req, - uint8_t *data, unsigned int length, - struct bsc_filter_state *state, - struct bsc_filter_reject_cause *cause) -{ - char mi_string[GSM48_MI_SIZE]; - uint8_t mi_type; - - if (length < 2) { - LOGP(DFILTER, LOGL_ERROR, "mi does not fit.\n"); - return -1; - } - - if (data[0] < length - 1) { - LOGP(DFILTER, LOGL_ERROR, "mi length too big.\n"); - return -2; - } - - mi_type = data[1] & GSM_MI_TYPE_MASK; - gsm48_mi_to_string(mi_string, sizeof(mi_string), &data[1], data[0]); - - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - state->imsi_checked = 1; - state->imsi = talloc_strdup(req->ctx, mi_string); - return auth_imsi(req, mi_string, cause); -} - - -/* Filter out CR data... */ -int bsc_msg_filter_initial(struct gsm48_hdr *hdr48, size_t hdr48_len, - struct bsc_filter_request *req, - int *con_type, - char **imsi, struct bsc_filter_reject_cause *cause) -{ - int ret = 0; - uint8_t msg_type, proto; - - *con_type = FLT_CON_TYPE_NONE; - cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - *imsi = NULL; - - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - if (proto == GSM48_PDISC_MM && - msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) { - *con_type = FLT_CON_TYPE_LU; - ret = _cr_check_loc_upd(req->ctx, &hdr48->data[0], - hdr48_len - sizeof(*hdr48), imsi); - } else if (proto == GSM48_PDISC_MM && - msg_type == GSM48_MT_MM_CM_SERV_REQ) { - *con_type = FLT_CON_TYPE_CM_SERV_REQ; - ret = _cr_check_cm_serv_req(req->ctx, &hdr48->data[0], - hdr48_len - sizeof(*hdr48), - con_type, imsi); - } else if (proto == GSM48_PDISC_RR && - msg_type == GSM48_MT_RR_PAG_RESP) { - *con_type = FLT_CON_TYPE_PAG_RESP; - ret = _cr_check_pag_resp(req->ctx, &hdr48->data[0], - hdr48_len - sizeof(*hdr48), imsi); - } else { - /* We only want to filter the above, let other things pass */ - *con_type = FLT_CON_TYPE_OTHER; - return 0; - } - - /* check if we are done */ - if (ret != 1) - return ret; - - /* the memory allocation failed */ - if (!*imsi) - return -1; - - /* now check the imsi */ - return auth_imsi(req, *imsi, cause); -} - -int bsc_msg_filter_data(struct gsm48_hdr *hdr48, size_t len, - struct bsc_filter_request *req, - struct bsc_filter_state *state, - struct bsc_filter_reject_cause *cause) -{ - uint8_t msg_type, proto; - - cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - - if (state->imsi_checked) - return 0; - - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - if (proto != GSM48_PDISC_MM || msg_type != GSM48_MT_MM_ID_RESP) - return 0; - - return _dt_check_id_resp(req, &hdr48->data[0], - len - sizeof(*hdr48), state, cause); -} diff --git a/src/libfilter/bsc_msg_vty.c b/src/libfilter/bsc_msg_vty.c deleted file mode 100644 index c342fdca0..000000000 --- a/src/libfilter/bsc_msg_vty.c +++ /dev/null @@ -1,140 +0,0 @@ -/* (C) 2010-2015 by Holger Hans Peter Freyther - * (C) 2010-2013 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 . - * - */ - -#include -#include -#include - -#include - -static struct llist_head *_acc_lst; -static void *_ctx; - -DEFUN(cfg_lst_no, - cfg_lst_no_cmd, - "no access-list NAME", - NO_STR "Remove an access-list by name\n" - "The access-list to remove\n") -{ - struct bsc_msg_acc_lst *acc; - acc = bsc_msg_acc_lst_find(_acc_lst, argv[0]); - if (!acc) - return CMD_WARNING; - - bsc_msg_acc_lst_delete(acc); - return CMD_SUCCESS; -} - -DEFUN(show_acc_lst, - show_acc_lst_cmd, - "show access-list NAME", - SHOW_STR "IMSI access list\n" "Name of the access list\n") -{ - struct bsc_msg_acc_lst *acc; - acc = bsc_msg_acc_lst_find(_acc_lst, argv[0]); - if (!acc) - return CMD_WARNING; - - vty_out(vty, "access-list %s%s", acc->name, VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", acc->stats); - - return CMD_SUCCESS; -} - -DEFUN(cfg_lst_imsi_allow, - cfg_lst_imsi_allow_cmd, - "access-list NAME imsi-allow [REGEXP]", - "Access list commands\n" - "Name of the access list\n" - "Add allowed IMSI to the list\n" - "Regexp for IMSIs\n") -{ - struct bsc_msg_acc_lst *acc; - struct bsc_msg_acc_lst_entry *entry; - - acc = bsc_msg_acc_lst_get(_ctx, _acc_lst, argv[0]); - if (!acc) - return CMD_WARNING; - - entry = bsc_msg_acc_lst_entry_create(acc); - if (!entry) - return CMD_WARNING; - - if (gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]) != 0) - return CMD_WARNING; - return CMD_SUCCESS; -} - -DEFUN(cfg_lst_imsi_deny, - cfg_lst_imsi_deny_cmd, - "access-list NAME imsi-deny [REGEXP] (<0-256>) (<0-256>)", - "Access list commands\n" - "Name of the access list\n" - "Add denied IMSI to the list\n" - "Regexp for IMSIs\n" - "CM Service Reject reason\n" - "LU Reject reason\n") -{ - struct bsc_msg_acc_lst *acc; - struct bsc_msg_acc_lst_entry *entry; - - acc = bsc_msg_acc_lst_get(_ctx, _acc_lst, argv[0]); - if (!acc) - return CMD_WARNING; - - entry = bsc_msg_acc_lst_entry_create(acc); - if (!entry) - return CMD_WARNING; - - if (gsm_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]) != 0) - return CMD_WARNING; - if (argc >= 3) - entry->cm_reject_cause = atoi(argv[2]); - if (argc >= 4) - entry->lu_reject_cause = atoi(argv[3]); - return CMD_SUCCESS; -} - -void bsc_msg_acc_lst_write(struct vty *vty, struct bsc_msg_acc_lst *lst) -{ - struct bsc_msg_acc_lst_entry *entry; - - llist_for_each_entry(entry, &lst->fltr_list, list) { - if (entry->imsi_allow) - vty_out(vty, " access-list %s imsi-allow %s%s", - lst->name, entry->imsi_allow, VTY_NEWLINE); - if (entry->imsi_deny) - vty_out(vty, " access-list %s imsi-deny %s %d %d%s", - lst->name, entry->imsi_deny, - entry->cm_reject_cause, entry->lu_reject_cause, - VTY_NEWLINE); - } -} - -void bsc_msg_lst_vty_init(void *ctx, struct llist_head *lst, int node) -{ - _ctx = ctx; - _acc_lst = lst; - install_element_ve(&show_acc_lst_cmd); - - /* access-list */ - install_element(node, &cfg_lst_imsi_allow_cmd); - install_element(node, &cfg_lst_imsi_deny_cmd); - install_element(node, &cfg_lst_no_cmd); -} diff --git a/src/libmsc/vty_interface_layer3.c b/src/libmsc/vty_interface_layer3.c index 864597d6c..b4c945097 100644 --- a/src/libmsc/vty_interface_layer3.c +++ b/src/libmsc/vty_interface_layer3.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/src/libtrau/Makefile.am b/src/libtrau/Makefile.am deleted file mode 100644 index 46becd6aa..000000000 --- a/src/libtrau/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - -I$(top_builddir) \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMONETIF_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -noinst_LIBRARIES = \ - libtrau.a \ - $(NULL) - -libtrau_a_SOURCES = \ - rtp_proxy.c \ - trau_mux.c \ - trau_upqueue.c \ - $(NULL) diff --git a/src/libtrau/rtp_proxy.c b/src/libtrau/rtp_proxy.c deleted file mode 100644 index 6b38ee5fe..000000000 --- a/src/libtrau/rtp_proxy.c +++ /dev/null @@ -1,764 +0,0 @@ -/* RTP proxy handling for ip.access nanoBTS */ - -/* (C) 2009-2013 by Harald Welte - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include /* gettimeofday() */ -#include /* get..() */ -#include /* clock() */ -#include /* uname() */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* attempt to determine byte order */ -#include -#include - -static LLIST_HEAD(rtp_sockets); - -/* should we mangle the CNAME inside SDES of RTCP packets? We disable - * this by default, as it seems to be not needed */ -static int mangle_rtcp_cname = 0; - -enum rtp_bfd_priv { - RTP_PRIV_NONE, - RTP_PRIV_RTP, - RTP_PRIV_RTCP -}; - -#define RTP_ALLOC_SIZE 1500 - -#define RTCP_TYPE_SDES 202 - -#define RTCP_IE_CNAME 1 - - -#define RTP_VERSION 2 - -/* 33 for FR, all other codecs have smaller size */ -#define MAX_RTP_PAYLOAD_LEN 33 - -/* decode an rtp frame and create a new buffer with payload */ -static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data) -{ - struct msgb *new_msg; - struct gsm_data_frame *frame; - struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data; - struct rtp_x_hdr *rtpxh; - uint8_t *payload, *payload_out; - int payload_len; - int msg_type; - int x_len; - - if (msg->len < 12) { - DEBUGPC(DLMUX, "received RTP frame too short (len = %d)\n", - msg->len); - return -EINVAL; - } - if (rtph->version != RTP_VERSION) { - DEBUGPC(DLMUX, "received RTP version %d not supported.\n", - rtph->version); - return -EINVAL; - } - payload = msg->data + sizeof(struct rtp_hdr) + (rtph->csrc_count << 2); - payload_len = msg->len - sizeof(struct rtp_hdr) - (rtph->csrc_count << 2); - if (payload_len < 0) { - DEBUGPC(DLMUX, "received RTP frame too short (len = %d, " - "csrc count = %d)\n", msg->len, rtph->csrc_count); - return -EINVAL; - } - if (rtph->extension) { - if (payload_len < sizeof(struct rtp_x_hdr)) { - DEBUGPC(DLMUX, "received RTP frame too short for " - "extension header\n"); - return -EINVAL; - } - rtpxh = (struct rtp_x_hdr *)payload; - x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr); - payload += x_len; - payload_len -= x_len; - if (payload_len < 0) { - DEBUGPC(DLMUX, "received RTP frame too short, " - "extension header exceeds frame length\n"); - return -EINVAL; - } - } - if (rtph->padding) { - if (payload_len < 1) { - DEBUGPC(DLMUX, "received RTP frame too short for " - "padding length\n"); - return -EINVAL; - } - payload_len -= payload[payload_len - 1]; - if (payload_len < 0) { - DEBUGPC(DLMUX, "received RTP frame with padding " - "greater than payload\n"); - return -EINVAL; - } - } - - switch (rtph->payload_type) { - case RTP_PT_GSM_FULL: - msg_type = GSM_TCHF_FRAME; - if (payload_len != RTP_LEN_GSM_FULL) { - DEBUGPC(DLMUX, "received RTP full rate frame with " - "payload length != %d (len = %d)\n", - RTP_LEN_GSM_FULL, payload_len); - return -EINVAL; - } - break; - case RTP_PT_GSM_EFR: - msg_type = GSM_TCHF_FRAME_EFR; - if (payload_len != RTP_LEN_GSM_EFR) { - DEBUGPC(DLMUX, "received RTP extended full rate frame " - "with payload length != %d (len = %d)\n", - RTP_LEN_GSM_EFR, payload_len); - return -EINVAL; - } - break; - case RTP_PT_GSM_HALF: - msg_type = GSM_TCHH_FRAME; - if (payload_len != RTP_LEN_GSM_HALF) { - DEBUGPC(DLMUX, "received RTP half rate frame with " - "payload length != %d (len = %d)\n", - RTP_LEN_GSM_HALF, payload_len); - return -EINVAL; - } - break; - case RTP_PT_AMR: - msg_type = GSM_TCH_FRAME_AMR; - break; - default: - DEBUGPC(DLMUX, "received RTP frame with unknown payload " - "type %d\n", rtph->payload_type); - return -EINVAL; - } - - if (payload_len > MAX_RTP_PAYLOAD_LEN || - (rtph->payload_type == RTP_PT_AMR && - payload_len > MAX_RTP_PAYLOAD_LEN - 1)) { - DEBUGPC(DLMUX, "RTP payload too large (%d octets)\n", - payload_len); - return -EINVAL; - } - - /* always allocate for the maximum possible size to avoid - * fragmentation */ - new_msg = msgb_alloc(sizeof(struct gsm_data_frame) + - MAX_RTP_PAYLOAD_LEN+1, "GSM-DATA (TCH)"); - - if (!new_msg) - return -ENOMEM; - frame = (struct gsm_data_frame *) msgb_put(new_msg, sizeof(struct gsm_data_frame)); - frame->msg_type = msg_type; - frame->callref = callref; - if (rtph->payload_type == RTP_PT_AMR) { - /* for FR/HR/EFR the length is implicit. In AMR, we - * need to make it explicit by using the first byte of - * the data[] buffer as length byte */ - uint8_t *data0 = msgb_put(new_msg, 1); - *data0 = payload_len; - } - payload_out = msgb_put(new_msg, payload_len); - memcpy(payload_out, payload, payload_len); - - *data = new_msg; - return 0; -} - -/*! \brief encode and send a rtp frame - * \param[in] rs RTP socket through which we shall send - * \param[in] frame GSM RTP frame to be sent - */ -int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame) -{ - struct rtp_sub_socket *rss = &rs->rtp; - struct msgb *msg; - struct rtp_hdr *rtph; - uint8_t *payload; - int payload_type; - int payload_len; - int duration; /* in samples */ - int is_bfi = 0; - - if (rs->tx_action != RTP_SEND_DOWNSTREAM) { - /* initialize sequences */ - rs->tx_action = RTP_SEND_DOWNSTREAM; - rs->transmit.ssrc = rand(); - rs->transmit.sequence = random(); - rs->transmit.timestamp = random(); - } - - switch (frame->msg_type) { - case GSM_TCHF_FRAME: - payload_type = RTP_PT_GSM_FULL; - payload_len = RTP_LEN_GSM_FULL; - duration = RTP_GSM_DURATION; - break; - case GSM_TCHF_FRAME_EFR: - payload_type = RTP_PT_GSM_EFR; - payload_len = RTP_LEN_GSM_EFR; - duration = RTP_GSM_DURATION; - break; - case GSM_TCHH_FRAME: - payload_type = RTP_PT_GSM_HALF; - payload_len = RTP_LEN_GSM_HALF; - duration = RTP_GSM_DURATION; - break; - case GSM_TCH_FRAME_AMR: - payload_type = RTP_PT_AMR; - payload_len = frame->data[0]; - duration = RTP_GSM_DURATION; - break; - case GSM_BAD_FRAME: - payload_type = 0; - payload_len = 0; - duration = RTP_GSM_DURATION; - is_bfi = 1; - break; - default: - DEBUGPC(DLMUX, "unsupported message type %d\n", - frame->msg_type); - return -EINVAL; - } - - if (payload_len > MAX_RTP_PAYLOAD_LEN) { - DEBUGPC(DLMUX, "RTP payload too large (%d octets)\n", - payload_len); - return -EINVAL; - } - - if (is_bfi) { - /* In case of a bad frame, just count and drop packet. */ - rs->transmit.timestamp += duration; - rs->transmit.sequence++; - return 0; - } - - msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM"); - if (!msg) - return -ENOMEM; - rtph = (struct rtp_hdr *) msgb_put(msg, sizeof(struct rtp_hdr)); - rtph->version = RTP_VERSION; - rtph->padding = 0; - rtph->extension = 0; - rtph->csrc_count = 0; - rtph->marker = 0; - rtph->payload_type = payload_type; - rtph->sequence = htons(rs->transmit.sequence++); - rtph->timestamp = htonl(rs->transmit.timestamp); - rs->transmit.timestamp += duration; - rtph->ssrc = htonl(rs->transmit.ssrc); - - payload = msgb_put(msg, payload_len); - if (frame->msg_type == GSM_TCH_FRAME_AMR) - memcpy(payload, frame->data + 1, payload_len); - else - memcpy(payload, frame->data, payload_len); - msgb_enqueue(&rss->tx_queue, msg); - rss->bfd.when |= BSC_FD_WRITE; - - return 0; -} - -/* iterate over all chunks in one RTCP message, look for CNAME IEs and - * replace all of those with 'new_cname' */ -static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh, - uint16_t *rtcp_len, const char *new_cname) -{ - uint8_t *rtcp_end; - uint8_t *cur = (uint8_t *) rh; - uint8_t tag, len = 0; - - rtcp_end = cur + *rtcp_len; - /* move cur to end of RTP header */ - cur += sizeof(*rh); - - /* iterate over Chunks */ - while (cur+4 < rtcp_end) { - /* skip four bytes SSRC/CSRC */ - cur += 4; - - /* iterate over IE's inside the chunk */ - while (cur+1 < rtcp_end) { - tag = *cur++; - if (tag == 0) { - /* end of chunk, skip additional zero */ - while ((*cur++ == 0) && (cur < rtcp_end)) { } - break; - } - len = *cur++; - - if (tag == RTCP_IE_CNAME) { - /* we've found the CNAME, lets mangle it */ - if (len < strlen(new_cname)) { - /* we need to make more space */ - int increase = strlen(new_cname) - len; - - msgb_push(msg, increase); - memmove(cur+len+increase, cur+len, - rtcp_end - (cur+len)); - /* FIXME: we have to respect RTCP - * padding/alignment rules! */ - len += increase; - *(cur-1) += increase; - rtcp_end += increase; - *rtcp_len += increase; - } - /* copy new CNAME into message */ - memcpy(cur, new_cname, strlen(new_cname)); - /* FIXME: zero the padding in case new CNAME - * is smaller than old one !!! */ - } - cur += len; - } - } - - return 0; -} - -static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs) -{ - struct rtp_sub_socket *rss = &rs->rtcp; - struct rtcp_hdr *rtph; - uint16_t old_len; - int rc; - - if (!mangle_rtcp_cname) - return 0; - - printf("RTCP\n"); - /* iterate over list of RTCP messages */ - rtph = (struct rtcp_hdr *)msg->data; - while ((void *)rtph + sizeof(*rtph) <= (void *)msg->data + msg->len) { - old_len = (ntohs(rtph->length) + 1) * 4; - if ((void *)rtph + old_len > (void *)msg->data + msg->len) { - DEBUGPC(DLMUX, "received RTCP packet too short for " - "length element\n"); - return -EINVAL; - } - if (rtph->type == RTCP_TYPE_SDES) { - char new_cname[255]; - osmo_strlcpy(new_cname, - inet_ntoa(rss->sin_local.sin_addr), - sizeof(new_cname)); - rc = rtcp_sdes_cname_mangle(msg, rtph, &old_len, - new_cname); - if (rc < 0) - return rc; - } - rtph = (void *)rtph + old_len; - } - - return 0; -} - -/* read from incoming RTP/RTCP socket */ -static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss) -{ - int rc; - struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP"); - struct msgb *new_msg; - struct rtp_sub_socket *other_rss; - - if (!msg) - return -ENOMEM; - - rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE); - if (rc == 0) { - rss->bfd.when &= ~BSC_FD_READ; - goto out_free; - } else if (rc < 0) { - /* Ignore "connection refused". this happens, If we open the - * socket faster than the remote side. */ - if (errno == ECONNREFUSED) - goto out_free; - DEBUGPC(DLMUX, "Read of RTP socket (%p) failed (errno %d, " - "%s)\n", rs, errno, strerror(errno)); - rss->bfd.when &= ~BSC_FD_READ; - goto out_free; - } - - msgb_put(msg, rc); - - switch (rs->rx_action) { - case RTP_PROXY: - if (!rs->proxy.other_sock) { - rc = -EIO; - goto out_free; - } - if (rss->bfd.priv_nr == RTP_PRIV_RTP) - other_rss = &rs->proxy.other_sock->rtp; - else if (rss->bfd.priv_nr == RTP_PRIV_RTCP) { - other_rss = &rs->proxy.other_sock->rtcp; - /* modify RTCP SDES CNAME */ - rc = rtcp_mangle(msg, rs); - if (rc < 0) - goto out_free; - } else { - rc = -EINVAL; - goto out_free; - } - msgb_enqueue(&other_rss->tx_queue, msg); - other_rss->bfd.when |= BSC_FD_WRITE; - break; - - case RTP_RECV_UPSTREAM: - if (!rs->receive.callref || !rs->receive.net) { - rc = -EIO; - goto out_free; - } - if (rss->bfd.priv_nr == RTP_PRIV_RTCP) { - if (!mangle_rtcp_cname) { - msgb_free(msg); - break; - } - /* modify RTCP SDES CNAME */ - rc = rtcp_mangle(msg, rs); - if (rc < 0) - goto out_free; - msgb_enqueue(&rss->tx_queue, msg); - rss->bfd.when |= BSC_FD_WRITE; - break; - } - if (rss->bfd.priv_nr != RTP_PRIV_RTP) { - rc = -EINVAL; - goto out_free; - } - rc = rtp_decode(msg, rs->receive.callref, &new_msg); - if (rc < 0) - goto out_free; - msgb_free(msg); - trau_tx_to_mncc(rs->receive.net, new_msg); - break; - - case RTP_NONE: /* if socket exists, but disabled by app */ - msgb_free(msg); - break; - } - - return 0; - -out_free: - msgb_free(msg); - return rc; -} - -/* \brief write from tx_queue to RTP/RTCP socket */ -static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss) -{ - struct msgb *msg; - int written; - - msg = msgb_dequeue(&rss->tx_queue); - if (!msg) { - rss->bfd.when &= ~BSC_FD_WRITE; - return 0; - } - - written = write(rss->bfd.fd, msg->data, msg->len); - if (written < msg->len) { - LOGP(DLMIB, LOGL_ERROR, "short write"); - msgb_free(msg); - return -EIO; - } - - msgb_free(msg); - - return 0; -} - - -/*! \brief callback for the select.c:bfd_* layer */ -static int rtp_bfd_cb(struct osmo_fd *bfd, unsigned int flags) -{ - struct rtp_socket *rs = bfd->data; - struct rtp_sub_socket *rss; - - switch (bfd->priv_nr) { - case RTP_PRIV_RTP: - rss = &rs->rtp; - break; - case RTP_PRIV_RTCP: - rss = &rs->rtcp; - break; - default: - return -EINVAL; - } - - if (flags & BSC_FD_READ) - rtp_socket_read(rs, rss); - - if (flags & BSC_FD_WRITE) - rtp_socket_write(rs, rss); - - return 0; -} - -/*! \brief initialize one rtp sub-socket */ -static void init_rss(struct rtp_sub_socket *rss, - struct rtp_socket *rs, int fd, int priv_nr) -{ - /* initialize bfd */ - rss->bfd.fd = fd; - rss->bfd.data = rs; - rss->bfd.priv_nr = priv_nr; - rss->bfd.cb = rtp_bfd_cb; -} - -/*! \brief create a new RTP/RTCP socket and bind it */ -struct rtp_socket *rtp_socket_create(void) -{ - int rc; - struct rtp_socket *rs; - - DEBUGP(DLMUX, "rtp_socket_create(): "); - - rs = talloc_zero(tall_bsc_ctx, struct rtp_socket); - if (!rs) - return NULL; - - INIT_LLIST_HEAD(&rs->rtp.tx_queue); - INIT_LLIST_HEAD(&rs->rtcp.tx_queue); - - rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (rc < 0) - goto out_free; - - init_rss(&rs->rtp, rs, rc, RTP_PRIV_RTP); - rc = osmo_fd_register(&rs->rtp.bfd); - if (rc < 0) - goto out_rtp_socket; - - rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (rc < 0) - goto out_rtp_bfd; - - init_rss(&rs->rtcp, rs, rc, RTP_PRIV_RTCP); - rc = osmo_fd_register(&rs->rtcp.bfd); - if (rc < 0) - goto out_rtcp_socket; - - DEBUGPC(DLMUX, "success\n"); - - rc = rtp_socket_bind(rs, INADDR_ANY); - if (rc < 0) - goto out_rtcp_bfd; - - return rs; - -out_rtcp_bfd: - osmo_fd_unregister(&rs->rtcp.bfd); -out_rtcp_socket: - close(rs->rtcp.bfd.fd); -out_rtp_bfd: - osmo_fd_unregister(&rs->rtp.bfd); -out_rtp_socket: - close(rs->rtp.bfd.fd); -out_free: - talloc_free(rs); - DEBUGPC(DLMUX, "failed\n"); - return NULL; -} - -static int rtp_sub_socket_bind(struct rtp_sub_socket *rss, uint32_t ip, - uint16_t port) -{ - int rc; - socklen_t alen = sizeof(rss->sin_local); - - rss->sin_local.sin_family = AF_INET; - rss->sin_local.sin_addr.s_addr = htonl(ip); - rss->sin_local.sin_port = htons(port); - rss->bfd.when |= BSC_FD_READ; - - rc = bind(rss->bfd.fd, (struct sockaddr *)&rss->sin_local, - sizeof(rss->sin_local)); - if (rc < 0) - return rc; - - /* retrieve the address we actually bound to, in case we - * passed INADDR_ANY as IP address */ - return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local, - &alen); -} - -#define RTP_PORT_BASE 30000 -static unsigned int next_udp_port = RTP_PORT_BASE; - -/*! \brief bind a RTP socket to a specific local address - * \param[in] rs RTP socket to be bound - * \param[in] ip local IP address to which socket is to be bound - */ -int rtp_socket_bind(struct rtp_socket *rs, uint32_t ip) -{ - int rc = -EIO; - struct in_addr ia; - - ia.s_addr = htonl(ip); - DEBUGP(DLMUX, "rtp_socket_bind(rs=%p, IP=%s): ", rs, - inet_ntoa(ia)); - - /* try to bind to a consecutive pair of ports */ - for (next_udp_port = next_udp_port % 0xffff; - next_udp_port < 0xffff; next_udp_port += 2) { - rc = rtp_sub_socket_bind(&rs->rtp, ip, next_udp_port); - if (rc != 0) - continue; - - rc = rtp_sub_socket_bind(&rs->rtcp, ip, next_udp_port+1); - if (rc == 0) - break; - } - if (rc < 0) { - DEBUGPC(DLMUX, "failed\n"); - return rc; - } - - ia.s_addr = rs->rtp.sin_local.sin_addr.s_addr; - DEBUGPC(DLMUX, "BOUND_IP=%s, BOUND_PORT=%u\n", - inet_ntoa(ia), ntohs(rs->rtp.sin_local.sin_port)); - return ntohs(rs->rtp.sin_local.sin_port); -} - -static int rtp_sub_socket_connect(struct rtp_sub_socket *rss, - uint32_t ip, uint16_t port) -{ - int rc; - socklen_t alen = sizeof(rss->sin_local); - - rss->sin_remote.sin_family = AF_INET; - rss->sin_remote.sin_addr.s_addr = htonl(ip); - rss->sin_remote.sin_port = htons(port); - - rc = connect(rss->bfd.fd, (struct sockaddr *) &rss->sin_remote, - sizeof(rss->sin_remote)); - if (rc < 0) - return rc; - - return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local, - &alen); -} - -/*! \brief 'connect' a RTP socket to a remote peer - * \param[in] rs RTP socket to be connected - * \param[in] ip remote IP address to which to connect - * \param[in] port remote UDP port number to which to connect - */ -int rtp_socket_connect(struct rtp_socket *rs, uint32_t ip, uint16_t port) -{ - int rc; - struct in_addr ia; - - ia.s_addr = htonl(ip); - DEBUGP(DLMUX, "rtp_socket_connect(rs=%p, ip=%s, port=%u)\n", - rs, inet_ntoa(ia), port); - - rc = rtp_sub_socket_connect(&rs->rtp, ip, port); - if (rc < 0) - return rc; - - return rtp_sub_socket_connect(&rs->rtcp, ip, port+1); -} - -/*! \brief bind two RTP/RTCP sockets together in the proxy - * \param[in] this First RTP socket - * \param[in] other Second RTP socket - */ -int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other) -{ - DEBUGP(DLMUX, "rtp_socket_proxy(this=%p, other=%p)\n", - this, other); - - this->rx_action = RTP_PROXY; - this->proxy.other_sock = other; - - other->rx_action = RTP_PROXY; - other->proxy.other_sock = this; - - return 0; -} - -/*! \brief bind RTP/RTCP socket to application, disabling proxy - * \param[in] this RTP socket - * \param[in] net gsm_network argument to trau_tx_to_mncc() - * \param[in] callref callref argument to trau_tx_to_mncc() - */ -int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, - uint32_t callref) -{ - DEBUGP(DLMUX, "rtp_socket_proxy(this=%p, callref=%u)\n", - this, callref); - - if (callref) { - this->rx_action = RTP_RECV_UPSTREAM; - this->receive.net = net; - this->receive.callref = callref; - } else - this->rx_action = RTP_NONE; - - return 0; -} - -static void free_tx_queue(struct rtp_sub_socket *rss) -{ - struct msgb *msg; - - while ((msg = msgb_dequeue(&rss->tx_queue))) - msgb_free(msg); -} - -/*! \brief Free/release a previously allocated RTP socket - * \param[in[] rs RTP/RTCP socket to be released - */ -int rtp_socket_free(struct rtp_socket *rs) -{ - DEBUGP(DLMUX, "rtp_socket_free(rs=%p)\n", rs); - - /* make sure we don't leave references dangling to us */ - if (rs->rx_action == RTP_PROXY && - rs->proxy.other_sock) - rs->proxy.other_sock->proxy.other_sock = NULL; - - osmo_fd_unregister(&rs->rtp.bfd); - close(rs->rtp.bfd.fd); - free_tx_queue(&rs->rtp); - - osmo_fd_unregister(&rs->rtcp.bfd); - close(rs->rtcp.bfd.fd); - free_tx_queue(&rs->rtcp); - - talloc_free(rs); - - return 0; -} diff --git a/src/libtrau/trau_mux.c b/src/libtrau/trau_mux.c deleted file mode 100644 index b37c7650e..000000000 --- a/src/libtrau/trau_mux.c +++ /dev/null @@ -1,547 +0,0 @@ -/* Simple TRAU frame reflector to route voice calls */ - -/* (C) 2009 by Harald Welte - * 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 . - * - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* this corresponds to the bit-lengths of the individual codec - * parameters as indicated in Table 1.1 of TS 06.10 */ -static const uint8_t gsm_fr_map[] = { - 6, 6, 5, 5, 4, 4, 3, 3, - 7, 2, 2, 6, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 7, 2, 2, 6, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 7, 2, 2, 6, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 7, 2, 2, 6, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3 -}; - - -/* - * EFR TRAU parity - * - * g(x) = x^3 + x^1 + 1 - */ -static const struct osmo_crc8gen_code gsm0860_efr_crc3 = { - .bits = 3, - .poly = 0x3, - .init = 0x0, - .remainder = 0x7, -}; - -/* EFR parity bits */ -static inline void efr_parity_bits_1(ubit_t *check_bits, const ubit_t *d_bits) -{ - memcpy(check_bits + 0 , d_bits + 0, 22); - memcpy(check_bits + 22 , d_bits + 24, 3); - check_bits[25] = d_bits[28]; -} - -static inline void efr_parity_bits_2(ubit_t *check_bits, const ubit_t *d_bits) -{ - memcpy(check_bits + 0 , d_bits + 42, 10); - memcpy(check_bits + 10 , d_bits + 90, 2); -} - -static inline void efr_parity_bits_3(ubit_t *check_bits, const ubit_t *d_bits) -{ - memcpy(check_bits + 0 , d_bits + 98, 5); - check_bits[5] = d_bits[104]; - memcpy(check_bits + 6 , d_bits + 143, 2); -} - -static inline void efr_parity_bits_4(ubit_t *check_bits, const ubit_t *d_bits) -{ - memcpy(check_bits + 0 , d_bits + 151, 10); - memcpy(check_bits + 10 , d_bits + 199, 2); -} - -static inline void efr_parity_bits_5(ubit_t *check_bits, const ubit_t *d_bits) -{ - memcpy(check_bits + 0 , d_bits + 207, 5); - check_bits[5] = d_bits[213]; - memcpy(check_bits + 6 , d_bits + 252, 2); -} - -struct map_entry { - struct llist_head list; - struct gsm_e1_subslot src, dst; -}; - -struct upqueue_entry { - struct llist_head list; - struct gsm_network *net; - struct gsm_e1_subslot src; - uint32_t callref; -}; - -static LLIST_HEAD(ss_map); -static LLIST_HEAD(ss_upqueue); - -void *tall_map_ctx, *tall_upq_ctx; - -/* map one particular subslot to another subslot */ -int trau_mux_map(const struct gsm_e1_subslot *src, - const struct gsm_e1_subslot *dst) -{ - struct map_entry *me; - - me = talloc(tall_map_ctx, struct map_entry); - if (!me) { - LOGP(DLMIB, LOGL_FATAL, "Out of memory\n"); - return -ENOMEM; - } - - DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) " - "and (e1=%u,ts=%u,ss=%u)\n", - src->e1_nr, src->e1_ts, src->e1_ts_ss, - dst->e1_nr, dst->e1_ts, dst->e1_ts_ss); - - /* make sure to get rid of any stale old mappings */ - trau_mux_unmap(src, 0); - trau_mux_unmap(dst, 0); - - memcpy(&me->src, src, sizeof(me->src)); - memcpy(&me->dst, dst, sizeof(me->dst)); - llist_add(&me->list, &ss_map); - - return 0; -} - -int trau_mux_map_lchan(const struct gsm_lchan *src, - const struct gsm_lchan *dst) -{ - struct gsm_e1_subslot *src_ss, *dst_ss; - - src_ss = &src->ts->e1_link; - dst_ss = &dst->ts->e1_link; - - return trau_mux_map(src_ss, dst_ss); -} - - -/* unmap one particular subslot from another subslot */ -int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref) -{ - struct map_entry *me, *me2; - struct upqueue_entry *ue, *ue2; - - if (ss) - llist_for_each_entry_safe(me, me2, &ss_map, list) { - if (!memcmp(&me->src, ss, sizeof(*ss)) || - !memcmp(&me->dst, ss, sizeof(*ss))) { - llist_del(&me->list); - return 0; - } - } - llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) { - if (ue->callref == callref) { - llist_del(&ue->list); - return 0; - } - if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) { - llist_del(&ue->list); - return 0; - } - } - return -ENOENT; -} - -/* look-up an enty in the TRAU mux map */ -static struct gsm_e1_subslot * -lookup_trau_mux_map(const struct gsm_e1_subslot *src) -{ - struct map_entry *me; - - llist_for_each_entry(me, &ss_map, list) { - if (!memcmp(&me->src, src, sizeof(*src))) - return &me->dst; - if (!memcmp(&me->dst, src, sizeof(*src))) - return &me->src; - } - return NULL; -} - -/* look-up an enty in the TRAU upqueue */ -struct upqueue_entry * -lookup_trau_upqueue(const struct gsm_e1_subslot *src) -{ - struct upqueue_entry *ue; - - llist_for_each_entry(ue, &ss_upqueue, list) { - if (!memcmp(&ue->src, src, sizeof(*src))) - return ue; - } - return NULL; -} - -static const uint8_t c_bits_check_fr[] = { 0, 0, 0, 1, 0 }; -static const uint8_t c_bits_check_efr[] = { 1, 1, 0, 1, 0 }; - -struct msgb *trau_decode_fr(uint32_t callref, - const struct decoded_trau_frame *tf) -{ - struct msgb *msg; - struct gsm_data_frame *frame; - unsigned char *data; - int i, j, k, l, o; - - msg = msgb_alloc(sizeof(struct gsm_data_frame) + 33, - "GSM-DATA"); - if (!msg) - return NULL; - - frame = (struct gsm_data_frame *)msg->data; - memset(frame, 0, sizeof(struct gsm_data_frame)); - data = frame->data; - data[0] = 0xd << 4; - /* reassemble d-bits */ - i = 0; /* counts bits */ - j = 4; /* counts output bits */ - k = gsm_fr_map[0]-1; /* current number bit in element */ - l = 0; /* counts element bits */ - o = 0; /* offset input bits */ - while (i < 260) { - data[j/8] |= (tf->d_bits[k+o] << (7-(j%8))); - /* to avoid out-of-bounds access in gsm_fr_map[++l] */ - if (i == 259) - break; - if (--k < 0) { - o += gsm_fr_map[l]; - k = gsm_fr_map[++l]-1; - } - i++; - j++; - } - if (tf->c_bits[11]) /* BFI */ - frame->msg_type = GSM_BAD_FRAME; - else - frame->msg_type = GSM_TCHF_FRAME; - frame->callref = callref; - msgb_put(msg, sizeof(struct gsm_data_frame) + 33); - - return msg; -} - -struct msgb *trau_decode_efr(uint32_t callref, - const struct decoded_trau_frame *tf) -{ - struct msgb *msg; - struct gsm_data_frame *frame; - unsigned char *data; - int i, j, rc; - ubit_t check_bits[26]; - - msg = msgb_alloc(sizeof(struct gsm_data_frame) + 31, - "GSM-DATA"); - if (!msg) - return NULL; - - frame = (struct gsm_data_frame *)msg->data; - memset(frame, 0, sizeof(struct gsm_data_frame)); - frame->msg_type = GSM_TCHF_FRAME_EFR; - frame->callref = callref; - msgb_put(msg, sizeof(struct gsm_data_frame) + 31); - - if (tf->c_bits[11]) /* BFI */ - goto bad_frame; - - data = frame->data; - data[0] = 0xc << 4; - /* reassemble d-bits */ - for (i = 1, j = 4; i < 39; i++, j++) - data[j/8] |= (tf->d_bits[i] << (7-(j%8))); - efr_parity_bits_1(check_bits, tf->d_bits); - rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26, - tf->d_bits + 39); - if (rc) - goto bad_frame; - for (i = 42, j = 42; i < 95; i++, j++) - data[j/8] |= (tf->d_bits[i] << (7-(j%8))); - efr_parity_bits_2(check_bits, tf->d_bits); - rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12, - tf->d_bits + 95); - if (rc) - goto bad_frame; - for (i = 98, j = 95; i < 148; i++, j++) - data[j/8] |= (tf->d_bits[i] << (7-(j%8))); - efr_parity_bits_3(check_bits, tf->d_bits); - rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8, - tf->d_bits + 148); - if (rc) - goto bad_frame; - for (i = 151, j = 145; i < 204; i++, j++) - data[j/8] |= (tf->d_bits[i] << (7-(j%8))); - efr_parity_bits_4(check_bits, tf->d_bits); - rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12, - tf->d_bits + 204); - if (rc) - goto bad_frame; - for (i = 207, j = 198; i < 257; i++, j++) - data[j/8] |= (tf->d_bits[i] << (7-(j%8))); - efr_parity_bits_5(check_bits, tf->d_bits); - rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8, - tf->d_bits + 257); - if (rc) - goto bad_frame; - - return msg; - -bad_frame: - frame->msg_type = GSM_BAD_FRAME; - - return msg; -} - -/* we get called by subchan_demux */ -int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, - const uint8_t *trau_bits, int num_bits) -{ - struct decoded_trau_frame tf; - uint8_t trau_bits_out[TRAU_FRAME_BITS]; - struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss); - struct subch_mux *mx; - struct upqueue_entry *ue; - int rc; - - /* decode TRAU, change it to downlink, re-encode */ - rc = decode_trau_frame(&tf, trau_bits); - if (rc) - return rc; - - if (!dst_e1_ss) { - struct msgb *msg = NULL; - /* frame shall be sent to upqueue */ - if (!(ue = lookup_trau_upqueue(src_e1_ss))) - return -EINVAL; - if (!ue->callref) - return -EINVAL; - if (!memcmp(tf.c_bits, c_bits_check_fr, 5)) - msg = trau_decode_fr(ue->callref, &tf); - else if (!memcmp(tf.c_bits, c_bits_check_efr, 5)) - msg = trau_decode_efr(ue->callref, &tf); - else { - DEBUGPC(DLMUX, "illegal trau (C1-C5) %s\n", - osmo_hexdump(tf.c_bits, 5)); - DEBUGPC(DLMUX, "test trau (C1-C5) %s\n", - osmo_hexdump(c_bits_check_efr, 5)); - return -EINVAL; - } - if (!msg) - return -ENOMEM; - trau_tx_to_mncc(ue->net, msg); - - return 0; - } - - mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts); - if (!mx) - return -EINVAL; - - trau_frame_up2down(&tf); - encode_trau_frame(trau_bits_out, &tf); - - /* and send it to the muxer */ - return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, - TRAU_FRAME_BITS); -} - -/* callback when a TRAU frame was received */ -int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len, - void *_priv) -{ - struct e1inp_ts *e1i_ts = _priv; - struct gsm_e1_subslot src_ss; - - src_ss.e1_nr = e1i_ts->line->num; - src_ss.e1_ts = e1i_ts->num; - src_ss.e1_ts_ss = ch; - - return trau_mux_input(&src_ss, data, len); -} - -/* add receiver instance for lchan and callref */ -int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref) -{ - struct gsm_e1_subslot *src_ss; - struct upqueue_entry *ue; - - ue = talloc(tall_upq_ctx, struct upqueue_entry); - if (!ue) - return -ENOMEM; - - src_ss = &lchan->ts->e1_link; - - DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) " - "and (callref 0x%x)\n", - src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss, - callref); - - /* make sure to get rid of any stale old mappings */ - trau_mux_unmap(src_ss, callref); - - memcpy(&ue->src, src_ss, sizeof(ue->src)); - ue->net = lchan->ts->trx->bts->network; - ue->callref = callref; - llist_add(&ue->list, &ss_upqueue); - - return 0; -} - -void trau_encode_fr(struct decoded_trau_frame *tf, - const unsigned char *data) -{ - int i, j, k, l, o; - - /* set c-bits and t-bits */ - tf->c_bits[0] = 1; - tf->c_bits[1] = 1; - tf->c_bits[2] = 1; - tf->c_bits[3] = 0; - tf->c_bits[4] = 0; - memset(&tf->c_bits[5], 0, 6); - memset(&tf->c_bits[11], 1, 10); - memset(&tf->t_bits[0], 1, 4); - /* reassemble d-bits */ - i = 0; /* counts bits */ - j = 4; /* counts input bits */ - k = gsm_fr_map[0]-1; /* current number bit in element */ - l = 0; /* counts element bits */ - o = 0; /* offset output bits */ - while (i < 260) { - tf->d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1; - /* to avoid out-of-bounds access in gsm_fr_map[++l] */ - if (i == 259) - break; - if (--k < 0) { - o += gsm_fr_map[l]; - k = gsm_fr_map[++l]-1; - } - i++; - j++; - } -} - -void trau_encode_efr(struct decoded_trau_frame *tf, - const unsigned char *data) -{ - int i, j; - ubit_t check_bits[26]; - - /* set c-bits and t-bits */ - tf->c_bits[0] = 1; - tf->c_bits[1] = 1; - tf->c_bits[2] = 0; - tf->c_bits[3] = 1; - tf->c_bits[4] = 0; - memset(&tf->c_bits[5], 0, 6); - memset(&tf->c_bits[11], 1, 10); - memset(&tf->t_bits[0], 1, 4); - /* reassemble d-bits */ - tf->d_bits[0] = 1; - for (i = 1, j = 4; i < 39; i++, j++) - tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; - efr_parity_bits_1(check_bits, tf->d_bits); - osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 26, - tf->d_bits + 39); - for (i = 42, j = 42; i < 95; i++, j++) - tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; - efr_parity_bits_2(check_bits, tf->d_bits); - osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12, - tf->d_bits + 95); - for (i = 98, j = 95; i < 148; i++, j++) - tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; - efr_parity_bits_3(check_bits, tf->d_bits); - osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8, - tf->d_bits + 148); - for (i = 151, j = 145; i < 204; i++, j++) - tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; - efr_parity_bits_4(check_bits, tf->d_bits); - osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12, - tf->d_bits + 204); - for (i = 207, j = 198; i < 257; i++, j++) - tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; - efr_parity_bits_5(check_bits, tf->d_bits); - osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8, - tf->d_bits + 257); -} - -int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame) -{ - uint8_t trau_bits_out[TRAU_FRAME_BITS]; - struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link; - struct subch_mux *mx; - struct decoded_trau_frame tf; - - mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts); - if (!mx) - return -EINVAL; - - switch (frame->msg_type) { - case GSM_TCHF_FRAME: - trau_encode_fr(&tf, frame->data); - break; - case GSM_TCHF_FRAME_EFR: - trau_encode_efr(&tf, frame->data); - break; - default: - DEBUGPC(DLMUX, "unsupported message type %d\n", - frame->msg_type); - return -EINVAL; - } - - encode_trau_frame(trau_bits_out, &tf); - - /* and send it to the muxer */ - return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, - TRAU_FRAME_BITS); -} - -/* switch trau muxer to new lchan */ -int switch_trau_mux(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan) -{ - struct gsm_network *net = old_lchan->ts->trx->bts->network; - struct gsm_trans *trans; - - /* look up transaction with TCH frame receive enabled */ - llist_for_each_entry(trans, &net->trans_list, entry) { - if (trans->conn && trans->conn->lchan == old_lchan && trans->tch_recv) { - /* switch */ - trau_recv_lchan(new_lchan, trans->callref); - } - } - - return 0; -} diff --git a/src/libtrau/trau_upqueue.c b/src/libtrau/trau_upqueue.c deleted file mode 100644 index f8edaf0ff..000000000 --- a/src/libtrau/trau_upqueue.c +++ /dev/null @@ -1,27 +0,0 @@ -/* trau_upqueue.c - Pass msgb's up the chain */ - -/* (C) 2010 by Harald Welte - * 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 . - * - */ - -#include -#include - -void trau_tx_to_mncc(struct gsm_network *net, struct msgb *msg) -{ - net->mncc_recv(net, msg); -} diff --git a/src/libvlr/vlr.c b/src/libvlr/vlr.c index d95d1b7ec..a5ea0f6d1 100644 --- a/src/libvlr/vlr.c +++ b/src/libvlr/vlr.c @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include @@ -438,6 +436,20 @@ int vlr_subscr_changed(struct vlr_subscr *vsub) * PDP context data ***********************************************************************/ +#define GSM_APN_LENGTH 102 + +/* 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; +}; + struct sgsn_subscriber_pdp_data * vlr_subscr_pdp_data_alloc(struct vlr_subscr *vsub) { diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am deleted file mode 100644 index 5642fb2ed..000000000 --- a/src/osmo-bsc/Makefile.am +++ /dev/null @@ -1,57 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - -I$(top_builddir) \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) \ - $(LIBOSMOCTRL_CFLAGS) \ - $(LIBOSMONETIF_CFLAGS) \ - $(LIBOSMOSCCP_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMOSIGTRAN_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -bin_PROGRAMS = \ - osmo-bsc \ - $(NULL) - -osmo_bsc_SOURCES = \ - osmo_bsc_main.c \ - osmo_bsc_vty.c \ - osmo_bsc_api.c \ - osmo_bsc_grace.c \ - osmo_bsc_msc.c \ - osmo_bsc_sigtran.c \ - osmo_bsc_filter.c \ - osmo_bsc_bssap.c \ - osmo_bsc_audio.c \ - osmo_bsc_ctrl.c \ - $(NULL) - -# once again since TRAU uses CC symbol :( -osmo_bsc_LDADD = \ - $(top_builddir)/src/libfilter/libfilter.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libmsc/libmsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOSCCP_LIBS) \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOCTRL_LIBS) \ - $(COVERAGE_LDFLAGS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOSIGTRAN_LIBS) \ - $(NULL) diff --git a/src/osmo-bsc/osmo_bsc_api.c b/src/osmo-bsc/osmo_bsc_api.c deleted file mode 100644 index f7343f743..000000000 --- a/src/osmo-bsc/osmo_bsc_api.c +++ /dev/null @@ -1,569 +0,0 @@ -/* (C) 2009-2015 by Holger Hans Peter Freyther - * (C) 2009-2011 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 . - * - */ - -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#define return_when_not_connected(conn) \ - if (!conn->sccp_con) {\ - LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \ - return; \ - } - -#define return_when_not_connected_val(conn, ret) \ - if (!conn->sccp_con) {\ - LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \ - return ret; \ - } - -#define queue_msg_or_return(resp) \ - if (!resp) { \ - LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); \ - return; \ - } \ - osmo_bsc_sigtran_send(conn->sccp_con, resp); - -static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause); -static int complete_layer3(struct gsm_subscriber_connection *conn, - struct msgb *msg, struct bsc_msc_data *msc); - -static uint16_t get_network_code_for_msc(struct bsc_msc_data *msc) -{ - if (msc->core_mnc != -1) - return msc->core_mnc; - return msc->network->network_code; -} - -static uint16_t get_country_code_for_msc(struct bsc_msc_data *msc) -{ - if (msc->core_mcc != -1) - return msc->core_mcc; - return msc->network->country_code; -} - -static uint16_t get_lac_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts) -{ - if (msc->core_lac != -1) - return msc->core_lac; - return bts->location_area_code; -} - -static uint16_t get_ci_for_msc(struct bsc_msc_data *msc, struct gsm_bts *bts) -{ - if (msc->core_ci != -1) - return msc->core_ci; - return bts->cell_identity; -} - -static void bsc_maybe_lu_reject(struct gsm_subscriber_connection *conn, int con_type, int cause) -{ - struct msgb *msg; - - /* ignore cm service request or such */ - if (con_type != FLT_CON_TYPE_LU) - return; - - msg = gsm48_create_loc_upd_rej(cause); - if (!msg) { - LOGP(DMM, LOGL_ERROR, "Failed to create msg for LOCATION UPDATING REJECT.\n"); - return; - } - - msg->lchan = conn->lchan; - gsm0808_submit_dtap(conn, msg, 0, 0); -} - -static int bsc_filter_initial(struct osmo_bsc_data *bsc, - struct bsc_msc_data *msc, - struct gsm_subscriber_connection *conn, - struct msgb *msg, char **imsi, int *con_type, - int *lu_cause) -{ - struct bsc_filter_request req; - struct bsc_filter_reject_cause cause; - struct gsm48_hdr *gh = msgb_l3(msg); - int rc; - - req.ctx = conn; - req.black_list = NULL; - req.access_lists = bsc_access_lists(); - req.local_lst_name = msc->acc_lst_name; - req.global_lst_name = conn->bts->network->bsc_data->acc_lst_name; - req.bsc_nr = 0; - - rc = bsc_msg_filter_initial(gh, msgb_l3len(msg), &req, - con_type, imsi, &cause); - *lu_cause = cause.lu_reject_cause; - return rc; -} - -static int bsc_filter_data(struct gsm_subscriber_connection *conn, - struct msgb *msg, int *lu_cause) -{ - struct bsc_filter_request req; - struct gsm48_hdr *gh = msgb_l3(msg); - struct bsc_filter_reject_cause cause; - int rc; - - req.ctx = conn; - req.black_list = NULL; - req.access_lists = bsc_access_lists(); - req.local_lst_name = conn->sccp_con->msc->acc_lst_name; - req.global_lst_name = conn->bts->network->bsc_data->acc_lst_name; - req.bsc_nr = 0; - - rc = bsc_msg_filter_data(gh, msgb_l3len(msg), &req, - &conn->sccp_con->filter_state, - &cause); - *lu_cause = cause.lu_reject_cause; - return rc; -} - -static void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci) -{ - struct msgb *resp; - return_when_not_connected(conn); - - LOGP(DMSC, LOGL_NOTICE, "Tx MSC SAPI N REJECT DLCI=0x%02x\n", dlci); - - resp = gsm0808_create_sapi_reject(dlci); - queue_msg_or_return(resp); -} - -static void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, - struct msgb *msg, uint8_t chosen_encr) -{ - struct msgb *resp; - return_when_not_connected(conn); - - LOGP(DMSC, LOGL_DEBUG, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n"); - resp = gsm0808_create_cipher_complete(msg, chosen_encr); - queue_msg_or_return(resp); -} - -static void bsc_send_ussd_no_srv(struct gsm_subscriber_connection *conn, - struct msgb *msg, const char *text) -{ - struct gsm48_hdr *gh; - int8_t pdisc; - uint8_t mtype; - int drop_message = 1; - - if (!text) - return; - - if (!msg || msgb_l3len(msg) < sizeof(*gh)) - return; - - gh = msgb_l3(msg); - pdisc = gsm48_hdr_pdisc(gh); - mtype = gsm48_hdr_msg_type(gh); - - /* Is CM service request? */ - if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) { - struct gsm48_service_request *cm; - - cm = (struct gsm48_service_request *) &gh->data[0]; - - /* Is type SMS or call? */ - if (cm->cm_service_type == GSM48_CMSERV_SMS) - drop_message = 0; - else if (cm->cm_service_type == GSM48_CMSERV_MO_CALL_PACKET) - drop_message = 0; - } - - if (drop_message) { - LOGP(DMSC, LOGL_DEBUG, "Skipping (not sending) USSD message: '%s'\n", text); - return; - } - - LOGP(DMSC, LOGL_INFO, "Sending CM Service Accept\n"); - gsm48_tx_mm_serv_ack(conn); - - LOGP(DMSC, LOGL_INFO, "Sending USSD message: '%s'\n", text); - bsc_send_ussd_notify(conn, 1, text); - bsc_send_ussd_release_complete(conn); -} - -/* - * Instruct to reserve data for a new connectiom, create the complete - * layer three message, send it to open the connection. - */ -static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg, - uint16_t chosen_channel) -{ - struct bsc_msc_data *msc; - - LOGP(DMSC, LOGL_INFO, "Tx MSC COMPL L3\n"); - - /* find the MSC link we want to use */ - msc = bsc_find_msc(conn, msg); - if (!msc) { - LOGP(DMSC, LOGL_ERROR, "Failed to find a MSC for a connection.\n"); - bsc_send_ussd_no_srv(conn, msg, - conn->bts->network->bsc_data->ussd_no_msc_txt); - return -1; - } - - return complete_layer3(conn, msg, msc); -} - -static int complete_layer3(struct gsm_subscriber_connection *conn, - struct msgb *msg, struct bsc_msc_data *msc) -{ - int con_type, rc, lu_cause; - char *imsi = NULL; - struct timeval tv; - struct msgb *resp; - uint16_t network_code; - uint16_t country_code; - uint16_t lac; - uint16_t ci; - enum bsc_con ret; - int send_ping = msc->advanced_ping; - - /* Advanced ping/pong handling */ - if (osmo_timer_pending(&msc->pong_timer)) - send_ping = 0; - if (msc->ping_timeout <= 0) - send_ping = 0; - if (send_ping && osmo_timer_remaining(&msc->ping_timer, NULL, &tv) == -1) - send_ping = 0; - - /* Check the filter */ - rc = bsc_filter_initial(msc->network->bsc_data, msc, conn, msg, - &imsi, &con_type, &lu_cause); - if (rc < 0) { - bsc_maybe_lu_reject(conn, con_type, lu_cause); - return BSC_API_CONN_POL_REJECT; - } - - /* allocate resource for a new connection */ - //ret = bsc_create_new_connection(conn, msc, send_ping); - ret = osmo_bsc_sigtran_new_conn(conn, msc); - - if (ret != BSC_CON_SUCCESS) { - /* allocation has failed */ - if (ret == BSC_CON_REJECT_NO_LINK) - bsc_send_ussd_no_srv(conn, msg, msc->ussd_msc_lost_txt); - else if (ret == BSC_CON_REJECT_RF_GRACE) - bsc_send_ussd_no_srv(conn, msg, msc->ussd_grace_txt); - - return BSC_API_CONN_POL_REJECT; - } - - if (imsi) - conn->sccp_con->filter_state.imsi = talloc_steal(conn, imsi); - conn->sccp_con->filter_state.con_type = con_type; - - /* check return value, if failed check msg for and send USSD */ - - network_code = get_network_code_for_msc(conn->sccp_con->msc); - country_code = get_country_code_for_msc(conn->sccp_con->msc); - lac = get_lac_for_msc(conn->sccp_con->msc, conn->bts); - ci = get_ci_for_msc(conn->sccp_con->msc, conn->bts); - - bsc_scan_bts_msg(conn, msg); - - resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci); - if (!resp) { - LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n"); - sccp_connection_free(conn->sccp_con->sccp); - osmo_bsc_sigtran_del_conn(conn->sccp_con); - return BSC_API_CONN_POL_REJECT; - } - - if (osmo_bsc_sigtran_open_conn(conn->sccp_con, resp) != 0) { - sccp_connection_free(conn->sccp_con->sccp); - osmo_bsc_sigtran_del_conn(conn->sccp_con); - msgb_free(resp); - return BSC_API_CONN_POL_REJECT; - } - - return BSC_API_CONN_POL_ACCEPT; -} - -/* - * Plastic surgery... we want to give up the current connection - */ -static int move_to_msc(struct gsm_subscriber_connection *_conn, - struct msgb *msg, struct bsc_msc_data *msc) -{ - struct osmo_bsc_sccp_con *old_con = _conn->sccp_con; - - /* - * 1. Give up the old connection. - * This happens by sending a clear request to the MSC, - * it should end with the MSC releasing the connection. - */ - old_con->conn = NULL; - bsc_clear_request(_conn, 0); - - /* - * 2. Attempt to create a new connection to the local - * MSC. If it fails the caller will need to handle this - * properly. - */ - _conn->sccp_con = NULL; - if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) { - gsm0808_clear(_conn); - bsc_subscr_con_free(_conn); - return 1; - } - - return 2; -} - -static int handle_cc_setup(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - uint8_t pdisc = gsm48_hdr_pdisc(gh); - uint8_t mtype = gsm48_hdr_msg_type(gh); - - struct bsc_msc_data *msc; - struct gsm_mncc_number called; - struct tlv_parsed tp; - unsigned payload_len; - - char _dest_nr[35]; - - /* - * Do we have a setup message here? if not return fast. - */ - if (pdisc != GSM48_PDISC_CC || mtype != GSM48_MT_CC_SETUP) - return 0; - - payload_len = msgb_l3len(msg) - sizeof(*gh); - - tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); - if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) { - LOGP(DMSC, LOGL_ERROR, "Called BCD not present in setup.\n"); - return -1; - } - - memset(&called, 0, sizeof(called)); - gsm48_decode_called(&called, - TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1); - - if (called.plan != 1 && called.plan != 0) - return 0; - - if (called.plan == 1 && called.type == 1) { - _dest_nr[0] = _dest_nr[1] = '0'; - memcpy(_dest_nr + 2, called.number, sizeof(called.number)); - } else - memcpy(_dest_nr, called.number, sizeof(called.number)); - - /* - * Check if the connection should be moved... - */ - llist_for_each_entry(msc, &conn->bts->network->bsc_data->mscs, entry) { - if (msc->type != MSC_CON_TYPE_LOCAL) - continue; - if (!msc->local_pref) - continue; - if (regexec(&msc->local_pref_reg, _dest_nr, 0, NULL, 0) != 0) - continue; - - return move_to_msc(conn, msg, msc); - } - - return 0; -} - - -static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) -{ - int lu_cause; - struct msgb *resp; - return_when_not_connected(conn); - - LOGP(DMSC, LOGL_INFO, "Tx MSC DTAP LINK_ID=0x%02x\n", link_id); - - /* - * We might want to move this connection to a new MSC. Ask someone - * to handle it. If it was handled we will return. - */ - if (handle_cc_setup(conn, msg) >= 1) - return; - - /* Check the filter */ - if (bsc_filter_data(conn, msg, &lu_cause) < 0) { - bsc_maybe_lu_reject(conn, - conn->sccp_con->filter_state.con_type, - lu_cause); - bsc_clear_request(conn, 0); - return; - } - - bsc_scan_bts_msg(conn, msg); - - resp = gsm0808_create_dtap(msg, link_id); - queue_msg_or_return(resp); -} - -static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_cause, - uint8_t chosen_channel, uint8_t encr_alg_id, - uint8_t speech_model) -{ - struct msgb *resp; - return_when_not_connected(conn); - - if (is_ipaccess_bts(conn->bts) && conn->sccp_con->rtp_ip) { - /* NOTE: In a network that makes use of an IPA base station - * and AoIP, we have to wait until the BTS reports its RTP - * IP/Port combination back to BSC via RSL. Unfortunately, the - * IPA protocol sends its Abis assignment complete message - * before it sends its RTP IP/Port via IPACC. So we will now - * postpone the AoIP assignment completed message until we - * know the RTP IP/Port combination. */ - LOGP(DMSC, LOGL_INFO, "POSTPONE MSC ASSIGN COMPL\n"); - conn->lchan->abis_ip.ass_compl.rr_cause = rr_cause; - conn->lchan->abis_ip.ass_compl.chosen_channel = chosen_channel; - conn->lchan->abis_ip.ass_compl.encr_alg_id = encr_alg_id; - conn->lchan->abis_ip.ass_compl.speech_mode = speech_model; - conn->lchan->abis_ip.ass_compl.valid = true; - - } else { - /* NOTE: Send the A assignment complete message immediately. */ - LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL\n"); - resp = gsm0808_create_assignment_completed(rr_cause, chosen_channel, - encr_alg_id, speech_model); - queue_msg_or_return(resp); - } -} - -static void bsc_assign_fail(struct gsm_subscriber_connection *conn, - uint8_t cause, uint8_t *rr_cause) -{ - struct msgb *resp; - return_when_not_connected(conn); - - LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN FAIL\n"); - - resp = gsm0808_create_assignment_failure(cause, rr_cause); - queue_msg_or_return(resp); -} - -static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause) -{ - struct osmo_bsc_sccp_con *sccp; - struct msgb *resp; - return_when_not_connected_val(conn, 1); - - LOGP(DMSC, LOGL_INFO, "Tx MSC CLEAR REQUEST\n"); - - /* - * Remove the connection from BSC<->SCCP part, the SCCP part - * will either be cleared by channel release or MSC disconnect - */ - sccp = conn->sccp_con; - sccp->conn = NULL; - conn->sccp_con = NULL; - - resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE); - if (!resp) { - LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); - return 1; - } - - osmo_bsc_sigtran_send(sccp, resp); - return 1; -} - -static void bsc_cm_update(struct gsm_subscriber_connection *conn, - const uint8_t *cm2, uint8_t cm2_len, - const uint8_t *cm3, uint8_t cm3_len) -{ - struct msgb *resp; - return_when_not_connected(conn); - - resp = gsm0808_create_classmark_update(cm2, cm2_len, cm3, cm3_len); - - queue_msg_or_return(resp); -} - -static void bsc_mr_config(struct gsm_subscriber_connection *conn, - struct gsm_lchan *lchan, int full_rate) -{ - struct bsc_msc_data *msc; - struct gsm48_multi_rate_conf *ms_conf, *bts_conf; - - if (!conn->sccp_con) { - LOGP(DMSC, LOGL_ERROR, - "No msc data available on conn %p. Audio will be broken.\n", - conn); - return; - } - - msc = conn->sccp_con->msc; - - /* initialize the data structure */ - lchan->mr_ms_lv[0] = sizeof(*ms_conf); - lchan->mr_bts_lv[0] = sizeof(*bts_conf); - ms_conf = (struct gsm48_multi_rate_conf *) &lchan->mr_ms_lv[1]; - bts_conf = (struct gsm48_multi_rate_conf *) &lchan->mr_bts_lv[1]; - memset(ms_conf, 0, sizeof(*ms_conf)); - memset(bts_conf, 0, sizeof(*bts_conf)); - - bts_conf->ver = ms_conf->ver = 1; - bts_conf->icmi = ms_conf->icmi = 1; - - /* maybe gcc see's it is copy of _one_ byte */ - bts_conf->m4_75 = ms_conf->m4_75 = msc->amr_conf.m4_75; - bts_conf->m5_15 = ms_conf->m5_15 = msc->amr_conf.m5_15; - bts_conf->m5_90 = ms_conf->m5_90 = msc->amr_conf.m5_90; - bts_conf->m6_70 = ms_conf->m6_70 = msc->amr_conf.m6_70; - bts_conf->m7_40 = ms_conf->m7_40 = msc->amr_conf.m7_40; - bts_conf->m7_95 = ms_conf->m7_95 = msc->amr_conf.m7_95; - if (full_rate) { - bts_conf->m10_2 = ms_conf->m10_2 = msc->amr_conf.m10_2; - bts_conf->m12_2 = ms_conf->m12_2 = msc->amr_conf.m12_2; - } - - /* now copy this into the bts structure */ - memcpy(lchan->mr_bts_lv, lchan->mr_ms_lv, sizeof(lchan->mr_ms_lv)); -} - -static struct bsc_api bsc_handler = { - .sapi_n_reject = bsc_sapi_n_reject, - .cipher_mode_compl = bsc_cipher_mode_compl, - .compl_l3 = bsc_compl_l3, - .dtap = bsc_dtap, - .assign_compl = bsc_assign_compl, - .assign_fail = bsc_assign_fail, - .clear_request = bsc_clear_request, - .classmark_chg = bsc_cm_update, - .mr_config = bsc_mr_config, -}; - -struct bsc_api *osmo_bsc_api() -{ - return &bsc_handler; -} diff --git a/src/osmo-bsc/osmo_bsc_audio.c b/src/osmo-bsc/osmo_bsc_audio.c deleted file mode 100644 index b4ffa88f1..000000000 --- a/src/osmo-bsc/osmo_bsc_audio.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * ipaccess audio handling - * - * (C) 2009-2010 by Holger Hans Peter Freyther - * (C) 2009-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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Generate and send assignment complete message */ -static int send_aoip_ass_compl(struct gsm_subscriber_connection *conn, struct gsm_lchan *lchan) -{ - struct msgb *resp; - struct sockaddr_storage rtp_addr; - struct sockaddr_in rtp_addr_in; - struct gsm0808_speech_codec sc; - - OSMO_ASSERT(lchan->abis_ip.ass_compl.valid == true); - - /* Package RTP-Address data */ - memset(&rtp_addr_in, 0, sizeof(rtp_addr_in)); - rtp_addr_in.sin_family = AF_INET; - rtp_addr_in.sin_port = htons(lchan->abis_ip.bound_port); - rtp_addr_in.sin_addr.s_addr = htonl(lchan->abis_ip.bound_ip); - memset(&rtp_addr, 0, sizeof(rtp_addr)); - memcpy(&rtp_addr, &rtp_addr_in, sizeof(rtp_addr_in)); - - /* Extrapolate speech codec from speech mode */ - gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode); - - /* Generate message */ - resp = gsm0808_create_ass_compl(lchan->abis_ip.ass_compl.rr_cause, - lchan->abis_ip.ass_compl.chosen_channel, - lchan->abis_ip.ass_compl.encr_alg_id, - lchan->abis_ip.ass_compl.speech_mode, - &rtp_addr, - &sc, - NULL); - - if (!resp) { - LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message!\n"); \ - return -EINVAL; - } - - return osmo_bsc_sigtran_send(conn->sccp_con, resp); -} - -static int handle_abisip_signal(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_subscriber_connection *con; - struct gsm_lchan *lchan = signal_data; - int rc; - uint32_t rtp_ip; - - if (subsys != SS_ABISIP) - return 0; - - con = lchan->conn; - if (!con || !con->sccp_con) - return 0; - - switch (signal) { - case S_ABISIP_CRCX_ACK: - /* - * TODO: handle handover here... then the audio should go to - * the old mgcp port.. - */ - - /* we can ask it to connect now */ - LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n", - con->sccp_con->rtp_port, lchan->abis_ip.conn_id); - - /* If AoIP is in use, the rtp_ip, which has been communicated - * via the A interface as connect_ip */ - if(con->sccp_con->rtp_ip) - rtp_ip = con->sccp_con->rtp_ip; - else - rtp_ip = ntohl(INADDR_ANY); - - rc = rsl_ipacc_mdcx(lchan, rtp_ip, - con->sccp_con->rtp_port, - lchan->abis_ip.rtp_payload2); - if (rc < 0) { - LOGP(DMSC, LOGL_ERROR, "Failed to send MDCX: %d\n", rc); - return rc; - } - break; - - case S_ABISIP_MDCX_ACK: - if (con->ho_lchan) { - /* NOTE: When an ho_lchan exists, the MDCX is part of an - * handover operation (intra-bsc). This means we will not - * inform the MSC about the event, which means that no - * assignment complete message is transmitted */ - LOGP(DMSC, LOGL_INFO," RTP connection handover complete\n"); - } else if (is_ipaccess_bts(con->bts) && con->sccp_con->rtp_ip) { - /* NOTE: This is only relevant on AoIP networks with - * IPA based base stations. See also osmo_bsc_api.c, - * function bsc_assign_compl() */ - LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL (POSTPONED)\n"); - if (send_aoip_ass_compl(con, lchan) != 0) - return -EINVAL; - } - break; - break; - } - - return 0; -} - -int osmo_bsc_audio_init(struct gsm_network *net) -{ - osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, net); - return 0; -} diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c deleted file mode 100644 index 9a5288bdc..000000000 --- a/src/osmo-bsc/osmo_bsc_bssap.c +++ /dev/null @@ -1,721 +0,0 @@ -/* GSM 08.08 BSSMAP handling */ -/* (C) 2009-2012 by Holger Hans Peter Freyther - * (C) 2009-2012 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define IP_V4_ADDR_LEN 4 - -/* - * helpers for the assignment command - */ - -/* Helper function for match_codec_pref(), looks up a matching permitted speech - * value for a given msc audio codec pref */ -enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support - *audio) -{ - if (audio->hr) { - switch (audio->ver) { - case 1: - return GSM0808_PERM_HR1; - break; - case 2: - return GSM0808_PERM_HR2; - break; - case 3: - return GSM0808_PERM_HR3; - break; - default: - LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", - audio->ver); - return GSM0808_PERM_FR1; - } - } else { - switch (audio->ver) { - case 1: - return GSM0808_PERM_FR1; - break; - case 2: - return GSM0808_PERM_FR2; - break; - case 3: - return GSM0808_PERM_FR3; - break; - default: - LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", - audio->ver); - return GSM0808_PERM_HR1; - } - } -} - -/* Helper function for match_codec_pref(), looks up a matching chan mode for - * a given permitted speech value */ -enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech) -{ - switch (speech) { - case GSM0808_PERM_HR1: - case GSM0808_PERM_FR1: - return GSM48_CMODE_SPEECH_V1; - break; - case GSM0808_PERM_HR2: - case GSM0808_PERM_FR2: - return GSM48_CMODE_SPEECH_EFR; - break; - case GSM0808_PERM_HR3: - case GSM0808_PERM_FR3: - return GSM48_CMODE_SPEECH_AMR; - break; - default: - LOGP(DMSC, LOGL_FATAL, - "Unsupported permitted speech selected, assuming AMR as channel mode...\n"); - return GSM48_CMODE_SPEECH_AMR; - } -} - -/* Helper function for match_codec_pref(), tests if a given audio support - * matches one of the permitted speech settings of the channel type element. - * The matched permitted speech value is then also compared against the - * speech codec list. (optional, only relevant for AoIP) */ -static bool test_codec_pref(const struct gsm0808_channel_type *ct, - const struct gsm0808_speech_codec_list *scl, - uint8_t perm_spch) -{ - unsigned int i; - bool match = false; - struct gsm0808_speech_codec sc; - int rc; - - /* Try to finde the given permitted speech value in the - * codec list of the channel type element */ - for (i = 0; i < ct->perm_spch_len; i++) { - if (ct->perm_spch[i] == perm_spch) { - match = true; - break; - } - } - - /* If we do not have a speech codec list to test against, - * we just exit early (will be always the case in non-AoIP networks) */ - if (!scl) - return match; - - /* If we failed to match until here, there is no - * point in testing further */ - if (match == false) - return false; - - /* Extrapolate speech codec data */ - rc = gsm0808_speech_codec_from_chan_type(&sc, perm_spch); - if (rc < 0) - return false; - - /* Try to find extrapolated speech codec data in - * the speech codec list */ - for (i = 0; i < scl->len; i++) { - if (memcmp(&sc, &scl->codec[i], sizeof(sc)) == 0) - return true; - } - - return false; -} - -/* Helper function for bssmap_handle_assignm_req(), matches the codec - * preferences from the MSC with the codec preferences */ -static int match_codec_pref(int *full_rate, enum gsm48_chan_mode *chan_mode, - const struct gsm0808_channel_type *ct, - const struct gsm0808_speech_codec_list *scl, - const struct bsc_msc_data *msc) -{ - unsigned int i; - uint8_t perm_spch; - bool match = false; - - for (i = 0; i < msc->audio_length; i++) { - perm_spch = audio_support_to_gsm88(msc->audio_support[i]); - if (test_codec_pref(ct, scl, perm_spch)) { - match = true; - break; - } - } - - /* Exit without result, in case no match can be deteched */ - if (!match) { - *full_rate = -1; - *chan_mode = GSM48_CMODE_SIGN; - return -1; - } - - /* Check if the result is a half or full rate codec */ - if (perm_spch == GSM0808_PERM_HR1 || perm_spch == GSM0808_PERM_HR2 - || perm_spch == GSM0808_PERM_HR3 || perm_spch == GSM0808_PERM_HR4 - || perm_spch == GSM0808_PERM_HR6) - *full_rate = 0; - else - *full_rate = 1; - - /* Lookup a channel mode for the selected codec */ - *chan_mode = gsm88_to_chan_mode(perm_spch); - - return 0; -} - -static int bssmap_handle_reset_ack(struct bsc_msc_data *msc, - struct msgb *msg, unsigned int length) -{ - LOGP(DMSC, LOGL_NOTICE, "RESET ACK from MSC: %s\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), - &msc->a.msc_addr)); - - /* Inform the FSM that controls the RESET/RESET-ACK procedure - * that we have successfully received the reset-ack message */ - a_reset_ack_confirm(msc->a.reset); - - return 0; -} - -/* Handle MSC sided reset */ -static int bssmap_handle_reset(struct bsc_msc_data *msc, - struct msgb *msg, unsigned int length) -{ - LOGP(DMSC, LOGL_NOTICE, "RESET from MSC: %s\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), - &msc->a.msc_addr)); - - /* Instruct the bsc to close all open sigtran connections and to - * close all active channels on the BTS side as well */ - osmo_bsc_sigtran_reset(msc); - - /* Inform the MSC that we have received the reset request and - * that we acted accordingly */ - osmo_bsc_sigtran_tx_reset_ack(msc); - - return 0; -} - -/* GSM 08.08 § 3.2.1.19 */ -static int bssmap_handle_paging(struct bsc_msc_data *msc, - struct msgb *msg, unsigned int payload_length) -{ - struct bsc_subscr *subscr; - struct tlv_parsed tp; - char mi_string[GSM48_MI_SIZE]; - uint32_t tmsi = GSM_RESERVED_TMSI; - unsigned int lac = GSM_LAC_RESERVED_ALL_BTS; - uint8_t data_length; - const uint8_t *data; - uint8_t chan_needed = RSL_CHANNEED_ANY; - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0); - - if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) { - LOGP(DMSC, LOGL_ERROR, "Mandatory IMSI not present.\n"); - return -1; - } else if ((TLVP_VAL(&tp, GSM0808_IE_IMSI)[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) { - LOGP(DMSC, LOGL_ERROR, "Wrong content in the IMSI\n"); - return -1; - } - - if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) { - LOGP(DMSC, LOGL_ERROR, "Mandatory CELL IDENTIFIER LIST not present.\n"); - return -1; - } - - if (TLVP_PRESENT(&tp, GSM0808_IE_TMSI) && - TLVP_LEN(&tp, GSM0808_IE_TMSI) == 4) { - tmsi = ntohl(tlvp_val32_unal(&tp, GSM0808_IE_TMSI)); - } - - /* - * parse the IMSI - */ - gsm48_mi_to_string(mi_string, sizeof(mi_string), - TLVP_VAL(&tp, GSM0808_IE_IMSI), TLVP_LEN(&tp, GSM0808_IE_IMSI)); - - /* - * parse the cell identifier list - */ - data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); - data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); - - /* - * Support paging to all network or one BTS at one LAC - */ - if (data_length == 3 && data[0] == CELL_IDENT_LAC) { - lac = osmo_load16be(&data[1]); - } else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) { - LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", osmo_hexdump(data, data_length)); - return -1; - } - - if (TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_NEEDED) && TLVP_LEN(&tp, GSM0808_IE_CHANNEL_NEEDED) == 1) - chan_needed = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_NEEDED)[0] & 0x03; - - if (TLVP_PRESENT(&tp, GSM0808_IE_EMLPP_PRIORITY)) { - LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n"); - } - - subscr = bsc_subscr_find_or_create_by_imsi(msc->network->bsc_subscribers, - mi_string); - if (!subscr) { - LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string); - return -1; - } - - subscr->lac = lac; - subscr->tmsi = tmsi; - - LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac); - bsc_grace_paging_request(msc->network->bsc_data->rf_ctrl->policy, - subscr, chan_needed, msc); - return 0; -} - -/* - * GSM 08.08 § 3.1.9.1 and 3.2.1.21... - * release our gsm_subscriber_connection and send message - */ -static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn, - struct msgb *msg, unsigned int payload_length) -{ - struct msgb *resp; - - /* TODO: handle the cause of this package */ - - if (conn->conn) { - LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn); - gsm0808_clear(conn->conn); - bsc_subscr_con_free(conn->conn); - conn->conn = NULL; - } - - /* send the clear complete message */ - resp = gsm0808_create_clear_complete(); - if (!resp) { - LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n"); - return -1; - } - - osmo_bsc_sigtran_send(conn, resp); - return 0; -} - -/* - * GSM 08.08 § 3.4.7 cipher mode handling. We will have to pick - * the cipher to be used for this. In case we are already using - * a cipher we will have to send cipher mode reject to the MSC, - * otherwise we will have to pick something that we and the MS - * is supporting. Currently we are doing it in a rather static - * way by picking one ecnryption or no encrytpion. - */ -static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn, - struct msgb *msg, unsigned int payload_length) -{ - uint16_t len; - struct gsm_network *network = NULL; - const uint8_t *data; - struct tlv_parsed tp; - struct msgb *resp; - int reject_cause = -1; - int include_imeisv = 1; - - if (!conn->conn) { - LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n"); - goto reject; - } - - if (conn->ciphering_handled) { - LOGP(DMSC, LOGL_ERROR, "Already seen ciphering command. Protocol Error.\n"); - goto reject; - } - - conn->ciphering_handled = 1; - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0); - if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) { - LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n"); - goto reject; - } - - /* - * check if our global setting is allowed - * - Currently we check for A5/0 and A5/1 - * - Copy the key if that is necessary - * - Otherwise reject - */ - len = TLVP_LEN(&tp, GSM0808_IE_ENCRYPTION_INFORMATION); - if (len < 1) { - LOGP(DMSC, LOGL_ERROR, "IE Encryption Information is too short.\n"); - goto reject; - } - - network = conn->conn->bts->network; - data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION); - - if (TLVP_PRESENT(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)) - include_imeisv = TLVP_VAL(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)[0] & 0x1; - - if (network->a5_encryption == 0 && (data[0] & 0x1) == 0x1) { - gsm0808_cipher_mode(conn->conn, 0, NULL, 0, include_imeisv); - } else if (network->a5_encryption != 0 && (data[0] & 0x2) == 0x2) { - gsm0808_cipher_mode(conn->conn, 1, &data[1], len - 1, include_imeisv); - } else { - LOGP(DMSC, LOGL_ERROR, "Can not select encryption...\n"); - goto reject; - } - - return 0; - -reject: - resp = gsm0808_create_cipher_reject(reject_cause); - if (!resp) { - LOGP(DMSC, LOGL_ERROR, "Sending the cipher reject failed.\n"); - return -1; - } - - osmo_bsc_sigtran_send(conn, resp); - return -1; -} - -/* - * Handle the assignment request message. - * - * See §3.2.1.1 for the message type - */ -static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn, - struct msgb *msg, unsigned int length) -{ - struct msgb *resp; - struct bsc_msc_data *msc; - struct tlv_parsed tp; - uint8_t timeslot = 0; - uint8_t multiplex = 0; - enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN; - int port, full_rate = -1; - bool aoip = false; - struct sockaddr_storage rtp_addr; - struct sockaddr_in *rtp_addr_in; - struct gsm0808_channel_type ct; - struct gsm0808_speech_codec_list scl; - struct gsm0808_speech_codec_list *scl_ptr = NULL; - int rc; - const uint8_t *data; - char len; - - if (!conn->conn) { - LOGP(DMSC, LOGL_ERROR, - "No lchan/msc_data in cipher mode command.\n"); - return -1; - } - - msc = conn->msc; - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0); - - /* Check for channel type element, if its missing, immediately reject */ - if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) { - LOGP(DMSC, LOGL_ERROR, "Mandatory channel type not present.\n"); - goto reject; - } - - /* Detect if a CIC code is present, if so, we use the classic ip.access - * method to calculate the RTP port */ - if (TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) { - conn->cic = - osmo_load16be(TLVP_VAL - (&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)); - timeslot = conn->cic & 0x1f; - multiplex = (conn->cic & ~0x1f) >> 5; - } else if (TLVP_PRESENT(&tp, GSM0808_IE_AOIP_TRASP_ADDR)) { - /* Decode AoIP transport address element */ - data = TLVP_VAL(&tp, GSM0808_IE_AOIP_TRASP_ADDR); - len = TLVP_LEN(&tp, GSM0808_IE_AOIP_TRASP_ADDR); - rc = gsm0808_dec_aoip_trasp_addr(&rtp_addr, data, len); - if (rc < 0) { - LOGP(DMSC, LOGL_ERROR, - "Unable to decode aoip transport address.\n"); - goto reject; - } - aoip = true; - } else { - LOGP(DMSC, LOGL_ERROR, - "transport address missing. Audio routing will not work.\n"); - goto reject; - } - - /* Decode speech codec list (AoIP) */ - if (aoip) { - /* Check for speech codec list element */ - if (!TLVP_PRESENT(&tp, GSM0808_IE_SPEECH_CODEC_LIST)) { - LOGP(DMSC, LOGL_ERROR, - "Mandatory speech codec list not present.\n"); - goto reject; - } - - /* Decode Speech Codec list */ - data = TLVP_VAL(&tp, GSM0808_IE_SPEECH_CODEC_LIST); - len = TLVP_LEN(&tp, GSM0808_IE_SPEECH_CODEC_LIST); - rc = gsm0808_dec_speech_codec_list(&scl, data, len); - if (rc < 0) { - LOGP(DMSC, LOGL_ERROR, - "Unable to decode speech codec list\n"); - goto reject; - } - scl_ptr = &scl; - } - - /* Decode Channel Type element */ - data = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE); - len = TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); - rc = gsm0808_dec_channel_type(&ct, data, len); - if (rc < 0) { - LOGP(DMSC, LOGL_ERROR, "unable to decode channel type.\n"); - goto reject; - } - - /* Currently we only support a limited subset of all - * possible channel types. The limitation ends by not using - * multi-slot, limiting the channel coding to speech */ - if (ct.ch_indctr != GSM0808_CHAN_SPEECH) { - LOGP(DMSC, LOGL_ERROR, - "Unsupported channel type, currently only speech is supported!\n"); - goto reject; - } - - /* Match codec information from the assignment command against the - * local preferences of the BSC */ - rc = match_codec_pref(&full_rate, &chan_mode, &ct, scl_ptr, msc); - if (rc < 0) { - LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n"); - goto reject; - } - - if (aoip == false) { - /* map it to a MGCP Endpoint and a RTP port */ - port = mgcp_timeslot_to_endpoint(multiplex, timeslot); - conn->rtp_port = rtp_calculate_port(port, msc->rtp_base); - conn->rtp_ip = 0; - } else { - /* use address / port supplied with the AoIP - * transport address element */ - if (rtp_addr.ss_family == AF_INET) { - rtp_addr_in = (struct sockaddr_in *)&rtp_addr; - conn->rtp_port = osmo_ntohs(rtp_addr_in->sin_port); - memcpy(&conn->rtp_ip, &rtp_addr_in->sin_addr.s_addr, - IP_V4_ADDR_LEN); - conn->rtp_ip = osmo_ntohl(conn->rtp_ip); - } else { - LOGP(DMSC, LOGL_ERROR, - "Unsopported addressing scheme. (supports only IPV4)\n"); - goto reject; - } - } - - return gsm0808_assign_req(conn->conn, chan_mode, full_rate); - -reject: - resp = - gsm0808_create_assignment_failure - (GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL); - if (!resp) { - LOGP(DMSC, LOGL_ERROR, "Channel allocation failure.\n"); - return -1; - } - - osmo_bsc_sigtran_send(conn, resp); - return -1; -} - -static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc, - struct msgb *msg, unsigned int length) -{ - int ret = 0; - - if (length < 1) { - LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length); - return -1; - } - - LOGP(DMSC, LOGL_INFO, "Rx MSC UDT BSSMAP %s\n", - gsm0808_bssmap_name(msg->l4h[0])); - - switch (msg->l4h[0]) { - case BSS_MAP_MSG_RESET_ACKNOWLEDGE: - ret = bssmap_handle_reset_ack(msc, msg, length); - break; - case BSS_MAP_MSG_RESET: - ret = bssmap_handle_reset(msc, msg, length); - break; - case BSS_MAP_MSG_PAGING: - ret = bssmap_handle_paging(msc, msg, length); - break; - } - - return ret; -} - -static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn, - struct msgb *msg, unsigned int length) -{ - int ret = 0; - - if (length < 1) { - LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length); - return -1; - } - - LOGP(DMSC, LOGL_INFO, "Rx MSC DT1 BSSMAP %s\n", - gsm0808_bssmap_name(msg->l4h[0])); - - switch (msg->l4h[0]) { - case BSS_MAP_MSG_CLEAR_CMD: - ret = bssmap_handle_clear_command(conn, msg, length); - break; - case BSS_MAP_MSG_CIPHER_MODE_CMD: - ret = bssmap_handle_cipher_mode(conn, msg, length); - break; - case BSS_MAP_MSG_ASSIGMENT_RQST: - ret = bssmap_handle_assignm_req(conn, msg, length); - break; - default: - LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n", - gsm0808_bssmap_name(msg->l4h[0])); - break; - } - - return ret; -} - -static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn, - struct msgb *msg, unsigned int length) -{ - struct dtap_header *header; - struct msgb *gsm48; - uint8_t *data; - int rc, dtap_rc; - - LOGP(DMSC, LOGL_DEBUG, "Rx MSC DTAP: %s\n", - osmo_hexdump(msg->l3h, length)); - - if (!conn->conn) { - LOGP(DMSC, LOGL_ERROR, "No subscriber connection available\n"); - return -1; - } - - header = (struct dtap_header *) msg->l3h; - if (sizeof(*header) >= length) { - LOGP(DMSC, LOGL_ERROR, "The DTAP header does not fit. Wanted: %zu got: %u\n", sizeof(*header), length); - LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length)); - return -1; - } - - if (header->length > length - sizeof(*header)) { - LOGP(DMSC, LOGL_ERROR, "The DTAP l4 information does not fit: header: %u length: %u\n", header->length, length); - LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length)); - return -1; - } - - LOGP(DMSC, LOGL_INFO, "Rx MSC DTAP, SAPI: %u CHAN: %u\n", header->link_id & 0x07, header->link_id & 0xC0); - - /* forward the data */ - gsm48 = gsm48_msgb_alloc_name("GSM 04.08 DTAP RCV"); - if (!gsm48) { - LOGP(DMSC, LOGL_ERROR, "Allocation of the message failed.\n"); - return -1; - } - - gsm48->l3h = gsm48->data; - data = msgb_put(gsm48, length - sizeof(*header)); - memcpy(data, msg->l3h + sizeof(*header), length - sizeof(*header)); - - /* pass it to the filter for extra actions */ - rc = bsc_scan_msc_msg(conn->conn, gsm48); - dtap_rc = gsm0808_submit_dtap(conn->conn, gsm48, header->link_id, 1); - if (rc == BSS_SEND_USSD) - bsc_send_welcome_ussd(conn->conn); - return dtap_rc; -} - -int bsc_handle_udt(struct bsc_msc_data *msc, - struct msgb *msgb, unsigned int length) -{ - struct bssmap_header *bs; - - LOGP(DMSC, LOGL_DEBUG, "Rx MSC UDT: %s\n", - osmo_hexdump(msgb->l3h, length)); - - if (length < sizeof(*bs)) { - LOGP(DMSC, LOGL_ERROR, "The header is too short.\n"); - return -1; - } - - bs = (struct bssmap_header *) msgb->l3h; - if (bs->length < length - sizeof(*bs)) - return -1; - - switch (bs->type) { - case BSSAP_MSG_BSS_MANAGEMENT: - msgb->l4h = &msgb->l3h[sizeof(*bs)]; - bssmap_rcvmsg_udt(msc, msgb, length - sizeof(*bs)); - break; - default: - LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n", - gsm0808_bssmap_name(bs->type)); - } - - return 0; -} - -int bsc_handle_dt(struct osmo_bsc_sccp_con *conn, - struct msgb *msg, unsigned int len) -{ - if (len < sizeof(struct bssmap_header)) { - LOGP(DMSC, LOGL_ERROR, "The header is too short.\n"); - } - - switch (msg->l3h[0]) { - case BSSAP_MSG_BSS_MANAGEMENT: - msg->l4h = &msg->l3h[sizeof(struct bssmap_header)]; - bssmap_rcvmsg_dt1(conn, msg, len - sizeof(struct bssmap_header)); - break; - case BSSAP_MSG_DTAP: - dtap_rcvmsg(conn, msg, len); - break; - default: - LOGP(DMSC, LOGL_NOTICE, "Unimplemented BSSAP msg type: %s\n", - gsm0808_bssap_name(msg->l3h[0])); - } - - return -1; -} diff --git a/src/osmo-bsc/osmo_bsc_ctrl.c b/src/osmo-bsc/osmo_bsc_ctrl.c deleted file mode 100644 index c23ed2187..000000000 --- a/src/osmo-bsc/osmo_bsc_ctrl.c +++ /dev/null @@ -1,680 +0,0 @@ -/* (C) 2011 by Daniel Willmann - * (C) 2011 by Holger Hans Peter Freyther - * (C) 2011 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con) -{ - struct ctrl_cmd *trap; - struct ctrl_handle *ctrl; - struct bsc_msc_data *msc_data; - - msc_data = (struct bsc_msc_data *) msc_con->write_queue.bfd.data; - ctrl = msc_data->network->ctrl; - - trap = ctrl_cmd_trap(cmd); - if (!trap) { - LOGP(DCTRL, LOGL_ERROR, "Failed to create trap.\n"); - return; - } - - ctrl_cmd_send_to_all(ctrl, trap); - ctrl_cmd_send(&msc_con->write_queue, trap); - - talloc_free(trap); -} - -CTRL_CMD_DEFINE_RO(msc_connection_status, "msc_connection_status"); -static int msc_connection_status = 0; - -static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data) -{ - if (msc_connection_status) - cmd->reply = "connected"; - else - cmd->reply = "disconnected"; - return CTRL_CMD_REPLY; -} - -static int msc_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) -{ - struct ctrl_cmd *cmd; - struct gsm_network *gsmnet = (struct gsm_network *)handler_data; - - if (signal == S_MSC_LOST && msc_connection_status == 1) { - LOGP(DCTRL, LOGL_DEBUG, "MSC connection lost, sending TRAP.\n"); - msc_connection_status = 0; - } else if (signal == S_MSC_CONNECTED && msc_connection_status == 0) { - LOGP(DCTRL, LOGL_DEBUG, "MSC connection (re)established, sending TRAP.\n"); - msc_connection_status = 1; - } else { - return 0; - } - - cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP); - if (!cmd) { - LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n"); - return 0; - } - - cmd->id = "0"; - cmd->variable = "msc_connection_status"; - - get_msc_connection_status(cmd, NULL); - - ctrl_cmd_send_to_all(gsmnet->ctrl, cmd); - - talloc_free(cmd); - - return 0; -} - -CTRL_CMD_DEFINE_RO(bts_connection_status, "bts_connection_status"); -static int bts_connection_status = 0; - -static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data) -{ - if (bts_connection_status) - cmd->reply = "connected"; - else - cmd->reply = "disconnected"; - return CTRL_CMD_REPLY; -} - -static int bts_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) -{ - struct ctrl_cmd *cmd; - struct gsm_network *gsmnet = (struct gsm_network *)handler_data; - struct gsm_bts *bts; - int bts_current_status; - - if (signal != S_L_INP_TEI_DN && signal != S_L_INP_TEI_UP) { - return 0; - } - - bts_current_status = 0; - /* Check if OML on at least one BTS is up */ - llist_for_each_entry(bts, &gsmnet->bts_list, list) { - if (bts->oml_link) { - bts_current_status = 1; - break; - } - } - if (bts_connection_status == 0 && bts_current_status == 1) { - LOGP(DCTRL, LOGL_DEBUG, "BTS connection (re)established, sending TRAP.\n"); - } else if (bts_connection_status == 1 && bts_current_status == 0) { - LOGP(DCTRL, LOGL_DEBUG, "No more BTS connected, sending TRAP.\n"); - } else { - return 0; - } - - cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP); - if (!cmd) { - LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n"); - return 0; - } - - bts_connection_status = bts_current_status; - - cmd->id = "0"; - cmd->variable = "bts_connection_status"; - - get_bts_connection_status(cmd, NULL); - - ctrl_cmd_send_to_all(gsmnet->ctrl, cmd); - - talloc_free(cmd); - - return 0; -} - -static int get_bts_loc(struct ctrl_cmd *cmd, void *data); - -static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_connection *msc_con) -{ - struct ctrl_cmd *cmd; - const char *oper, *admin, *policy; - - cmd = ctrl_cmd_create(msc_con, CTRL_TYPE_TRAP); - if (!cmd) { - LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n"); - return; - } - - cmd->id = "0"; - cmd->variable = talloc_asprintf(cmd, "bts.%i.location-state", bts->nr); - - /* Prepare the location reply */ - cmd->node = bts; - get_bts_loc(cmd, NULL); - - oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts)); - admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts)); - policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts)); - - cmd->reply = talloc_asprintf_append(cmd->reply, - ",%s,%s,%s,%d,%d", - oper, admin, policy, - bts->network->country_code, - bts->network->network_code); - - osmo_bsc_send_trap(cmd, msc_con); - talloc_free(cmd); -} - -void bsc_gen_location_state_trap(struct gsm_bts *bts) -{ - struct bsc_msc_data *msc; - - llist_for_each_entry(msc, &bts->network->bsc_data->mscs, entry) - generate_location_state_trap(bts, msc->msc_con); -} - -static int location_equal(struct bts_location *a, struct bts_location *b) -{ - return ((a->tstamp == b->tstamp) && (a->valid == b->valid) && (a->lat == b->lat) && - (a->lon == b->lon) && (a->height == b->height)); -} - -static void cleanup_locations(struct llist_head *locations) -{ - struct bts_location *myloc, *tmp; - int invalpos = 0, i = 0; - - LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n"); - llist_for_each_entry_safe(myloc, tmp, locations, list) { - i++; - if (i > 3) { - LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n"); - llist_del(&myloc->list); - talloc_free(myloc); - } else if (myloc->valid == BTS_LOC_FIX_INVALID) { - /* Only capture the newest of subsequent invalid positions */ - invalpos++; - if (invalpos > 1) { - LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n"); - invalpos--; - i--; - llist_del(&myloc->list); - talloc_free(myloc); - } - } else { - invalpos = 0; - } - } - LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i); -} - -CTRL_CMD_DEFINE(bts_loc, "location"); -static int get_bts_loc(struct ctrl_cmd *cmd, void *data) -{ - struct bts_location *curloc; - struct gsm_bts *bts = (struct gsm_bts *) cmd->node; - if (!bts) { - cmd->reply = "bts not found."; - return CTRL_CMD_ERROR; - } - - if (llist_empty(&bts->loc_list)) { - cmd->reply = talloc_asprintf(cmd, "0,invalid,0,0,0"); - return CTRL_CMD_REPLY; - } else { - curloc = llist_entry(bts->loc_list.next, struct bts_location, list); - } - - cmd->reply = talloc_asprintf(cmd, "%lu,%s,%f,%f,%f", curloc->tstamp, - get_value_string(bts_loc_fix_names, curloc->valid), curloc->lat, curloc->lon, curloc->height); - if (!cmd->reply) { - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; - } - - return CTRL_CMD_REPLY; -} - -static int set_bts_loc(struct ctrl_cmd *cmd, void *data) -{ - char *saveptr, *lat, *lon, *height, *tstamp, *valid, *tmp; - struct bts_location *curloc, *lastloc; - int ret; - struct gsm_bts *bts = (struct gsm_bts *) cmd->node; - if (!bts) { - cmd->reply = "bts not found."; - return CTRL_CMD_ERROR; - } - - tmp = talloc_strdup(cmd, cmd->value); - if (!tmp) - goto oom; - - curloc = talloc_zero(tall_bsc_ctx, struct bts_location); - if (!curloc) { - talloc_free(tmp); - goto oom; - } - INIT_LLIST_HEAD(&curloc->list); - - - tstamp = strtok_r(tmp, ",", &saveptr); - valid = strtok_r(NULL, ",", &saveptr); - lat = strtok_r(NULL, ",", &saveptr); - lon = strtok_r(NULL, ",", &saveptr); - height = strtok_r(NULL, "\0", &saveptr); - - curloc->tstamp = atol(tstamp); - curloc->valid = get_string_value(bts_loc_fix_names, valid); - curloc->lat = atof(lat); - curloc->lon = atof(lon); - curloc->height = atof(height); - talloc_free(tmp); - - lastloc = llist_entry(bts->loc_list.next, struct bts_location, list); - - /* Add location to the end of the list */ - llist_add(&curloc->list, &bts->loc_list); - - ret = get_bts_loc(cmd, data); - - if (!location_equal(curloc, lastloc)) - bsc_gen_location_state_trap(bts); - - cleanup_locations(&bts->loc_list); - - return ret; - -oom: - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; -} - -static int verify_bts_loc(struct ctrl_cmd *cmd, const char *value, void *data) -{ - char *saveptr, *latstr, *lonstr, *heightstr, *tstampstr, *validstr, *tmp; - time_t tstamp; - int valid; - double lat, lon, height __attribute__((unused)); - - tmp = talloc_strdup(cmd, value); - if (!tmp) - return 1; - - tstampstr = strtok_r(tmp, ",", &saveptr); - validstr = strtok_r(NULL, ",", &saveptr); - latstr = strtok_r(NULL, ",", &saveptr); - lonstr = strtok_r(NULL, ",", &saveptr); - heightstr = strtok_r(NULL, "\0", &saveptr); - - if ((tstampstr == NULL) || (validstr == NULL) || (latstr == NULL) || - (lonstr == NULL) || (heightstr == NULL)) - goto err; - - tstamp = atol(tstampstr); - valid = get_string_value(bts_loc_fix_names, validstr); - lat = atof(latstr); - lon = atof(lonstr); - height = atof(heightstr); - talloc_free(tmp); - tmp = NULL; - - if (((tstamp == 0) && (valid != BTS_LOC_FIX_INVALID)) || (lat < -90) || (lat > 90) || - (lon < -180) || (lon > 180) || (valid < 0)) { - goto err; - } - - return 0; - -err: - talloc_free(tmp); - cmd->reply = talloc_strdup(cmd, "The format is ,(invalid|fix2d|fix3d),,,"); - return 1; -} - -CTRL_CMD_DEFINE(net_timezone, "timezone"); -static int get_net_timezone(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_network *net = (struct gsm_network*)cmd->node; - - struct gsm_tz *tz = &net->tz; - if (tz->override) - cmd->reply = talloc_asprintf(cmd, "%d,%d,%d", - tz->hr, tz->mn, tz->dst); - else - cmd->reply = talloc_asprintf(cmd, "off"); - - if (!cmd->reply) { - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; - } - - return CTRL_CMD_REPLY; -} - -static int set_net_timezone(struct ctrl_cmd *cmd, void *data) -{ - char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0; - int override; - struct gsm_network *net = (struct gsm_network*)cmd->node; - - tmp = talloc_strdup(cmd, cmd->value); - if (!tmp) - goto oom; - - hourstr = strtok_r(tmp, ",", &saveptr); - minstr = strtok_r(NULL, ",", &saveptr); - dststr = strtok_r(NULL, ",", &saveptr); - - override = 0; - - if (hourstr != NULL) - override = strcasecmp(hourstr, "off") != 0; - - struct gsm_tz *tz = &net->tz; - tz->override = override; - - if (override) { - tz->hr = hourstr ? atol(hourstr) : 0; - tz->mn = minstr ? atol(minstr) : 0; - tz->dst = dststr ? atol(dststr) : 0; - } - - talloc_free(tmp); - tmp = NULL; - - return get_net_timezone(cmd, data); - -oom: - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; -} - -static int verify_net_timezone(struct ctrl_cmd *cmd, const char *value, void *data) -{ - char *saveptr, *hourstr, *minstr, *dststr, *tmp; - int override, tz_hours, tz_mins, tz_dst; - - tmp = talloc_strdup(cmd, value); - if (!tmp) - return 1; - - hourstr = strtok_r(tmp, ",", &saveptr); - minstr = strtok_r(NULL, ",", &saveptr); - dststr = strtok_r(NULL, ",", &saveptr); - - if (hourstr == NULL) - goto err; - - override = strcasecmp(hourstr, "off") != 0; - - if (!override) { - talloc_free(tmp); - return 0; - } - - if (minstr == NULL || dststr == NULL) - goto err; - - tz_hours = atol(hourstr); - tz_mins = atol(minstr); - tz_dst = atol(dststr); - - talloc_free(tmp); - tmp = NULL; - - if ((tz_hours < -19) || (tz_hours > 19) || - (tz_mins < 0) || (tz_mins >= 60) || (tz_mins % 15 != 0) || - (tz_dst < 0) || (tz_dst > 2)) - goto err; - - return 0; - -err: - talloc_free(tmp); - cmd->reply = talloc_strdup(cmd, "The format is ,, or 'off' where -19 <= hours <= 19, mins in {0, 15, 30, 45}, and 0 <= dst <= 2"); - return 1; -} - -CTRL_CMD_DEFINE(net_notification, "notification"); -static int get_net_notification(struct ctrl_cmd *cmd, void *data) -{ - cmd->reply = "There is nothing to read"; - return CTRL_CMD_ERROR; -} - -static int set_net_notification(struct ctrl_cmd *cmd, void *data) -{ - struct ctrl_cmd *trap; - struct gsm_network *net; - - net = cmd->node; - - trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP); - if (!trap) { - LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n"); - goto handled; - } - - trap->id = "0"; - trap->variable = "notification"; - trap->reply = talloc_strdup(trap, cmd->value); - - /* - * This should only be sent to local systems. In the future - * we might even ask for systems to register to receive - * the notifications. - */ - ctrl_cmd_send_to_all(net->ctrl, trap); - talloc_free(trap); - -handled: - return CTRL_CMD_HANDLED; -} - -static int verify_net_notification(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -CTRL_CMD_DEFINE(net_inform_msc, "inform-msc-v1"); -static int get_net_inform_msc(struct ctrl_cmd *cmd, void *data) -{ - cmd->reply = "There is nothing to read"; - return CTRL_CMD_ERROR; -} - -static int set_net_inform_msc(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_network *net; - struct bsc_msc_data *msc; - - net = cmd->node; - llist_for_each_entry(msc, &net->bsc_data->mscs, entry) { - struct ctrl_cmd *trap; - - trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP); - if (!trap) { - LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n"); - continue; - } - - trap->id = "0"; - trap->variable = "inform-msc-v1"; - trap->reply = talloc_strdup(trap, cmd->value); - ctrl_cmd_send(&msc->msc_con->write_queue, trap); - talloc_free(trap); - } - - - return CTRL_CMD_HANDLED; -} - -static int verify_net_inform_msc(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -CTRL_CMD_DEFINE(net_ussd_notify, "ussd-notify-v1"); -static int get_net_ussd_notify(struct ctrl_cmd *cmd, void *data) -{ - cmd->reply = "There is nothing to read"; - return CTRL_CMD_ERROR; -} - -static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data) -{ - struct gsm_subscriber_connection *conn; - struct gsm_network *net; - char *saveptr = NULL; - char *cic_str, *alert_str, *text_str; - int cic, alert; - - /* Verify has done the test for us */ - cic_str = strtok_r(cmd->value, ",", &saveptr); - alert_str = strtok_r(NULL, ",", &saveptr); - text_str = strtok_r(NULL, ",", &saveptr); - - if (!cic_str || !alert_str || !text_str) { - cmd->reply = "Programming issue. How did this pass verify?"; - return CTRL_CMD_ERROR; - } - - cmd->reply = "No connection found"; - - cic = atoi(cic_str); - alert = atoi(alert_str); - - net = cmd->node; - llist_for_each_entry(conn, &net->subscr_conns, entry) { - if (!conn->sccp_con) - continue; - - if (conn->sccp_con->cic != cic) - continue; - - /* - * This is a hack. My E71 does not like to immediately - * receive a release complete on a TCH. So schedule a - * release complete to clear any previous attempt. The - * right thing would be to track invokeId and only send - * the release complete when we get a returnResultLast - * for this invoke id. - */ - bsc_send_ussd_release_complete(conn); - bsc_send_ussd_notify(conn, alert, text_str); - cmd->reply = "Found a connection"; - break; - } - - return CTRL_CMD_REPLY; -} - -static int verify_net_ussd_notify(struct ctrl_cmd *cmd, const char *value, void *data) -{ - char *saveptr = NULL; - char *inp, *cic, *alert, *text; - - OSMO_ASSERT(cmd); - inp = talloc_strdup(cmd, value); - - cic = strtok_r(inp, ",", &saveptr); - alert = strtok_r(NULL, ",", &saveptr); - text = strtok_r(NULL, ",", &saveptr); - - talloc_free(inp); - if (!cic || !alert || !text) - return 1; - return 0; -} - -static int msc_signal_handler(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct msc_signal_data *msc; - struct gsm_network *net; - struct gsm_bts *bts; - - if (subsys != SS_MSC) - return 0; - if (signal != S_MSC_AUTHENTICATED) - return 0; - - msc = signal_data; - - net = msc->data->network; - llist_for_each_entry(bts, &net->bts_list, list) - generate_location_state_trap(bts, msc->data->msc_con); - - return 0; -} - -int bsc_ctrl_cmds_install(struct gsm_network *net) -{ - int rc; - - rc = bsc_base_ctrl_cmds_install(); - if (rc) - goto end; - rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc); - if (rc) - goto end; - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_timezone); - if (rc) - goto end; - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_msc_connection_status); - if (rc) - goto end; - rc = osmo_signal_register_handler(SS_MSC, &msc_connection_status_trap_cb, net); - if (rc) - goto end; - rc = osmo_signal_register_handler(SS_MSC, msc_signal_handler, NULL); - if (rc) - goto end; - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_bts_connection_status); - if (rc) - goto end; - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_notification); - if (rc) - goto end; - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_inform_msc); - if (rc) - goto end; - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_ussd_notify); - if (rc) - goto end; - rc = osmo_signal_register_handler(SS_L_INPUT, &bts_connection_status_trap_cb, net); - -end: - return rc; -} diff --git a/src/osmo-bsc/osmo_bsc_filter.c b/src/osmo-bsc/osmo_bsc_filter.c deleted file mode 100644 index 2c84b169f..000000000 --- a/src/osmo-bsc/osmo_bsc_filter.c +++ /dev/null @@ -1,381 +0,0 @@ -/* (C) 2009-2011 by Holger Hans Peter Freyther - * (C) 2009-2011 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -static void handle_lu_request(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm48_hdr *gh; - struct gsm48_loc_upd_req *lu; - struct gsm48_loc_area_id lai; - struct gsm_network *net; - - if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) { - LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg)); - return; - } - - net = conn->bts->network; - - gh = msgb_l3(msg); - lu = (struct gsm48_loc_upd_req *) gh->data; - - gsm48_generate_lai(&lai, net->country_code, net->network_code, - conn->bts->location_area_code); - - if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) { - LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n"); - conn->sccp_con->new_subscriber = 1; - } -} - -/* extract a subscriber from the paging response */ -static struct bsc_subscr *extract_sub(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - uint8_t mi_type; - char mi_string[GSM48_MI_SIZE]; - struct gsm48_hdr *gh; - struct gsm48_pag_resp *resp; - struct bsc_subscr *subscr; - - if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) { - LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg)); - return NULL; - } - - gh = msgb_l3(msg); - resp = (struct gsm48_pag_resp *) &gh->data[0]; - - gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh), - mi_string, &mi_type); - DEBUGP(DRR, "PAGING RESPONSE: MI(%s)=%s\n", - gsm48_mi_type_name(mi_type), mi_string); - - switch (mi_type) { - case GSM_MI_TYPE_TMSI: - subscr = bsc_subscr_find_by_tmsi(conn->network->bsc_subscribers, - tmsi_from_string(mi_string)); - break; - case GSM_MI_TYPE_IMSI: - subscr = bsc_subscr_find_by_imsi(conn->network->bsc_subscribers, - mi_string); - break; - default: - subscr = NULL; - break; - } - - return subscr; -} - -/* we will need to stop the paging request */ -static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg) -{ - struct bsc_subscr *subscr = extract_sub(conn, msg); - - if (!subscr) { - LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n"); - return -1; - } - - paging_request_stop(&conn->network->bts_list, conn->bts, subscr, conn, - msg); - bsc_subscr_put(subscr); - return 0; -} - -static int is_cm_service_for_emerg(struct msgb *msg) -{ - struct gsm48_service_request *cm; - struct gsm48_hdr *gh = msgb_l3(msg); - - if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*cm)) { - LOGP(DMSC, LOGL_ERROR, "CM ServiceRequest does not fit.\n"); - return 0; - } - - cm = (struct gsm48_service_request *) &gh->data[0]; - return cm->cm_service_type == GSM48_CMSERV_EMERGENCY; -} - -struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, - struct msgb *msg) -{ - struct gsm48_hdr *gh; - int8_t pdisc; - uint8_t mtype; - struct osmo_bsc_data *bsc; - struct bsc_msc_data *msc, *pag_msc; - struct bsc_subscr *subscr; - int is_emerg = 0; - - bsc = conn->bts->network->bsc_data; - - if (msgb_l3len(msg) < sizeof(*gh)) { - LOGP(DMSC, LOGL_ERROR, "There is no GSM48 header here.\n"); - return NULL; - } - - gh = msgb_l3(msg); - pdisc = gsm48_hdr_pdisc(gh); - mtype = gsm48_hdr_msg_type(gh); - - /* - * We are asked to select a MSC here but they are not equal. We - * want to respond to a paging request on the MSC where we got the - * request from. This is where we need to decide where this connection - * will go. - */ - if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP) - goto paging; - else if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) { - is_emerg = is_cm_service_for_emerg(msg); - goto round_robin; - } else - goto round_robin; - -round_robin: - llist_for_each_entry(msc, &bsc->mscs, entry) { - if (!msc->msc_con->is_authenticated) - continue; - if (!is_emerg && msc->type != MSC_CON_TYPE_NORMAL) - continue; - if (is_emerg && !msc->allow_emerg) - continue; - - /* force round robin by moving it to the end */ - llist_move_tail(&msc->entry, &bsc->mscs); - return msc; - } - - return NULL; - -paging: - subscr = extract_sub(conn, msg); - - if (!subscr) { - LOGP(DMSC, LOGL_ERROR, "Got paged but no subscriber found.\n"); - return NULL; - } - - pag_msc = paging_get_data(conn->bts, subscr); - bsc_subscr_put(subscr); - - llist_for_each_entry(msc, &bsc->mscs, entry) { - if (msc != pag_msc) - continue; - - /* - * We don't check if the MSC is connected. In case it - * is not the connection will be dropped. - */ - - /* force round robin by moving it to the end */ - llist_move_tail(&msc->entry, &bsc->mscs); - return msc; - } - - LOGP(DMSC, LOGL_ERROR, "Got paged but no request found.\n"); - return NULL; -} - - -/** - * This is used to scan a message for extra functionality of the BSC. This - * includes scanning for location updating requests/acceptd and then send - * a welcome USSD message to the subscriber. - */ -int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - uint8_t pdisc = gsm48_hdr_pdisc(gh); - uint8_t mtype = gsm48_hdr_msg_type(gh); - - if (pdisc == GSM48_PDISC_MM) { - if (mtype == GSM48_MT_MM_LOC_UPD_REQUEST) - handle_lu_request(conn, msg); - } else if (pdisc == GSM48_PDISC_RR) { - if (mtype == GSM48_MT_RR_PAG_RESP) - handle_page_resp(conn, msg); - } - - return 0; -} - -static int send_welcome_ussd(struct gsm_subscriber_connection *conn) -{ - struct osmo_bsc_sccp_con *bsc_con; - - bsc_con = conn->sccp_con; - if (!bsc_con) { - LOGP(DMSC, LOGL_DEBUG, "No SCCP connection associated.\n"); - return 0; - } - - if (!bsc_con->msc->ussd_welcome_txt) { - LOGP(DMSC, LOGL_DEBUG, "No USSD Welcome text defined.\n"); - return 0; - } - - return BSS_SEND_USSD; -} - -int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn) -{ - bsc_send_ussd_notify(conn, 1, conn->sccp_con->msc->ussd_welcome_txt); - bsc_send_ussd_release_complete(conn); - - return 0; -} - -static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn, - uint8_t *data, unsigned int length) -{ - struct tlv_parsed tp; - int parse_res; - struct gsm_bts *bts = conn->bts; - int tzunits; - uint8_t tzbsd = 0; - uint8_t dst = 0; - - parse_res = tlv_parse(&tp, &gsm48_mm_att_tlvdef, data, length, 0, 0); - if (parse_res <= 0 && parse_res != -3) - /* FIXME: -3 means unknown IE error, so this accepts messages - * with unknown IEs. But parsing has aborted with the unknown - * IE and the message is broken or parsed incompletely. */ - return 0; - - /* Is TZ patching enabled? */ - struct gsm_tz *tz = &bts->network->tz; - if (!tz->override) - return 0; - - /* Convert tz.hr and tz.mn to units */ - if (tz->hr < 0) { - tzunits = -tz->hr*4; - tzbsd |= 0x08; - } else - tzunits = tz->hr*4; - - tzunits = tzunits + (tz->mn/15); - - tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10); - - /* Convert DST value */ - if (tz->dst >= 0 && tz->dst <= 2) - dst = tz->dst; - - if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) { - LOGP(DMSC, LOGL_DEBUG, - "Changing 'Local time zone' from 0x%02x to 0x%02x.\n", - TLVP_VAL(&tp, GSM48_IE_UTC)[6], tzbsd); - ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_UTC)))[0] = tzbsd; - } - if (TLVP_PRESENT(&tp, GSM48_IE_NET_TIME_TZ)) { - LOGP(DMSC, LOGL_DEBUG, - "Changing 'Universal time and local time zone' TZ from " - "0x%02x to 0x%02x.\n", - TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)[6], tzbsd); - ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)))[6] = tzbsd; - } -#ifdef GSM48_IE_NET_DST - if (TLVP_PRESENT(&tp, GSM48_IE_NET_DST)) { - LOGP(DMSC, LOGL_DEBUG, - "Changing 'Network daylight saving time' from " - "0x%02x to 0x%02x.\n", - TLVP_VAL(&tp, GSM48_IE_NET_DST)[0], dst); - ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_DST)))[0] = dst; - } -#endif - - return 0; -} - -static int has_core_identity(struct bsc_msc_data *msc) -{ - if (msc->core_mnc != -1) - return 1; - if (msc->core_mcc != -1) - return 1; - if (msc->core_lac != -1) - return 1; - if (msc->core_ci != -1) - return 1; - return 0; -} - -/** - * Messages coming back from the MSC. - */ -int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg) -{ - struct bsc_msc_data *msc; - struct gsm_network *net; - struct gsm48_loc_area_id *lai; - struct gsm48_hdr *gh; - uint8_t pdisc; - uint8_t mtype; - int length = msgb_l3len(msg); - - if (length < sizeof(*gh)) { - LOGP(DMSC, LOGL_ERROR, "GSM48 header does not fit.\n"); - return -1; - } - - gh = (struct gsm48_hdr *) msgb_l3(msg); - length -= (const char *)&gh->data[0] - (const char *)gh; - - pdisc = gsm48_hdr_pdisc(gh); - if (pdisc != GSM48_PDISC_MM) - return 0; - - mtype = gsm48_hdr_msg_type(gh); - net = conn->bts->network; - msc = conn->sccp_con->msc; - - if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) { - if (has_core_identity(msc)) { - if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) { - /* overwrite LAI in the message */ - lai = (struct gsm48_loc_area_id *) &gh->data[0]; - gsm48_generate_lai(lai, net->country_code, - net->network_code, - conn->bts->location_area_code); - } - } - - if (conn->sccp_con->new_subscriber) - return send_welcome_ussd(conn); - return 0; - } else if (mtype == GSM48_MT_MM_INFO) { - bsc_patch_mm_info(conn, &gh->data[0], length); - } - - return 0; -} diff --git a/src/osmo-bsc/osmo_bsc_grace.c b/src/osmo-bsc/osmo_bsc_grace.c deleted file mode 100644 index 63afa20d0..000000000 --- a/src/osmo-bsc/osmo_bsc_grace.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * (C) 2010-2013 by Holger Hans Peter Freyther - * (C) 2010-2013 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include - -int bsc_grace_allow_new_connection(struct gsm_network *network, struct gsm_bts *bts) -{ - if (bts->excl_from_rf_lock) - return 1; - return network->bsc_data->rf_ctrl->policy == S_RF_ON; -} - - -static int normal_paging(struct bsc_subscr *subscr, int chan_needed, - struct bsc_msc_data *msc) -{ - /* we can't page by lac.. we need to page everything */ - if (msc->core_lac != -1) { - struct gsm_bts *bts; - - llist_for_each_entry(bts, &msc->network->bts_list, list) - paging_request_bts(bts, subscr, chan_needed, NULL, msc); - - return 0; - } - - return paging_request(msc->network, subscr, chan_needed, NULL, msc); -} - -static int locked_paging(struct bsc_subscr *subscr, int chan_needed, - struct bsc_msc_data *msc) -{ - struct gsm_bts *bts = NULL; - - /* - * Check if there is any BTS that is on for the given lac. Start - * with NULL and iterate through all bts. - */ - llist_for_each_entry(bts, &msc->network->bts_list, list) { - /* - * continue if the BTS is not excluded from the lock - */ - if (!bts->excl_from_rf_lock) - continue; - - /* in case of no lac patching is in place, check the BTS */ - if (msc->core_lac == -1 && subscr->lac != bts->location_area_code) - continue; - - /* - * now page on this bts - */ - paging_request_bts(bts, subscr, chan_needed, NULL, msc); - }; - - /* All bts are either off or in the grace period */ - return 0; -} - -/** - * Try to not page if everything the cell is not on. - */ -int bsc_grace_paging_request(enum signal_rf rf_policy, - struct bsc_subscr *subscr, - int chan_needed, - struct bsc_msc_data *msc) -{ - if (rf_policy == S_RF_ON) - return normal_paging(subscr, chan_needed, msc); - return locked_paging(subscr, chan_needed, msc); -} - -static int handle_sub(struct gsm_lchan *lchan, const char *text) -{ - struct gsm_subscriber_connection *conn; - - /* only send it to TCH */ - if (lchan->type != GSM_LCHAN_TCH_H && lchan->type != GSM_LCHAN_TCH_F) - return -1; - - /* only send on the primary channel */ - conn = lchan->conn; - if (!conn) - return -1; - - if (conn->lchan != lchan) - return -1; - - /* only when active */ - if (lchan->state != LCHAN_S_ACTIVE) - return -1; - - bsc_send_ussd_notify(conn, 0, text); - bsc_send_ussd_release_complete(conn); - - return 0; -} - -/* - * The place to handle the grace mode. Right now we will send - * USSD messages to the subscriber, in the future we might start - * a timer to have different modes for the grace period. - */ -static int handle_grace(struct gsm_network *network) -{ - int ts_nr, lchan_nr; - struct gsm_bts *bts; - struct gsm_bts_trx *trx; - - if (!network->bsc_data->mid_call_txt) - return 0; - - llist_for_each_entry(bts, &network->bts_list, list) { - llist_for_each_entry(trx, &bts->trx_list, list) { - for (ts_nr = 0; ts_nr < TRX_NR_TS; ++ts_nr) { - struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr]; - for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; ++lchan_nr) { - handle_sub(&ts->lchan[lchan_nr], - network->bsc_data->mid_call_txt); - } - } - } - } - return 0; -} - -static int handle_rf_signal(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct rf_signal_data *sig; - - if (subsys != SS_RF) - return -1; - - sig = signal_data; - - if (signal == S_RF_GRACE) - handle_grace(sig->net); - - return 0; -} - -static __attribute__((constructor)) void on_dso_load_grace(void) -{ - osmo_signal_register_handler(SS_RF, handle_rf_signal, NULL); -} diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c deleted file mode 100644 index cf188a9e0..000000000 --- a/src/osmo-bsc/osmo_bsc_main.c +++ /dev/null @@ -1,307 +0,0 @@ -/* (C) 2008-2009 by Harald Welte - * (C) 2009-2011 by Holger Hans Peter Freyther - * (C) 2009-2011 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include - - -#include "../../bscconfig.h" - -struct gsm_network *bsc_gsmnet = 0; -static const char *config_file = "openbsc.cfg"; -static const char *rf_ctrl = NULL; -extern const char *openbsc_copyright; -static int daemonize = 0; -static struct llist_head access_lists; - -struct llist_head *bsc_access_lists(void) -{ - return &access_lists; -} - -static void print_usage() -{ - printf("Usage: osmo-bsc\n"); -} - -static void print_help() -{ - printf(" Some useful help...\n"); - printf(" -h --help this text\n"); - printf(" -D --daemonize Fork the process into a background daemon\n"); - printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n"); - printf(" -s --disable-color\n"); - printf(" -T --timestamp. Print a timestamp in the debug output.\n"); - printf(" -c --config-file filename The config file to use.\n"); - printf(" -l --local=IP. The local address of the MGCP.\n"); - printf(" -e --log-level number. Set a global loglevel.\n"); - printf(" -r --rf-ctl NAME. A unix domain socket to listen for cmds.\n"); - printf(" -t --testmode. A special mode to provoke failures at the MSC.\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'}, - {"local", 1, 0, 'l'}, - {"log-level", 1, 0, 'e'}, - {"rf-ctl", 1, 0, 'r'}, - {"testmode", 0, 0, 't'}, - {0, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "hd:DsTc:e:r:t", - 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 'r': - rf_ctrl = optarg; - break; - default: - /* ignore */ - break; - } - } -} - -extern int bsc_vty_go_parent(struct vty *vty); - -static struct vty_app_info vty_info = { - .name = "OsmoBSC", - .version = PACKAGE_VERSION, - .go_parent_cb = bsc_vty_go_parent, - .is_config_node = bsc_vty_is_config_node, -}; - -extern int bsc_shutdown_net(struct gsm_network *net); -static void signal_handler(int signal) -{ - struct bsc_msc_data *msc; - - fprintf(stdout, "signal %u received\n", signal); - - switch (signal) { - case SIGINT: - case SIGTERM: - bsc_shutdown_net(bsc_gsmnet); - osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); - sleep(3); - 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: - if (!bsc_gsmnet->bsc_data) - return; - llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) - bsc_msc_lost(msc->msc_con); - break; - default: - break; - } -} - -int main(int argc, char **argv) -{ - struct bsc_msc_data *msc; - struct osmo_bsc_data *data; - int rc; - - tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); - msgb_talloc_ctx_init(tall_bsc_ctx, 0); - - /* Allocate global gsm_network struct */ - rc = bsc_network_alloc(NULL); - if (rc) { - fprintf(stderr, "Allocation failed. exiting.\n"); - exit(1); - } - - osmo_init_logging(&log_info); - osmo_stats_init(tall_bsc_ctx); - - bts_init(); - libosmo_abis_init(tall_bsc_ctx); - - /* enable filters */ - - /* This needs to precede handle_options() */ - vty_info.copyright = openbsc_copyright; - vty_init(&vty_info); - bsc_vty_init(bsc_gsmnet); - bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE); - ctrl_vty_init(tall_bsc_ctx); - - /* Initalize SS7 */ - osmo_ss7_init(); - osmo_ss7_vty_init_asp(tall_bsc_ctx); - - INIT_LLIST_HEAD(&access_lists); - - /* parse options */ - handle_options(argc, argv); - - /* seed the PRNG */ - srand(time(NULL)); - - /* initialize SCCP */ - sccp_set_log_area(DSCCP); - - /* Read the config */ - rc = bsc_network_configure(config_file); - if (rc < 0) { - fprintf(stderr, "Bootstrapping the network failed. exiting.\n"); - exit(1); - } - bsc_api_init(bsc_gsmnet, osmo_bsc_api()); - - /* start control interface after reading config for - * ctrl_vty_get_bind_addr() */ - bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, - ctrl_vty_get_bind_addr(), - OSMO_CTRL_PORT_NITB_BSC); - if (!bsc_gsmnet->ctrl) { - fprintf(stderr, "Failed to init the control interface. Exiting.\n"); - exit(1); - } - - rc = bsc_ctrl_cmds_install(bsc_gsmnet); - if (rc < 0) { - fprintf(stderr, "Failed to install control commands. Exiting.\n"); - exit(1); - } - - data = bsc_gsmnet->bsc_data; - if (rf_ctrl) - osmo_talloc_replace_string(data, &data->rf_ctrl_name, rf_ctrl); - - data->rf_ctrl = osmo_bsc_rf_create(data->rf_ctrl_name, bsc_gsmnet); - if (!data->rf_ctrl) { - fprintf(stderr, "Failed to create the RF service.\n"); - exit(1); - } - - llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) { - if (osmo_bsc_msc_init(msc) != 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to start up. Exiting.\n"); - exit(1); - } - } - - if (osmo_bsc_sigtran_init(&bsc_gsmnet->bsc_data->mscs) != 0) { - LOGP(DNM, LOGL_ERROR, "Failed to initalize sigtran backhaul.\n"); - exit(1); - } - - if (osmo_bsc_audio_init(bsc_gsmnet) != 0) { - LOGP(DMSC, LOGL_ERROR, "Failed to register audio support.\n"); - exit(1); - } - - signal(SIGINT, &signal_handler); - signal(SIGTERM, &signal_handler); - signal(SIGABRT, &signal_handler); - signal(SIGUSR1, &signal_handler); - signal(SIGUSR2, &signal_handler); - osmo_init_ignore_signals(); - - if (daemonize) { - rc = osmo_daemonize(); - if (rc < 0) { - perror("Error during daemonize"); - exit(1); - } - } - - while (1) { - osmo_select_main(0); - } - - return 0; -} diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c deleted file mode 100644 index 351fd2ced..000000000 --- a/src/osmo-bsc/osmo_bsc_msc.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * Handle the connection to the MSC. This include ping/timeout/reconnect - * (C) 2008-2009 by Harald Welte - * (C) 2009-2015 by Holger Hans Peter Freyther - * (C) 2009-2015 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include - -#include - -#include -#include -#include - -#if 0 -static void initialize_if_needed(struct bsc_msc_connection *conn); -static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn); -static void send_id_get_response(struct bsc_msc_data *data, int fd, struct msgb *inp); -static void send_ping(struct bsc_msc_data *data); -static void schedule_ping_pong(struct bsc_msc_data *data); - -/* - * MGCP forwarding code - */ - -#endif -static int mgcp_do_read(struct osmo_fd *fd) -{ - struct bsc_msc_data *data = (struct bsc_msc_data *) fd->data; - struct msgb *mgcp; - int ret; - - mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw"); - if (!mgcp) { - LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n"); - return -1; - } - - ret = read(fd->fd, mgcp->data, 4096 - 128); - if (ret <= 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno)); - msgb_free(mgcp); - return -1; - } else if (ret > 4096 - 128) { - LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret); - msgb_free(mgcp); - return -1; - } - - mgcp->l2h = msgb_put(mgcp, ret); - msc_queue_write(data->msc_con, mgcp, IPAC_PROTO_MGCP_OLD); - return 0; -} - -static int mgcp_do_write(struct osmo_fd *fd, struct msgb *msg) -{ - int ret; - - LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len); - - ret = write(fd->fd, msg->data, msg->len); - if (ret != msg->len) - LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW (%s).\n", strerror(errno)); - - return ret; -} - -#if 0 -static void mgcp_forward(struct bsc_msc_data *data, struct msgb *msg) -{ - struct msgb *mgcp; - - if (msgb_l2len(msg) > 4096) { - LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n"); - return; - } - - mgcp = msgb_alloc(4096, "mgcp_to_gw"); - if (!mgcp) { - LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n"); - return; - } - - msgb_put(mgcp, msgb_l2len(msg)); - memcpy(mgcp->data, msg->l2h, mgcp->len); - if (osmo_wqueue_enqueue(&data->mgcp_agent, mgcp) != 0) { - LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n"); - msgb_free(mgcp); - } -} -#endif - -static int mgcp_create_port(struct bsc_msc_data *data) -{ - int on; - struct sockaddr_in addr; - - data->mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); - if (data->mgcp_agent.bfd.fd < 0) { - LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno); - return -1; - } - - on = 1; - setsockopt(data->mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - /* try to bind the socket */ - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = 0; - - if (bind(data->mgcp_agent.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - LOGP(DMGCP, LOGL_FATAL, "Failed to bind to any port.\n"); - close(data->mgcp_agent.bfd.fd); - data->mgcp_agent.bfd.fd = -1; - return -1; - } - - /* connect to the remote */ - addr.sin_port = htons(2427); - if (connect(data->mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) { - LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %s\n", strerror(errno)); - close(data->mgcp_agent.bfd.fd); - data->mgcp_agent.bfd.fd = -1; - return -1; - } - - osmo_wqueue_init(&data->mgcp_agent, 10); - data->mgcp_agent.bfd.when = BSC_FD_READ; - data->mgcp_agent.bfd.data = data; - data->mgcp_agent.read_cb = mgcp_do_read; - data->mgcp_agent.write_cb = mgcp_do_write; - - if (osmo_fd_register(&data->mgcp_agent.bfd) != 0) { - LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n"); - close(data->mgcp_agent.bfd.fd); - data->mgcp_agent.bfd.fd = -1; - return -1; - } - - return 0; -} - - -/* - * Send data to the network - */ -int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto) -{ - ipa_prepend_header(msg, proto); - if (osmo_wqueue_enqueue(&conn->write_queue, msg) != 0) { - LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto); - msgb_free(msg); - return -1; - } - - return 0; -} - -#if 0 -int msc_queue_write_with_ping(struct bsc_msc_connection *conn, - struct msgb *msg, int proto) -{ - struct bsc_msc_data *data; - uint8_t val; - - /* prepend the header */ - ipa_prepend_header(msg, proto); - if (osmo_wqueue_enqueue(&conn->write_queue, msg) != 0) { - LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto); - msgb_free(msg); - return -1; - } - - /* add the ping as the other message */ - val = IPAC_MSGT_PING; - msgb_l16tv_put(msg, 1, IPAC_PROTO_IPACCESS, &val); - - data = (struct bsc_msc_data *) conn->write_queue.bfd.data; - schedule_ping_pong(data); - return 0; -} - -static int msc_alink_do_write(struct osmo_fd *fd, struct msgb *msg) -{ - int ret; - - LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg)); - LOGP(DLMI, LOGL_DEBUG, "MSC TX %s\n", osmo_hexdump(msg->data, msg->len)); - - ret = write(fd->fd, msg->data, msg->len); - if (ret < msg->len) - perror("MSC: Failed to send SCCP"); - - return ret; -} - -static void handle_ctrl(struct bsc_msc_data *msc, struct msgb *msg) -{ - int ret; - struct ctrl_cmd *cmd; - - cmd = ctrl_cmd_parse(msc->msc_con, msg); - if (!cmd) { - LOGP(DMSC, LOGL_ERROR, "Failed to parse control message.\n"); - cmd = talloc_zero(msc->msc_con, struct ctrl_cmd); - if (!cmd) { - LOGP(DMSC, LOGL_ERROR, "OOM!\n"); - return; - } - cmd->type = CTRL_TYPE_ERROR; - cmd->id = "err"; - cmd->reply = "Failed to parse control message."; - - ctrl_cmd_send(&msc->msc_con->write_queue, cmd); - talloc_free(cmd); - - return; - } - - ret = ctrl_cmd_handle(msc->network->ctrl, cmd, msc->network); - if (ret != CTRL_CMD_HANDLED) - ctrl_cmd_send(&msc->msc_con->write_queue, cmd); - talloc_free(cmd); -} - -static void osmo_ext_handle(struct bsc_msc_data *msc, struct msgb *msg) -{ - struct ipaccess_head *hh; - struct ipaccess_head_ext *hh_ext; - - hh = (struct ipaccess_head *) msg->data; - hh_ext = (struct ipaccess_head_ext *) hh->data; - if (msg->len < sizeof(*hh) + sizeof(*hh_ext)) { - LOGP(DMSC, LOGL_ERROR, "Packet too short for extended header.\n"); - return; - } - - msg->l2h = hh_ext->data; - if (hh_ext->proto == IPAC_PROTO_EXT_MGCP) - mgcp_forward(msc, msg); - else if (hh_ext->proto == IPAC_PROTO_EXT_LAC) - send_lacs(msc->network, msc->msc_con); - else if (hh_ext->proto == IPAC_PROTO_EXT_CTRL) - handle_ctrl(msc, msg); -} - -static int ipaccess_a_fd_cb(struct osmo_fd *bfd) -{ - struct msgb *msg = NULL; - struct ipaccess_head *hh; - struct bsc_msc_data *data = (struct bsc_msc_data *) bfd->data; - int ret; - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &data->msc_con->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - if (ret == 0) { - LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n"); - bsc_msc_lost(data->msc_con); - return -1; - } - - LOGP(DMSC, LOGL_ERROR, "Failed to parse ip access message: %d\n", ret); - return -1; - } - - LOGP(DLMI, LOGL_DEBUG, "From MSC: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]); - - /* handle base message handling */ - hh = (struct ipaccess_head *) msg->data; - - /* initialize the networking. This includes sending a GSM08.08 message */ - msg->cb[0] = (unsigned long) data; - if (hh->proto == IPAC_PROTO_IPACCESS) { - ipa_ccm_rcvmsg_base(msg, bfd); - if (msg->l2h[0] == IPAC_MSGT_ID_ACK) - initialize_if_needed(data->msc_con); - else if (msg->l2h[0] == IPAC_MSGT_ID_GET) { - send_id_get_response(data, bfd->fd, msg); - } else if (msg->l2h[0] == IPAC_MSGT_PONG) { - osmo_timer_del(&data->pong_timer); - } - } else if (hh->proto == IPAC_PROTO_SCCP) { - sccp_system_incoming_ctx(msg, data->msc_con); - } else if (hh->proto == IPAC_PROTO_MGCP_OLD) { - mgcp_forward(data, msg); - } else if (hh->proto == IPAC_PROTO_OSMO) { - osmo_ext_handle(data, msg); - } - - msgb_free(msg); - return 0; -} - -static void send_ping(struct bsc_msc_data *data) -{ - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "ping"); - if (!msg) { - LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n"); - return; - } - - msg->l2h = msgb_put(msg, 1); - msg->l2h[0] = IPAC_MSGT_PING; - - msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS); -} - -static void schedule_ping_pong(struct bsc_msc_data *data) -{ - /* send another ping in 20 seconds */ - osmo_timer_schedule(&data->ping_timer, data->ping_timeout, 0); - - /* also start a pong timer */ - osmo_timer_schedule(&data->pong_timer, data->pong_timeout, 0); -} - -static void msc_ping_timeout_cb(void *_data) -{ - struct bsc_msc_data *data = (struct bsc_msc_data *) _data; - if (data->ping_timeout <= 0) - return; - - send_ping(data); - schedule_ping_pong(data); -} - -static void msc_pong_timeout_cb(void *_data) -{ -// struct bsc_msc_data *data = (struct bsc_msc_data *) _data; - - LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n"); -// bsc_msc_lost(data->msc_con); -} - -static void msc_connection_connected(struct bsc_msc_connection *con) -{ - struct msc_signal_data sig; - struct bsc_msc_data *data; - int ret, on; - on = 1; -// ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); -// if (ret != 0) -// LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno)); - -// data = (struct bsc_msc_data *) con->write_queue.bfd.data; -// msc_ping_timeout_cb(data); - - sig.data = data; - osmo_signal_dispatch(SS_MSC, S_MSC_CONNECTED, &sig); -} - -/* - * The connection to the MSC was lost and we will need to free all - * resources and then attempt to reconnect. - */ -static void msc_connection_was_lost(struct bsc_msc_connection *msc) -{ -// struct msc_signal_data sig; -// struct bsc_msc_data *data; - - LOGP(DMSC, LOGL_ERROR, "Lost MSC connection. Freing stuff.\n"); - -// data = (struct bsc_msc_data *) msc->write_queue.bfd.data; -// osmo_timer_del(&data->ping_timer); -// osmo_timer_del(&data->pong_timer); -// -// sig.data = data; -// osmo_signal_dispatch(SS_MSC, S_MSC_LOST, &sig); - - msc->is_authenticated = 0; -// bsc_msc_schedule_connect(msc); -} - -static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn) -{ - struct ipac_ext_lac_cmd *lac; - struct gsm_bts *bts; - struct msgb *msg; - int lacs = 0; - - if (llist_empty(&net->bts_list)) { - LOGP(DMSC, LOGL_ERROR, "No BTSs configured. Not sending LACs.\n"); - return; - } - - msg = msgb_alloc_headroom(4096, 128, "LAC Command"); - if (!msg) { - LOGP(DMSC, LOGL_ERROR, "Failed to create the LAC command.\n"); - return; - } - - lac = (struct ipac_ext_lac_cmd *) msgb_put(msg, sizeof(*lac)); - lac->add_remove = 1; - - llist_for_each_entry(bts, &net->bts_list, list) { - if (lacs++ == 0) - lac->lac = htons(bts->location_area_code); - else - msgb_put_u16(msg, htons(bts->location_area_code)); - } - - lac->nr_extra_lacs = lacs - 1; - ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_LAC); - msc_queue_write(conn, msg, IPAC_PROTO_OSMO); -} - -static void initialize_if_needed(struct bsc_msc_connection *conn) -{ - struct msgb *msg; - - if (!conn->is_authenticated) { - /* send a gsm 08.08 reset message from here */ - msg = gsm0808_create_reset(); - if (!msg) { - LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n"); - return; - } - - sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0, conn); - msgb_free(msg); - conn->is_authenticated = 1; - } -} - -static int answer_challenge(struct bsc_msc_data *data, struct msgb *inp, struct osmo_auth_vector *vec) -{ - int ret; - struct tlv_parsed tvp; - const uint8_t *mrand; - uint8_t mrand_len; - struct osmo_sub_auth_data auth = { - .type = OSMO_AUTH_TYPE_GSM, - .algo = OSMO_AUTH_ALG_MILENAGE, - }; - - ret = ipa_ccm_idtag_parse_off(&tvp, - inp->l2h + 1, - msgb_l2len(inp) - 1, 1); - if (ret < 0) { - LOGP(DMSC, LOGL_ERROR, "ignoring IPA response " - "message with malformed TLVs: %s\n", osmo_hexdump(inp->l2h + 1, - msgb_l2len(inp) - 1)); - return 0; - } - - mrand = TLVP_VAL(&tvp, 0x23); - mrand_len = TLVP_LEN(&tvp, 0x23); - if (mrand_len != 16) { - LOGP(DMSC, LOGL_ERROR, - "RAND is not 16 bytes. Was %d\n", - mrand_len); - return 0; - } - - /* copy the key */ - memcpy(auth.u.umts.opc, data->bsc_key, 16); - memcpy(auth.u.umts.k, data->bsc_key, 16); - memset(auth.u.umts.amf, 0, 2); - auth.u.umts.sqn = 0; - - /* generate the result */ - memset(vec, 0, sizeof(*vec)); - osmo_auth_gen_vec(vec, &auth, mrand); - return 1; -} - - -static void send_id_get_response(struct bsc_msc_data *data, int fd, struct msgb *inp) -{ - struct msc_signal_data sig; - struct msgb *msg; - struct osmo_auth_vector vec; - int valid = 0; - - if (data->bsc_key_present) - valid = answer_challenge(data, inp, &vec); - - msg = bsc_msc_id_get_resp(valid, data->bsc_token, - vec.res, valid ? vec.res_len : 0); - if (!msg) - return; - msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS); - - sig.data = data; - osmo_signal_dispatch(SS_MSC, S_MSC_AUTHENTICATED, &sig); -} - -#endif - -int osmo_bsc_msc_init(struct bsc_msc_data *data) -{ - if (mgcp_create_port(data) != 0) - return -1; - - data->msc_con = bsc_msc_create(data, &data->dests); - if (!data->msc_con) { - LOGP(DMSC, LOGL_ERROR, "Creating the MSC network connection failed.\n"); - return -1; - } - -// osmo_timer_setup(&data->ping_timer, msc_ping_timeout_cb, data); -// osmo_timer_setup(&data->pong_timer, msc_pong_timeout_cb, data); - - data->msc_con->write_queue.bfd.data = data; -// data->msc_con->connection_loss = msc_connection_was_lost; -// data->msc_con->connected = msc_connection_connected; -// data->msc_con->write_queue.read_cb = ipaccess_a_fd_cb; -// data->msc_con->write_queue.write_cb = msc_alink_do_write; -// bsc_msc_connect(data->msc_con); - - data->msc_con->is_connected = 1; - data->msc_con->is_authenticated = 1; - - - return 0; -} - - -struct bsc_msc_data *osmo_msc_data_find(struct gsm_network *net, int nr) -{ - struct bsc_msc_data *msc_data; - - llist_for_each_entry(msc_data, &net->bsc_data->mscs, entry) - if (msc_data->nr == nr) - return msc_data; - return NULL; -} - -struct bsc_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr) -{ - struct bsc_msc_data *msc_data; - - /* check if there is already one */ - msc_data = osmo_msc_data_find(net, nr); - if (msc_data) - return msc_data; - - msc_data = talloc_zero(net, struct bsc_msc_data); - if (!msc_data) - return NULL; - - llist_add_tail(&msc_data->entry, &net->bsc_data->mscs); - - /* Init back pointer */ - msc_data->network = net; - - INIT_LLIST_HEAD(&msc_data->dests); - msc_data->ping_timeout = 20; - msc_data->pong_timeout = 5; - msc_data->core_mnc = -1; - msc_data->core_mcc = -1; - msc_data->core_ci = -1; - msc_data->core_lac = -1; - msc_data->rtp_base = 4000; - - msc_data->nr = nr; - msc_data->allow_emerg = 1; - - /* Defaults for the audio setup */ - msc_data->amr_conf.m5_90 = 1; - - return msc_data; -} - diff --git a/src/osmo-bsc/osmo_bsc_reset.c b/src/osmo-bsc/osmo_bsc_reset.c deleted file mode 100644 index 0baf08089..000000000 --- a/src/osmo-bsc/osmo_bsc_reset.c +++ /dev/null @@ -1,190 +0,0 @@ -/* (C) 2017 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RESET_RESEND_INTERVAL 2 /* sec */ -#define RESET_RESEND_TIMER_NO 1234 /* FIXME: dig out the real timer number */ -#define BAD_CONNECTION_THRESOLD 3 /* connection failures */ - -enum fsm_states { - ST_DISC, /* Disconnected from MSC */ - ST_CONN, /* We have a confirmed connection to the MSC */ -}; - -static const struct value_string fsm_state_names[] = { - {ST_DISC, "ST_DISC (disconnected)"}, - {ST_CONN, "ST_CONN (connected)"}, - {0, NULL}, -}; - -enum fsm_evt { - EV_RESET_ACK, /* got reset acknowlegement from the MSC */ - EV_N_DISCONNECT, /* lost a connection */ - EV_N_CONNECT, /* made a successful connection */ -}; - -static const struct value_string fsm_evt_names[] = { - {EV_RESET_ACK, "EV_RESET_ACK"}, - {EV_N_DISCONNECT, "EV_N_DISCONNECT"}, - {EV_N_CONNECT, "EV_N_CONNECT"}, - {0, NULL}, -}; - -/* Disconnected state */ -static void fsm_disc_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct bsc_msc_data *msc = (struct bsc_msc_data *)data; - - LOGP(DMSC, LOGL_NOTICE, "fsm-state (msc-reset): %s, fsm-event: %s, MSC No.: %i\n", - get_value_string(fsm_state_names, ST_DISC), get_value_string(fsm_evt_names, event), msc->nr); - msc->msc_con->msc_conn_loss_count = 0; - osmo_fsm_inst_state_chg(fi, ST_CONN, 0, 0); -} - -/* Connected state */ -static void fsm_conn_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) -{ - struct bsc_msc_data *msc = (struct bsc_msc_data *)data; - - LOGP(DMSC, LOGL_NOTICE, "fsm-state (msc-reset): %s, fsm-event: %s, MSC No.: %i\n", - get_value_string(fsm_state_names, ST_CONN), get_value_string(fsm_evt_names, event), msc->nr); - - OSMO_ASSERT(msc); - - switch (event) { - case EV_N_DISCONNECT: - if (msc->msc_con->msc_conn_loss_count >= BAD_CONNECTION_THRESOLD) { - LOGP(DMSC, LOGL_NOTICE, "SIGTRAN connection to MSC No.: %i down, reconnecting...\n", msc->nr); - osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO); - } else - msc->msc_con->msc_conn_loss_count++; - break; - case EV_N_CONNECT: - msc->msc_con->msc_conn_loss_count = 0; - break; - } -} - -/* Timer callback to retransmit the reset signal */ -static int fsm_reset_ack_timeout_cb(struct osmo_fsm_inst *fi) -{ - struct bsc_msc_data *msc = (struct bsc_msc_data *)fi->priv; - - LOGP(DMSC, LOGL_NOTICE, "reset-ack timeout (T%i) in state %s, MSC No.: %i, resending...\n", fi->T, - get_value_string(fsm_state_names, fi->state), msc->nr); - - osmo_bsc_sigtran_reset(msc); - osmo_bsc_sigtran_tx_reset(msc); - - osmo_fsm_inst_state_chg(fi, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO); - return 0; -} - -static struct osmo_fsm_state fsm_states[] = { - [ST_DISC] = { - .in_event_mask = (1 << EV_RESET_ACK), - .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN), - .name = "DISC", - .action = fsm_disc_cb, - }, - [ST_CONN] = { - .in_event_mask = (1 << EV_N_DISCONNECT) | (1 << EV_N_CONNECT), - .out_state_mask = (1 << ST_DISC) | (1 << ST_CONN), - .name = "CONN", - .action = fsm_conn_cb, - }, -}; - -/* State machine definition */ -static struct osmo_fsm fsm = { - .name = "FSM RESET", - .states = fsm_states, - .num_states = ARRAY_SIZE(fsm_states), - .log_subsys = DMSC, - .timer_cb = fsm_reset_ack_timeout_cb, -}; - -/* Create and start state machine which handles the reset/reset-ack procedure */ -void start_reset_fsm(struct bsc_msc_data *msc) -{ - OSMO_ASSERT(msc); - OSMO_ASSERT(msc->msc_con); - - osmo_fsm_register(&fsm); - msc->msc_con->fsm_reset = osmo_fsm_inst_alloc(&fsm, NULL, NULL, LOGL_DEBUG, "FSM RESET INST"); - OSMO_ASSERT(msc->msc_con->fsm_reset); - - msc->msc_con->fsm_reset->priv = msc; - - /* kick off reset-ack sending mechanism */ - osmo_fsm_inst_state_chg(msc->msc_con->fsm_reset, ST_DISC, RESET_RESEND_INTERVAL, RESET_RESEND_TIMER_NO); -} - -/* Confirm that we sucessfully received a reset acknowlege message */ -void reset_ack_confirm(struct bsc_msc_data *msc) -{ - OSMO_ASSERT(msc); - OSMO_ASSERT(msc->msc_con); - OSMO_ASSERT(msc->msc_con->fsm_reset); - - osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_RESET_ACK, msc); -} - -/* Report a failed connection */ -void report_conn_fail(struct bsc_msc_data *msc) -{ - OSMO_ASSERT(msc); - OSMO_ASSERT(msc->msc_con); - OSMO_ASSERT(msc->msc_con->fsm_reset); - - osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_N_DISCONNECT, msc); -} - -/* Report a successful connection */ -void report_conn_success(struct bsc_msc_data *msc) -{ - OSMO_ASSERT(msc); - OSMO_ASSERT(msc->msc_con); - OSMO_ASSERT(msc->msc_con->fsm_reset); - - osmo_fsm_inst_dispatch(msc->msc_con->fsm_reset, EV_N_CONNECT, msc); -} - -/* Check if we have a connection to a specified msc */ -bool sccp_conn_ready(struct bsc_msc_data *msc) -{ - OSMO_ASSERT(msc); - OSMO_ASSERT(msc->msc_con); - OSMO_ASSERT(msc->msc_con->fsm_reset); - if (msc->msc_con->fsm_reset->state == ST_CONN) - return true; - - return false; -} diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c deleted file mode 100644 index 0f6ca334f..000000000 --- a/src/osmo-bsc/osmo_bsc_sigtran.c +++ /dev/null @@ -1,561 +0,0 @@ -/* (C) 2017 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* A pointer to a list with all involved MSCs - * (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */ -static struct llist_head *msc_list; - -#define RESET_INTERVAL 1 /* sek */ -#define SCCP_MSG_MAXSIZE 1024 -#define CS7_POINTCODE_DEFAULT_OFFSET 2 - -/* Internal list with connections we currently maintain. This - * list is of type struct osmo_bsc_sccp_con */ -static LLIST_HEAD(active_connections); - -/* The SCCP stack will not assign connection IDs to us automatically, we - * will do this ourselves using a counter variable, that counts one up - * for every new connection */ -static uint32_t conn_id_counter; - -/* Helper function to Check if the given connection id is already assigned */ -static struct osmo_bsc_sccp_con *get_bsc_conn_by_conn_id(int conn_id) -{ - conn_id &= 0xFFFFFF; - struct osmo_bsc_sccp_con *bsc_con; - - llist_for_each_entry(bsc_con, &active_connections, entry) { - if (bsc_con->conn_id == conn_id) - return bsc_con; - } - - return NULL; -} - -/* Pick a free connection id */ -static int pick_free_conn_id(const struct bsc_msc_data *msc) -{ - int conn_id = conn_id_counter; - int i; - - for (i = 0; i < 0xFFFFFF; i++) { - conn_id++; - conn_id &= 0xFFFFFF; - if (get_bsc_conn_by_conn_id(conn_id) == false) { - conn_id_counter = conn_id; - return conn_id; - } - } - - return -1; -} - -/* Send reset to MSC */ -static void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc) -{ - struct osmo_ss7_instance *ss7; - struct msgb *msg; - - ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); - OSMO_ASSERT(ss7); - LOGP(DMSC, LOGL_NOTICE, "Sending RESET to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr)); - msg = gsm0808_create_reset(); - osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr, - &msc->a.msc_addr, msg); -} - -/* Send reset-ack to MSC */ -void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc) -{ - struct osmo_ss7_instance *ss7; - struct msgb *msg; - OSMO_ASSERT(msc); - - ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); - OSMO_ASSERT(ss7); - LOGP(DMSC, LOGL_NOTICE, "Sending RESET ACK to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr)); - msg = gsm0808_create_reset_ack(); - osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr, - &msc->a.msc_addr, msg); -} - -/* Find an MSC by its sigtran point code */ -static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_addr) -{ - struct osmo_ss7_instance *ss7; - struct bsc_msc_data *msc; - llist_for_each_entry(msc, msc_list, entry) { - if (memcmp(msc_addr, &msc->a.msc_addr, sizeof(*msc_addr)) == 0) - return msc; - } - - ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); - OSMO_ASSERT(ss7); - LOGP(DMSC, LOGL_ERROR, "Unable to find MSC data under address: %s\n", osmo_sccp_addr_name(ss7, msc_addr)); - return NULL; -} - -/* Send data to MSC, use the connection id which MSC it is */ -static int handle_data_from_msc(int conn_id, struct msgb *msg) -{ - struct osmo_bsc_sccp_con *bsc_con = get_bsc_conn_by_conn_id(conn_id); - int rc = -EINVAL; - - if (bsc_con) { - msg->l3h = msgb_l2(msg); - rc = bsc_handle_dt(bsc_con, msg, msgb_l2len(msg)); - } else - LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id); - - return rc; -} - -/* Sent unitdata to MSC, use the point code to determine which MSC it is */ -static int handle_unitdata_from_msc(const struct osmo_sccp_addr *msc_addr, struct msgb *msg, - const struct osmo_sccp_user *scu) -{ - struct osmo_ss7_instance *ss7; - struct bsc_msc_data *msc = get_msc_by_addr(msc_addr); - int rc = -EINVAL; - - if (msc) { - msg->l3h = msgb_l2(msg); - rc = bsc_handle_udt(msc, msg, msgb_l2len(msg)); - } else { - ss7 = osmo_sccp_get_ss7(osmo_sccp_get_sccp(scu)); - OSMO_ASSERT(ss7); - LOGP(DMSC, LOGL_NOTICE, "incoming unitdata data from unknown remote address: %s\n", - osmo_sccp_addr_name(ss7, msc_addr)); - } - return rc; -} - -/* Callback function, called by the SSCP stack when data arrives */ -static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu) -{ - struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph; - struct osmo_sccp_user *scu = _scu; - struct osmo_bsc_sccp_con *bsc_con; - int rc = 0; - - switch (OSMO_PRIM_HDR(&scu_prim->oph)) { - case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION): - /* Handle inbound UNITDATA */ - DEBUGP(DMSC, "N-UNITDATA.ind(%s)\n", osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); - rc = handle_unitdata_from_msc(&scu_prim->u.unitdata.calling_addr, oph->msg, scu); - break; - - case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION): - /* Handle (Reject) inbound connections */ - DEBUGP(DMSC, "N-CONNECT.ind(X->%u)\n", scu_prim->u.connect.conn_id); - LOGP(DMSC, LOGL_DEBUG, "Rejecting inbound SCCP connection...\n"); - rc = osmo_sccp_tx_disconn(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, 0); - break; - - case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): - /* Handle outbound connection confirmation */ - if (msgb_l2len(oph->msg) > 0) { - DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id, - osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); - rc = handle_data_from_msc(scu_prim->u.connect.conn_id, oph->msg); - } else - DEBUGP(DRANAP, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id); - break; - - case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION): - /* Handle incoming connection oriented data */ - DEBUGP(DMSC, "N-DATA.ind(%u, %s)\n", scu_prim->u.data.conn_id, - osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); - - /* Incoming data is a sign of a vital connection */ - bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id); - if (bsc_con) - a_reset_conn_success(bsc_con->msc->a.reset); - - rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg); - break; - - case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): - /* indication of disconnect */ - if (msgb_l2len(oph->msg) > 0) { - DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id, - osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause); - handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg); - } else - DEBUGP(DRANAP, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id, - scu_prim->u.disconnect.cause); - - bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id); - if (bsc_con) { - /* We might have a connectivity problem. Maybe we need to go - * through the reset procedure again? */ - if (scu_prim->u.disconnect.cause == 0) - a_reset_conn_fail(bsc_con->msc->a.reset); - - rc = osmo_bsc_sigtran_del_conn(bsc_con); - } - break; - - default: - LOGP(DMSC, LOGL_ERROR, "Unhandled SIGTRAN primitive: %u:%u\n", oph->primitive, oph->operation); - break; - } - - msgb_free(oph->msg); - return rc; -} - -/* Allocate resources to make a new connection oriented sigtran connection - * (not the connection ittself!) */ -enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc) -{ - struct osmo_ss7_instance *ss7; - struct osmo_bsc_sccp_con *bsc_con; - int conn_id; - - OSMO_ASSERT(conn); - OSMO_ASSERT(msc); - - ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); - OSMO_ASSERT(ss7); - LOGP(DMSC, LOGL_NOTICE, "Initializing resources for new SIGTRAN connection to MSC: %s...\n", - osmo_sccp_addr_name(ss7, &msc->a.msc_addr)); - - if (a_reset_conn_ready(msc->a.reset) == false) { - LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n"); - return BSC_CON_REJECT_NO_LINK; - } - - if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) { - LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n"); - return BSC_CON_REJECT_RF_GRACE; - } - - bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con); - if (!bsc_con) { - LOGP(DMSC, LOGL_ERROR, "Failed to allocate new SIGTRAN connection.\n"); - return BSC_CON_NO_MEM; - } - - bsc_con->msc = msc; - bsc_con->conn = conn; - llist_add_tail(&bsc_con->entry, &active_connections); - conn->sccp_con = bsc_con; - - /* Pick a free connection id */ - conn_id = pick_free_conn_id(msc); - if (conn_id < 0) - return BSC_CON_REJECT_NO_LINK; - bsc_con->conn_id = conn_id; - - LOGP(DMSC, LOGL_NOTICE, "Allocated new connection id: %i\n", conn_id); - - return BSC_CON_SUCCESS; -} - -/* Open a new connection oriented sigtran connection */ -int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg) -{ - struct osmo_ss7_instance *ss7; - struct bsc_msc_data *msc; - int conn_id; - int rc; - - OSMO_ASSERT(conn); - OSMO_ASSERT(msg); - OSMO_ASSERT(conn->msc); - - msc = conn->msc; - - if (a_reset_conn_ready(msc->a.reset) == false) { - LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n"); - return -EINVAL; - } - - conn_id = conn->conn_id; - ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); - OSMO_ASSERT(ss7); - LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC: %s\n", conn_id, - osmo_sccp_addr_name(ss7, &msc->a.msc_addr)); - - rc = osmo_sccp_tx_conn_req_msg(msc->a.sccp_user, conn_id, &msc->a.bsc_addr, - &msc->a.msc_addr, msg); - - return rc; -} - -/* Send data to MSC */ -int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg) -{ - struct osmo_ss7_instance *ss7; - int conn_id; - int rc; - struct bsc_msc_data *msc; - - OSMO_ASSERT(conn); - OSMO_ASSERT(msg); - OSMO_ASSERT(conn->msc); - - msc = conn->msc; - - if (a_reset_conn_ready(msc->a.reset) == false) { - LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n"); - return -EINVAL; - } - - conn_id = conn->conn_id; - - ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); - OSMO_ASSERT(ss7); - LOGP(DMSC, LOGL_DEBUG, "Sending connection (id=%i) oriented data to MSC: %si\n", - conn_id, osmo_sccp_addr_name(ss7, &msc->a.msc_addr)); - - rc = osmo_sccp_tx_data_msg(msc->a.sccp_user, conn_id, msg); - - return rc; -} - -/* Delete a connection from the list with open connections - * (called by osmo_bsc_api.c on failing open connections and - * locally, when a connection is closed by the MSC */ -int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *conn) -{ - if (!conn) - return 0; - - if (conn->conn) { - LOGP(DMSC, LOGL_ERROR, - "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n", - conn->conn_id); - bsc_subscr_con_free(conn->conn); - conn->conn = NULL; - - /* This bahaviour might be caused by a bad connection. Maybe we - * will have to go through the reset procedure again */ - a_reset_conn_fail(conn->msc->a.reset); - } - - llist_del(&conn->entry); - talloc_free(conn); - - return 0; -} - -/* Send an USSD notification in case we loose the connection to the MSC */ -static void bsc_notify_msc_lost(const struct osmo_bsc_sccp_con *conn) -{ - struct gsm_subscriber_connection *subscr_conn; - - /* Check if sccp conn is still present */ - if (!conn) - return; - subscr_conn = conn->conn; - - /* send USSD notification if string configured and conn->data is set */ - if (!subscr_conn) - return; - - /* check for config string */ - if (!conn->msc->ussd_msc_lost_txt) - return; - if (conn->msc->ussd_msc_lost_txt[0] == '\0') - return; - - /* send USSD notification */ - bsc_send_ussd_notify(subscr_conn, 1, subscr_conn->sccp_con->msc->ussd_msc_lost_txt); - bsc_send_ussd_release_complete(subscr_conn); -} - -/* Close all open sigtran connections and channels */ -void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc) -{ - struct osmo_bsc_sccp_con *conn; - struct osmo_bsc_sccp_con *conn_temp; - OSMO_ASSERT(msc); - - /* Close all open connections */ - llist_for_each_entry_safe(conn, conn_temp, &active_connections, entry) { - - /* We only may close connections which actually belong to this - * MSC. All other open connections are left untouched */ - if (conn->msc == msc) { - /* Notify active connection users via USSD that the MSC is down */ - bsc_notify_msc_lost(conn); - - /* Take down all occopied RF channels */ - if (conn->conn) - gsm0808_clear(conn->conn); - - /* Disconnect all Sigtran connections */ - osmo_sccp_tx_disconn(msc->a.sccp_user, conn->conn_id, &msc->a.bsc_addr, 0); - - /* Delete subscriber connection */ - osmo_bsc_sigtran_del_conn(conn); - } - } -} - -/* Callback function: Close all open connections */ -static void osmo_bsc_sigtran_reset_cb(const void *priv) -{ - struct bsc_msc_data *msc = (struct bsc_msc_data*) priv; - - /* Shut down all ongoing traffic */ - osmo_bsc_sigtran_reset(msc); - - /* Send reset to MSC */ - osmo_bsc_sigtran_tx_reset(msc); -} - -/* Default point-code to be used as local address (BSC) */ -#define BSC_DEFAULT_PC "0.23.3" - -/* Default point-code to be used as remote address (MSC) */ -#define MSC_DEFAULT_PC "0.23.1" - -/* Initalize osmo sigtran backhaul */ -int osmo_bsc_sigtran_init(struct llist_head *mscs) -{ - bool free_attempt_used = false; - bool fail_on_next_invalid_cfg = false; - - struct bsc_msc_data *msc; - char msc_name[32]; - uint32_t default_pc; - - OSMO_ASSERT(mscs); - msc_list = mscs; - - llist_for_each_entry(msc, msc_list, entry) { - snprintf(msc_name, sizeof(msc_name), "msc-%u", msc->nr); - LOGP(DMSC, LOGL_NOTICE, "Initializing SCCP connection to MSC %s\n", msc_name); - - /* Check if the VTY could determine a valid CS7 instance, - * use safe default in case none is set */ - if (msc->a.cs7_instance_valid == false) { - msc->a.cs7_instance = 0; - if (fail_on_next_invalid_cfg) - goto fail_auto_cofiguration; - free_attempt_used = true; - } - LOGP(DMSC, LOGL_NOTICE, "CS7 Instance identifier, A-Interface: %u\n", msc->a.cs7_instance); - - /* Pre-Check if there is an ss7 instance present */ - if (osmo_ss7_instance_find(msc->a.cs7_instance) == NULL) { - if (fail_on_next_invalid_cfg) - goto fail_auto_cofiguration; - free_attempt_used = true; - } - - /* SS7 Protocol stack */ - default_pc = osmo_ss7_pointcode_parse(NULL, BSC_DEFAULT_PC); - msc->a.sccp = - osmo_sccp_simple_client_on_ss7_id(msc, msc->a.cs7_instance, msc_name, default_pc, - OSMO_SS7_ASP_PROT_M3UA, 0, NULL, 0, NULL); - if (!msc->a.sccp) - return -EINVAL; - - /* Check if the sccp-address fullfills minimum requirements (SSN+PC is present, - * automatically recover addresses if the addresses are not set up properly) */ - if (!osmo_sccp_check_addr(&msc->a.bsc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) { - if (fail_on_next_invalid_cfg) - goto fail_auto_cofiguration; - free_attempt_used = true; - - LOGP(DMSC, LOGL_NOTICE, - "A-interface: invalid or missing local (BSC) SCCP address (a.bsc_addr=%s)\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr)); - osmo_sccp_local_addr_by_instance(&msc->a.bsc_addr, msc->a.sccp, SCCP_SSN_BSSAP); - LOGP(DMSC, LOGL_NOTICE, - "A-interface: using automatically generated local (BSC) SCCP address (a.bsc_addr=%s)\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr)); - } else { - LOGP(DMSC, LOGL_NOTICE, - "A-interface: using local (BSC) automatically SCCP address (a.msc_addr=%s)\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr)); - } - - if (!osmo_sccp_check_addr(&msc->a.msc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) { - if (fail_on_next_invalid_cfg) - goto fail_auto_cofiguration; - free_attempt_used = true; - - LOGP(DMSC, LOGL_NOTICE, - "A-interface: invalid or missing remote (MSC) SCCP address for the MSC (a.msc_addr=%s)\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr)); - osmo_sccp_local_addr_by_instance(&msc->a.msc_addr, msc->a.sccp, SCCP_SSN_BSSAP); - msc->a.msc_addr.pc = osmo_ss7_pointcode_parse(NULL, MSC_DEFAULT_PC); - LOGP(DMSC, LOGL_NOTICE, - "A-interface: using automatically generated remote (MSC) SCCP address (a.msc_addr=%s)\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr)); - free_attempt_used = true; - } else { - LOGP(DMSC, LOGL_NOTICE, - "A-interface: using remote (MSC) automatically SCCP address (a.msc_addr=%s)\n", - osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr)); - } - - /* Bind SCCP user */ - msc->a.sccp_user = osmo_sccp_user_bind(msc->a.sccp, msc_name, sccp_sap_up, msc->a.bsc_addr.ssn); - if (!msc->a.sccp_user) - return -EINVAL; - - /* Start MSC-Reset procedure */ - msc->a.reset = a_reset_alloc(msc, msc_name, osmo_bsc_sigtran_reset_cb, msc); - if (!msc->a.reset) - return -EINVAL; - - /* If we have detected that the SS7 configuration of the MSC we have just initalized - * was incomplete or completely missing, we can not tolerate another incomplete - * configuration. The reson for this is that we do only specify exactly one default - * pointcode pair. We also specify localhost as default IP-Address. If we have wanted - * to support multiple MSCs with automatic configuration we would be forced to invent - * a complex ruleset how to allocate the pointcodes and respective IP-Addresses. - * Furthermore, the situation where a single BSC is connected to multiple MSCs - * is a very rare situation anyway. In this case we expect the user to experienced - * enough to create a valid SS7/CS7 VTY configuration that does not lack any - * components */ - if (free_attempt_used) - fail_on_next_invalid_cfg = true; - } - - return 0; - -fail_auto_cofiguration: - LOGP(DMSC, LOGL_ERROR, - "A-interface: More than one invalid/inclomplete configuration detected, unable to revover - check config file!\n"); - return -EINVAL; -} diff --git a/src/osmo-bsc/osmo_bsc_vty.c b/src/osmo-bsc/osmo_bsc_vty.c deleted file mode 100644 index 8edcbf390..000000000 --- a/src/osmo-bsc/osmo_bsc_vty.c +++ /dev/null @@ -1,1039 +0,0 @@ -/* Osmo BSC VTY Configuration */ -/* (C) 2009-2015 by Holger Hans Peter Freyther - * (C) 2009-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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - - -#define IPA_STR "IP.ACCESS specific\n" - -extern struct gsm_network *bsc_gsmnet; - -static struct osmo_bsc_data *osmo_bsc_data(struct vty *vty) -{ - return bsc_gsmnet->bsc_data; -} - -static struct bsc_msc_data *bsc_msc_data(struct vty *vty) -{ - return vty->index; -} - -static struct cmd_node bsc_node = { - BSC_NODE, - "%s(config-bsc)# ", - 1, -}; - -static struct cmd_node msc_node = { - MSC_NODE, - "%s(config-msc)# ", - 1, -}; - -DEFUN(cfg_net_msc, cfg_net_msc_cmd, - "msc [<0-1000>]", "Configure MSC details\n" "MSC connection to configure\n") -{ - int index = argc == 1 ? atoi(argv[0]) : 0; - struct bsc_msc_data *msc; - - msc = osmo_msc_data_alloc(bsc_gsmnet, index); - if (!msc) { - vty_out(vty, "%%Failed to allocate MSC data.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty->index = msc; - vty->node = MSC_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc, cfg_net_bsc_cmd, - "bsc", "Configure BSC\n") -{ - vty->node = BSC_NODE; - return CMD_SUCCESS; -} - -static void write_msc_amr_options(struct vty *vty, struct bsc_msc_data *msc) -{ -#define WRITE_AMR(vty, msc, name, var) \ - vty_out(vty, " amr-config %s %s%s", \ - name, msc->amr_conf.var ? "allowed" : "forbidden", \ - VTY_NEWLINE); - - WRITE_AMR(vty, msc, "12_2k", m12_2); - WRITE_AMR(vty, msc, "10_2k", m10_2); - WRITE_AMR(vty, msc, "7_95k", m7_95); - WRITE_AMR(vty, msc, "7_40k", m7_40); - WRITE_AMR(vty, msc, "6_70k", m6_70); - WRITE_AMR(vty, msc, "5_90k", m5_90); - WRITE_AMR(vty, msc, "5_15k", m5_15); - WRITE_AMR(vty, msc, "4_75k", m4_75); -#undef WRITE_AMR -} - -static void write_msc(struct vty *vty, struct bsc_msc_data *msc) -{ - struct bsc_msc_dest *dest; - - vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE); - if (msc->bsc_token) - vty_out(vty, " token %s%s", msc->bsc_token, VTY_NEWLINE); - if (msc->bsc_key_present) - vty_out(vty, " auth-key %s%s", - osmo_hexdump(msc->bsc_key, sizeof(msc->bsc_key)), VTY_NEWLINE); - if (msc->core_mnc != -1) - vty_out(vty, " core-mobile-network-code %d%s", - msc->core_mnc, VTY_NEWLINE); - if (msc->core_mcc != -1) - vty_out(vty, " core-mobile-country-code %d%s", - msc->core_mcc, VTY_NEWLINE); - if (msc->core_lac != -1) - vty_out(vty, " core-location-area-code %d%s", - msc->core_lac, VTY_NEWLINE); - if (msc->core_ci != -1) - vty_out(vty, " core-cell-identity %d%s", - msc->core_ci, VTY_NEWLINE); - vty_out(vty, " ip.access rtp-base %d%s", msc->rtp_base, VTY_NEWLINE); - - if (msc->ping_timeout == -1) - vty_out(vty, " no timeout-ping%s", VTY_NEWLINE); - else { - vty_out(vty, " timeout-ping %d%s", msc->ping_timeout, VTY_NEWLINE); - vty_out(vty, " timeout-pong %d%s", msc->pong_timeout, VTY_NEWLINE); - if (msc->advanced_ping) - vty_out(vty, " timeout-ping advanced%s", VTY_NEWLINE); - else - vty_out(vty, " no timeout-ping advanced%s", VTY_NEWLINE); - } - - if (msc->ussd_welcome_txt) - vty_out(vty, " bsc-welcome-text %s%s", msc->ussd_welcome_txt, VTY_NEWLINE); - else - vty_out(vty, " no bsc-welcome-text%s", VTY_NEWLINE); - - if (msc->ussd_msc_lost_txt && msc->ussd_msc_lost_txt[0]) - vty_out(vty, " bsc-msc-lost-text %s%s", msc->ussd_msc_lost_txt, VTY_NEWLINE); - else - vty_out(vty, " no bsc-msc-lost-text%s", VTY_NEWLINE); - - if (msc->ussd_grace_txt && msc->ussd_grace_txt[0]) - vty_out(vty, " bsc-grace-text %s%s", msc->ussd_grace_txt, VTY_NEWLINE); - else - vty_out(vty, " no bsc-grace-text%s", VTY_NEWLINE); - - if (msc->audio_length != 0) { - int i; - - vty_out(vty, " codec-list "); - for (i = 0; i < msc->audio_length; ++i) { - if (i != 0) - vty_out(vty, " "); - - if (msc->audio_support[i]->hr) - vty_out(vty, "hr%.1u", msc->audio_support[i]->ver); - else - vty_out(vty, "fr%.1u", msc->audio_support[i]->ver); - } - vty_out(vty, "%s", VTY_NEWLINE); - - } - - llist_for_each_entry(dest, &msc->dests, list) - vty_out(vty, " dest %s %d %d%s", dest->ip, dest->port, - dest->dscp, VTY_NEWLINE); - - vty_out(vty, " type %s%s", msc->type == MSC_CON_TYPE_NORMAL ? - "normal" : "local", VTY_NEWLINE); - vty_out(vty, " allow-emergency %s%s", msc->allow_emerg ? - "allow" : "deny", VTY_NEWLINE); - - if (msc->local_pref) - vty_out(vty, " local-prefix %s%s", msc->local_pref, VTY_NEWLINE); - - if (msc->acc_lst_name) - vty_out(vty, " access-list-name %s%s", msc->acc_lst_name, VTY_NEWLINE); - - /* write amr options */ - write_msc_amr_options(vty, msc); - - /* write sccp connection configuration */ - if (msc->a.bsc_addr_name) { - vty_out(vty, " bsc-addr %s%s", - msc->a.bsc_addr_name, VTY_NEWLINE); - } - if (msc->a.msc_addr_name) { - vty_out(vty, " msc-addr %s%s", - msc->a.msc_addr_name, VTY_NEWLINE); - } -} - -static int config_write_msc(struct vty *vty) -{ - struct bsc_msc_data *msc; - struct osmo_bsc_data *bsc = osmo_bsc_data(vty); - - llist_for_each_entry(msc, &bsc->mscs, entry) - write_msc(vty, msc); - - return CMD_SUCCESS; -} - -static int config_write_bsc(struct vty *vty) -{ - struct osmo_bsc_data *bsc = osmo_bsc_data(vty); - - vty_out(vty, "bsc%s", VTY_NEWLINE); - if (bsc->mid_call_txt) - vty_out(vty, " mid-call-text %s%s", bsc->mid_call_txt, VTY_NEWLINE); - vty_out(vty, " mid-call-timeout %d%s", bsc->mid_call_timeout, VTY_NEWLINE); - if (bsc->rf_ctrl_name) - vty_out(vty, " bsc-rf-socket %s%s", - bsc->rf_ctrl_name, VTY_NEWLINE); - - if (bsc->auto_off_timeout != -1) - vty_out(vty, " bsc-auto-rf-off %d%s", - bsc->auto_off_timeout, VTY_NEWLINE); - - if (bsc->ussd_no_msc_txt && bsc->ussd_no_msc_txt[0]) - vty_out(vty, " missing-msc-text %s%s", bsc->ussd_no_msc_txt, VTY_NEWLINE); - else - vty_out(vty, " no missing-msc-text%s", VTY_NEWLINE); - if (bsc->acc_lst_name) - vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_token, - cfg_net_bsc_token_cmd, - "token TOKEN", - "A token for the BSC to be sent to the MSC\n" "A token\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - osmo_talloc_replace_string(osmo_bsc_data(vty), &data->bsc_token, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_key, - cfg_net_bsc_key_cmd, - "auth-key KEY", - "Authentication (secret) key configuration\n" - "Security key\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - osmo_hexparse(argv[0], data->bsc_key, sizeof(data->bsc_key)); - data->bsc_key_present = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_net_no_bsc_key, cfg_net_bsc_no_key_cmd, - "no auth-key", - NO_STR "Authentication (secret) key configuration\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - memset(data->bsc_key, 0, sizeof(data->bsc_key)); - data->bsc_key_present = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_ncc, - cfg_net_bsc_ncc_cmd, - "core-mobile-network-code <1-999>", - "Use this network code for the core network\n" "MNC value\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->core_mnc = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_mcc, - cfg_net_bsc_mcc_cmd, - "core-mobile-country-code <1-999>", - "Use this country code for the core network\n" "MCC value\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->core_mcc = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_lac, - cfg_net_bsc_lac_cmd, - "core-location-area-code <0-65535>", - "Use this location area code for the core network\n" "LAC value\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->core_lac = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_ci, - cfg_net_bsc_ci_cmd, - "core-cell-identity <0-65535>", - "Use this cell identity for the core network\n" "CI value\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->core_ci = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_rtp_base, - cfg_net_bsc_rtp_base_cmd, - "ip.access rtp-base <1-65000>", - IPA_STR - "Set the rtp-base port for the RTP stream\n" - "Port number\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->rtp_base = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_codec_list, - cfg_net_bsc_codec_list_cmd, - "codec-list .LIST", - "Set the allowed audio codecs\n" - "List of audio codecs, e.g. fr3 fr1 hr3\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - int saw_fr, saw_hr; - int i; - - saw_fr = saw_hr = 0; - - /* free the old list... if it exists */ - if (data->audio_support) { - talloc_free(data->audio_support); - data->audio_support = NULL; - data->audio_length = 0; - } - - /* create a new array */ - data->audio_support = - talloc_zero_array(osmo_bsc_data(vty), struct gsm_audio_support *, argc); - data->audio_length = argc; - - for (i = 0; i < argc; ++i) { - /* check for hrX or frX */ - if (strlen(argv[i]) != 3 - || argv[i][1] != 'r' - || (argv[i][0] != 'h' && argv[i][0] != 'f') - || argv[i][2] < 0x30 - || argv[i][2] > 0x39) - goto error; - - data->audio_support[i] = talloc_zero(data->audio_support, - struct gsm_audio_support); - data->audio_support[i]->ver = atoi(argv[i] + 2); - - if (strncmp("hr", argv[i], 2) == 0) { - data->audio_support[i]->hr = 1; - saw_hr = 1; - } else if (strncmp("fr", argv[i], 2) == 0) { - data->audio_support[i]->hr = 0; - saw_fr = 1; - } - - if (saw_hr && saw_fr) { - vty_out(vty, "Can not have full-rate and half-rate codec.%s", - VTY_NEWLINE); - return CMD_ERR_INCOMPLETE; - } - } - - return CMD_SUCCESS; - -error: - vty_out(vty, "Codec name must be hrX or frX. Was '%s'%s", - argv[i], VTY_NEWLINE); - return CMD_ERR_INCOMPLETE; -} - -DEFUN(cfg_net_msc_dest, - cfg_net_msc_dest_cmd, - "dest A.B.C.D <1-65000> <0-255>", - "Add a destination to a MUX/MSC\n" - "IP Address\n" "Port\n" "DSCP\n") -{ - struct bsc_msc_dest *dest; - struct bsc_msc_data *data = bsc_msc_data(vty); - - dest = talloc_zero(osmo_bsc_data(vty), struct bsc_msc_dest); - if (!dest) { - vty_out(vty, "%%Failed to create structure.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - dest->ip = talloc_strdup(dest, argv[0]); - if (!dest->ip) { - vty_out(vty, "%%Failed to copy dest ip.%s", VTY_NEWLINE); - talloc_free(dest); - return CMD_WARNING; - } - - dest->port = atoi(argv[1]); - dest->dscp = atoi(argv[2]); - llist_add_tail(&dest->list, &data->dests); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_no_dest, - cfg_net_msc_no_dest_cmd, - "no dest A.B.C.D <1-65000> <0-255>", - NO_STR "Remove a destination to a MUX/MSC\n" - "IP Address\n" "Port\n" "DSCP\n") -{ - struct bsc_msc_dest *dest, *tmp; - struct bsc_msc_data *data = bsc_msc_data(vty); - - int port = atoi(argv[1]); - int dscp = atoi(argv[2]); - - llist_for_each_entry_safe(dest, tmp, &data->dests, list) { - if (port != dest->port || dscp != dest->dscp - || strcmp(dest->ip, argv[0]) != 0) - continue; - - llist_del(&dest->list); - talloc_free(dest); - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_no_ping_time, - cfg_net_msc_no_ping_time_cmd, - "no timeout-ping", - NO_STR "Disable the ping/pong handling on A-link\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->ping_timeout = -1; - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_ping_time, - cfg_net_msc_ping_time_cmd, - "timeout-ping <1-2147483647>", - "Set the PING interval, negative for not sending PING\n" - "Timeout in seconds\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->ping_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_pong_time, - cfg_net_msc_pong_time_cmd, - "timeout-pong <1-2147483647>", - "Set the time to wait for a PONG\n" "Timeout in seconds\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->pong_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_advanced_ping, - cfg_net_msc_advanced_ping_cmd, - "timeout-ping advanced", - "Ping timeout handling\nEnable advanced mode during SCCP\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - if (data->ping_timeout == -1) { - vty_out(vty, "%%ping handling is disabled. Enable it first.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - data->advanced_ping = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_no_net_msc_advanced_ping, - cfg_no_net_msc_advanced_ping_cmd, - "no timeout-ping advanced", - NO_STR "Ping timeout handling\nEnable advanced mode during SCCP\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->advanced_ping = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_welcome_ussd, - cfg_net_msc_welcome_ussd_cmd, - "bsc-welcome-text .TEXT", - "Set the USSD notification to be sent\n" "Text to be sent\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - char *str = argv_concat(argv, argc, 0); - if (!str) - return CMD_WARNING; - - osmo_talloc_replace_string(osmo_bsc_data(vty), &data->ussd_welcome_txt, str); - talloc_free(str); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_no_welcome_ussd, - cfg_net_msc_no_welcome_ussd_cmd, - "no bsc-welcome-text", - NO_STR "Clear the USSD notification to be sent\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - talloc_free(data->ussd_welcome_txt); - data->ussd_welcome_txt = NULL; - - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_lost_ussd, - cfg_net_msc_lost_ussd_cmd, - "bsc-msc-lost-text .TEXT", - "Set the USSD notification to be sent on MSC connection loss\n" "Text to be sent\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - char *str = argv_concat(argv, argc, 0); - if (!str) - return CMD_WARNING; - - osmo_talloc_replace_string(osmo_bsc_data(vty), &data->ussd_msc_lost_txt, str); - talloc_free(str); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_no_lost_ussd, - cfg_net_msc_no_lost_ussd_cmd, - "no bsc-msc-lost-text", - NO_STR "Clear the USSD notification to be sent on MSC connection loss\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - talloc_free(data->ussd_msc_lost_txt); - data->ussd_msc_lost_txt = 0; - - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_grace_ussd, - cfg_net_msc_grace_ussd_cmd, - "bsc-grace-text .TEXT", - "Set the USSD notification to be sent when the MSC has entered the grace period\n" "Text to be sent\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - char *str = argv_concat(argv, argc, 0); - if (!str) - return CMD_WARNING; - - osmo_talloc_replace_string(osmo_bsc_data(vty), &data->ussd_grace_txt, str); - talloc_free(str); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_no_grace_ussd, - cfg_net_msc_no_grace_ussd_cmd, - "no bsc-grace-text", - NO_STR "Clear the USSD notification to be sent when the MSC has entered the grace period\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - talloc_free(data->ussd_grace_txt); - data->ussd_grace_txt = NULL; - - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_missing_msc_ussd, - cfg_net_bsc_missing_msc_ussd_cmd, - "missing-msc-text .TEXT", - "Set the USSD notification to be send when a MSC has not been found.\n" "Text to be sent\n") -{ - struct osmo_bsc_data *data = osmo_bsc_data(vty); - char *txt = argv_concat(argv, argc, 0); - if (!txt) - return CMD_WARNING; - - osmo_talloc_replace_string(data, &data->ussd_no_msc_txt, txt); - talloc_free(txt); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_no_missing_msc_text, - cfg_net_bsc_no_missing_msc_text_cmd, - "no missing-msc-text", - NO_STR "Clear the USSD notification to be send when a MSC has not been found.\n") -{ - struct osmo_bsc_data *data = osmo_bsc_data(vty); - - talloc_free(data->ussd_no_msc_txt); - data->ussd_no_msc_txt = 0; - - return CMD_SUCCESS; -} - - -DEFUN(cfg_net_msc_type, - cfg_net_msc_type_cmd, - "type (normal|local)", - "Select the MSC type\n" - "Plain GSM MSC\n" "Special MSC for local call routing\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - - if (strcmp(argv[0], "normal") == 0) - data->type = MSC_CON_TYPE_NORMAL; - else if (strcmp(argv[0], "local") == 0) - data->type = MSC_CON_TYPE_LOCAL; - - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_emerg, - cfg_net_msc_emerg_cmd, - "allow-emergency (allow|deny)", - "Allow CM ServiceRequests with type emergency\n" - "Allow\n" "Deny\n") -{ - struct bsc_msc_data *data = bsc_msc_data(vty); - data->allow_emerg = strcmp("allow", argv[0]) == 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_net_msc_local_prefix, - cfg_net_msc_local_prefix_cmd, - "local-prefix REGEXP", - "Prefix for local numbers\n" "REGEXP used\n") -{ - struct bsc_msc_data *msc = bsc_msc_data(vty); - - if (gsm_parse_reg(msc, &msc->local_pref_reg, &msc->local_pref, argc, argv) != 0) { - vty_out(vty, "%%Failed to parse the regexp: '%s'%s", - argv[0], VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -#define AMR_CONF_STR "AMR Multirate Configuration\n" -#define AMR_COMMAND(name) \ - DEFUN(cfg_net_msc_amr_##name, \ - cfg_net_msc_amr_##name##_cmd, \ - "amr-config " #name "k (allowed|forbidden)", \ - AMR_CONF_STR "Bitrate\n" "Allowed\n" "Forbidden\n") \ -{ \ - struct bsc_msc_data *msc = bsc_msc_data(vty); \ - \ - msc->amr_conf.m##name = strcmp(argv[0], "allowed") == 0; \ - return CMD_SUCCESS; \ -} - -AMR_COMMAND(12_2) -AMR_COMMAND(10_2) -AMR_COMMAND(7_95) -AMR_COMMAND(7_40) -AMR_COMMAND(6_70) -AMR_COMMAND(5_90) -AMR_COMMAND(5_15) -AMR_COMMAND(4_75) - -DEFUN(cfg_msc_acc_lst_name, - cfg_msc_acc_lst_name_cmd, - "access-list-name NAME", - "Set the name of the access list to use.\n" - "The name of the to be used access list.") -{ - struct bsc_msc_data *msc = bsc_msc_data(vty); - - osmo_talloc_replace_string(msc, &msc->acc_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_msc_no_acc_lst_name, - cfg_msc_no_acc_lst_name_cmd, - "no access-list-name", - NO_STR "Remove the access list from the NAT.\n") -{ - struct bsc_msc_data *msc = bsc_msc_data(vty); - - if (msc->acc_lst_name) { - talloc_free(msc->acc_lst_name); - msc->acc_lst_name = NULL; - } - - return CMD_SUCCESS; -} - -/* Make sure only standard SSN numbers are used. If no ssn number is - * configured, silently apply the default SSN */ -static void enforce_standard_ssn(struct vty *vty, struct osmo_sccp_addr *addr) -{ - if (addr->presence & OSMO_SCCP_ADDR_T_SSN) { - if (addr->ssn != SCCP_SSN_BSSAP) - vty_out(vty, - "setting an SSN (%u) different from the standard (%u) is not allowd, will use standard SSN for address: %s%s", - addr->ssn, SCCP_SSN_BSSAP, osmo_sccp_addr_dump(addr), VTY_NEWLINE); - } - - addr->presence |= OSMO_SCCP_ADDR_T_SSN; - addr->ssn = SCCP_SSN_BSSAP; -} - -DEFUN(cfg_msc_cs7_bsc_addr, - cfg_msc_cs7_bsc_addr_cmd, - "bsc-addr NAME", - "Calling Address (local address of this BSC)\n" "SCCP address name\n") -{ - struct bsc_msc_data *msc = bsc_msc_data(vty); - const char *bsc_addr_name = argv[0]; - struct osmo_ss7_instance *ss7; - - ss7 = osmo_sccp_addr_by_name(&msc->a.bsc_addr, bsc_addr_name); - if (!ss7) { - vty_out(vty, "No sccp address %s found%s", bsc_addr_name, - VTY_NEWLINE); - return CMD_WARNING; - } - - /* Prevent mixing addresses from different CS7/SS7 instances */ - if (msc->a.cs7_instance_valid) { - if (msc->a.cs7_instance != ss7->cfg.id) { - vty_out(vty, - "SCCP address %s from different CS7 instance%s", - bsc_addr_name, VTY_NEWLINE); - return CMD_WARNING; - } - } - - msc->a.cs7_instance = ss7->cfg.id; - msc->a.cs7_instance_valid = true; - enforce_standard_ssn(vty, &msc->a.bsc_addr); - msc->a.bsc_addr_name = talloc_strdup(msc, bsc_addr_name); - return CMD_SUCCESS; -} - -DEFUN(cfg_msc_cs7_msc_addr, - cfg_msc_cs7_msc_addr_cmd, - "msc-addr NAME", - "Called Address (remote address of the MSC)\n" "SCCP address name\n") -{ - struct bsc_msc_data *msc = bsc_msc_data(vty); - const char *msc_addr_name = argv[0]; - struct osmo_ss7_instance *ss7; - - ss7 = osmo_sccp_addr_by_name(&msc->a.msc_addr, msc_addr_name); - if (!ss7) { - vty_out(vty, "No sccp address %s found%s", msc_addr_name, - VTY_NEWLINE); - return CMD_WARNING; - } - - /* Prevent mixing addresses from different CS7/SS7 instances */ - if (msc->a.cs7_instance_valid) { - if (msc->a.cs7_instance != ss7->cfg.id) { - vty_out(vty, - "SCCP address %s from different CS7 instance%s", - msc_addr_name, VTY_NEWLINE); - return CMD_WARNING; - } - } - - msc->a.cs7_instance = ss7->cfg.id; - msc->a.cs7_instance_valid = true; - enforce_standard_ssn(vty, &msc->a.msc_addr); - msc->a.msc_addr_name = talloc_strdup(msc, msc_addr_name); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_mid_call_text, - cfg_net_bsc_mid_call_text_cmd, - "mid-call-text .TEXT", - "Set the USSD notification to be send.\n" "Text to be sent\n") -{ - struct osmo_bsc_data *data = osmo_bsc_data(vty); - char *txt = argv_concat(argv, argc, 0); - if (!txt) - return CMD_WARNING; - - osmo_talloc_replace_string(data, &data->mid_call_txt, txt); - talloc_free(txt); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_bsc_mid_call_timeout, - cfg_net_bsc_mid_call_timeout_cmd, - "mid-call-timeout NR", - "Switch from Grace to Off in NR seconds.\n" "Timeout in seconds\n") -{ - struct osmo_bsc_data *data = osmo_bsc_data(vty); - data->mid_call_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_rf_socket, - cfg_net_rf_socket_cmd, - "bsc-rf-socket PATH", - "Set the filename for the RF control interface.\n" "RF Control path\n") -{ - struct osmo_bsc_data *data = osmo_bsc_data(vty); - - osmo_talloc_replace_string(data, &data->rf_ctrl_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_rf_off_time, - cfg_net_rf_off_time_cmd, - "bsc-auto-rf-off <1-65000>", - "Disable RF on MSC Connection\n" "Timeout\n") -{ - struct osmo_bsc_data *data = osmo_bsc_data(vty); - data->auto_off_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_net_no_rf_off_time, - cfg_net_no_rf_off_time_cmd, - "no bsc-auto-rf-off", - NO_STR "Disable RF on MSC Connection\n") -{ - struct osmo_bsc_data *data = osmo_bsc_data(vty); - data->auto_off_timeout = -1; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_acc_lst_name, - cfg_bsc_acc_lst_name_cmd, - "access-list-name NAME", - "Set the name of the access list to use.\n" - "The name of the to be used access list.") -{ - struct osmo_bsc_data *bsc = osmo_bsc_data(vty); - - osmo_talloc_replace_string(bsc, &bsc->acc_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_acc_lst_name, - cfg_bsc_no_acc_lst_name_cmd, - "no access-list-name", - NO_STR "Remove the access list from the BSC\n") -{ - struct osmo_bsc_data *bsc = osmo_bsc_data(vty); - - if (bsc->acc_lst_name) { - talloc_free(bsc->acc_lst_name); - bsc->acc_lst_name = NULL; - } - - return CMD_SUCCESS; -} - -DEFUN(show_statistics, - show_statistics_cmd, - "show statistics", - SHOW_STR "Statistics about the BSC\n") -{ - openbsc_vty_print_statistics(vty, bsc_gsmnet); - return CMD_SUCCESS; -} - -DEFUN(show_mscs, - show_mscs_cmd, - "show mscs", - SHOW_STR "MSC Connections and State\n") -{ - struct bsc_msc_data *msc; - llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) { - vty_out(vty, "MSC Nr: %d is connected: %d auth: %d.%s", - msc->nr, - msc->msc_con ? msc->msc_con->is_connected : -1, - msc->msc_con ? msc->msc_con->is_authenticated : -1, - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(show_pos, - show_pos_cmd, - "show position", - SHOW_STR "Position information of the BTS\n") -{ - struct gsm_bts *bts; - struct bts_location *curloc; - struct tm time; - char timestr[50]; - - llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) { - if (llist_empty(&bts->loc_list)) { - vty_out(vty, "BTS Nr: %d position invalid%s", bts->nr, - VTY_NEWLINE); - continue; - } - curloc = llist_entry(bts->loc_list.next, struct bts_location, list); - if (gmtime_r(&curloc->tstamp, &time) == NULL) { - vty_out(vty, "Time conversion failed for BTS %d%s", bts->nr, - VTY_NEWLINE); - continue; - } - if (asctime_r(&time, timestr) == NULL) { - vty_out(vty, "Time conversion failed for BTS %d%s", bts->nr, - VTY_NEWLINE); - continue; - } - /* Last character in asctime is \n */ - timestr[strlen(timestr)-1] = 0; - - vty_out(vty, "BTS Nr: %d position: %s time: %s%s", bts->nr, - get_value_string(bts_loc_fix_names, curloc->valid), timestr, - VTY_NEWLINE); - vty_out(vty, " lat: %f lon: %f height: %f%s", curloc->lat, curloc->lon, - curloc->height, VTY_NEWLINE); - } - return CMD_SUCCESS; -} - -DEFUN(gen_position_trap, - gen_position_trap_cmd, - "generate-location-state-trap <0-255>", - "Generate location state report\n" - "BTS to report\n") -{ - int bts_nr; - struct gsm_bts *bts; - struct gsm_network *net = bsc_gsmnet; - - bts_nr = atoi(argv[0]); - if (bts_nr >= net->num_bts) { - vty_out(vty, "%% can't find BTS '%s'%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - - bts = gsm_bts_num(net, bts_nr); - bsc_gen_location_state_trap(bts); - return CMD_SUCCESS; -} - -DEFUN(logging_fltr_imsi, - logging_fltr_imsi_cmd, - "logging filter imsi IMSI", - LOGGING_STR FILTER_STR - "Filter log messages by IMSI\n" "IMSI to be used as filter\n") -{ - struct bsc_subscr *bsc_subscr; - struct log_target *tgt = osmo_log_vty2tgt(vty); - const char *imsi = argv[0]; - - bsc_subscr = bsc_subscr_find_by_imsi(bsc_gsmnet->bsc_subscribers, imsi); - - if (!bsc_subscr) { - vty_out(vty, "%%no subscriber with IMSI(%s)%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - log_set_filter_bsc_subscr(tgt, bsc_subscr); - return CMD_SUCCESS; -} - -int bsc_vty_init_extra(void) -{ - install_element(CONFIG_NODE, &cfg_net_msc_cmd); - install_element(CONFIG_NODE, &cfg_net_bsc_cmd); - - install_node(&bsc_node, config_write_bsc); - vty_install_default(BSC_NODE); - install_element(BSC_NODE, &cfg_net_bsc_mid_call_text_cmd); - install_element(BSC_NODE, &cfg_net_bsc_mid_call_timeout_cmd); - install_element(BSC_NODE, &cfg_net_rf_socket_cmd); - install_element(BSC_NODE, &cfg_net_rf_off_time_cmd); - install_element(BSC_NODE, &cfg_net_no_rf_off_time_cmd); - install_element(BSC_NODE, &cfg_net_bsc_missing_msc_ussd_cmd); - install_element(BSC_NODE, &cfg_net_bsc_no_missing_msc_text_cmd); - install_element(BSC_NODE, &cfg_bsc_acc_lst_name_cmd); - install_element(BSC_NODE, &cfg_bsc_no_acc_lst_name_cmd); - - install_node(&msc_node, config_write_msc); - vty_install_default(MSC_NODE); - install_element(MSC_NODE, &cfg_net_bsc_token_cmd); - install_element(MSC_NODE, &cfg_net_bsc_key_cmd); - install_element(MSC_NODE, &cfg_net_bsc_no_key_cmd); - install_element(MSC_NODE, &cfg_net_bsc_ncc_cmd); - install_element(MSC_NODE, &cfg_net_bsc_mcc_cmd); - install_element(MSC_NODE, &cfg_net_bsc_lac_cmd); - install_element(MSC_NODE, &cfg_net_bsc_ci_cmd); - install_element(MSC_NODE, &cfg_net_bsc_rtp_base_cmd); - install_element(MSC_NODE, &cfg_net_bsc_codec_list_cmd); - install_element(MSC_NODE, &cfg_net_msc_dest_cmd); - install_element(MSC_NODE, &cfg_net_msc_no_dest_cmd); - install_element(MSC_NODE, &cfg_net_msc_no_ping_time_cmd); - install_element(MSC_NODE, &cfg_net_msc_ping_time_cmd); - install_element(MSC_NODE, &cfg_net_msc_pong_time_cmd); - install_element(MSC_NODE, &cfg_net_msc_advanced_ping_cmd); - install_element(MSC_NODE, &cfg_no_net_msc_advanced_ping_cmd); - install_element(MSC_NODE, &cfg_net_msc_welcome_ussd_cmd); - install_element(MSC_NODE, &cfg_net_msc_no_welcome_ussd_cmd); - install_element(MSC_NODE, &cfg_net_msc_lost_ussd_cmd); - install_element(MSC_NODE, &cfg_net_msc_no_lost_ussd_cmd); - install_element(MSC_NODE, &cfg_net_msc_grace_ussd_cmd); - install_element(MSC_NODE, &cfg_net_msc_no_grace_ussd_cmd); - install_element(MSC_NODE, &cfg_net_msc_type_cmd); - install_element(MSC_NODE, &cfg_net_msc_emerg_cmd); - install_element(MSC_NODE, &cfg_net_msc_local_prefix_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_12_2_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_10_2_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_7_95_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_7_40_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_6_70_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_5_90_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_5_15_cmd); - install_element(MSC_NODE, &cfg_net_msc_amr_4_75_cmd); - install_element(MSC_NODE, &cfg_msc_acc_lst_name_cmd); - install_element(MSC_NODE, &cfg_msc_no_acc_lst_name_cmd); - install_element(MSC_NODE, &cfg_msc_cs7_bsc_addr_cmd); - install_element(MSC_NODE, &cfg_msc_cs7_msc_addr_cmd); - - install_element_ve(&show_statistics_cmd); - install_element_ve(&show_mscs_cmd); - install_element_ve(&show_pos_cmd); - install_element_ve(&logging_fltr_imsi_cmd); - - install_element(ENABLE_NODE, &gen_position_trap_cmd); - - install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd); - - return 0; -} diff --git a/src/osmo-bsc_nat/Makefile.am b/src/osmo-bsc_nat/Makefile.am deleted file mode 100644 index 1eec7aa1c..000000000 --- a/src/osmo-bsc_nat/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - -I$(top_builddir) \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) \ - $(LIBOSMOCTRL_CFLAGS) \ - $(LIBOSMOSCCP_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMONETIF_CFLAGS) \ - $(LIBOSMOLEGACYMGCP_CFLAGS) \ - $(LIBCRYPTO_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -bin_PROGRAMS = \ - osmo-bsc_nat \ - $(NULL) - -osmo_bsc_nat_SOURCES = \ - bsc_filter.c \ - bsc_mgcp_utils.c \ - bsc_nat.c \ - bsc_nat_utils.c \ - bsc_nat_vty.c \ - bsc_sccp.c \ - bsc_ussd.c \ - bsc_nat_ctrl.c \ - bsc_nat_rewrite.c \ - bsc_nat_rewrite_trie.c \ - bsc_nat_filter.c \ - $(NULL) - -osmo_bsc_nat_LDADD = \ - $(top_builddir)/src/libfilter/libfilter.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOSCCP_LIBS) \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOCTRL_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMONETIF_LIBS) \ - $(LIBOSMOSIGTRAN_LIBS) \ - $(LIBOSMOLEGACYMGCP_LIBS) \ - $(LIBCRYPTO_LIBS) \ - $(LIBRARY_GSM) \ - -lrt \ - $(NULL) diff --git a/src/osmo-bsc_nat/bsc_filter.c b/src/osmo-bsc_nat/bsc_filter.c deleted file mode 100644 index 6a9e99fb8..000000000 --- a/src/osmo-bsc_nat/bsc_filter.c +++ /dev/null @@ -1,218 +0,0 @@ -/* BSC Multiplexer/NAT */ - -/* - * (C) 2010 by Holger Hans Peter Freyther - * (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 . - * - */ - -#include -#include -#include -#include - -#include -#include - -#include - -/* - * The idea is to have a simple struct describing a IPA packet with - * SCCP SSN and the GSM 08.08 payload and decide. We will both have - * a white and a blacklist of packets we want to handle. - * - * TODO: Implement a "NOT" in the filter language. - */ - -#define ALLOW_ANY -1 - -#define FILTER_TO_BSC 1 -#define FILTER_TO_MSC 2 -#define FILTER_TO_BOTH 3 - - -struct bsc_pkt_filter { - int ipa_proto; - int dest_ssn; - int bssap; - int gsm; - int filter_dir; -}; - -static struct bsc_pkt_filter black_list[] = { - /* filter reset messages to the MSC */ - { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC }, - - /* filter reset ack messages to the BSC */ - { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC }, - - /* filter ip access */ - { IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC }, -}; - -static struct bsc_pkt_filter white_list[] = { - /* allow IPAC_PROTO_SCCP messages to both sides */ - { IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH }, - - /* allow MGCP messages to both sides */ - { IPAC_PROTO_MGCP_OLD, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH }, -}; - -struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg) -{ - struct sccp_parse_result result; - struct bsc_nat_parsed *parsed; - struct ipaccess_head *hh; - - /* quick fail */ - if (msg->len < 4) - return NULL; - - parsed = talloc_zero(msg, struct bsc_nat_parsed); - if (!parsed) - return NULL; - - /* more init */ - parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1; - parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1; - - /* start parsing */ - hh = (struct ipaccess_head *) msg->data; - parsed->ipa_proto = hh->proto; - - msg->l2h = &hh->data[0]; - - /* do a size check on the input */ - if (ntohs(hh->len) != msgb_l2len(msg)) { - LOGP(DLINP, LOGL_ERROR, "Wrong input length?\n"); - talloc_free(parsed); - return NULL; - } - - /* analyze sccp down here */ - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - memset(&result, 0, sizeof(result)); - if (sccp_parse_header(msg, &result) != 0) { - talloc_free(parsed); - return 0; - } - - if (msg->l3h && msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n"); - talloc_free(parsed); - return 0; - } - - parsed->sccp_type = sccp_determine_msg_type(msg); - parsed->src_local_ref = result.source_local_reference; - parsed->dest_local_ref = result.destination_local_reference; - if (parsed->dest_local_ref) - parsed->original_dest_ref = *parsed->dest_local_ref; - parsed->called_ssn = result.called.ssn; - parsed->calling_ssn = result.calling.ssn; - - /* in case of connection confirm we have no payload */ - if (msg->l3h) { - parsed->bssap = msg->l3h[0]; - parsed->gsm_type = msg->l3h[2]; - } - } - - return parsed; -} - -int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed) -{ - int i; - - /* go through the blacklist now */ - for (i = 0; i < ARRAY_SIZE(black_list); ++i) { - /* ignore the rule? */ - if (black_list[i].filter_dir != FILTER_TO_BOTH - && black_list[i].filter_dir != dir) - continue; - - /* the proto is not blacklisted */ - if (black_list[i].ipa_proto != ALLOW_ANY - && black_list[i].ipa_proto != parsed->ipa_proto) - continue; - - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - /* the SSN is not blacklisted */ - if (black_list[i].dest_ssn != ALLOW_ANY - && black_list[i].dest_ssn != parsed->called_ssn) - continue; - - /* bssap */ - if (black_list[i].bssap != ALLOW_ANY - && black_list[i].bssap != parsed->bssap) - continue; - - /* gsm */ - if (black_list[i].gsm != ALLOW_ANY - && black_list[i].gsm != parsed->gsm_type) - continue; - - /* blacklisted */ - LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i); - return 1; - } else { - /* blacklisted, we have no content sniffing yet */ - LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i); - return 1; - } - } - - /* go through the whitelust now */ - for (i = 0; i < ARRAY_SIZE(white_list); ++i) { - /* ignore the rule? */ - if (white_list[i].filter_dir != FILTER_TO_BOTH - && white_list[i].filter_dir != dir) - continue; - - /* the proto is not whitelisted */ - if (white_list[i].ipa_proto != ALLOW_ANY - && white_list[i].ipa_proto != parsed->ipa_proto) - continue; - - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - /* the SSN is not whitelisted */ - if (white_list[i].dest_ssn != ALLOW_ANY - && white_list[i].dest_ssn != parsed->called_ssn) - continue; - - /* bssap */ - if (white_list[i].bssap != ALLOW_ANY - && white_list[i].bssap != parsed->bssap) - continue; - - /* gsm */ - if (white_list[i].gsm != ALLOW_ANY - && white_list[i].gsm != parsed->gsm_type) - continue; - - /* whitelisted */ - LOGP(DNAT, LOGL_INFO, "Whitelisted with rule %d\n", i); - return 0; - } else { - /* whitelisted */ - return 0; - } - } - - return 1; -} diff --git a/src/osmo-bsc_nat/bsc_mgcp_utils.c b/src/osmo-bsc_nat/bsc_mgcp_utils.c deleted file mode 100644 index 49050fc89..000000000 --- a/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ /dev/null @@ -1,1151 +0,0 @@ -/** - * This file contains helper routines for MGCP Gateway handling. - * - * The first thing to remember is that each BSC has its own namespace/range - * of endpoints. Whenever a BSSMAP ASSIGNMENT REQUEST is received this code - * will be called to select an endpoint on the BSC. The mapping from original - * multiplex/timeslot to BSC multiplex'/timeslot' will be stored. - * - * The second part is to take messages on the public MGCP GW interface - * and forward them to the right BSC. This requires the MSC to first - * assign the timeslot. This assumption has been true so far. We are using - * the policy_cb of the MGCP protocol code to decide if the request should - * be immediately answered or delayed. An extension "Z: noanswer" is used - * to request the BSC to not respond. This is saving some bytes of bandwidth - * and as we are using TCP to forward the message we know it will arrive. - * The mgcp_do_read method reads these messages and hands them to the protocol - * parsing code which will call the mentioned policy_cb. The bsc_mgcp_forward - * method is used on the way back from the BSC to the network. - * - * The third part is to patch messages forwarded to the BSC. This includes - * the endpoint number, the ports to be used inside the SDP file and maybe - * some other bits. - * - */ -/* - * (C) 2010-2012 by Holger Hans Peter Freyther - * (C) 2010-2012 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include - -static void send_direct(struct bsc_nat *nat, struct msgb *output) -{ - if (osmo_wqueue_enqueue(&nat->mgcp_cfg->gw_fd, output) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n"); - msgb_free(output); - } -} - -static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output) -{ - if (nat->mgcp_ipa) - bsc_nat_send_mgcp_to_msc(nat, output); - else - send_direct(nat, output); -} - -int bsc_mgcp_nr_multiplexes(int max_endpoints) -{ - int div = max_endpoints / 32; - - if ((max_endpoints % 32) != 0) - div += 1; - - return div; -} - -static int bsc_init_endps_if_needed(struct bsc_connection *con) -{ - int multiplexes; - - /* we have done that */ - if (con->_endpoint_status) - return 0; - - /* we have no config... */ - if (!con->cfg) - return -1; - - multiplexes = bsc_mgcp_nr_multiplexes(con->cfg->max_endpoints); - con->number_multiplexes = multiplexes; - con->max_endpoints = con->cfg->max_endpoints; - con->_endpoint_status = talloc_zero_array(con, char, 32 * multiplexes + 1); - return con->_endpoint_status == NULL; -} - -static int bsc_assign_endpoint(struct bsc_connection *bsc, struct nat_sccp_connection *con) -{ - int multiplex; - int timeslot; - const int number_endpoints = bsc->max_endpoints; - int i; - - mgcp_endpoint_to_timeslot(bsc->last_endpoint, &multiplex, ×lot); - timeslot += 1; - - for (i = 0; i < number_endpoints; ++i) { - int endpoint; - - /* Wrap around timeslots */ - if (timeslot == 0) - timeslot = 1; - - if (timeslot == 0x1f) { - timeslot = 1; - multiplex += 1; - } - - /* Wrap around the multiplex */ - if (multiplex >= bsc->number_multiplexes) - multiplex = 0; - - endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot); - - /* Now check if we are allowed to assign this one */ - if (endpoint >= bsc->max_endpoints) { - multiplex = 0; - timeslot = 1; - endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot); - } - - - if (bsc->_endpoint_status[endpoint] == 0) { - bsc->_endpoint_status[endpoint] = 1; - con->bsc_endp = endpoint; - bsc->last_endpoint = endpoint; - return 0; - } - - timeslot += 1; - } - - return -1; -} - -static uint16_t create_cic(int endpoint) -{ - int timeslot, multiplex; - - mgcp_endpoint_to_timeslot(endpoint, &multiplex, ×lot); - return (multiplex << 5) | (timeslot & 0x1f); -} - -int bsc_mgcp_assign_patch(struct nat_sccp_connection *con, struct msgb *msg) -{ - struct nat_sccp_connection *mcon; - struct tlv_parsed tp; - uint16_t cic; - uint8_t timeslot; - uint8_t multiplex; - unsigned int endp; - - if (!msg->l3h) { - LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n"); - return -1; - } - - if (msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n"); - return -1; - } - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0); - if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) { - LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n"); - return -1; - } - - cic = ntohs(tlvp_val16_unal(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)); - timeslot = cic & 0x1f; - multiplex = (cic & ~0x1f) >> 5; - - - endp = mgcp_timeslot_to_endpoint(multiplex, timeslot); - - if (endp >= con->bsc->nat->mgcp_cfg->trunk.number_endpoints) { - LOGP(DNAT, LOGL_ERROR, - "MSC attempted to assign bad endpoint 0x%x\n", - endp); - return -1; - } - - /* find stale connections using that endpoint */ - llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) { - if (mcon->msc_endp == endp) { - LOGP(DNAT, LOGL_ERROR, - "Endpoint %d was assigned to 0x%x and now 0x%x\n", - endp, - sccp_src_ref_to_int(&mcon->patched_ref), - sccp_src_ref_to_int(&con->patched_ref)); - bsc_mgcp_dlcx(mcon); - } - } - - con->msc_endp = endp; - if (bsc_init_endps_if_needed(con->bsc) != 0) - return -1; - if (bsc_assign_endpoint(con->bsc, con) != 0) - return -1; - - /* - * now patch the message for the new CIC... - * still assumed to be one multiplex only - */ - cic = htons(create_cic(con->bsc_endp)); - memcpy((uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE), - &cic, sizeof(cic)); - - return 0; -} - -static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i) -{ - if (nat->bsc_endpoints[i].transaction_id) { - talloc_free(nat->bsc_endpoints[i].transaction_id); - nat->bsc_endpoints[i].transaction_id = NULL; - } - - nat->bsc_endpoints[i].transaction_state = 0; - nat->bsc_endpoints[i].bsc = NULL; -} - -void bsc_mgcp_free_endpoints(struct bsc_nat *nat) -{ - int i; - - for (i = 1; i < nat->mgcp_cfg->trunk.number_endpoints; ++i){ - bsc_mgcp_free_endpoint(nat, i); - mgcp_release_endp(&nat->mgcp_cfg->trunk.endpoints[i]); - } -} - -/* send a MDCX where we do not want a response */ -static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp_endpoint *endp) -{ - char buf[2096]; - int len; - - len = snprintf(buf, sizeof(buf), - "MDCX 23 %x@mgw MGCP 1.0\r\n" - "Z: noanswer\r\n" - "\r\n" - "c=IN IP4 %s\r\n" - "m=audio %d RTP/AVP 255\r\n", - port, mgcp_bts_src_addr(endp), - endp->bts_end.local_port); - if (len < 0) { - LOGP(DMGCP, LOGL_ERROR, "snprintf for MDCX failed.\n"); - return; - } - - bsc_write_mgcp(bsc, (uint8_t *) buf, len); -} - -static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint, int trans) -{ - char buf[2096]; - int len; - - /* - * The following is a bit of a spec violation. According to the - * MGCP grammar the transaction id is are upto 9 digits but we - * prefix it with an alpha numeric value so we can easily recognize - * it as a response. - */ - len = snprintf(buf, sizeof(buf), - "DLCX nat-%u %x@mgw MGCP 1.0\r\n", - trans, endpoint); - if (len < 0) { - LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n"); - return; - } - - bsc_write_mgcp(bsc, (uint8_t *) buf, len); -} - -void bsc_mgcp_init(struct nat_sccp_connection *con) -{ - con->msc_endp = -1; - con->bsc_endp = -1; -} - -/** - * This code will remember the network side of the audio statistics and - * once the internal DLCX response arrives this can be combined with the - * the BSC side and forwarded as a trap. - */ -static void remember_pending_dlcx(struct nat_sccp_connection *con, uint32_t transaction) -{ - struct bsc_nat_call_stats *stats; - struct bsc_connection *bsc = con->bsc; - struct mgcp_endpoint *endp; - - stats = talloc_zero(bsc, struct bsc_nat_call_stats); - if (!stats) { - LOGP(DNAT, LOGL_NOTICE, - "Failed to allocate statistics for endpoint 0x%x\n", - con->msc_endp); - return; - } - - /* take the endpoint here */ - endp = &bsc->nat->mgcp_cfg->trunk.endpoints[con->msc_endp]; - - stats->remote_ref = con->remote_ref; - stats->src_ref = con->patched_ref; - - stats->ci = endp->ci; - stats->bts_rtp_port = endp->bts_end.rtp_port; - stats->bts_addr = endp->bts_end.addr; - stats->net_rtp_port = endp->net_end.rtp_port; - stats->net_addr = endp->net_end.addr; - - stats->net_ps = endp->net_end.packets; - stats->net_os = endp->net_end.octets; - stats->bts_pr = endp->bts_end.packets; - stats->bts_or = endp->bts_end.octets; - mgcp_state_calc_loss(&endp->bts_state, &endp->bts_end, - &stats->bts_expected, &stats->bts_loss); - stats->bts_jitter = mgcp_state_calc_jitter(&endp->bts_state); - - stats->trans_id = transaction; - stats->msc_endpoint = con->msc_endp; - - /* - * Too many pending requests.. let's remove the first two items. - */ - if (!llist_empty(&bsc->pending_dlcx) && - bsc->pending_dlcx_count >= bsc->cfg->max_endpoints * 3) { - struct bsc_nat_call_stats *tmp; - LOGP(DNAT, LOGL_ERROR, - "Too many(%d) pending DLCX responses on BSC: %d\n", - bsc->pending_dlcx_count, bsc->cfg->nr); - bsc->pending_dlcx_count -= 1; - tmp = (struct bsc_nat_call_stats *) bsc->pending_dlcx.next; - llist_del(&tmp->entry); - talloc_free(tmp); - } - - bsc->pending_dlcx_count += 1; - llist_add_tail(&stats->entry, &bsc->pending_dlcx); -} - -void bsc_mgcp_dlcx(struct nat_sccp_connection *con) -{ - /* send a DLCX down the stream */ - if (con->bsc_endp != -1 && con->bsc->_endpoint_status) { - LOGP(DNAT, LOGL_NOTICE, - "Endpoint 0x%x was allocated for bsc: %d. Freeing it.\n", - con->bsc_endp, con->bsc->cfg->nr); - if (con->bsc->_endpoint_status[con->bsc_endp] != 1) - LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp); - remember_pending_dlcx(con, con->bsc->next_transaction); - con->bsc->_endpoint_status[con->bsc_endp] = 0; - bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp, con->bsc->next_transaction++); - bsc_mgcp_free_endpoint(con->bsc->nat, con->msc_endp); - } - - bsc_mgcp_init(con); - -} - -/* - * Search for the pending request - */ -static void handle_dlcx_response(struct bsc_connection *bsc, struct msgb *msg, - int code, const char *transaction) -{ - uint32_t trans_id = UINT32_MAX; - uint32_t b_ps, b_os, n_pr, n_or, jitter; - int loss; - struct bsc_nat_call_stats *tmp, *stat = NULL; - struct ctrl_cmd *cmd; - - /* parse the transaction identifier */ - int rc = sscanf(transaction, "nat-%u", &trans_id); - if (rc != 1) { - LOGP(DNAT, LOGL_ERROR, "Can not parse transaction id: '%s'\n", - transaction); - return; - } - - /* find the answer for the request we made */ - llist_for_each_entry(tmp, &bsc->pending_dlcx, entry) { - if (trans_id != tmp->trans_id) - continue; - - stat = tmp; - break; - } - - if (!stat) { - LOGP(DNAT, LOGL_ERROR, - "Can not find transaction for: %u\n", trans_id); - return; - } - - /* attempt to parse the data now */ - rc = mgcp_parse_stats(msg, &b_ps, &b_os, &n_pr, &n_or, &loss, &jitter); - if (rc != 0) - LOGP(DNAT, LOGL_ERROR, - "Can not parse connection statistics: %d\n", rc); - - /* send a trap now */ - cmd = ctrl_cmd_create(bsc, CTRL_TYPE_TRAP); - if (!cmd) { - LOGP(DNAT, LOGL_ERROR, - "Creating a ctrl cmd failed.\n"); - goto free_stat; - } - - cmd->id = "0"; - cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.call_stats.v2", - bsc->cfg->nr); - cmd->reply = talloc_asprintf(cmd, - "mg_ip_addr=%s,mg_port=%d,", - inet_ntoa(stat->net_addr), - stat->net_rtp_port); - cmd->reply = talloc_asprintf_append(cmd->reply, - "endpoint_ip_addr=%s,endpoint_port=%d,", - inet_ntoa(stat->bts_addr), - stat->bts_rtp_port); - cmd->reply = talloc_asprintf_append(cmd->reply, - "nat_pkt_in=%u,nat_pkt_out=%u," - "nat_bytes_in=%u,nat_bytes_out=%u," - "nat_jitter=%u,nat_pkt_lost=%d,", - stat->bts_pr, stat->net_ps, - stat->bts_or, stat->net_os, - stat->bts_jitter, stat->bts_loss); - cmd->reply = talloc_asprintf_append(cmd->reply, - "bsc_pkt_in=%u,bsc_pkt_out=%u," - "bsc_bytes_in=%u,bsc_bytes_out=%u," - "bsc_jitter=%u,bsc_pkt_lost=%d,", - n_pr, b_ps, - n_or, b_os, - jitter, loss); - cmd->reply = talloc_asprintf_append(cmd->reply, - "sccp_src_ref=%u,sccp_dst_ref=%u", - sccp_src_ref_to_int(&stat->src_ref), - sccp_src_ref_to_int(&stat->remote_ref)); - - /* send it and be done */ - ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd); - talloc_free(cmd); - -free_stat: - bsc->pending_dlcx_count -= 1; - llist_del(&stat->entry); - talloc_free(stat); -} - - -struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint) -{ - struct nat_sccp_connection *con = NULL; - struct nat_sccp_connection *sccp; - - llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) { - if (sccp->msc_endp == -1) - continue; - if (sccp->msc_endp != endpoint) - continue; - - con = sccp; - } - - if (con) - return con; - - LOGP(DMGCP, LOGL_ERROR, - "Failed to find the connection for endpoint: 0x%x\n", endpoint); - return NULL; -} - -static int nat_osmux_only(struct mgcp_config *mgcp_cfg, struct bsc_config *bsc_cfg) -{ - if (mgcp_cfg->osmux == OSMUX_USAGE_ONLY) - return 1; - if (bsc_cfg->osmux == OSMUX_USAGE_ONLY) - return 1; - return 0; -} - -static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int state, const char *transaction_id) -{ - struct bsc_nat *nat; - struct bsc_endpoint *bsc_endp; - struct nat_sccp_connection *sccp; - struct mgcp_endpoint *mgcp_endp; - struct msgb *bsc_msg; - - nat = tcfg->cfg->data; - bsc_endp = &nat->bsc_endpoints[endpoint]; - mgcp_endp = &nat->mgcp_cfg->trunk.endpoints[endpoint]; - - if (bsc_endp->transaction_id) { - LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n", - endpoint, bsc_endp->transaction_id); - talloc_free(bsc_endp->transaction_id); - bsc_endp->transaction_id = NULL; - bsc_endp->transaction_state = 0; - } - bsc_endp->bsc = NULL; - - sccp = bsc_mgcp_find_con(nat, endpoint); - - if (!sccp) { - LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for change on endpoint: 0x%x state: %d\n", endpoint, state); - - switch (state) { - case MGCP_ENDP_CRCX: - return MGCP_POLICY_REJECT; - break; - case MGCP_ENDP_DLCX: - return MGCP_POLICY_CONT; - break; - case MGCP_ENDP_MDCX: - return MGCP_POLICY_CONT; - break; - default: - LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state); - return MGCP_POLICY_CONT; - break; - } - } - - /* Allocate a Osmux circuit ID */ - if (state == MGCP_ENDP_CRCX) { - if (nat->mgcp_cfg->osmux && sccp->bsc->cfg->osmux) { - osmux_allocate_cid(mgcp_endp); - if (mgcp_endp->osmux.allocated_cid < 0 && - nat_osmux_only(nat->mgcp_cfg, sccp->bsc->cfg)) { - LOGP(DMGCP, LOGL_ERROR, - "Rejecting usage of endpoint\n"); - return MGCP_POLICY_REJECT; - } - } - } - - /* we need to generate a new and patched message */ - bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length, - sccp->bsc_endp, mgcp_bts_src_addr(mgcp_endp), - mgcp_endp->bts_end.local_port, - mgcp_endp->osmux.allocated_cid, - &mgcp_endp->net_end.codec.payload_type, - nat->sdp_ensure_amr_mode_set); - if (!bsc_msg) { - LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n"); - return MGCP_POLICY_CONT; - } - - - bsc_endp->transaction_id = talloc_strdup(nat, transaction_id); - bsc_endp->transaction_state = state; - bsc_endp->bsc = sccp->bsc; - - /* we need to update some bits */ - if (state == MGCP_ENDP_CRCX) { - struct sockaddr_in sock; - - /* Annotate the allocated Osmux CID until the bsc confirms that - * it agrees to use Osmux for this voice flow. - */ - if (mgcp_endp->osmux.allocated_cid >= 0 && - mgcp_endp->osmux.state != OSMUX_STATE_ENABLED) { - mgcp_endp->osmux.state = OSMUX_STATE_NEGOTIATING; - mgcp_endp->osmux.cid = mgcp_endp->osmux.allocated_cid; - } - - socklen_t len = sizeof(sock); - if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n", - errno, strerror(errno)); - } else { - mgcp_endp->bts_end.addr = sock.sin_addr; - } - - /* send the message and a fake MDCX to force sending of a dummy packet */ - bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD); - bsc_mgcp_send_mdcx(sccp->bsc, sccp->bsc_endp, mgcp_endp); - return MGCP_POLICY_DEFER; - } else if (state == MGCP_ENDP_DLCX) { - /* we will free the endpoint now and send a DLCX to the BSC */ - msgb_free(bsc_msg); - bsc_mgcp_dlcx(sccp); - - /* libmgcp clears the MGCP endpoint for us */ - if (mgcp_endp->osmux.state == OSMUX_STATE_ENABLED) - osmux_release_cid(mgcp_endp); - - return MGCP_POLICY_CONT; - } else { - bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD); - return MGCP_POLICY_DEFER; - } -} - -/* - * We do have a failure, free data downstream.. - */ -static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint *bsc_endp, - struct bsc_connection *bsc) -{ - LOGP(DMGCP, LOGL_ERROR, "No CI, freeing endpoint 0x%x in state %d\n", - ENDPOINT_NUMBER(endp), bsc_endp->transaction_state); - - /* if a CRCX failed... send a DLCX down the stream */ - if (bsc_endp->transaction_state == MGCP_ENDP_CRCX) { - struct nat_sccp_connection *con; - con = bsc_mgcp_find_con(bsc->nat, ENDPOINT_NUMBER(endp)); - if (!con) { - LOGP(DMGCP, LOGL_ERROR, - "No SCCP connection for endp 0x%x\n", - ENDPOINT_NUMBER(endp)); - } else { - if (con->bsc == bsc) { - bsc_mgcp_send_dlcx(bsc, con->bsc_endp, con->bsc->next_transaction++); - } else { - LOGP(DMGCP, LOGL_ERROR, - "Endpoint belongs to a different BSC\n"); - } - } - } - - bsc_mgcp_free_endpoint(bsc->nat, ENDPOINT_NUMBER(endp)); - mgcp_release_endp(endp); -} - -static void bsc_mgcp_osmux_confirm(struct mgcp_endpoint *endp, const char *str) -{ - unsigned int osmux_cid; - char *res; - - res = strstr(str, "X-Osmux: "); - if (!res) { - LOGP(DMGCP, LOGL_INFO, - "BSC doesn't want to use Osmux, failing back to RTP\n"); - goto err; - } - - if (sscanf(res, "X-Osmux: %u", &osmux_cid) != 1) { - LOGP(DMGCP, LOGL_ERROR, "Failed to parse Osmux CID '%s'\n", - str); - goto err; - } - - if (endp->osmux.cid != osmux_cid) { - LOGP(DMGCP, LOGL_ERROR, - "BSC sent us wrong CID %u, we expected %u", - osmux_cid, endp->osmux.cid); - goto err; - } - - LOGP(DMGCP, LOGL_NOTICE, "bsc accepted to use Osmux (cid=%u)\n", - osmux_cid); - endp->osmux.state = OSMUX_STATE_ACTIVATING; - return; -err: - osmux_release_cid(endp); - endp->osmux.state = OSMUX_STATE_DISABLED; -} - -/* - * We have received a msg from the BSC. We will see if we know - * this transaction and if it belongs to the BSC. Then we will - * need to patch the content to point to the local network and we - * need to update the I: that was assigned by the BSS. - * - * Only responses to CRCX and DLCX should arrive here. The DLCX - * needs to be handled specially to combine the two statistics. - */ -void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg) -{ - struct msgb *output; - struct bsc_endpoint *bsc_endp = NULL; - struct mgcp_endpoint *endp = NULL; - int i, code; - char transaction_id[60]; - - /* Some assumption that our buffer is big enough.. and null terminate */ - if (msgb_l2len(msg) > 2000) { - LOGP(DMGCP, LOGL_ERROR, "MGCP message too long.\n"); - return; - } - - msg->l2h[msgb_l2len(msg)] = '\0'; - - if (bsc_mgcp_parse_response((const char *) msg->l2h, &code, transaction_id) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to parse response code.\n"); - return; - } - - for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) { - if (bsc->nat->bsc_endpoints[i].bsc != bsc) - continue; - /* no one listening? a bug? */ - if (!bsc->nat->bsc_endpoints[i].transaction_id) - continue; - if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0) - continue; - - endp = &bsc->nat->mgcp_cfg->trunk.endpoints[i]; - bsc_endp = &bsc->nat->bsc_endpoints[i]; - break; - } - - if (!bsc_endp && strncmp("nat-", transaction_id, 4) == 0) { - handle_dlcx_response(bsc, msg, code, transaction_id); - return; - } - - if (!bsc_endp) { - LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n", - transaction_id, (const char *) msg->l2h); - return; - } - - endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h); - if (endp->ci == CI_UNUSED) { - free_chan_downstream(endp, bsc_endp, bsc); - return; - } - - if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) - bsc_mgcp_osmux_confirm(endp, (const char *) msg->l2h); - - /* If we require osmux and it is disabled.. fail */ - if (nat_osmux_only(bsc->nat->mgcp_cfg, bsc->cfg) && - endp->osmux.state == OSMUX_STATE_DISABLED) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to activate osmux endpoint 0x%x\n", - ENDPOINT_NUMBER(endp)); - free_chan_downstream(endp, bsc_endp, bsc); - return; - } - - /* free some stuff */ - talloc_free(bsc_endp->transaction_id); - bsc_endp->transaction_id = NULL; - bsc_endp->transaction_state = 0; - - /* - * rewrite the information. In case the endpoint was deleted - * there should be nothing for us to rewrite so putting endp->rtp_port - * with the value of 0 should be no problem. - */ - output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1, - mgcp_net_src_addr(endp), - endp->net_end.local_port, -1, - &endp->bts_end.codec.payload_type, - bsc->nat->sdp_ensure_amr_mode_set); - if (!output) { - LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n"); - return; - } - - mgcp_queue_for_call_agent(bsc->nat, output); -} - -int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]) -{ - int rc; - /* we want to parse two strings */ - rc = sscanf(str, "%3d %59s\n", code, transaction) != 2; - transaction[59] = '\0'; - return rc; -} - -uint32_t bsc_mgcp_extract_ci(const char *str) -{ - unsigned int ci; - char *res = strstr(str, "I: "); - if (!res) { - LOGP(DMGCP, LOGL_ERROR, "No CI in msg '%s'\n", str); - return CI_UNUSED; - } - - if (sscanf(res, "I: %u", &ci) != 1) { - LOGP(DMGCP, LOGL_ERROR, "Failed to parse CI in msg '%s'\n", str); - return CI_UNUSED; - } - - return ci; -} - -/** - * Create a new MGCPCommand based on the input and endpoint from a message - */ -static void patch_mgcp(struct msgb *output, const char *op, const char *tok, - int endp, int len, int cr, int osmux_cid) -{ - int slen; - int ret; - char buf[40]; - char osmux_extension[strlen("\nX-Osmux: 255") + 1]; - - buf[0] = buf[39] = '\0'; - ret = sscanf(tok, "%*s %s", buf); - if (ret != 1) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to find Endpoint in: %s\n", tok); - return; - } - - if (osmux_cid >= 0) - sprintf(osmux_extension, "\nX-Osmux: %u", osmux_cid & 0xff); - else - osmux_extension[0] = '\0'; - - slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s%s", - op, buf, endp, osmux_extension, cr ? "\r\n" : "\n"); - output->l3h = msgb_put(output, slen); -} - -/* we need to replace some strings... */ -struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint, - const char *ip, int port, int osmux_cid, - int *first_payload_type, int ensure_mode_set) -{ - static const char crcx_str[] = "CRCX "; - static const char dlcx_str[] = "DLCX "; - static const char mdcx_str[] = "MDCX "; - - static const char ip_str[] = "c=IN IP4 "; - static const char aud_str[] = "m=audio "; - static const char fmt_str[] = "a=fmtp:"; - - char buf[128]; - char *running, *token; - struct msgb *output; - - /* keep state to add the a=fmtp line */ - int found_fmtp = 0; - int payload = -1; - int cr = 1; - - if (length > 4096 - 256) { - LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n"); - return NULL; - } - - output = msgb_alloc_headroom(4096, 128, "MGCP rewritten"); - if (!output) { - LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n"); - return NULL; - } - - running = input; - output->l2h = output->data; - output->l3h = output->l2h; - for (token = strsep(&running, "\n"); running; token = strsep(&running, "\n")) { - int len = strlen(token); - cr = len > 0 && token[len - 1] == '\r'; - - if (strncmp(crcx_str, token, (sizeof crcx_str) - 1) == 0) { - patch_mgcp(output, "CRCX", token, endpoint, len, cr, osmux_cid); - } else if (strncmp(dlcx_str, token, (sizeof dlcx_str) - 1) == 0) { - patch_mgcp(output, "DLCX", token, endpoint, len, cr, -1); - } else if (strncmp(mdcx_str, token, (sizeof mdcx_str) - 1) == 0) { - patch_mgcp(output, "MDCX", token, endpoint, len, cr, -1); - } else if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) { - output->l3h = msgb_put(output, strlen(ip_str)); - memcpy(output->l3h, ip_str, strlen(ip_str)); - output->l3h = msgb_put(output, strlen(ip)); - memcpy(output->l3h, ip, strlen(ip)); - - if (cr) { - output->l3h = msgb_put(output, 2); - output->l3h[0] = '\r'; - output->l3h[1] = '\n'; - } else { - output->l3h = msgb_put(output, 1); - output->l3h[0] = '\n'; - } - } else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) { - int offset; - if (sscanf(token, "m=audio %*d RTP/AVP %n%d", &offset, &payload) != 1) { - LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n"); - msgb_free(output); - return NULL; - } - - snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %s\n", - port, &token[offset]); - buf[sizeof(buf)-1] = '\0'; - - output->l3h = msgb_put(output, strlen(buf)); - memcpy(output->l3h, buf, strlen(buf)); - } else if (strncmp(fmt_str, token, (sizeof fmt_str) - 1) == 0) { - found_fmtp = 1; - goto copy; - } else { -copy: - output->l3h = msgb_put(output, len + 1); - memcpy(output->l3h, token, len); - output->l3h[len] = '\n'; - } - } - - /* - * the above code made sure that we have 128 bytes lefts. So we can - * safely append another line. - */ - if (ensure_mode_set && !found_fmtp && payload != -1) { - snprintf(buf, sizeof(buf) - 1, "a=fmtp:%d mode-set=2%s", - payload, cr ? "\r\n" : "\n"); - buf[sizeof(buf) - 1] = '\0'; - output->l3h = msgb_put(output, strlen(buf)); - memcpy(output->l3h, buf, strlen(buf)); - } - - if (payload != -1 && first_payload_type) - *first_payload_type = payload; - - return output; -} - -/* - * This comes from the MSC and we will now parse it. The caller needs - * to free the msgb. - */ -void bsc_nat_handle_mgcp(struct bsc_nat *nat, struct msgb *msg) -{ - struct msgb *resp; - - if (!nat->mgcp_ipa) { - LOGP(DMGCP, LOGL_ERROR, "MGCP message not allowed on IPA.\n"); - return; - } - - if (msgb_l2len(msg) > sizeof(nat->mgcp_msg) - 1) { - LOGP(DMGCP, LOGL_ERROR, "MGCP msg too big for handling.\n"); - return; - } - - memcpy(nat->mgcp_msg, msg->l2h, msgb_l2len(msg)); - nat->mgcp_length = msgb_l2len(msg); - nat->mgcp_msg[nat->mgcp_length] = '\0'; - - /* now handle the message */ - resp = mgcp_handle_message(nat->mgcp_cfg, msg); - - /* we do have a direct answer... e.g. AUEP */ - if (resp) - mgcp_queue_for_call_agent(nat, resp); - - return; -} - -static int mgcp_do_read(struct osmo_fd *fd) -{ - struct bsc_nat *nat; - struct msgb *msg, *resp; - int rc; - - nat = fd->data; - - rc = read(fd->fd, nat->mgcp_msg, sizeof(nat->mgcp_msg) - 1); - if (rc <= 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno); - return -1; - } - - nat->mgcp_msg[rc] = '\0'; - nat->mgcp_length = rc; - - msg = msgb_alloc(sizeof(nat->mgcp_msg), "MGCP GW Read"); - if (!msg) { - LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n"); - return -1; - } - - msg->l2h = msgb_put(msg, rc); - memcpy(msg->l2h, nat->mgcp_msg, msgb_l2len(msg)); - resp = mgcp_handle_message(nat->mgcp_cfg, msg); - msgb_free(msg); - - /* we do have a direct answer... e.g. AUEP */ - if (resp) - mgcp_queue_for_call_agent(nat, resp); - - return 0; -} - -static int mgcp_do_write(struct osmo_fd *bfd, struct msgb *msg) -{ - int rc; - - rc = write(bfd->fd, msg->data, msg->len); - - if (rc != msg->len) { - LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n"); - return -1; - } - - return rc; -} - -static int init_mgcp_socket(struct bsc_nat *nat, struct mgcp_config *cfg) -{ - struct sockaddr_in addr; - int on; - - cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); - if (cfg->gw_fd.bfd.fd < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno); - return -1; - } - - on = 1; - setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(cfg->source_port); - inet_aton(cfg->source_addr, &addr.sin_addr); - - if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to bind on %s:%d errno: %d\n", - cfg->source_addr, cfg->source_port, errno); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - addr.sin_port = htons(2727); - inet_aton(cfg->call_agent_addr, &addr.sin_addr); - if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n", - cfg->call_agent_addr, errno); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - osmo_wqueue_init(&cfg->gw_fd, 10); - cfg->gw_fd.bfd.when = BSC_FD_READ; - cfg->gw_fd.bfd.data = nat; - cfg->gw_fd.read_cb = mgcp_do_read; - cfg->gw_fd.write_cb = mgcp_do_write; - - if (osmo_fd_register(&cfg->gw_fd.bfd) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n"); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - return 0; -} - -int bsc_mgcp_nat_init(struct bsc_nat *nat) -{ - struct mgcp_config *cfg = nat->mgcp_cfg; - - if (!cfg->call_agent_addr) { - LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n"); - return -1; - } - - if (cfg->bts_ip) { - LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n"); - return -1; - } - - /* initialize the MGCP socket */ - if (!nat->mgcp_ipa) { - int rc = init_mgcp_socket(nat, cfg); - if (rc != 0) - return rc; - } - - - /* some more MGCP config handling */ - cfg->data = nat; - cfg->policy_cb = bsc_mgcp_policy_cb; - - if (cfg->bts_ip) - talloc_free(cfg->bts_ip); - cfg->bts_ip = ""; - - nat->bsc_endpoints = talloc_zero_array(nat, - struct bsc_endpoint, - cfg->trunk.number_endpoints + 1); - if (!nat->bsc_endpoints) { - LOGP(DMGCP, LOGL_ERROR, "Failed to allocate nat endpoints\n"); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - if (mgcp_reset_transcoder(cfg) < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to send packet to the transcoder.\n"); - talloc_free(nat->bsc_endpoints); - nat->bsc_endpoints = NULL; - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - return 0; -} - -void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc) -{ - struct rate_ctr *ctr = NULL; - int i; - - if (bsc->cfg) - ctr = &bsc->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_CALLS]; - - for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) { - struct bsc_endpoint *bsc_endp = &bsc->nat->bsc_endpoints[i]; - - if (bsc_endp->bsc != bsc) - continue; - - if (ctr) - rate_ctr_inc(ctr); - - bsc_mgcp_free_endpoint(bsc->nat, i); - mgcp_release_endp(&bsc->nat->mgcp_cfg->trunk.endpoints[i]); - } -} diff --git a/src/osmo-bsc_nat/bsc_nat.c b/src/osmo-bsc_nat/bsc_nat.c deleted file mode 100644 index 401288d84..000000000 --- a/src/osmo-bsc_nat/bsc_nat.c +++ /dev/null @@ -1,1739 +0,0 @@ -/* BSC Multiplexer/NAT */ - -/* - * (C) 2010-2013 by Holger Hans Peter Freyther - * (C) 2010-2013 by On-Waves - * (C) 2009 by Harald Welte - * 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 . - * - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include - -#include "../../bscconfig.h" - -#define SCCP_CLOSE_TIME 20 -#define SCCP_CLOSE_TIME_TIMEOUT 19 - -static const char *config_file = "bsc-nat.cfg"; -static struct in_addr local_addr; -static struct osmo_fd bsc_listen; -static const char *msc_ip = NULL; -static struct osmo_timer_list sccp_close; -static int daemonize = 0; - -const char *openbsc_copyright = - "Copyright (C) 2010 Holger Hans Peter Freyther and On-Waves\r\n" - "License AGPLv3+: GNU AGPL version 3 or later \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 struct bsc_nat *nat; -static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsigned int length, int); -static void msc_send_reset(struct bsc_msc_connection *con); -static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal); - -struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num) -{ - struct bsc_config *conf; - - llist_for_each_entry(conf, &nat->bsc_configs, entry) - if (conf->nr == num) - return conf; - - return NULL; -} - -static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg) -{ - if (!con) { - LOGP(DLINP, LOGL_ERROR, "No MSC Connection assigned. Check your code.\n"); - msgb_free(msg); - return; - } - - - if (osmo_wqueue_enqueue(&con->write_queue, msg) != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the write.\n"); - msgb_free(msg); - } -} - -static void send_reset_ack(struct bsc_connection *bsc) -{ - static const uint8_t gsm_reset_ack[] = { - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03, - 0x00, 0x01, 0x31, - }; - - bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack), IPAC_PROTO_SCCP); -} - -static void send_ping(struct bsc_connection *bsc) -{ - static const uint8_t id_ping[] = { - IPAC_MSGT_PING, - }; - - bsc_send_data(bsc, id_ping, sizeof(id_ping), IPAC_PROTO_IPACCESS); -} - -static void send_pong(struct bsc_connection *bsc) -{ - static const uint8_t id_pong[] = { - IPAC_MSGT_PONG, - }; - - bsc_send_data(bsc, id_pong, sizeof(id_pong), IPAC_PROTO_IPACCESS); -} - -static void bsc_pong_timeout(void *_bsc) -{ - struct bsc_connection *bsc = _bsc; - - LOGP(DNAT, LOGL_ERROR, "BSC Nr: %d PONG timeout.\n", bsc->cfg->nr); - bsc_close_connection(bsc); -} - -static void bsc_ping_timeout(void *_bsc) -{ - struct bsc_connection *bsc = _bsc; - - if (bsc->nat->ping_timeout < 0) - return; - - send_ping(bsc); - - /* send another ping in 20 seconds */ - osmo_timer_schedule(&bsc->ping_timeout, bsc->nat->ping_timeout, 0); - - /* also start a pong timer */ - osmo_timer_schedule(&bsc->pong_timeout, bsc->nat->pong_timeout, 0); -} - -static void start_ping_pong(struct bsc_connection *bsc) -{ - osmo_timer_setup(&bsc->pong_timeout, bsc_pong_timeout, bsc); - osmo_timer_setup(&bsc->ping_timeout, bsc_ping_timeout, bsc); - - bsc_ping_timeout(bsc); -} - -static void send_id_ack(struct bsc_connection *bsc) -{ - static const uint8_t id_ack[] = { - IPAC_MSGT_ID_ACK - }; - - bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS); -} - -static void send_id_req(struct bsc_nat *nat, struct bsc_connection *bsc) -{ - static const uint8_t s_id_req[] = { - IPAC_MSGT_ID_GET, - 0x01, IPAC_IDTAG_UNIT, - 0x01, IPAC_IDTAG_MACADDR, - 0x01, IPAC_IDTAG_LOCATION1, - 0x01, IPAC_IDTAG_LOCATION2, - 0x01, IPAC_IDTAG_EQUIPVERS, - 0x01, IPAC_IDTAG_SWVERSION, - 0x01, IPAC_IDTAG_UNITNAME, - 0x01, IPAC_IDTAG_SERNR, - }; - - uint8_t *mrand; - uint8_t id_req[sizeof(s_id_req) + (2+16)]; - uint8_t *buf = &id_req[sizeof(s_id_req)]; - - /* copy the static data */ - memcpy(id_req, s_id_req, sizeof(s_id_req)); - - /* put the RAND with length, tag, value */ - buf = v_put(buf, 0x11); - buf = v_put(buf, 0x23); - mrand = bsc->last_rand; - - if (RAND_bytes(mrand, 16) != 1) - goto failed_random; - - memcpy(buf, mrand, 16); - buf += 16; - - bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS); - return; - -failed_random: - /* the timeout will trigger and close this connection */ - LOGP(DNAT, LOGL_ERROR, "Failed to read from urandom.\n"); - return; -} - -static struct msgb *nat_create_rlsd(struct nat_sccp_connection *conn) -{ - struct sccp_connection_released *rel; - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "rlsd"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate released.\n"); - return NULL; - } - - msg->l2h = msgb_put(msg, sizeof(*rel)); - rel = (struct sccp_connection_released *) msg->l2h; - rel->type = SCCP_MSG_TYPE_RLSD; - rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE; - rel->destination_local_reference = conn->remote_ref; - rel->source_local_reference = conn->patched_ref; - - return msg; -} - -static void nat_send_rlsd_ussd(struct bsc_nat *nat, struct nat_sccp_connection *conn) -{ - struct msgb *msg; - - if (!nat->ussd_con) - return; - - msg = nat_create_rlsd(conn); - if (!msg) - return; - - bsc_do_write(&nat->ussd_con->queue, msg, IPAC_PROTO_SCCP); -} - -static void nat_send_rlsd_msc(struct nat_sccp_connection *conn) -{ - struct msgb *msg; - - msg = nat_create_rlsd(conn); - if (!msg) - return; - - ipa_prepend_header(msg, IPAC_PROTO_SCCP); - queue_for_msc(conn->msc_con, msg); -} - -static void nat_send_rlsd_bsc(struct nat_sccp_connection *conn) -{ - struct msgb *msg; - struct sccp_connection_released *rel; - - msg = msgb_alloc_headroom(4096, 128, "rlsd"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n"); - return; - } - - msg->l2h = msgb_put(msg, sizeof(*rel)); - rel = (struct sccp_connection_released *) msg->l2h; - rel->type = SCCP_MSG_TYPE_RLSD; - rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE; - rel->destination_local_reference = conn->real_ref; - rel->source_local_reference = conn->remote_ref; - - bsc_write(conn->bsc, msg, IPAC_PROTO_SCCP); -} - -static struct msgb *nat_creat_clrc(struct nat_sccp_connection *conn, uint8_t cause) -{ - struct msgb *msg; - struct msgb *sccp; - - msg = gsm0808_create_clear_command(cause); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n"); - return NULL; - } - - sccp = sccp_create_dt1(&conn->real_ref, msg->data, msg->len); - if (!sccp) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate SCCP msg.\n"); - msgb_free(msg); - return NULL; - } - - msgb_free(msg); - return sccp; -} - -static int nat_send_clrc_bsc(struct nat_sccp_connection *conn) -{ - struct msgb *sccp; - - sccp = nat_creat_clrc(conn, 0x20); - if (!sccp) - return -1; - return bsc_write(conn->bsc, sccp, IPAC_PROTO_SCCP); -} - -static void nat_send_rlc(struct bsc_msc_connection *msc_con, - struct sccp_source_reference *src, - struct sccp_source_reference *dst) -{ - struct sccp_connection_release_complete *rlc; - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "rlc"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to sccp rlc.\n"); - return; - } - - msg->l2h = msgb_put(msg, sizeof(*rlc)); - rlc = (struct sccp_connection_release_complete *) msg->l2h; - rlc->type = SCCP_MSG_TYPE_RLC; - rlc->destination_local_reference = *dst; - rlc->source_local_reference = *src; - - ipa_prepend_header(msg, IPAC_PROTO_SCCP); - - queue_for_msc(msc_con, msg); -} - -static void send_mgcp_reset(struct bsc_connection *bsc) -{ - static const uint8_t mgcp_reset[] = { - "RSIP 1 13@mgw MGCP 1.0\r\n" - }; - - bsc_write_mgcp(bsc, mgcp_reset, sizeof mgcp_reset - 1); -} - -void bsc_nat_send_mgcp_to_msc(struct bsc_nat *nat, struct msgb *msg) -{ - ipa_prepend_header(msg, IPAC_PROTO_MGCP_OLD); - queue_for_msc(nat->msc_con, msg); -} - -/* - * Below is the handling of messages coming - * from the MSC and need to be forwarded to - * a real BSC. - */ -static void initialize_msc_if_needed(struct bsc_msc_connection *msc_con) -{ - if (msc_con->first_contact) - return; - - msc_con->first_contact = 1; - msc_send_reset(msc_con); -} - -static void send_id_get_response(struct bsc_msc_connection *msc_con) -{ - struct msgb *msg = bsc_msc_id_get_resp(0, nat->token, NULL, 0); - if (!msg) - return; - - ipa_prepend_header(msg, IPAC_PROTO_IPACCESS); - queue_for_msc(msc_con, msg); -} - -/* - * Currently we are lacking refcounting so we need to copy each message. - */ -static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsigned int length, int proto) -{ - struct msgb *msg; - - if (length > 4096 - 128) { - LOGP(DLINP, LOGL_ERROR, "Can not send message of that size.\n"); - return; - } - - msg = msgb_alloc_headroom(4096, 128, "to-bsc"); - if (!msg) { - LOGP(DLINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n"); - return; - } - - msg->l2h = msgb_put(msg, length); - memcpy(msg->data, data, length); - - bsc_write(bsc, msg, proto); -} - -/* - * Update the release statistics - */ -static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal) -{ - if (!bsc->cfg) { - LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated."); - return; - } - - if (filter >= 0) { - LOGP(DNAT, LOGL_ERROR, "Connection was not rejected"); - return; - } - - if (filter == -1) - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_ILL_PACKET]); - else if (normal) - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_REJECTED_MSG]); - else - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_REJECTED_CR]); -} - -/* - * Release an established connection. We will have to release it to the BSC - * and to the network and we do it the following way. - * 1.) Give up on the MSC side - * 1.1) Send a RLSD message, it is a bit non standard but should work, we - * ignore the RLC... we might complain about it. Other options would - * be to send a Release Request, handle the Release Complete.. - * 1.2) Mark the data structure to be con_local and wait for 2nd - * - * 2.) Give up on the BSC side - * 2.1) Depending on the con type reject the service, or just close it - */ -static void bsc_send_con_release(struct bsc_connection *bsc, - struct nat_sccp_connection *con, - struct bsc_filter_reject_cause *cause) -{ - struct msgb *rlsd; - /* 1. release the network */ - rlsd = sccp_create_rlsd(&con->patched_ref, &con->remote_ref, - SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); - if (!rlsd) - LOGP(DNAT, LOGL_ERROR, "Failed to create RLSD message.\n"); - else { - ipa_prepend_header(rlsd, IPAC_PROTO_SCCP); - queue_for_msc(con->msc_con, rlsd); - } - con->con_local = NAT_CON_END_LOCAL; - con->msc_con = NULL; - - /* 2. release the BSC side */ - if (con->filter_state.con_type == FLT_CON_TYPE_LU) { - struct msgb *payload, *udt; - payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause); - - if (payload) { - gsm0808_prepend_dtap_header(payload, 0); - udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len); - if (udt) - bsc_write(bsc, udt, IPAC_PROTO_SCCP); - else - LOGP(DNAT, LOGL_ERROR, "Failed to create DT1\n"); - - msgb_free(payload); - } else { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate LU Reject.\n"); - } - } - - nat_send_clrc_bsc(con); - - rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref, - SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); - if (!rlsd) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate RLSD for the BSC.\n"); - sccp_connection_destroy(con); - return; - } - - con->filter_state.con_type = FLT_CON_TYPE_LOCAL_REJECT; - bsc_write(bsc, rlsd, IPAC_PROTO_SCCP); -} - -static void bsc_send_con_refuse(struct bsc_connection *bsc, - struct bsc_nat_parsed *parsed, int con_type, - struct bsc_filter_reject_cause *cause) -{ - struct msgb *payload; - struct msgb *refuse; - - if (con_type == FLT_CON_TYPE_LU) - payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause); - else if (con_type == FLT_CON_TYPE_CM_SERV_REQ || con_type == FLT_CON_TYPE_SSA) - payload = gsm48_create_mm_serv_rej(cause->cm_reject_cause); - else { - LOGP(DNAT, LOGL_ERROR, "Unknown connection type: %d\n", con_type); - payload = NULL; - } - - /* - * Some BSCs do not handle the payload inside a SCCP CREF msg - * so we will need to: - * 1.) Allocate a local connection and mark it as local.. - * 2.) queue data for downstream.. and the RLC should delete everything - */ - if (payload) { - struct msgb *cc, *udt, *clear, *rlsd; - struct nat_sccp_connection *con; - con = create_sccp_src_ref(bsc, parsed); - if (!con) - goto send_refuse; - - /* declare it local and assign a unique remote_ref */ - con->filter_state.con_type = FLT_CON_TYPE_LOCAL_REJECT; - con->con_local = NAT_CON_END_LOCAL; - con->has_remote_ref = 1; - con->remote_ref = con->patched_ref; - - /* 1. create a confirmation */ - cc = sccp_create_cc(&con->remote_ref, &con->real_ref); - if (!cc) - goto send_refuse; - - /* 2. create the DT1 */ - gsm0808_prepend_dtap_header(payload, 0); - udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len); - if (!udt) { - msgb_free(cc); - goto send_refuse; - } - - /* 3. send a Clear Command */ - clear = nat_creat_clrc(con, 0x20); - if (!clear) { - msgb_free(cc); - msgb_free(udt); - goto send_refuse; - } - - /* 4. send a RLSD */ - rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref, - SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); - if (!rlsd) { - msgb_free(cc); - msgb_free(udt); - msgb_free(clear); - goto send_refuse; - } - - bsc_write(bsc, cc, IPAC_PROTO_SCCP); - bsc_write(bsc, udt, IPAC_PROTO_SCCP); - bsc_write(bsc, clear, IPAC_PROTO_SCCP); - bsc_write(bsc, rlsd, IPAC_PROTO_SCCP); - msgb_free(payload); - return; - } - - -send_refuse: - if (payload) - msgb_free(payload); - - refuse = sccp_create_refuse(parsed->src_local_ref, - SCCP_REFUSAL_SCCP_FAILURE, NULL, 0); - if (!refuse) { - LOGP(DNAT, LOGL_ERROR, - "Creating refuse msg failed for SCCP 0x%x on BSC Nr: %d.\n", - sccp_src_ref_to_int(parsed->src_local_ref), bsc->cfg->nr); - return; - } - - bsc_write(bsc, refuse, IPAC_PROTO_SCCP); -} - -static void bsc_nat_send_paging(struct bsc_connection *bsc, struct msgb *msg) -{ - if (bsc->cfg->forbid_paging) { - LOGP(DNAT, LOGL_DEBUG, "Paging forbidden for BTS: %d\n", bsc->cfg->nr); - return; - } - - bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), IPAC_PROTO_SCCP); -} - -static void bsc_nat_handle_paging(struct bsc_nat *nat, struct msgb *msg) -{ - struct bsc_connection *bsc; - const uint8_t *paging_start; - int paging_length, i, ret; - - ret = bsc_nat_find_paging(msg, &paging_start, &paging_length); - if (ret != 0) { - LOGP(DNAT, LOGL_ERROR, "Could not parse paging message: %d\n", ret); - return; - } - - /* This is quite expensive now */ - for (i = 0; i < paging_length; i += 2) { - unsigned int _lac = ntohs(*(unsigned int *) &paging_start[i]); - unsigned int paged = 0; - llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) { - if (!bsc->cfg) - continue; - if (!bsc->authenticated) - continue; - if (!bsc_config_handles_lac(bsc->cfg, _lac)) - continue; - bsc_nat_send_paging(bsc, msg); - paged += 1; - } - - /* highlight a possible config issue */ - if (paged == 0) - LOGP(DNAT, LOGL_ERROR, "No BSC for LAC %d/0x%d\n", _lac, _lac); - - } -} - - -/* - * Update the auth status. This can be either a CIPHER MODE COMMAND or - * a CM Serivce Accept. Maybe also LU Accept or such in the future. - */ -static void update_con_authorize(struct nat_sccp_connection *con, - struct bsc_nat_parsed *parsed, - struct msgb *msg) -{ - if (!con) - return; - if (con->authorized) - return; - - if (parsed->bssap == BSSAP_MSG_BSS_MANAGEMENT && - parsed->gsm_type == BSS_MAP_MSG_CIPHER_MODE_CMD) { - con->authorized = 1; - } else if (parsed->bssap == BSSAP_MSG_DTAP) { - uint8_t msg_type, proto; - uint32_t len; - struct gsm48_hdr *hdr48; - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return; - - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - if (proto == GSM48_PDISC_MM && - msg_type == GSM48_MT_MM_CM_SERV_ACC) - con->authorized = 1; - } -} - -static int forward_sccp_to_bts(struct bsc_msc_connection *msc_con, struct msgb *msg) -{ - struct nat_sccp_connection *con = NULL; - struct bsc_connection *bsc; - struct bsc_nat_parsed *parsed; - int proto; - - /* filter, drop, patch the message? */ - parsed = bsc_nat_parse(msg); - if (!parsed) { - LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n"); - return -1; - } - - if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed)) - goto exit; - - proto = parsed->ipa_proto; - - /* Route and modify the SCCP packet */ - if (proto == IPAC_PROTO_SCCP) { - switch (parsed->sccp_type) { - case SCCP_MSG_TYPE_UDT: - /* forward UDT messages to every BSC */ - goto send_to_all; - break; - case SCCP_MSG_TYPE_RLSD: - case SCCP_MSG_TYPE_CREF: - case SCCP_MSG_TYPE_DT1: - case SCCP_MSG_TYPE_IT: - con = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) { - osmo_counter_inc(nat->stats.sccp.calls); - - if (con) { - struct rate_ctr_group *ctrg; - ctrg = con->bsc->cfg->stats.ctrg; - rate_ctr_inc(&ctrg->ctr[BCFG_CTR_SCCP_CALLS]); - if (bsc_mgcp_assign_patch(con, msg) != 0) - LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n"); - } else - LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n"); - } else if (con && con->con_local == NAT_CON_END_USSD && - parsed->gsm_type == BSS_MAP_MSG_CLEAR_CMD) { - LOGP(DNAT, LOGL_NOTICE, "Clear Command for USSD Connection. Ignoring.\n"); - con = NULL; - } - break; - case SCCP_MSG_TYPE_CC: - con = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - if (!con || update_sccp_src_ref(con, parsed) != 0) - goto exit; - break; - case SCCP_MSG_TYPE_RLC: - LOGP(DNAT, LOGL_ERROR, "Unexpected release complete from MSC.\n"); - goto exit; - break; - case SCCP_MSG_TYPE_CR: - /* MSC never opens a SCCP connection, fall through */ - default: - goto exit; - } - - if (!con && parsed->sccp_type == SCCP_MSG_TYPE_RLSD) { - LOGP(DNAT, LOGL_NOTICE, "Sending fake RLC on RLSD message to network.\n"); - /* Exchange src/dest for the reply */ - nat_send_rlc(msc_con, &parsed->original_dest_ref, - parsed->src_local_ref); - } else if (!con) - LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x from the MSC.\n", parsed->sccp_type); - } - - if (!con) { - talloc_free(parsed); - return -1; - } - if (!con->bsc->authenticated) { - talloc_free(parsed); - LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n"); - return -1; - } - - update_con_authorize(con, parsed, msg); - talloc_free(parsed); - - bsc_send_data(con->bsc, msg->l2h, msgb_l2len(msg), proto); - return 0; - -send_to_all: - /* - * Filter Paging from the network. We do not want to send a PAGING - * Command to every BSC in our network. We will analys the PAGING - * message and then send it to the authenticated messages... - */ - if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) { - bsc_nat_handle_paging(nat, msg); - goto exit; - } - /* currently send this to every BSC connected */ - llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) { - if (!bsc->authenticated) - continue; - - bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto); - } - -exit: - talloc_free(parsed); - return 0; -} - -static void msc_connection_was_lost(struct bsc_msc_connection *con) -{ - struct bsc_connection *bsc, *tmp; - - LOGP(DMSC, LOGL_ERROR, "Closing all connections downstream.\n"); - llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry) - bsc_close_connection(bsc); - - bsc_mgcp_free_endpoints(nat); - bsc_msc_schedule_connect(con); -} - -static void msc_connection_connected(struct bsc_msc_connection *con) -{ - osmo_counter_inc(nat->stats.msc.reconn); -} - -static void msc_send_reset(struct bsc_msc_connection *msc_con) -{ - static const uint8_t reset[] = { - 0x00, 0x12, 0xfd, - 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, - 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04, - 0x01, 0x20 - }; - - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "08.08 reset"); - if (!msg) { - LOGP(DMSC, LOGL_ERROR, "Failed to allocate reset msg.\n"); - return; - } - - msg->l2h = msgb_put(msg, sizeof(reset)); - memcpy(msg->l2h, reset, msgb_l2len(msg)); - - queue_for_msc(msc_con, msg); - - LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n"); -} - -static int ipaccess_msc_read_cb(struct osmo_fd *bfd) -{ - struct bsc_msc_connection *msc_con; - struct msgb *msg = NULL; - struct ipaccess_head *hh; - int ret; - - msc_con = (struct bsc_msc_connection *) bfd->data; - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &msc_con->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - if (ret == 0) - LOGP(DNAT, LOGL_FATAL, - "The connection the MSC(%s) was lost, exiting\n", - msc_con->name); - else - LOGP(DNAT, LOGL_ERROR, - "Failed to parse ip access message on %s: %d\n", - msc_con->name, ret); - - bsc_msc_lost(msc_con); - return -1; - } - - LOGP(DNAT, LOGL_DEBUG, - "MSG from MSC(%s): %s proto: %d\n", msc_con->name, - osmo_hexdump(msg->data, msg->len), msg->l2h[0]); - - /* handle base message handling */ - hh = (struct ipaccess_head *) msg->data; - - /* initialize the networking. This includes sending a GSM08.08 message */ - if (hh->proto == IPAC_PROTO_IPACCESS) { - ipa_ccm_rcvmsg_base(msg, bfd); - if (msg->l2h[0] == IPAC_MSGT_ID_ACK) - initialize_msc_if_needed(msc_con); - else if (msg->l2h[0] == IPAC_MSGT_ID_GET) - send_id_get_response(msc_con); - } else if (hh->proto == IPAC_PROTO_SCCP) { - forward_sccp_to_bts(msc_con, msg); - } else if (hh->proto == IPAC_PROTO_MGCP_OLD) { - bsc_nat_handle_mgcp(nat, msg); - } - - msgb_free(msg); - return 0; -} - -static int ipaccess_msc_write_cb(struct osmo_fd *bfd, struct msgb *msg) -{ - int rc; - rc = write(bfd->fd, msg->data, msg->len); - - if (rc != msg->len) { - LOGP(DNAT, LOGL_ERROR, "Failed to write MSG to MSC.\n"); - return -1; - } - - return rc; -} - -/* - * Below is the handling of messages coming - * from the BSC and need to be forwarded to - * a real BSC. - */ - -/* - * Remove the connection from the connections list, - * remove it from the patching of SCCP header lists - * as well. Maybe in the future even close connection.. - */ -void bsc_close_connection(struct bsc_connection *connection) -{ - struct nat_sccp_connection *sccp_patch, *tmp; - struct bsc_cmd_list *cmd_entry, *cmd_tmp; - struct rate_ctr *ctr = NULL; - - /* stop the timeout timer */ - osmo_timer_del(&connection->id_timeout); - osmo_timer_del(&connection->ping_timeout); - osmo_timer_del(&connection->pong_timeout); - - if (connection->cfg) - ctr = &connection->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_SCCP]; - - /* remove all SCCP connections */ - llist_for_each_entry_safe(sccp_patch, tmp, &nat->sccp_connections, list_entry) { - if (sccp_patch->bsc != connection) - continue; - - if (ctr) - rate_ctr_inc(ctr); - if (sccp_patch->has_remote_ref) { - if (sccp_patch->con_local == NAT_CON_END_MSC) - nat_send_rlsd_msc(sccp_patch); - else if (sccp_patch->con_local == NAT_CON_END_USSD) - nat_send_rlsd_ussd(nat, sccp_patch); - } - - sccp_connection_destroy(sccp_patch); - } - - /* Reply to all outstanding commands */ - llist_for_each_entry_safe(cmd_entry, cmd_tmp, &connection->cmd_pending, list_entry) { - cmd_entry->cmd->type = CTRL_TYPE_ERROR; - cmd_entry->cmd->reply = "BSC closed the connection"; - ctrl_cmd_send(&cmd_entry->ccon->write_queue, cmd_entry->cmd); - bsc_nat_ctrl_del_pending(cmd_entry); - } - - /* close endpoints allocated by this BSC */ - bsc_mgcp_clear_endpoints_for(connection); - - osmo_fd_unregister(&connection->write_queue.bfd); - close(connection->write_queue.bfd.fd); - osmo_wqueue_clear(&connection->write_queue); - llist_del(&connection->list_entry); - - if (connection->pending_msg) { - LOGP(DNAT, LOGL_ERROR, "Dropping partial message on connection %d.\n", - connection->cfg ? connection->cfg->nr : -1); - msgb_free(connection->pending_msg); - connection->pending_msg = NULL; - } - - talloc_free(connection); -} - -static void bsc_maybe_close(struct bsc_connection *bsc) -{ - struct nat_sccp_connection *sccp; - if (!bsc->nat->blocked) - return; - - /* are there any connections left */ - llist_for_each_entry(sccp, &bsc->nat->sccp_connections, list_entry) - if (sccp->bsc == bsc) - return; - - /* nothing left, close the BSC */ - LOGP(DNAT, LOGL_NOTICE, "Cleaning up BSC %d in blocking mode.\n", - bsc->cfg ? bsc->cfg->nr : -1); - bsc_close_connection(bsc); -} - -static void ipaccess_close_bsc(void *data) -{ - struct sockaddr_in sock; - socklen_t len = sizeof(sock); - struct bsc_connection *conn = data; - - - getpeername(conn->write_queue.bfd.fd, (struct sockaddr *) &sock, &len); - LOGP(DNAT, LOGL_ERROR, "BSC on %s didn't respond to identity request. Closing.\n", - inet_ntoa(sock.sin_addr)); - bsc_close_connection(conn); -} - -static int verify_key(struct bsc_connection *conn, struct bsc_config *conf, const uint8_t *key, const int keylen) -{ - struct osmo_auth_vector vec; - - struct osmo_sub_auth_data auth = { - .type = OSMO_AUTH_TYPE_GSM, - .algo = OSMO_AUTH_ALG_MILENAGE, - }; - - /* expect a specific keylen */ - if (keylen != 8) { - LOGP(DNAT, LOGL_ERROR, "Key length is wrong: %d for bsc nr %d\n", - keylen, conf->nr); - return 0; - } - - memcpy(auth.u.umts.opc, conf->key, 16); - memcpy(auth.u.umts.k, conf->key, 16); - memset(auth.u.umts.amf, 0, 2); - auth.u.umts.sqn = 0; - - memset(&vec, 0, sizeof(vec)); - osmo_auth_gen_vec(&vec, &auth, conn->last_rand); - - if (vec.res_len != 8) { - LOGP(DNAT, LOGL_ERROR, "Res length is wrong: %d for bsc nr %d\n", - vec.res_len, conf->nr); - return 0; - } - - return osmo_constant_time_cmp(vec.res, key, 8) == 0; -} - -static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc) -{ - struct bsc_config *conf; - const char *token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME); - int len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); - const uint8_t *xres = TLVP_VAL(tvp, 0x24); - const int xlen = TLVP_LEN(tvp, 0x24); - - if (bsc->cfg) { - LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n", - bsc->write_queue.bfd.fd, bsc->cfg->nr); - return; - } - - if (len <= 0) { - LOGP(DNAT, LOGL_ERROR, "Token with length zero on fd: %d\n", - bsc->write_queue.bfd.fd); - return; - } - - if (token[len - 1] != '\0') { - LOGP(DNAT, LOGL_ERROR, "Token not null terminated on fd: %d\n", - bsc->write_queue.bfd.fd); - return; - } - - /* - * New systems have fixed the structure of the message but - * we need to support old ones too. - */ - if (len >= 2 && token[len - 2] == '\0') - len -= 1; - - conf = bsc_config_by_token(bsc->nat, token, len); - if (!conf) { - LOGP(DNAT, LOGL_ERROR, - "No bsc found for token '%s' len %d on fd: %d.\n", token, - bsc->write_queue.bfd.fd, len); - bsc_close_connection(bsc); - return; - } - - /* We have set a key and expect it to be present */ - if (conf->key_present && !verify_key(bsc, conf, xres, xlen - 1)) { - LOGP(DNAT, LOGL_ERROR, - "Wrong key for bsc nr %d fd: %d.\n", conf->nr, - bsc->write_queue.bfd.fd); - bsc_close_connection(bsc); - return; - } - - rate_ctr_inc(&conf->stats.ctrg->ctr[BCFG_CTR_NET_RECONN]); - bsc->authenticated = 1; - bsc->cfg = conf; - osmo_timer_del(&bsc->id_timeout); - LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d on fd %d\n", - conf->nr, bsc->write_queue.bfd.fd); - start_ping_pong(bsc); -} - -static void handle_con_stats(struct nat_sccp_connection *con) -{ - struct rate_ctr_group *ctrg; - int id = bsc_conn_type_to_ctr(con); - - if (id == -1) - return; - - if (!con->bsc || !con->bsc->cfg) - return; - - ctrg = con->bsc->cfg->stats.ctrg; - rate_ctr_inc(&ctrg->ctr[id]); -} - -static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) -{ - int con_filter = 0; - char *imsi = NULL; - struct bsc_msc_connection *con_msc = NULL; - struct bsc_connection *con_bsc = NULL; - int con_type; - struct bsc_nat_parsed *parsed; - struct bsc_filter_reject_cause cause; - - /* Parse and filter messages */ - parsed = bsc_nat_parse(msg); - if (!parsed) { - LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n"); - msgb_free(msg); - return -1; - } - - if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed)) - goto exit; - - /* - * check authentication after filtering to not reject auth - * responses coming from the BSC. We have to make sure that - * nothing from the exit path will forward things to the MSC - */ - if (!bsc->authenticated) { - LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated.\n"); - msgb_free(msg); - return -1; - } - - - /* modify the SCCP entries */ - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - int filter; - struct nat_sccp_connection *con; - switch (parsed->sccp_type) { - case SCCP_MSG_TYPE_CR: - memset(&cause, 0, sizeof(cause)); - filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed, - &con_type, &imsi, &cause); - if (filter < 0) { - if (imsi) - bsc_nat_inform_reject(bsc, imsi); - bsc_stat_reject(filter, bsc, 0); - goto exit3; - } - - if (!create_sccp_src_ref(bsc, parsed)) - goto exit2; - con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); - OSMO_ASSERT(con); - con->msc_con = bsc->nat->msc_con; - con_msc = con->msc_con; - con->filter_state.con_type = con_type; - con->filter_state.imsi_checked = filter; - bsc_nat_extract_lac(bsc, con, parsed, msg); - if (imsi) - con->filter_state.imsi = talloc_steal(con, imsi); - imsi = NULL; - con_bsc = con->bsc; - handle_con_stats(con); - break; - case SCCP_MSG_TYPE_RLSD: - case SCCP_MSG_TYPE_CREF: - case SCCP_MSG_TYPE_DT1: - case SCCP_MSG_TYPE_CC: - case SCCP_MSG_TYPE_IT: - con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); - if (con) { - /* only filter non local connections */ - if (!con->con_local) { - memset(&cause, 0, sizeof(cause)); - filter = bsc_nat_filter_dt(bsc, msg, - con, parsed, &cause); - if (filter < 0) { - if (con->filter_state.imsi) - bsc_nat_inform_reject(bsc, - con->filter_state.imsi); - bsc_stat_reject(filter, bsc, 1); - bsc_send_con_release(bsc, con, &cause); - con = NULL; - goto exit2; - } - - /* hand data to a side channel */ - if (bsc_ussd_check(con, parsed, msg) == 1) - con->con_local = NAT_CON_END_USSD; - - /* - * Optionally rewrite setup message. This can - * replace the msg and the parsed structure becomes - * invalid. - */ - msg = bsc_nat_rewrite_msg(bsc->nat, msg, parsed, - con->filter_state.imsi); - talloc_free(parsed); - parsed = NULL; - } else if (con->con_local == NAT_CON_END_USSD) { - bsc_ussd_check(con, parsed, msg); - } - - con_bsc = con->bsc; - con_msc = con->msc_con; - con_filter = con->con_local; - } - - break; - case SCCP_MSG_TYPE_RLC: - con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); - if (con) { - con_bsc = con->bsc; - con_msc = con->msc_con; - con_filter = con->con_local; - } - remove_sccp_src_ref(bsc, msg, parsed); - bsc_maybe_close(bsc); - break; - case SCCP_MSG_TYPE_UDT: - /* simply forward everything */ - con = NULL; - break; - default: - LOGP(DNAT, LOGL_ERROR, "Not forwarding to msc sccp type: 0x%x\n", parsed->sccp_type); - con = NULL; - goto exit2; - break; - } - } else if (parsed->ipa_proto == IPAC_PROTO_MGCP_OLD) { - bsc_mgcp_forward(bsc, msg); - goto exit2; - } else { - LOGP(DNAT, LOGL_ERROR, "Not forwarding unknown stream id: 0x%x\n", parsed->ipa_proto); - goto exit2; - } - - if (con_msc && con_bsc != bsc) { - LOGP(DNAT, LOGL_ERROR, "The connection belongs to a different BTS: input: %d con: %d\n", - bsc->cfg->nr, con_bsc->cfg->nr); - goto exit2; - } - - /* do not forward messages to the MSC */ - if (con_filter) - goto exit2; - - if (!con_msc) { - LOGP(DNAT, LOGL_ERROR, "Not forwarding data bsc_nr: %d ipa: %d type: 0x%x\n", - bsc->cfg->nr, - parsed ? parsed->ipa_proto : -1, - parsed ? parsed->sccp_type : -1); - goto exit2; - } - - /* send the non-filtered but maybe modified msg */ - queue_for_msc(con_msc, msg); - if (parsed) - talloc_free(parsed); - return 0; - -exit: - /* if we filter out the reset send an ack to the BSC */ - if (parsed->bssap == 0 && parsed->gsm_type == BSS_MAP_MSG_RESET) { - send_reset_ack(bsc); - send_reset_ack(bsc); - } else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) { - /* do we know who is handling this? */ - if (msg->l2h[0] == IPAC_MSGT_ID_RESP && msgb_l2len(msg) > 2) { - struct tlv_parsed tvp; - int ret; - ret = ipa_ccm_idtag_parse_off(&tvp, - (unsigned char *) msg->l2h + 2, - msgb_l2len(msg) - 2, 0); - if (ret < 0) { - LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " - "message with malformed TLVs\n"); - return ret; - } - if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) - ipaccess_auth_bsc(&tvp, bsc); - } - - goto exit2; - } - -exit2: - if (imsi) - talloc_free(imsi); - talloc_free(parsed); - msgb_free(msg); - return -1; - -exit3: - /* send a SCCP Connection Refused */ - if (imsi) - talloc_free(imsi); - bsc_send_con_refuse(bsc, parsed, con_type, &cause); - talloc_free(parsed); - msgb_free(msg); - return -1; -} - -static int ipaccess_bsc_read_cb(struct osmo_fd *bfd) -{ - struct bsc_connection *bsc = bfd->data; - struct msgb *msg = NULL; - struct ipaccess_head *hh; - struct ipaccess_head_ext *hh_ext; - int ret; - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &bsc->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - if (ret == 0) - LOGP(DNAT, LOGL_ERROR, - "The connection to the BSC Nr: %d was lost. Cleaning it\n", - bsc->cfg ? bsc->cfg->nr : -1); - else - LOGP(DNAT, LOGL_ERROR, - "Stream error on BSC Nr: %d. Failed to parse ip access message: %d (%s)\n", - bsc->cfg ? bsc->cfg->nr : -1, ret, strerror(-ret)); - - bsc_close_connection(bsc); - return -1; - } - - - LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]); - - /* Handle messages from the BSC */ - hh = (struct ipaccess_head *) msg->data; - - /* stop the pong timeout */ - if (hh->proto == IPAC_PROTO_IPACCESS) { - if (msg->l2h[0] == IPAC_MSGT_PONG) { - osmo_timer_del(&bsc->pong_timeout); - msgb_free(msg); - return 0; - } else if (msg->l2h[0] == IPAC_MSGT_PING) { - send_pong(bsc); - msgb_free(msg); - return 0; - } - /* Message contains the ipaccess_head_ext header, investigate further */ - } else if (hh->proto == IPAC_PROTO_OSMO && - msg->len > sizeof(*hh) + sizeof(*hh_ext)) { - - hh_ext = (struct ipaccess_head_ext *) hh->data; - /* l2h is where the actual command data is expected */ - msg->l2h = hh_ext->data; - - if (hh_ext->proto == IPAC_PROTO_EXT_CTRL) - return bsc_nat_handle_ctrlif_msg(bsc, msg); - } - - /* FIXME: Currently no PONG is sent to the BSC */ - /* FIXME: Currently no ID ACK is sent to the BSC */ - forward_sccp_to_msc(bsc, msg); - - return 0; -} - -static int ipaccess_listen_bsc_cb(struct osmo_fd *bfd, unsigned int what) -{ - struct bsc_connection *bsc; - int fd, rc, on; - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - - if (!(what & BSC_FD_READ)) - return 0; - - fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len); - if (fd < 0) { - perror("accept"); - return fd; - } - - /* count the reconnect */ - osmo_counter_inc(nat->stats.bsc.reconn); - - /* - * if we are not connected to a msc... just close the socket - */ - if (!bsc_nat_msc_is_connected(nat)) { - LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n"); - close(fd); - return 0; - } - - if (nat->blocked) { - LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due NAT being blocked.\n"); - close(fd); - return 0; - } - - on = 1; - rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - if (rc != 0) - LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno)); - - rc = setsockopt(fd, IPPROTO_IP, IP_TOS, - &nat->bsc_ip_dscp, sizeof(nat->bsc_ip_dscp)); - if (rc != 0) - LOGP(DNAT, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno)); - - /* todo... do something with the connection */ - /* todo... use GNUtls to see if we want to trust this as a BTS */ - - /* - * - */ - bsc = bsc_connection_alloc(nat); - if (!bsc) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n"); - close(fd); - return -1; - } - - bsc->write_queue.bfd.data = bsc; - bsc->write_queue.bfd.fd = fd; - bsc->write_queue.read_cb = ipaccess_bsc_read_cb; - bsc->write_queue.write_cb = bsc_write_cb; - bsc->write_queue.bfd.when = BSC_FD_READ; - if (osmo_fd_register(&bsc->write_queue.bfd) < 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n"); - close(fd); - talloc_free(bsc); - return -2; - } - - LOGP(DNAT, LOGL_NOTICE, "BSC connection on %d with IP: %s\n", - fd, inet_ntoa(sa.sin_addr)); - - llist_add(&bsc->list_entry, &nat->bsc_connections); - bsc->last_id = 0; - - send_id_ack(bsc); - send_id_req(nat, bsc); - send_mgcp_reset(bsc); - - /* - * start the hangup timer - */ - osmo_timer_setup(&bsc->id_timeout, ipaccess_close_bsc, bsc); - osmo_timer_schedule(&bsc->id_timeout, nat->auth_timeout, 0); - return 0; -} - -static void print_usage() -{ - printf("Usage: bsc_nat\n"); -} - -static void print_help() -{ - printf(" Some useful help...\n"); - printf(" -h --help this text\n"); - printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n"); - printf(" -D --daemonize Fork the process into a background daemon\n"); - printf(" -s --disable-color\n"); - printf(" -c --config-file filename The config file to use.\n"); - printf(" -m --msc=IP. The address of the MSC.\n"); - printf(" -l --local=IP. The local address of this BSC.\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'}, - {"msc", 1, 0, 'm'}, - {"local", 1, 0, 'l'}, - {0, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "hd:sTPc:m:l:D", - 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 'm': - msc_ip = optarg; - break; - case 'l': - inet_aton(optarg, &local_addr); - break; - default: - /* ignore */ - break; - } - } -} - -static void signal_handler(int signal) -{ - switch (signal) { - 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_full(tall_bsc_ctx, stderr); - break; - default: - break; - } -} - -static void sccp_close_unconfirmed(void *_data) -{ - int destroyed = 0; - struct bsc_connection *bsc, *bsc_tmp; - struct nat_sccp_connection *conn, *tmp1; - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - llist_for_each_entry_safe(conn, tmp1, &nat->sccp_connections, list_entry) { - if (conn->has_remote_ref) - continue; - - int diff = (now.tv_sec - conn->creation_time.tv_sec) / 60; - if (diff < SCCP_CLOSE_TIME_TIMEOUT) - continue; - - LOGP(DNAT, LOGL_ERROR, - "SCCP connection 0x%x/0x%x was never confirmed on bsc nr. %d\n", - sccp_src_ref_to_int(&conn->real_ref), - sccp_src_ref_to_int(&conn->patched_ref), - conn->bsc->cfg->nr); - sccp_connection_destroy(conn); - destroyed = 1; - } - - if (!destroyed) - goto out; - - /* now close out any BSC */ - llist_for_each_entry_safe(bsc, bsc_tmp, &nat->bsc_connections, list_entry) - bsc_maybe_close(bsc); - -out: - osmo_timer_schedule(&sccp_close, SCCP_CLOSE_TIME, 0); -} - -extern void *tall_ctr_ctx; -static void talloc_init_ctx() -{ - tall_bsc_ctx = talloc_named_const(NULL, 0, "nat"); - msgb_talloc_ctx_init(tall_bsc_ctx, 0); - tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter"); -} - -extern int bsc_vty_go_parent(struct vty *vty); - -static struct vty_app_info vty_info = { - .name = "OsmoBSCNAT", - .version = PACKAGE_VERSION, - .go_parent_cb = bsc_vty_go_parent, - .is_config_node = bsc_vty_is_config_node, -}; - - -int main(int argc, char **argv) -{ - int rc; - - talloc_init_ctx(); - - osmo_init_logging(&log_info); - - nat = bsc_nat_alloc(); - if (!nat) { - fprintf(stderr, "Failed to allocate the BSC nat.\n"); - return -4; - } - - nat->mgcp_cfg = mgcp_config_alloc(); - if (!nat->mgcp_cfg) { - fprintf(stderr, "Failed to allocate MGCP cfg.\n"); - return -5; - } - - /* We need to add mode-set for amr codecs */ - nat->sdp_ensure_amr_mode_set = 1; - - vty_info.copyright = openbsc_copyright; - vty_init(&vty_info); - logging_vty_add_cmds(NULL); - osmo_stats_vty_add_cmds(&log_info); - bsc_nat_vty_init(nat); - ctrl_vty_init(tall_bsc_ctx); - - - /* parse options */ - local_addr.s_addr = INADDR_ANY; - handle_options(argc, argv); - - nat->include_base = dirname(talloc_strdup(tall_bsc_ctx, config_file)); - - rate_ctr_init(tall_bsc_ctx); - osmo_stats_init(tall_bsc_ctx); - - /* Ensure that forced enpoint allocation is turned on by default */ - nat->mgcp_cfg->trunk.force_realloc = 1; - - /* init vty and parse */ - if (mgcp_parse_config(config_file, nat->mgcp_cfg, MGCP_BSC_NAT) < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); - return -3; - } - - /* start telnet after reading config for vty_get_bind_addr() */ - if (telnet_init_dynif(tall_bsc_ctx, NULL, vty_get_bind_addr(), - OSMO_VTY_PORT_BSC_NAT)) { - fprintf(stderr, "Creating VTY telnet line failed\n"); - return -5; - } - - /* over rule the VTY config for MSC IP */ - if (msc_ip) - bsc_nat_set_msc_ip(nat, msc_ip); - - /* seed the PRNG */ - srand(time(NULL)); - - LOGP(DNAT, LOGL_NOTICE, "BSCs configured from %s\n", nat->resolved_path); - - /* - * Setup the MGCP code.. - */ - if (bsc_mgcp_nat_init(nat) != 0) - return -4; - - /* connect to the MSC */ - nat->msc_con = bsc_msc_create(nat, &nat->dests); - if (!nat->msc_con) { - fprintf(stderr, "Creating a bsc_msc_connection failed.\n"); - exit(1); - } - - /* start control interface after reading config for - * ctrl_vty_get_bind_addr() */ - nat->ctrl = bsc_nat_controlif_setup(nat, ctrl_vty_get_bind_addr(), - OSMO_CTRL_PORT_BSC_NAT); - if (!nat->ctrl) { - fprintf(stderr, "Creating the control interface failed.\n"); - exit(1); - } - - nat->msc_con->name = "main MSC"; - nat->msc_con->connection_loss = msc_connection_was_lost; - nat->msc_con->connected = msc_connection_connected; - nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb; - nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;; - nat->msc_con->write_queue.bfd.data = nat->msc_con; - bsc_msc_connect(nat->msc_con); - - /* wait for the BSC */ - rc = make_sock(&bsc_listen, IPPROTO_TCP, ntohl(local_addr.s_addr), - 5000, 0, ipaccess_listen_bsc_cb, nat); - if (rc != 0) { - fprintf(stderr, "Failed to listen for BSC.\n"); - exit(1); - } - - rc = bsc_ussd_init(nat); - if (rc != 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to bind the USSD socket.\n"); - exit(1); - } - - signal(SIGABRT, &signal_handler); - signal(SIGUSR1, &signal_handler); - osmo_init_ignore_signals(); - - if (daemonize) { - rc = osmo_daemonize(); - if (rc < 0) { - perror("Error during daemonize"); - exit(1); - } - } - - /* recycle timer */ - sccp_set_log_area(DSCCP); - osmo_timer_setup(&sccp_close, sccp_close_unconfirmed, NULL); - osmo_timer_schedule(&sccp_close, SCCP_CLOSE_TIME, 0); - - while (1) { - osmo_select_main(0); - } - - return 0; -} - -/* Close all connections handed out to the USSD module */ -int bsc_ussd_close_connections(struct bsc_nat *nat) -{ - struct nat_sccp_connection *con; - llist_for_each_entry(con, &nat->sccp_connections, list_entry) { - if (con->con_local != NAT_CON_END_USSD) - continue; - if (!con->bsc) - continue; - - nat_send_clrc_bsc(con); - nat_send_rlsd_bsc(con); - } - - return 0; -} diff --git a/src/osmo-bsc_nat/bsc_nat_ctrl.c b/src/osmo-bsc_nat/bsc_nat_ctrl.c deleted file mode 100644 index ff6a73978..000000000 --- a/src/osmo-bsc_nat/bsc_nat_ctrl.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * (C) 2011-2012 by Holger Hans Peter Freyther - * (C) 2011-2012 by On-Waves - * (C) 2011 by Daniel Willmann - * 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 . - * - */ - -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#define NAT_MAX_CTRL_ID 65535 - -static struct bsc_nat *g_nat; - -static int bsc_id_unused(int id, struct bsc_connection *bsc) -{ - struct bsc_cmd_list *pending; - - llist_for_each_entry(pending, &bsc->cmd_pending, list_entry) { - if (pending->nat_id == id) - return 0; - } - return 1; -} - -static int get_next_free_bsc_id(struct bsc_connection *bsc) -{ - int new_id, overflow = 0; - - new_id = bsc->last_id; - - do { - new_id++; - if (new_id == NAT_MAX_CTRL_ID) { - new_id = 1; - overflow++; - } - - if (bsc_id_unused(new_id, bsc)) { - bsc->last_id = new_id; - return new_id; - } - } while (overflow != 2); - - return -1; -} - -void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending) -{ - llist_del(&pending->list_entry); - osmo_timer_del(&pending->timeout); - talloc_free(pending->cmd); - talloc_free(pending); -} - -static struct bsc_cmd_list *bsc_get_pending(struct bsc_connection *bsc, char *id_str) -{ - struct bsc_cmd_list *cmd_entry; - int id = atoi(id_str); - if (id == 0) - return NULL; - - llist_for_each_entry(cmd_entry, &bsc->cmd_pending, list_entry) { - if (cmd_entry->nat_id == id) { - return cmd_entry; - } - } - return NULL; -} - -int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg) -{ - struct ctrl_cmd *cmd; - struct bsc_cmd_list *pending; - char *var, *id; - - cmd = ctrl_cmd_parse(bsc, msg); - msgb_free(msg); - - if (!cmd) { - cmd = talloc_zero(bsc, struct ctrl_cmd); - if (!cmd) { - LOGP(DNAT, LOGL_ERROR, "OOM!\n"); - return -ENOMEM; - } - cmd->type = CTRL_TYPE_ERROR; - cmd->id = "err"; - cmd->reply = "Failed to parse command."; - goto err; - } - - if (bsc->cfg && !llist_empty(&bsc->cfg->lac_list)) { - if (cmd->variable) { - var = talloc_asprintf(cmd, "net.0.bsc.%i.%s", bsc->cfg->nr, - cmd->variable); - if (!var) { - cmd->type = CTRL_TYPE_ERROR; - cmd->reply = "OOM"; - goto err; - } - talloc_free(cmd->variable); - cmd->variable = var; - } - - /* We have to handle TRAPs before matching pending */ - if (cmd->type == CTRL_TYPE_TRAP) { - ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd); - talloc_free(cmd); - return 0; - } - - /* Find the pending command */ - pending = bsc_get_pending(bsc, cmd->id); - if (pending) { - id = talloc_strdup(cmd, pending->cmd->id); - if (!id) { - cmd->type = CTRL_TYPE_ERROR; - cmd->reply = "OOM"; - goto err; - } - cmd->id = id; - ctrl_cmd_send(&pending->ccon->write_queue, cmd); - bsc_nat_ctrl_del_pending(pending); - } else { - /* We need to handle TRAPS here */ - if ((cmd->type != CTRL_TYPE_ERROR) && - (cmd->type != CTRL_TYPE_TRAP)) { - LOGP(DNAT, LOGL_NOTICE, "Got control message " - "from BSC without pending entry\n"); - cmd->type = CTRL_TYPE_ERROR; - cmd->reply = "No request outstanding"; - goto err; - } - } - } - talloc_free(cmd); - return 0; -err: - ctrl_cmd_send(&bsc->write_queue, cmd); - talloc_free(cmd); - return 0; -} - -static void pending_timeout_cb(void *data) -{ - struct bsc_cmd_list *pending = data; - LOGP(DNAT, LOGL_ERROR, "Command timed out\n"); - pending->cmd->type = CTRL_TYPE_ERROR; - pending->cmd->reply = "Command timed out"; - ctrl_cmd_send(&pending->ccon->write_queue, pending->cmd); - - bsc_nat_ctrl_del_pending(pending); -} - -static void ctrl_conn_closed_cb(struct ctrl_connection *connection) -{ - struct bsc_connection *bsc; - struct bsc_cmd_list *pending, *tmp; - - llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) { - llist_for_each_entry_safe(pending, tmp, &bsc->cmd_pending, list_entry) { - if (pending->ccon == connection) - bsc_nat_ctrl_del_pending(pending); - } - } -} - -static int extract_bsc_nr_variable(char *variable, unsigned int *nr, char **bsc_variable) -{ - char *nr_str, *tmp, *saveptr = NULL; - - tmp = strtok_r(variable, ".", &saveptr); - tmp = strtok_r(NULL, ".", &saveptr); - tmp = strtok_r(NULL, ".", &saveptr); - nr_str = strtok_r(NULL, ".", &saveptr); - if (!nr_str) - return 0; - *nr = atoi(nr_str); - - tmp = strtok_r(NULL, "\0", &saveptr); - if (!tmp) - return 0; - - *bsc_variable = tmp; - return 1; -} - -static int forward_to_bsc(struct ctrl_cmd *cmd) -{ - int ret = CTRL_CMD_HANDLED; - struct ctrl_cmd *bsc_cmd = NULL; - struct bsc_connection *bsc; - struct bsc_cmd_list *pending; - unsigned int nr; - char *bsc_variable; - - /* Skip over the beginning (bsc.) */ - if (!extract_bsc_nr_variable(cmd->variable, &nr, &bsc_variable)) { - cmd->reply = "command incomplete"; - goto err; - } - - - llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) { - if (!bsc->cfg) - continue; - if (!bsc->authenticated) - continue; - if (bsc->cfg->nr == nr) { - /* Add pending command to list */ - pending = talloc_zero(bsc, struct bsc_cmd_list); - if (!pending) { - cmd->reply = "OOM"; - goto err; - } - - pending->nat_id = get_next_free_bsc_id(bsc); - if (pending->nat_id < 0) { - cmd->reply = "No free ID found"; - goto err; - } - - bsc_cmd = ctrl_cmd_cpy(bsc, cmd); - if (!bsc_cmd) { - cmd->reply = "Could not forward command"; - goto err; - } - - talloc_free(bsc_cmd->id); - bsc_cmd->id = talloc_asprintf(bsc_cmd, "%i", pending->nat_id); - if (!bsc_cmd->id) { - cmd->reply = "OOM"; - goto err; - } - - talloc_free(bsc_cmd->variable); - bsc_cmd->variable = talloc_strdup(bsc_cmd, bsc_variable); - if (!bsc_cmd->variable) { - cmd->reply = "OOM"; - goto err; - } - - if (ctrl_cmd_send(&bsc->write_queue, bsc_cmd)) { - cmd->reply = "Sending failed"; - goto err; - } - pending->ccon = cmd->ccon; - pending->ccon->closed_cb = ctrl_conn_closed_cb; - pending->cmd = cmd; - - /* Setup the timeout */ - osmo_timer_setup(&pending->timeout, pending_timeout_cb, - pending); - /* TODO: Make timeout configurable */ - osmo_timer_schedule(&pending->timeout, 10, 0); - llist_add_tail(&pending->list_entry, &bsc->cmd_pending); - - goto done; - } - } - /* We end up here if there's no bsc to handle our LAC */ - cmd->reply = "no BSC with this nr"; -err: - ret = CTRL_CMD_ERROR; -done: - talloc_free(bsc_cmd); - return ret; - -} - - -CTRL_CMD_DEFINE(fwd_cmd, "net 0 bsc *"); -static int get_fwd_cmd(struct ctrl_cmd *cmd, void *data) -{ - return forward_to_bsc(cmd); -} - -static int set_fwd_cmd(struct ctrl_cmd *cmd, void *data) -{ - return forward_to_bsc(cmd); -} - -static int verify_fwd_cmd(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -static int extract_bsc_cfg_variable(struct ctrl_cmd *cmd, struct bsc_config **cfg, - char **bsc_variable) -{ - unsigned int nr; - - if (!extract_bsc_nr_variable(cmd->variable, &nr, bsc_variable)) { - cmd->reply = "command incomplete"; - return 0; - } - - *cfg = bsc_config_num(g_nat, nr); - if (!*cfg) { - cmd->reply = "Unknown BSC"; - return 0; - } - - return 1; -} - -CTRL_CMD_DEFINE(net_cfg_cmd, "net 0 bsc_cfg *"); -static int get_net_cfg_cmd(struct ctrl_cmd *cmd, void *data) -{ - char *bsc_variable; - struct bsc_config *bsc_cfg; - - if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable)) - return CTRL_CMD_ERROR; - - if (strcmp(bsc_variable, "access-list-name") == 0) { - cmd->reply = talloc_asprintf(cmd, "%s", - bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : ""); - return CTRL_CMD_REPLY; - } - - cmd->reply = "unknown command"; - return CTRL_CMD_ERROR; -} - -static int set_net_cfg_cmd(struct ctrl_cmd *cmd, void *data) -{ - char *bsc_variable; - struct bsc_config *bsc_cfg; - - if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable)) - return CTRL_CMD_ERROR; - - if (strcmp(bsc_variable, "access-list-name") == 0) { - osmo_talloc_replace_string(bsc_cfg, &bsc_cfg->acc_lst_name, cmd->value); - cmd->reply = talloc_asprintf(cmd, "%s", - bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : ""); - return CTRL_CMD_REPLY; - } else if (strcmp(bsc_variable, "no-access-list-name") == 0) { - talloc_free(bsc_cfg->acc_lst_name); - bsc_cfg->acc_lst_name = NULL; - cmd->reply = ""; - return CTRL_CMD_REPLY; - } - - cmd->reply = "unknown command"; - return CTRL_CMD_ERROR; -} - -static int verify_net_cfg_cmd(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -CTRL_CMD_DEFINE(net_cfg_acc_cmd, "net 0 add allow access-list *"); -static const char *extract_acc_name(const char *var) -{ - char *str; - - str = strstr(var, "net.0.add.allow.access-list."); - if (!str) - return NULL; - str += strlen("net.0.add.allow.access-list."); - if (strlen(str) == 0) - return NULL; - return str; -} - -static int get_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data) -{ - cmd->reply = "Append only"; - return CTRL_CMD_ERROR; -} - -static int set_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data) -{ - const char *access_name = extract_acc_name(cmd->variable); - struct bsc_msg_acc_lst *acc; - struct bsc_msg_acc_lst_entry *entry; - const char *value = cmd->value; - int rc; - - /* Should have been caught by verify_net_cfg_acc_cmd */ - acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name); - if (!acc) { - cmd->reply = "Access list not found"; - return CTRL_CMD_ERROR; - } - - entry = bsc_msg_acc_lst_entry_create(acc); - if (!entry) { - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; - } - - rc = gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, 1, &value); - if (rc != 0) { - cmd->reply = "Failed to compile expression"; - return CTRL_CMD_ERROR; - } - - cmd->reply = "IMSI allow added to access list"; - return CTRL_CMD_REPLY; -} - -static int verify_net_cfg_acc_cmd(struct ctrl_cmd *cmd, const char *value, void *data) -{ - const char *access_name = extract_acc_name(cmd->variable); - struct bsc_msg_acc_lst *acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name); - - if (!acc) { - cmd->reply = "Access list not known"; - return -1; - } - - return 0; -} - -CTRL_CMD_DEFINE_WO_NOVRF(net_save_cmd, "net 0 save-configuration"); - -static int set_net_save_cmd(struct ctrl_cmd *cmd, void *data) -{ - int rc = osmo_vty_save_config_file(); - cmd->reply = talloc_asprintf(cmd, "%d", rc); - if (!cmd->reply) { - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; - } - - return CTRL_CMD_REPLY; -} - -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, - const char *bind_addr, int port) -{ - struct ctrl_handle *ctrl; - int rc; - - - ctrl = bsc_controlif_setup(NULL, bind_addr, OSMO_CTRL_PORT_BSC_NAT); - if (!ctrl) { - fprintf(stderr, "Failed to initialize the control interface. Exiting.\n"); - return NULL; - } - - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_fwd_cmd); - if (rc) { - fprintf(stderr, "Failed to install the control command. Exiting.\n"); - goto error; - } - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_cmd); - if (rc) { - fprintf(stderr, "Failed to install the net cfg command. Exiting.\n"); - goto error; - } - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_acc_cmd); - if (rc) { - fprintf(stderr, "Failed to install the net acc command. Exiting.\n"); - goto error; - } - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_save_cmd); - if (rc) { - fprintf(stderr, "Failed to install the net save command. Exiting.\n"); - goto error; - } - - g_nat = nat; - return ctrl; - -error: - osmo_fd_unregister(&ctrl->listen_fd); - close(ctrl->listen_fd.fd); - talloc_free(ctrl); - return NULL; -} - -void bsc_nat_inform_reject(struct bsc_connection *conn, const char *imsi) -{ - struct ctrl_cmd *cmd; - - cmd = ctrl_cmd_create(conn, CTRL_TYPE_TRAP); - if (!cmd) { - LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n"); - return; - } - - cmd->id = "0"; - cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.notification-rejection-v1", - conn->cfg->nr); - cmd->reply = talloc_asprintf(cmd, "imsi=%s", imsi); - - ctrl_cmd_send_to_all(conn->cfg->nat->ctrl, cmd); - talloc_free(cmd); -} diff --git a/src/osmo-bsc_nat/bsc_nat_filter.c b/src/osmo-bsc_nat/bsc_nat_filter.c deleted file mode 100644 index e73529097..000000000 --- a/src/osmo-bsc_nat/bsc_nat_filter.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * (C) 2010-2015 by Holger Hans Peter Freyther - * (C) 2010-2012 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 . - * - */ - -#include -#include -#include -#include - -#include - -#include -#include - -#include - -/* Filter out CR data... */ -int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, - struct bsc_nat_parsed *parsed, int *con_type, - char **imsi, struct bsc_filter_reject_cause *cause) -{ - struct bsc_filter_request req; - struct tlv_parsed tp; - struct gsm48_hdr *hdr48; - int hdr48_len; - int len; - - *con_type = FLT_CON_TYPE_NONE; - cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - *imsi = NULL; - - if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) { - LOGP(DNAT, LOGL_ERROR, - "Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type); - return -1; - } - - /* the parsed has had some basic l3 length check */ - len = msg->l3h[1]; - if (msgb_l3len(msg) - 3 < len) { - LOGP(DNAT, LOGL_ERROR, - "The CR Data has not enough space...\n"); - return -1; - } - - msg->l4h = &msg->l3h[3]; - len -= 1; - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0); - - if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) { - LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n"); - return -1; - } - - hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION); - - if (hdr48_len < sizeof(*hdr48)) { - LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n"); - return -1; - } - - hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION); - req.ctx = bsc; - req.black_list = &bsc->nat->imsi_black_list; - req.access_lists = &bsc->nat->access_lists; - req.local_lst_name = bsc->cfg->acc_lst_name; - req.global_lst_name = bsc->nat->acc_lst_name; - req.bsc_nr = bsc->cfg->nr; - return bsc_msg_filter_initial(hdr48, hdr48_len, &req, con_type, imsi, cause); -} - -int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, - struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct bsc_filter_reject_cause *cause) -{ - uint32_t len; - struct gsm48_hdr *hdr48; - struct bsc_filter_request req; - - cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - - if (con->filter_state.imsi_checked) - return 0; - - /* only care about DTAP messages */ - if (parsed->bssap != BSSAP_MSG_DTAP) - return 0; - - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return -1; - - req.ctx = con; - req.black_list = &bsc->nat->imsi_black_list; - req.access_lists = &bsc->nat->access_lists; - req.local_lst_name = bsc->cfg->acc_lst_name; - req.global_lst_name = bsc->nat->acc_lst_name; - req.bsc_nr = bsc->cfg->nr; - return bsc_msg_filter_data(hdr48, len, &req, &con->filter_state, cause); -} diff --git a/src/osmo-bsc_nat/bsc_nat_rewrite.c b/src/osmo-bsc_nat/bsc_nat_rewrite.c deleted file mode 100644 index e7c387c22..000000000 --- a/src/osmo-bsc_nat/bsc_nat_rewrite.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Message rewriting functionality - */ -/* - * (C) 2010-2013 by Holger Hans Peter Freyther - * (C) 2010-2013 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include - -static char *trie_lookup(struct nat_rewrite *trie, const char *number, - regoff_t off, void *ctx) -{ - struct nat_rewrite_rule *rule; - - if (!trie) { - LOGP(DCC, LOGL_ERROR, - "Asked to do a table lookup but no table.\n"); - return NULL; - } - - rule = nat_rewrite_lookup(trie, number); - if (!rule) { - LOGP(DCC, LOGL_DEBUG, - "Couldn't find a prefix rule for %s\n", number); - return NULL; - } - - return talloc_asprintf(ctx, "%s%s", rule->rewrite, &number[off]); -} - -static char *match_and_rewrite_number(void *ctx, const char *number, - const char *imsi, struct llist_head *list, - struct nat_rewrite *trie) -{ - struct bsc_nat_num_rewr_entry *entry; - char *new_number = NULL; - - /* need to find a replacement and then fix it */ - llist_for_each_entry(entry, list, list) { - regmatch_t matches[2]; - - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - - /* this regexp matches... */ - if (regexec(&entry->num_reg, number, 2, matches, 0) == 0 - && matches[1].rm_eo != -1) { - if (entry->is_prefix_lookup) - new_number = trie_lookup(trie, number, - matches[1].rm_so, ctx); - else - new_number = talloc_asprintf(ctx, "%s%s", - entry->replace, - &number[matches[1].rm_so]); - } - - if (new_number) - break; - } - - return new_number; -} - -static char *rewrite_isdn_number(struct bsc_nat *nat, struct llist_head *rewr_list, - void *ctx, const char *imsi, - struct gsm_mncc_number *called) -{ - char int_number[sizeof(called->number) + 2]; - char *number = called->number; - - if (llist_empty(&nat->num_rewr)) { - LOGP(DCC, LOGL_DEBUG, "Rewrite rules empty.\n"); - return NULL; - } - - /* only ISDN plan */ - if (called->plan != 1) { - LOGP(DCC, LOGL_DEBUG, "Called plan is not 1 it was %d\n", - called->plan); - return NULL; - } - - /* international, prepend */ - if (called->type == 1) { - int_number[0] = '+'; - memcpy(&int_number[1], number, strlen(number) + 1); - number = int_number; - } - - return match_and_rewrite_number(ctx, number, - imsi, rewr_list, nat->num_rewr_trie); -} - -static void update_called_number(struct gsm_mncc_number *called, - const char *chosen_number) -{ - if (strncmp(chosen_number, "00", 2) == 0) { - called->type = 1; - osmo_strlcpy(called->number, chosen_number + 2, - sizeof(called->number)); - } else { - /* rewrite international to unknown */ - if (called->type == 1) - called->type = 0; - osmo_strlcpy(called->number, chosen_number, - sizeof(called->number)); - } -} - -/** - * Rewrite non global numbers... according to rules based on the IMSI - */ -static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg, - struct bsc_nat_parsed *parsed, const char *imsi, - struct gsm48_hdr *hdr48, const uint32_t len) -{ - struct tlv_parsed tp; - unsigned int payload_len; - struct gsm_mncc_number called; - struct msgb *out; - char *new_number_pre = NULL, *new_number_post = NULL, *chosen_number; - uint8_t *outptr; - const uint8_t *msgptr; - int sec_len; - - /* decode and rewrite the message */ - payload_len = len - sizeof(*hdr48); - tlv_parse(&tp, &gsm48_att_tlvdef, hdr48->data, payload_len, 0, 0); - - /* no number, well let us ignore it */ - if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) - return NULL; - - memset(&called, 0, sizeof(called)); - gsm48_decode_called(&called, - TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1); - - /* check if it looks international and stop */ - LOGP(DCC, LOGL_DEBUG, - "Pre-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n", - imsi, called.plan, called.type, called.number); - new_number_pre = rewrite_isdn_number(nat, &nat->num_rewr, msg, imsi, &called); - - if (!new_number_pre) { - LOGP(DCC, LOGL_DEBUG, "No IMSI(%s) match found, returning message.\n", - imsi); - return NULL; - } - - if (strlen(new_number_pre) > sizeof(called.number)) { - LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n", - new_number_pre); - talloc_free(new_number_pre); - return NULL; - } - update_called_number(&called, new_number_pre); - - /* another run through the re-write engine with other rules */ - LOGP(DCC, LOGL_DEBUG, - "Post-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n", - imsi, called.plan, called.type, called.number); - new_number_post = rewrite_isdn_number(nat, &nat->num_rewr_post, msg, - imsi, &called); - chosen_number = new_number_post ? new_number_post : new_number_pre; - - - if (strlen(chosen_number) > sizeof(called.number)) { - LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n", - chosen_number); - talloc_free(new_number_pre); - talloc_free(new_number_post); - return NULL; - } - - /* - * Need to create a new message now based on the old onew - * with a new number. We can sadly not patch this in place - * so we will need to regenerate it. - */ - - out = msgb_alloc_headroom(4096, 128, "changed-setup"); - if (!out) { - LOGP(DCC, LOGL_ERROR, "Failed to allocate.\n"); - talloc_free(new_number_pre); - talloc_free(new_number_post); - return NULL; - } - - /* copy the header */ - outptr = msgb_put(out, sizeof(*hdr48)); - memcpy(outptr, hdr48, sizeof(*hdr48)); - - /* copy everything up to the number */ - sec_len = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 2 - &hdr48->data[0]; - outptr = msgb_put(out, sec_len); - memcpy(outptr, &hdr48->data[0], sec_len); - - /* create the new number */ - update_called_number(&called, chosen_number); - LOGP(DCC, LOGL_DEBUG, - "Chosen number for IMSI(%s) is Plan(%d) Type(%d) Number(%s)\n", - imsi, called.plan, called.type, called.number); - gsm48_encode_called(out, &called); - - /* copy thre rest */ - msgptr = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) + - TLVP_LEN(&tp, GSM48_IE_CALLED_BCD); - sec_len = payload_len - (msgptr - &hdr48->data[0]); - outptr = msgb_put(out, sec_len); - memcpy(outptr, msgptr, sec_len); - - talloc_free(new_number_pre); - talloc_free(new_number_post); - return out; -} - -/** - * Find a new SMSC address, returns an allocated string that needs to be - * freed or is NULL. - */ -static char *find_new_smsc(struct bsc_nat *nat, void *ctx, const char *imsi, - const char *smsc_addr, const char *dest_nr) -{ - struct bsc_nat_num_rewr_entry *entry; - char *new_number = NULL; - uint8_t dest_match = llist_empty(&nat->tpdest_match); - - /* We will find a new number now */ - llist_for_each_entry(entry, &nat->smsc_rewr, list) { - regmatch_t matches[2]; - - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - - /* this regexp matches... */ - if (regexec(&entry->num_reg, smsc_addr, 2, matches, 0) == 0 && - matches[1].rm_eo != -1) - new_number = talloc_asprintf(ctx, "%s%s", - entry->replace, - &smsc_addr[matches[1].rm_so]); - if (new_number) - break; - } - - if (!new_number) - return NULL; - - /* - * now match the number against another list - */ - llist_for_each_entry(entry, &nat->tpdest_match, list) { - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - - if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) == 0) { - dest_match = 1; - break; - } - } - - if (!dest_match) { - talloc_free(new_number); - return NULL; - } - - return new_number; -} - -/** - * Clear the TP-SRR from the TPDU header - */ -static uint8_t sms_new_tpdu_hdr(struct bsc_nat *nat, const char *imsi, - const char *dest_nr, uint8_t hdr) -{ - struct bsc_nat_num_rewr_entry *entry; - - /* We will find a new number now */ - llist_for_each_entry(entry, &nat->sms_clear_tp_srr, list) { - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) != 0) - continue; - - /* matched phone number and imsi */ - return hdr & ~0x20; - } - - return hdr; -} - -/** - * Check if we need to rewrite the number. For this SMS. - */ -static char *sms_new_dest_nr(struct bsc_nat *nat, void *ctx, - const char *imsi, const char *dest_nr) -{ - return match_and_rewrite_number(ctx, dest_nr, imsi, - &nat->sms_num_rewr, NULL); -} - -/** - * This is a helper for GSM 04.11 8.2.5.2 Destination address element - */ -void sms_encode_addr_element(struct msgb *out, const char *new_number, - int format, int tp_data) -{ - uint8_t new_addr_len; - uint8_t new_addr[26]; - - /* - * Copy the new number. We let libosmocore encode it, then set - * the extension followed after the length. Depending on if - * we want to write RP we will let the TLV code add the - * length for us or we need to use strlen... This is not very clear - * as of 03.40 and 04.11. - */ - new_addr_len = gsm48_encode_bcd_number(new_addr, ARRAY_SIZE(new_addr), - 1, new_number); - new_addr[1] = format; - if (tp_data) { - uint8_t *data = msgb_put(out, new_addr_len); - memcpy(data, new_addr, new_addr_len); - data[0] = strlen(new_number); - } else { - msgb_lv_put(out, new_addr_len - 1, new_addr + 1); - } -} - -static struct msgb *sms_create_new(uint8_t type, uint8_t ref, - struct gsm48_hdr *old_hdr48, - const uint8_t *orig_addr_ptr, - int orig_addr_len, const char *new_number, - const uint8_t *data_ptr, int data_len, - uint8_t tpdu_first_byte, - const int old_dest_len, const char *new_dest_nr) -{ - struct gsm48_hdr *new_hdr48; - struct msgb *out; - - /* - * We need to re-create the patched structure. This is why we have - * saved the above pointers. - */ - out = msgb_alloc_headroom(4096, 128, "changed-smsc"); - if (!out) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n"); - return NULL; - } - - out->l2h = out->data; - msgb_v_put(out, GSM411_MT_RP_DATA_MO); - msgb_v_put(out, ref); - msgb_lv_put(out, orig_addr_len, orig_addr_ptr); - - sms_encode_addr_element(out, new_number, 0x91, 0); - - - /* Patch the TPDU from here on */ - - /** - * Do we need to put a new TP-Destination-Address (TP-DA) here or - * can we copy the old thing? For the TP-DA we need to find out the - * new size. - */ - if (new_dest_nr) { - uint8_t *data, *new_size; - - /* reserve the size and write the header */ - new_size = msgb_put(out, 1); - out->l3h = new_size + 1; - msgb_v_put(out, tpdu_first_byte); - msgb_v_put(out, data_ptr[1]); - - /* encode the new number and put it */ - if (strncmp(new_dest_nr, "00", 2) == 0) - sms_encode_addr_element(out, new_dest_nr + 2, 0x91, 1); - else - sms_encode_addr_element(out, new_dest_nr, 0x81, 1); - - /* Copy the rest after the TP-DS */ - data = msgb_put(out, data_len - 2 - 1 - old_dest_len); - memcpy(data, &data_ptr[2 + 1 + old_dest_len], data_len - 2 - 1 - old_dest_len); - - /* fill in the new size */ - new_size[0] = msgb_l3len(out); - } else { - msgb_v_put(out, data_len); - msgb_tv_fixed_put(out, tpdu_first_byte, data_len - 1, &data_ptr[1]); - } - - /* prepend GSM 04.08 header */ - new_hdr48 = (struct gsm48_hdr *) msgb_push(out, sizeof(*new_hdr48) + 1); - memcpy(new_hdr48, old_hdr48, sizeof(*old_hdr48)); - new_hdr48->data[0] = msgb_l2len(out); - - return out; -} - -/** - * Parse the SMS and check if it needs to be rewritten - */ -static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg, - struct bsc_nat_parsed *parsed, const char *imsi, - struct gsm48_hdr *hdr48, const uint32_t len) -{ - unsigned int payload_len; - unsigned int cp_len; - - uint8_t ref; - uint8_t orig_addr_len, *orig_addr_ptr; - uint8_t dest_addr_len, *dest_addr_ptr; - uint8_t data_len, *data_ptr; - char smsc_addr[30]; - - - uint8_t dest_len, orig_dest_len; - char _dest_nr[30]; - char *dest_nr; - char *new_dest_nr; - - char *new_number = NULL; - uint8_t tpdu_hdr; - struct msgb *out; - - payload_len = len - sizeof(*hdr48); - if (payload_len < 1) { - LOGP(DNAT, LOGL_ERROR, "SMS too short for things. %d\n", payload_len); - return NULL; - } - - cp_len = hdr48->data[0]; - if (payload_len + 1 < cp_len) { - LOGP(DNAT, LOGL_ERROR, "SMS RPDU can not fit in: %d %d\n", cp_len, payload_len); - return NULL; - } - - if (hdr48->data[1] != GSM411_MT_RP_DATA_MO) - return NULL; - - if (cp_len < 5) { - LOGP(DNAT, LOGL_ERROR, "RD-DATA can not fit in the CP len: %d\n", cp_len); - return NULL; - } - - /* RP */ - ref = hdr48->data[2]; - orig_addr_len = hdr48->data[3]; - orig_addr_ptr = &hdr48->data[4]; - - /* the +1 is for checking if the following element has some space */ - if (cp_len < 3 + orig_addr_len + 1) { - LOGP(DNAT, LOGL_ERROR, "RP-Originator addr does not fit: %d\n", orig_addr_len); - return NULL; - } - - dest_addr_len = hdr48->data[3 + orig_addr_len + 1]; - dest_addr_ptr = &hdr48->data[3 + orig_addr_len + 2]; - - if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1) { - LOGP(DNAT, LOGL_ERROR, "RP-Destination addr does not fit: %d\n", dest_addr_len); - return NULL; - } - gsm48_decode_bcd_number(smsc_addr, ARRAY_SIZE(smsc_addr), dest_addr_ptr - 1, 1); - - data_len = hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 1]; - data_ptr = &hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 2]; - - if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1 + data_len) { - LOGP(DNAT, LOGL_ERROR, "RP-Data does not fit: %d\n", data_len); - return NULL; - } - - if (data_len < 3) { - LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT is too short.\n"); - return NULL; - } - - /* TP-PDU starts here */ - if ((data_ptr[0] & 0x03) != GSM340_SMS_SUBMIT_MS2SC) - return NULL; - - /* - * look into the phone number. The length is in semi-octets, we will - * need to add the byte for the number type as well. - */ - orig_dest_len = data_ptr[2]; - dest_len = ((orig_dest_len + 1) / 2) + 1; - if (data_len < dest_len + 3 || dest_len < 2) { - LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT can not have TP-DestAddr.\n"); - return NULL; - } - - if ((data_ptr[3] & 0x80) == 0) { - LOGP(DNAT, LOGL_ERROR, "TP-DestAddr has extension. Not handled.\n"); - return NULL; - } - - if ((data_ptr[3] & 0x0F) == 0) { - LOGP(DNAT, LOGL_ERROR, "TP-DestAddr is of unknown type.\n"); - return NULL; - } - - /** - * Besides of what I think I read in GSM 03.40 and 04.11 the TP-DA - * contains the semi-octets as length (strlen), change it to the - * the number of bytes, but then change it back. - */ - data_ptr[2] = dest_len; - gsm48_decode_bcd_number(_dest_nr + 2, ARRAY_SIZE(_dest_nr) - 2, - &data_ptr[2], 1); - data_ptr[2] = orig_dest_len; - if ((data_ptr[3] & 0x70) == 0x10) { - _dest_nr[0] = _dest_nr[1] = '0'; - dest_nr = &_dest_nr[0]; - } else { - dest_nr = &_dest_nr[2]; - } - - /** - * Call functions to rewrite the data - */ - tpdu_hdr = sms_new_tpdu_hdr(nat, imsi, dest_nr, data_ptr[0]); - new_number = find_new_smsc(nat, msg, imsi, smsc_addr, dest_nr); - new_dest_nr = sms_new_dest_nr(nat, msg, imsi, dest_nr); - - if (tpdu_hdr == data_ptr[0] && !new_number && !new_dest_nr) - return NULL; - - out = sms_create_new(GSM411_MT_RP_DATA_MO, ref, hdr48, - orig_addr_ptr, orig_addr_len, - new_number ? new_number : smsc_addr, - data_ptr, data_len, tpdu_hdr, - dest_len, new_dest_nr); - talloc_free(new_number); - talloc_free(new_dest_nr); - return out; -} - -struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *parsed, const char *imsi) -{ - struct gsm48_hdr *hdr48; - uint32_t len; - uint8_t msg_type, proto; - struct msgb *new_msg = NULL, *sccp; - uint8_t link_id; - - if (!imsi || strlen(imsi) < 5) - return msg; - - /* only care about DTAP messages */ - if (parsed->bssap != BSSAP_MSG_DTAP) - return msg; - if (!parsed->dest_local_ref) - return msg; - - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return msg; - - link_id = msg->l3h[1]; - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - - if (proto == GSM48_PDISC_CC && msg_type == GSM48_MT_CC_SETUP) - new_msg = rewrite_setup(nat, msg, parsed, imsi, hdr48, len); - else if (proto == GSM48_PDISC_SMS && msg_type == GSM411_MT_CP_DATA) - new_msg = rewrite_sms(nat, msg, parsed, imsi, hdr48, len); - - if (!new_msg) - return msg; - - /* wrap with DTAP, SCCP, then IPA. TODO: Stop copying */ - gsm0808_prepend_dtap_header(new_msg, link_id); - sccp = sccp_create_dt1(parsed->dest_local_ref, new_msg->data, new_msg->len); - talloc_free(new_msg); - - if (!sccp) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n"); - return msg; - } - - ipa_prepend_header(sccp, IPAC_PROTO_SCCP); - - /* the parsed hangs off from msg but it needs to survive */ - talloc_steal(sccp, parsed); - msgb_free(msg); - return sccp; -} - -static void num_rewr_free_data(struct bsc_nat_num_rewr_entry *entry) -{ - regfree(&entry->msisdn_reg); - regfree(&entry->num_reg); - talloc_free(entry->replace); -} - -void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, - const struct osmo_config_list *list) -{ - struct bsc_nat_num_rewr_entry *entry, *tmp; - struct osmo_config_entry *cfg_entry; - - /* free the old data */ - llist_for_each_entry_safe(entry, tmp, head, list) { - num_rewr_free_data(entry); - llist_del(&entry->list); - talloc_free(entry); - } - - - if (!list) - return; - - llist_for_each_entry(cfg_entry, &list->entry, list) { - char *regexp; - if (cfg_entry->text[0] == '+') { - LOGP(DNAT, LOGL_ERROR, - "Plus is not allowed in the number\n"); - continue; - } - - entry = talloc_zero(ctx, struct bsc_nat_num_rewr_entry); - if (!entry) { - LOGP(DNAT, LOGL_ERROR, - "Allocation of the num_rewr entry failed.\n"); - continue; - } - - entry->replace = talloc_strdup(entry, cfg_entry->text); - if (!entry->replace) { - LOGP(DNAT, LOGL_ERROR, - "Failed to copy the replacement text.\n"); - talloc_free(entry); - continue; - } - - if (strcmp("prefix_lookup", entry->replace) == 0) - entry->is_prefix_lookup = 1; - - /* we will now build a regexp string */ - if (cfg_entry->mcc[0] == '^') { - regexp = talloc_strdup(entry, cfg_entry->mcc); - } else { - regexp = talloc_asprintf(entry, "^%s%s", - cfg_entry->mcc[0] == '*' ? - "[0-9][0-9][0-9]" : cfg_entry->mcc, - cfg_entry->mnc[0] == '*' ? - "[0-9][0-9]" : cfg_entry->mnc); - } - - if (!regexp) { - LOGP(DNAT, LOGL_ERROR, "Failed to create a regexp string.\n"); - talloc_free(entry); - continue; - } - - if (regcomp(&entry->msisdn_reg, regexp, 0) != 0) { - LOGP(DNAT, LOGL_ERROR, - "Failed to compile regexp '%s'\n", regexp); - talloc_free(regexp); - talloc_free(entry); - continue; - } - - talloc_free(regexp); - if (regcomp(&entry->num_reg, cfg_entry->option, REG_EXTENDED) != 0) { - LOGP(DNAT, LOGL_ERROR, - "Failed to compile regexp '%s'\n", cfg_entry->option); - regfree(&entry->msisdn_reg); - talloc_free(entry); - continue; - } - - /* we have copied the number */ - llist_add_tail(&entry->list, head); - } -} diff --git a/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c b/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c deleted file mode 100644 index 633fa87d0..000000000 --- a/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c +++ /dev/null @@ -1,259 +0,0 @@ -/* Handling for loading a re-write file/database */ -/* - * (C) 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 . - * - */ - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#define CHECK_IS_DIGIT_OR_FAIL(prefix, pos) \ - if (!isdigit(prefix[pos]) && prefix[pos] != '+') { \ - LOGP(DNAT, LOGL_ERROR, \ - "Prefix(%s) contains non ascii text at(%d=%c)\n", \ - prefix, pos, prefix[pos]); \ - goto fail; \ - } -#define TO_INT(c) \ - ((c) == '+' ? 10 : ((c - '0') % 10)) - -static void insert_rewrite_node(struct nat_rewrite_rule *rule, struct nat_rewrite *root) -{ - struct nat_rewrite_rule *new = &root->rule; - - const int len = strlen(rule->prefix); - int i; - - if (len <= 0) { - LOGP(DNAT, LOGL_ERROR, "An empty prefix does not make sense.\n"); - goto fail; - } - - for (i = 0; i < len - 1; ++i) { - int pos; - - /* check if the input is valid */ - CHECK_IS_DIGIT_OR_FAIL(rule->prefix, i); - - /* check if the next node is already valid */ - pos = TO_INT(rule->prefix[i]); - if (!new->rules[pos]) { - new->rules[pos] = talloc_zero(root, struct nat_rewrite_rule); - if (!new->rules[pos]) { - LOGP(DNAT, LOGL_ERROR, - "Failed to allocate memory.\n"); - goto fail; - } - - new->rules[pos]->empty = 1; - } - - /* we continue here */ - new = new->rules[pos]; - } - - /* new now points to the place where we want to add it */ - int pos; - - /* check if the input is valid */ - CHECK_IS_DIGIT_OR_FAIL(rule->prefix, (len - 1)); - - /* check if the next node is already valid */ - pos = TO_INT(rule->prefix[len - 1]); - if (!new->rules[pos]) - new->rules[pos] = rule; - else if (new->rules[pos]->empty) { - /* copy over entries */ - new->rules[pos]->empty = 0; - memcpy(new->rules[pos]->prefix, rule->prefix, sizeof(rule->prefix)); - memcpy(new->rules[pos]->rewrite, rule->rewrite, sizeof(rule->rewrite)); - talloc_free(rule); - } else { - LOGP(DNAT, LOGL_ERROR, - "Prefix(%s) is already installed\n", rule->prefix); - goto fail; - } - - root->prefixes += 1; - return; - -fail: - talloc_free(rule); - return; -} - -static void handle_line(struct nat_rewrite *rewrite, char *line) -{ - char *split; - struct nat_rewrite_rule *rule; - size_t size_prefix, size_end, len; - - - /* Find the ',' in the line */ - len = strlen(line); - split = strstr(line, ","); - if (!split) { - LOGP(DNAT, LOGL_ERROR, "Line doesn't contain ','\n"); - return; - } - - /* Check if there is space for the rewrite rule */ - size_prefix = split - line; - if (len - size_prefix <= 2) { - LOGP(DNAT, LOGL_ERROR, "No rewrite available.\n"); - return; - } - - /* Continue after the ',' to the end */ - split = &line[size_prefix + 1]; - size_end = strlen(split) - 1; - - /* Check if both strings can fit into the static array */ - if (size_prefix > sizeof(rule->prefix) - 1) { - LOGP(DNAT, LOGL_ERROR, - "Prefix is too long with %zu\n", size_prefix); - return; - } - - if (size_end > sizeof(rule->rewrite) - 1) { - LOGP(DNAT, LOGL_ERROR, - "Rewrite is too long with %zu on %s\n", - size_end, &line[size_prefix + 1]); - return; - } - - /* Now create the entry and insert it into the trie */ - rule = talloc_zero(rewrite, struct nat_rewrite_rule); - if (!rule) { - LOGP(DNAT, LOGL_ERROR, "Can not allocate memory\n"); - return; - } - - memcpy(rule->prefix, line, size_prefix); - assert(size_prefix < sizeof(rule->prefix)); - rule->prefix[size_prefix] = '\0'; - - memcpy(rule->rewrite, split, size_end); - assert(size_end < sizeof(rule->rewrite)); - rule->rewrite[size_end] = '\0'; - - /* now insert and balance the tree */ - insert_rewrite_node(rule, rewrite); -} - -struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename) -{ - FILE *file; - char *line = NULL; - size_t n = 0; - struct nat_rewrite *res; - - file = fopen(filename, "r"); - if (!file) - return NULL; - - res = talloc_zero(ctx, struct nat_rewrite); - if (!res) { - fclose(file); - return NULL; - } - - /* mark the root as empty */ - res->rule.empty = 1; - - while (getline(&line, &n, file) != -1) { - handle_line(res, line); - } - - free(line); - fclose(file); - return res; -} - -/** - * Simple find that tries to do a longest match... - */ -struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *rewrite, - const char *prefix) -{ - struct nat_rewrite_rule *rule = &rewrite->rule; - struct nat_rewrite_rule *last = NULL; - const int len = OSMO_MIN(strlen(prefix), (sizeof(rule->prefix) - 1)); - int i; - - for (i = 0; rule && i < len; ++i) { - int pos; - - CHECK_IS_DIGIT_OR_FAIL(prefix, i); - pos = TO_INT(prefix[i]); - - rule = rule->rules[pos]; - if (rule && !rule->empty) - last = rule; - } - - return last; - -fail: - return NULL; -} - -static void nat_rewrite_dump_rec(struct nat_rewrite_rule *rule) -{ - int i; - if (!rule->empty) - printf("%s,%s\n", rule->prefix, rule->rewrite); - - for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) { - if (!rule->rules[i]) - continue; - nat_rewrite_dump_rec(rule->rules[i]); - } -} - -void nat_rewrite_dump(struct nat_rewrite *rewrite) -{ - nat_rewrite_dump_rec(&rewrite->rule); -} - -static void nat_rewrite_dump_rec_vty(struct vty *vty, struct nat_rewrite_rule *rule) -{ - int i; - if (!rule->empty) - vty_out(vty, "%s,%s%s", rule->prefix, rule->rewrite, VTY_NEWLINE); - - for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) { - if (!rule->rules[i]) - continue; - nat_rewrite_dump_rec_vty(vty, rule->rules[i]); - } -} - -void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewrite) -{ - nat_rewrite_dump_rec_vty(vty, &rewrite->rule); -} diff --git a/src/osmo-bsc_nat/bsc_nat_utils.c b/src/osmo-bsc_nat/bsc_nat_utils.c deleted file mode 100644 index c12b29f1f..000000000 --- a/src/osmo-bsc_nat/bsc_nat_utils.c +++ /dev/null @@ -1,535 +0,0 @@ - -/* BSC Multiplexer/NAT Utilities */ - -/* - * (C) 2010-2011 by Holger Hans Peter Freyther - * (C) 2010-2011 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -static const struct rate_ctr_desc bsc_cfg_ctr_description[] = { - [BCFG_CTR_SCCP_CONN] = { "sccp.conn", "SCCP Connections "}, - [BCFG_CTR_SCCP_CALLS] = { "sccp.calls", "SCCP Assignment Commands "}, - [BCFG_CTR_NET_RECONN] = { "net.reconnects", "Network reconnects "}, - [BCFG_CTR_DROPPED_SCCP] = { "dropped.sccp", "Dropped SCCP connections."}, - [BCFG_CTR_DROPPED_CALLS] = { "dropped.calls", "Dropped active calls. "}, - [BCFG_CTR_REJECTED_CR] = { "rejected.cr", "Rejected CR due filter "}, - [BCFG_CTR_REJECTED_MSG] = { "rejected.msg", "Rejected MSG due filter "}, - [BCFG_CTR_ILL_PACKET] = { "rejected.ill", "Rejected due parse error "}, - [BCFG_CTR_CON_TYPE_LU] = { "conn.lu", "Conn Location Update "}, - [BCFG_CTR_CON_CMSERV_RQ] = { "conn.rq", "Conn CM Service Req "}, - [BCFG_CTR_CON_PAG_RESP] = { "conn.pag", "Conn Paging Response "}, - [BCFG_CTR_CON_SSA] = { "conn.ssa", "Conn USSD "}, - [BCFG_CTR_CON_OTHER] = { "conn.other", "Conn Other "}, -}; - -static const struct rate_ctr_group_desc bsc_cfg_ctrg_desc = { - .group_name_prefix = "nat.bsc", - .group_description = "NAT BSC Statistics", - .num_ctr = ARRAY_SIZE(bsc_cfg_ctr_description), - .ctr_desc = bsc_cfg_ctr_description, - .class_id = OSMO_STATS_CLASS_PEER, -}; - -struct bsc_nat *bsc_nat_alloc(void) -{ - struct bsc_nat *nat = talloc_zero(tall_bsc_ctx, struct bsc_nat); - if (!nat) - return NULL; - - nat->main_dest = talloc_zero(nat, struct bsc_msc_dest); - if (!nat->main_dest) { - talloc_free(nat); - return NULL; - } - - INIT_LLIST_HEAD(&nat->sccp_connections); - INIT_LLIST_HEAD(&nat->bsc_connections); - INIT_LLIST_HEAD(&nat->paging_groups); - INIT_LLIST_HEAD(&nat->bsc_configs); - INIT_LLIST_HEAD(&nat->access_lists); - INIT_LLIST_HEAD(&nat->dests); - INIT_LLIST_HEAD(&nat->num_rewr); - INIT_LLIST_HEAD(&nat->num_rewr_post); - INIT_LLIST_HEAD(&nat->smsc_rewr); - INIT_LLIST_HEAD(&nat->tpdest_match); - INIT_LLIST_HEAD(&nat->sms_clear_tp_srr); - INIT_LLIST_HEAD(&nat->sms_num_rewr); - - nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn"); - nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls"); - nat->stats.bsc.reconn = osmo_counter_alloc("nat.bsc.conn"); - nat->stats.bsc.auth_fail = osmo_counter_alloc("nat.bsc.auth_fail"); - nat->stats.msc.reconn = osmo_counter_alloc("nat.msc.conn"); - nat->stats.ussd.reconn = osmo_counter_alloc("nat.ussd.conn"); - nat->auth_timeout = 2; - nat->ping_timeout = 20; - nat->pong_timeout = 5; - - llist_add(&nat->main_dest->list, &nat->dests); - nat->main_dest->ip = talloc_strdup(nat, "127.0.0.1"); - nat->main_dest->port = 5000; - - return nat; -} - -void bsc_nat_free(struct bsc_nat *nat) -{ - struct bsc_config *cfg, *tmp; - struct bsc_msg_acc_lst *lst, *tmp_lst; - - llist_for_each_entry_safe(cfg, tmp, &nat->bsc_configs, entry) - bsc_config_free(cfg); - llist_for_each_entry_safe(lst, tmp_lst, &nat->access_lists, list) - bsc_msg_acc_lst_delete(lst); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_num_rewr, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->tpdest_match, NULL); - - osmo_counter_free(nat->stats.sccp.conn); - osmo_counter_free(nat->stats.sccp.calls); - osmo_counter_free(nat->stats.bsc.reconn); - osmo_counter_free(nat->stats.bsc.auth_fail); - osmo_counter_free(nat->stats.msc.reconn); - osmo_counter_free(nat->stats.ussd.reconn); - talloc_free(nat->mgcp_cfg); - talloc_free(nat); -} - -void bsc_nat_set_msc_ip(struct bsc_nat *nat, const char *ip) -{ - osmo_talloc_replace_string(nat, &nat->main_dest->ip, ip); -} - -struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat) -{ - struct bsc_connection *con = talloc_zero(nat, struct bsc_connection); - if (!con) - return NULL; - - con->nat = nat; - osmo_wqueue_init(&con->write_queue, 100); - INIT_LLIST_HEAD(&con->cmd_pending); - INIT_LLIST_HEAD(&con->pending_dlcx); - return con; -} - -struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, - unsigned int number) -{ - struct bsc_config *conf = talloc_zero(nat, struct bsc_config); - if (!conf) - return NULL; - - conf->token = talloc_strdup(conf, token); - conf->nr = number; - conf->nat = nat; - conf->max_endpoints = 32; - conf->paging_group = PAGIN_GROUP_UNASSIGNED; - - INIT_LLIST_HEAD(&conf->lac_list); - - llist_add_tail(&conf->entry, &nat->bsc_configs); - ++nat->num_bsc; - - conf->stats.ctrg = rate_ctr_group_alloc(conf, &bsc_cfg_ctrg_desc, conf->nr); - if (!conf->stats.ctrg) { - llist_del(&conf->entry); - talloc_free(conf); - return NULL; - } - - return conf; -} - -struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len) -{ - struct bsc_config *conf; - - llist_for_each_entry(conf, &nat->bsc_configs, entry) { - /* - * Add the '\0' of the token for the memcmp, the IPA messages - * for some reason added null termination. - */ - const int token_len = strlen(conf->token) + 1; - - if (token_len == len && memcmp(conf->token, token, token_len) == 0) - return conf; - } - - return NULL; -} - -void bsc_config_free(struct bsc_config *cfg) -{ - llist_del(&cfg->entry); - rate_ctr_group_free(cfg->stats.ctrg); - cfg->nat->num_bsc--; - OSMO_ASSERT(cfg->nat->num_bsc >= 0) - talloc_free(cfg); -} - -static void _add_lac(void *ctx, struct llist_head *list, int _lac) -{ - struct bsc_lac_entry *lac; - - llist_for_each_entry(lac, list, entry) - if (lac->lac == _lac) - return; - - lac = talloc_zero(ctx, struct bsc_lac_entry); - if (!lac) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n"); - return; - } - - lac->lac = _lac; - llist_add_tail(&lac->entry, list); -} - -static void _del_lac(struct llist_head *list, int _lac) -{ - struct bsc_lac_entry *lac; - - llist_for_each_entry(lac, list, entry) - if (lac->lac == _lac) { - llist_del(&lac->entry); - talloc_free(lac); - return; - } -} - -void bsc_config_add_lac(struct bsc_config *cfg, int _lac) -{ - _add_lac(cfg, &cfg->lac_list, _lac); -} - -void bsc_config_del_lac(struct bsc_config *cfg, int _lac) -{ - _del_lac(&cfg->lac_list, _lac); -} - -struct bsc_nat_paging_group *bsc_nat_paging_group_create(struct bsc_nat *nat, int group) -{ - struct bsc_nat_paging_group *pgroup; - - pgroup = talloc_zero(nat, struct bsc_nat_paging_group); - if (!pgroup) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate a paging group.\n"); - return NULL; - } - - pgroup->nr = group; - INIT_LLIST_HEAD(&pgroup->lists); - llist_add_tail(&pgroup->entry, &nat->paging_groups); - return pgroup; -} - -void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *pgroup) -{ - llist_del(&pgroup->entry); - talloc_free(pgroup); -} - -struct bsc_nat_paging_group *bsc_nat_paging_group_num(struct bsc_nat *nat, int group) -{ - struct bsc_nat_paging_group *pgroup; - - llist_for_each_entry(pgroup, &nat->paging_groups, entry) - if (pgroup->nr == group) - return pgroup; - - return NULL; -} - -void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *pgroup, int lac) -{ - _add_lac(pgroup, &pgroup->lists, lac); -} - -void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *pgroup, int lac) -{ - _del_lac(&pgroup->lists, lac); -} - -int bsc_config_handles_lac(struct bsc_config *cfg, int lac_nr) -{ - struct bsc_nat_paging_group *pgroup; - struct bsc_lac_entry *entry; - - llist_for_each_entry(entry, &cfg->lac_list, entry) - if (entry->lac == lac_nr) - return 1; - - /* now lookup the paging group */ - pgroup = bsc_nat_paging_group_num(cfg->nat, cfg->paging_group); - if (!pgroup) - return 0; - - llist_for_each_entry(entry, &pgroup->lists, entry) - if (entry->lac == lac_nr) - return 1; - - return 0; -} - -void sccp_connection_destroy(struct nat_sccp_connection *conn) -{ - LOGP(DNAT, LOGL_DEBUG, "Destroy 0x%x <-> 0x%x mapping for con %p\n", - sccp_src_ref_to_int(&conn->real_ref), - sccp_src_ref_to_int(&conn->patched_ref), conn->bsc); - bsc_mgcp_dlcx(conn); - llist_del(&conn->list_entry); - talloc_free(conn); -} - - -int bsc_nat_find_paging(struct msgb *msg, - const uint8_t **out_data, int *out_leng) -{ - int data_length; - const uint8_t *data; - struct tlv_parsed tp; - - if (!msg->l3h || msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Paging message is too short.\n"); - return -1; - } - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0); - if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) { - LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n"); - return -2; - } - - data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); - data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); - - /* No need to try a different BSS */ - if (data[0] == CELL_IDENT_BSS) { - return -3; - } else if (data[0] != CELL_IDENT_LAC) { - LOGP(DNAT, LOGL_ERROR, "Unhandled cell ident discrminator: %d\n", data[0]); - return -4; - } - - *out_data = &data[1]; - *out_leng = data_length - 1; - return 0; -} - -int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length) -{ - struct msgb *msg; - - if (length > 4096 - 128) { - LOGP(DLINP, LOGL_ERROR, "Can not send message of that size.\n"); - return -1; - } - - msg = msgb_alloc_headroom(4096, 128, "to-bsc"); - if (!msg) { - LOGP(DLINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n"); - return -1; - } - - /* copy the data */ - msg->l3h = msgb_put(msg, length); - memcpy(msg->l3h, data, length); - - return bsc_write(bsc, msg, IPAC_PROTO_MGCP_OLD); -} - -int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto) -{ - return bsc_do_write(&bsc->write_queue, msg, proto); -} - -int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int proto) -{ - /* prepend the header */ - ipa_prepend_header(msg, proto); - return bsc_write_msg(queue, msg); -} - -int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg) -{ - if (osmo_wqueue_enqueue(queue, msg) != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the write.\n"); - msgb_free(msg); - return -1; - } - - return 0; -} - -struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, - struct msgb *msg, uint32_t *len) -{ - /* gsm_type is actually the size of the dtap */ - *len = parsed->gsm_type; - if (*len < msgb_l3len(msg) - 3) { - LOGP(DNAT, LOGL_ERROR, "Not enough space for DTAP.\n"); - return NULL; - } - - if (msgb_l3len(msg) - 3 < msg->l3h[2]) { - LOGP(DNAT, LOGL_ERROR, - "GSM48 payload does not fit: %d %d\n", - msg->l3h[2], msgb_l3len(msg) - 3); - return NULL; - } - - msg->l4h = &msg->l3h[3]; - return (struct gsm48_hdr *) msg->l4h; -} - -static const char *con_types [] = { - [FLT_CON_TYPE_NONE] = "n/a", - [FLT_CON_TYPE_LU] = "Location Update", - [FLT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req", - [FLT_CON_TYPE_PAG_RESP] = "Paging Response", - [FLT_CON_TYPE_SSA] = "Supplementar Service Activation", - [FLT_CON_TYPE_LOCAL_REJECT] = "Local Reject", - [FLT_CON_TYPE_OTHER] = "Other", -}; - -const char *bsc_con_type_to_string(int type) -{ - return con_types[type]; -} - -int bsc_nat_msc_is_connected(struct bsc_nat *nat) -{ - return nat->msc_con->is_connected; -} - -static const int con_to_ctr[] = { - [FLT_CON_TYPE_NONE] = -1, - [FLT_CON_TYPE_LU] = BCFG_CTR_CON_TYPE_LU, - [FLT_CON_TYPE_CM_SERV_REQ] = BCFG_CTR_CON_CMSERV_RQ, - [FLT_CON_TYPE_PAG_RESP] = BCFG_CTR_CON_PAG_RESP, - [FLT_CON_TYPE_SSA] = BCFG_CTR_CON_SSA, - [FLT_CON_TYPE_LOCAL_REJECT] = -1, - [FLT_CON_TYPE_OTHER] = BCFG_CTR_CON_OTHER, -}; - -int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn) -{ - return con_to_ctr[conn->filter_state.con_type]; -} - -int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg) -{ - int rc; - - rc = write(bfd->fd, msg->data, msg->len); - if (rc != msg->len) - LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n"); - - return rc; -} - -static void extract_lac(const uint8_t *data, uint16_t *lac, uint16_t *ci) -{ - memcpy(lac, &data[0], sizeof(*lac)); - memcpy(ci, &data[2], sizeof(*ci)); - - *lac = ntohs(*lac); - *ci = ntohs(*ci); -} - -int bsc_nat_extract_lac(struct bsc_connection *bsc, - struct nat_sccp_connection *con, - struct bsc_nat_parsed *parsed, struct msgb *msg) -{ - int data_length; - const uint8_t *data; - struct tlv_parsed tp; - uint16_t lac, ci; - - if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) { - LOGP(DNAT, LOGL_ERROR, "Can only extract LAC from Complete Layer3\n"); - return -1; - } - - if (!msg->l3h || msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Complete Layer3 mssage is too short.\n"); - return -1; - } - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0); - if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)) { - LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n"); - return -2; - } - - data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER); - data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER); - - /* Attemt to get the LAC/CI from it */ - if (data[0] == CELL_IDENT_WHOLE_GLOBAL) { - if (data_length != 8) { - LOGP(DNAT, LOGL_ERROR, - "Ident too short: %d\n", data_length); - return -3; - } - extract_lac(&data[1 + 3], &lac, &ci); - } else if (data[0] == CELL_IDENT_LAC_AND_CI) { - if (data_length != 5) { - LOGP(DNAT, LOGL_ERROR, - "Ident too short: %d\n", data_length); - return -3; - } - extract_lac(&data[1], &lac, &ci); - } else { - LOGP(DNAT, LOGL_ERROR, - "Unhandled cell identifier: %d\n", data[0]); - return -1; - } - - con->lac = lac; - con->ci = ci; - return 0; -} diff --git a/src/osmo-bsc_nat/bsc_nat_vty.c b/src/osmo-bsc_nat/bsc_nat_vty.c deleted file mode 100644 index fed530676..000000000 --- a/src/osmo-bsc_nat/bsc_nat_vty.c +++ /dev/null @@ -1,1336 +0,0 @@ -/* OpenBSC NAT interface to quagga VTY */ -/* (C) 2010-2015 by Holger Hans Peter Freyther - * (C) 2010-2015 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -static struct bsc_nat *_nat; - - -#define BSC_STR "Information about BSCs\n" -#define MGCP_STR "MGCP related status\n" -#define PAGING_STR "Paging\n" -#define SMSC_REWRITE "SMSC Rewriting\n" - -static struct cmd_node nat_node = { - NAT_NODE, - "%s(config-nat)# ", - 1, -}; - -static struct cmd_node bsc_node = { - NAT_BSC_NODE, - "%s(config-nat-bsc)# ", - 1, -}; - -static struct cmd_node pgroup_node = { - PGROUP_NODE, - "%s(config-nat-paging-group)# ", - 1, -}; - -static int config_write_pgroup(struct vty *vty) -{ - return CMD_SUCCESS; -} - -static void dump_lac(struct vty *vty, struct llist_head *head) -{ - struct bsc_lac_entry *lac; - llist_for_each_entry(lac, head, entry) - vty_out(vty, " location_area_code %u%s", lac->lac, VTY_NEWLINE); -} - - -static void write_pgroup_lst(struct vty *vty, struct bsc_nat_paging_group *pgroup) -{ - vty_out(vty, " paging-group %d%s", pgroup->nr, VTY_NEWLINE); - dump_lac(vty, &pgroup->lists); -} - -static int config_write_nat(struct vty *vty) -{ - struct bsc_msg_acc_lst *lst; - struct bsc_nat_paging_group *pgroup; - - vty_out(vty, "nat%s", VTY_NEWLINE); - vty_out(vty, " msc ip %s%s", _nat->main_dest->ip, VTY_NEWLINE); - vty_out(vty, " msc port %d%s", _nat->main_dest->port, VTY_NEWLINE); - vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE); - vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE); - vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE); - if (_nat->include_file) - vty_out(vty, " bscs-config-file %s%s", _nat->include_file, VTY_NEWLINE); - if (_nat->token) - vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE); - vty_out(vty, " ip-dscp %d%s", _nat->bsc_ip_dscp, VTY_NEWLINE); - if (_nat->acc_lst_name) - vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE); - if (_nat->imsi_black_list_fn) - vty_out(vty, " imsi-black-list-file-name %s%s", - _nat->imsi_black_list_fn, VTY_NEWLINE); - if (_nat->ussd_lst_name) - vty_out(vty, " ussd-list-name %s%s", _nat->ussd_lst_name, VTY_NEWLINE); - if (_nat->ussd_query) - vty_out(vty, " ussd-query %s%s", _nat->ussd_query, VTY_NEWLINE); - if (_nat->ussd_token) - vty_out(vty, " ussd-token %s%s", _nat->ussd_token, VTY_NEWLINE); - if (_nat->ussd_local) - vty_out(vty, " ussd-local-ip %s%s", _nat->ussd_local, VTY_NEWLINE); - - if (_nat->num_rewr_name) - vty_out(vty, " number-rewrite %s%s", _nat->num_rewr_name, VTY_NEWLINE); - if (_nat->num_rewr_post_name) - vty_out(vty, " number-rewrite-post %s%s", - _nat->num_rewr_post_name, VTY_NEWLINE); - - if (_nat->smsc_rewr_name) - vty_out(vty, " rewrite-smsc addr %s%s", - _nat->smsc_rewr_name, VTY_NEWLINE); - if (_nat->tpdest_match_name) - vty_out(vty, " rewrite-smsc tp-dest-match %s%s", - _nat->tpdest_match_name, VTY_NEWLINE); - if (_nat->sms_clear_tp_srr_name) - vty_out(vty, " sms-clear-tp-srr %s%s", - _nat->sms_clear_tp_srr_name, VTY_NEWLINE); - if (_nat->sms_num_rewr_name) - vty_out(vty, " sms-number-rewrite %s%s", - _nat->sms_num_rewr_name, VTY_NEWLINE); - if (_nat->num_rewr_trie_name) - vty_out(vty, " prefix-tree %s%s", - _nat->num_rewr_trie_name, VTY_NEWLINE); - - llist_for_each_entry(lst, &_nat->access_lists, list) - bsc_msg_acc_lst_write(vty, lst); - llist_for_each_entry(pgroup, &_nat->paging_groups, entry) - write_pgroup_lst(vty, pgroup); - if (_nat->mgcp_ipa) - vty_out(vty, " use-msc-ipa-for-mgcp%s", VTY_NEWLINE); - vty_out(vty, " %ssdp-ensure-amr-mode-set%s", - _nat->sdp_ensure_amr_mode_set ? "" : "no ", VTY_NEWLINE); - - return CMD_SUCCESS; -} - -static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc) -{ - vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE); - vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE); - if (bsc->key_present) - vty_out(vty, " auth-key %s%s", osmo_hexdump(bsc->key, 16), VTY_NEWLINE); - dump_lac(vty, &bsc->lac_list); - if (bsc->description) - vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE); - if (bsc->acc_lst_name) - vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE); - vty_out(vty, " max-endpoints %d%s", bsc->max_endpoints, VTY_NEWLINE); - if (bsc->paging_group != -1) - vty_out(vty, " paging group %d%s", bsc->paging_group, VTY_NEWLINE); - vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE); - switch (bsc->osmux) { - case OSMUX_USAGE_ON: - vty_out(vty, " osmux on%s", VTY_NEWLINE); - break; - case OSMUX_USAGE_ONLY: - vty_out(vty, " osmux only%s", VTY_NEWLINE); - break; - } -} - -static int config_write_bsc(struct vty *vty) -{ - struct bsc_config *bsc; - - llist_for_each_entry(bsc, &_nat->bsc_configs, entry) - config_write_bsc_single(vty, bsc); - return CMD_SUCCESS; -} - -DEFUN(show_bscs, show_bscs_cmd, "show bscs-config", - SHOW_STR "Show configured BSCs\n" - "Both from included file and vty\n") -{ - vty_out(vty, "BSCs configuration loaded from %s:%s", _nat->resolved_path, - VTY_NEWLINE); - return config_write_bsc(vty); -} - -DEFUN(show_sccp, show_sccp_cmd, "show sccp connections", - SHOW_STR "Display information about SCCP\n" - "All active connections\n") -{ - struct nat_sccp_connection *con; - vty_out(vty, "Listing all open SCCP connections%s", VTY_NEWLINE); - - llist_for_each_entry(con, &_nat->sccp_connections, list_entry) { - vty_out(vty, "For BSC Nr: %d BSC ref: 0x%x; MUX ref: 0x%x; Network has ref: %d ref: 0x%x MSC/BSC mux: 0x%x/0x%x type: %s%s", - con->bsc->cfg ? con->bsc->cfg->nr : -1, - sccp_src_ref_to_int(&con->real_ref), - sccp_src_ref_to_int(&con->patched_ref), - con->has_remote_ref, - sccp_src_ref_to_int(&con->remote_ref), - con->msc_endp, con->bsc_endp, - bsc_con_type_to_string(con->filter_state.con_type), - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(show_nat_bsc, show_nat_bsc_cmd, "show nat num-bscs-configured", - SHOW_STR "Display NAT configuration details\n" - "BSCs-related\n") -{ - vty_out(vty, "%d BSCs configured%s", _nat->num_bsc, VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(show_bsc, show_bsc_cmd, "show bsc connections", - SHOW_STR BSC_STR - "All active connections\n") -{ - struct bsc_connection *con; - struct sockaddr_in sock; - socklen_t len = sizeof(sock); - - llist_for_each_entry(con, &_nat->bsc_connections, list_entry) { - getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len); - vty_out(vty, "BSC nr: %d auth: %d fd: %d peername: %s pending-stats: %u%s", - con->cfg ? con->cfg->nr : -1, - con->authenticated, con->write_queue.bfd.fd, - inet_ntoa(sock.sin_addr), con->pending_dlcx_count, - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(show_bsc_mgcp, show_bsc_mgcp_cmd, "show bsc mgcp NR", - SHOW_STR BSC_STR MGCP_STR "Identifier of the BSC\n") -{ - struct bsc_connection *con; - int nr = atoi(argv[0]); - int i, j, endp; - - llist_for_each_entry(con, &_nat->bsc_connections, list_entry) { - int max; - if (!con->cfg) - continue; - if (con->cfg->nr != nr) - continue; - - /* this bsc has no audio endpoints yet */ - if (!con->_endpoint_status) - continue; - - vty_out(vty, "MGCP Status for %d%s", con->cfg->nr, VTY_NEWLINE); - max = bsc_mgcp_nr_multiplexes(con->max_endpoints); - for (i = 0; i < max; ++i) { - for (j = 1; j < 32; ++j) { - endp = mgcp_timeslot_to_endpoint(i, j); - vty_out(vty, " Endpoint 0x%x %s%s", endp, - con->_endpoint_status[endp] == 0 - ? "free" : "allocated", - VTY_NEWLINE); - } - } - break; - } - - return CMD_SUCCESS; -} - -DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config", - SHOW_STR BSC_STR "Configuration of BSCs\n") -{ - struct bsc_config *conf; - llist_for_each_entry(conf, &_nat->bsc_configs, entry) { - vty_out(vty, "BSC token: '%s' nr: %u%s", - conf->token, conf->nr, VTY_NEWLINE); - if (conf->acc_lst_name) - vty_out(vty, " access-list: %s%s", - conf->acc_lst_name, VTY_NEWLINE); - vty_out(vty, " paging forbidden: %d%s", - conf->forbid_paging, VTY_NEWLINE); - if (conf->description) - vty_out(vty, " description: %s%s", conf->description, VTY_NEWLINE); - else - vty_out(vty, " No description.%s", VTY_NEWLINE); - - } - - return CMD_SUCCESS; -} - -static void dump_stat_total(struct vty *vty, struct bsc_nat *nat) -{ - vty_out(vty, "NAT statistics%s", VTY_NEWLINE); - vty_out(vty, " SCCP Connections %lu total, %lu calls%s", - osmo_counter_get(nat->stats.sccp.conn), - osmo_counter_get(nat->stats.sccp.calls), VTY_NEWLINE); - vty_out(vty, " MSC Connections %lu%s", - osmo_counter_get(nat->stats.msc.reconn), VTY_NEWLINE); - vty_out(vty, " MSC Connected: %d%s", - bsc_nat_msc_is_connected(nat), VTY_NEWLINE); - vty_out(vty, " BSC Connections %lu total, %lu auth failed.%s", - osmo_counter_get(nat->stats.bsc.reconn), - osmo_counter_get(nat->stats.bsc.auth_fail), VTY_NEWLINE); -} - -static void dump_stat_bsc(struct vty *vty, struct bsc_config *conf) -{ - int connected = 0; - struct bsc_connection *con; - - vty_out(vty, " BSC nr: %d%s", - conf->nr, VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", conf->stats.ctrg); - - llist_for_each_entry(con, &conf->nat->bsc_connections, list_entry) { - if (con->cfg != conf) - continue; - connected = 1; - break; - } - - vty_out(vty, " Connected: %d%s", connected, VTY_NEWLINE); -} - -DEFUN(show_stats, - show_stats_cmd, - "show statistics [NR]", - SHOW_STR "Display network statistics\n" - "Number of the BSC\n") -{ - struct bsc_config *conf; - - int nr = -1; - - if (argc == 1) - nr = atoi(argv[0]); - - dump_stat_total(vty, _nat); - llist_for_each_entry(conf, &_nat->bsc_configs, entry) { - if (argc == 1 && nr != conf->nr) - continue; - dump_stat_bsc(vty, conf); - } - - return CMD_SUCCESS; -} - -DEFUN(show_stats_lac, - show_stats_lac_cmd, - "show statistics-by-lac <0-65535>", - SHOW_STR "Display network statistics by lac\n" - "The lac of the BSC\n") -{ - int lac; - struct bsc_config *conf; - - lac = atoi(argv[0]); - - dump_stat_total(vty, _nat); - llist_for_each_entry(conf, &_nat->bsc_configs, entry) { - if (!bsc_config_handles_lac(conf, lac)) - continue; - dump_stat_bsc(vty, conf); - } - - return CMD_SUCCESS; -} - -DEFUN(show_msc, - show_msc_cmd, - "show msc connection", - SHOW_STR "MSC related information\n" - "Status of the A-link connection\n") -{ - if (!_nat->msc_con) { - vty_out(vty, "The MSC is not yet configured.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "MSC is connected: %d%s", - bsc_nat_msc_is_connected(_nat), VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(close_bsc, - close_bsc_cmd, - "close bsc connection BSC_NR", - "Close\n" "A-link\n" "Connection\n" "Identifier of the BSC\n") -{ - struct bsc_connection *bsc; - int bsc_nr = atoi(argv[0]); - - llist_for_each_entry(bsc, &_nat->bsc_connections, list_entry) { - if (!bsc->cfg || bsc->cfg->nr != bsc_nr) - continue; - bsc_close_connection(bsc); - break; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configure the NAT") -{ - vty->index = _nat; - vty->node = NAT_NODE; - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_msc_ip, - cfg_nat_msc_ip_cmd, - "msc ip A.B.C.D", - "MSC related configuration\n" - "Configure the IP address\n" IP_STR) -{ - bsc_nat_set_msc_ip(_nat, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_msc_port, - cfg_nat_msc_port_cmd, - "msc port <1-65500>", - "MSC related configuration\n" - "Configure the port\n" - "Port number\n") -{ - _nat->main_dest->port = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_auth_time, - cfg_nat_auth_time_cmd, - "timeout auth <1-256>", - "Timeout configuration\n" - "Authentication timeout\n" - "Timeout in seconds\n") -{ - _nat->auth_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ping_time, - cfg_nat_ping_time_cmd, - "timeout ping NR", - "Timeout configuration\n" - "Time between two pings\n" - "Timeout in seconds\n") -{ - _nat->ping_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_pong_time, - cfg_nat_pong_time_cmd, - "timeout pong NR", - "Timeout configuration\n" - "Waiting for pong timeout\n" - "Timeout in seconds\n") -{ - _nat->pong_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_token, cfg_nat_token_cmd, - "token TOKEN", - "Authentication token configuration\n" - "Token of the BSC, currently transferred in cleartext\n") -{ - osmo_talloc_replace_string(_nat, &_nat->token, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_bsc_ip_dscp, cfg_nat_bsc_ip_dscp_cmd, - "ip-dscp <0-255>", - "Set the IP DSCP for the BSCs to use\n" "Set the IP_TOS attribute") -{ - _nat->bsc_ip_dscp = atoi(argv[0]); - return CMD_SUCCESS; -} - -ALIAS_DEPRECATED(cfg_nat_bsc_ip_dscp, cfg_nat_bsc_ip_tos_cmd, - "ip-tos <0-255>", - "Use ip-dscp in the future.\n" "Set the DSCP\n") - - -DEFUN(cfg_nat_acc_lst_name, - cfg_nat_acc_lst_name_cmd, - "access-list-name NAME", - "Set the name of the access list to use.\n" - "The name of the to be used access list.") -{ - osmo_talloc_replace_string(_nat, &_nat->acc_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_include, - cfg_nat_include_cmd, - "bscs-config-file NAME", - "Set the filename of the BSC configuration to include.\n" - "The filename to be included.") -{ - char *path; - int rc; - struct bsc_config *cf1, *cf2; - struct bsc_connection *con1, *con2; - - if ('/' == argv[0][0]) - osmo_talloc_replace_string(_nat, &_nat->resolved_path, argv[0]); - else { - path = talloc_asprintf(_nat, "%s/%s", _nat->include_base, - argv[0]); - osmo_talloc_replace_string(_nat, &_nat->resolved_path, path); - talloc_free(path); - } - - llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) { - cf1->remove = true; - cf1->token_updated = false; - } - - rc = vty_read_config_file(_nat->resolved_path, NULL); - if (rc < 0) { - vty_out(vty, "Failed to parse the config file %s: %s%s", - _nat->resolved_path, strerror(-rc), VTY_NEWLINE); - return CMD_WARNING; - } - - osmo_talloc_replace_string(_nat, &_nat->include_file, argv[0]); - - llist_for_each_entry_safe(con1, con2, &_nat->bsc_connections, - list_entry) { - if (con1->cfg) - if (con1->cfg->token_updated || con1->cfg->remove) - bsc_close_connection(con1); - } - - llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) { - if (cf1->remove) - bsc_config_free(cf1); - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_acc_lst_name, - cfg_nat_no_acc_lst_name_cmd, - "no access-list-name", - NO_STR "Remove the access list from the NAT.\n") -{ - if (_nat->acc_lst_name) { - talloc_free(_nat->acc_lst_name); - _nat->acc_lst_name = NULL; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_imsi_black_list_fn, - cfg_nat_imsi_black_list_fn_cmd, - "imsi-black-list-file-name NAME", - "IMSI black listing\n" "Filename IMSI and reject-cause\n") -{ - - osmo_talloc_replace_string(_nat, &_nat->imsi_black_list_fn, argv[0]); - if (_nat->imsi_black_list_fn) { - int rc; - struct osmo_config_list *rewr = NULL; - rewr = osmo_config_list_parse(_nat, _nat->imsi_black_list_fn); - rc = bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, rewr); - if (rc != 0) { - vty_out(vty, "%%There was an error parsing the list." - " Please see the error log.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; - } - - bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_imsi_black_list_fn, - cfg_nat_no_imsi_black_list_fn_cmd, - "no imsi-black-list-file-name", - NO_STR "Remove the imsi-black-list\n") -{ - talloc_free(_nat->imsi_black_list_fn); - _nat->imsi_black_list_fn = NULL; - bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL); - return CMD_SUCCESS; -} - -static int replace_rules(struct bsc_nat *nat, char **name, - struct llist_head *head, const char *file) -{ - struct osmo_config_list *rewr = NULL; - - osmo_talloc_replace_string(nat, name, file); - if (*name) { - rewr = osmo_config_list_parse(nat, *name); - bsc_nat_num_rewr_entry_adapt(nat, head, rewr); - talloc_free(rewr); - return CMD_SUCCESS; - } else { - bsc_nat_num_rewr_entry_adapt(nat, head, NULL); - return CMD_SUCCESS; - } -} - -DEFUN(cfg_nat_number_rewrite, - cfg_nat_number_rewrite_cmd, - "number-rewrite FILENAME", - "Set the file with rewriting rules.\n" "Filename") -{ - return replace_rules(_nat, &_nat->num_rewr_name, - &_nat->num_rewr, argv[0]); -} - -DEFUN(cfg_nat_no_number_rewrite, - cfg_nat_no_number_rewrite_cmd, - "no number-rewrite", - NO_STR "Set the file with rewriting rules.\n") -{ - talloc_free(_nat->num_rewr_name); - _nat->num_rewr_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_number_rewrite_post, - cfg_nat_number_rewrite_post_cmd, - "number-rewrite-post FILENAME", - "Set the file with post-routing rewriting rules.\n" "Filename") -{ - return replace_rules(_nat, &_nat->num_rewr_post_name, - &_nat->num_rewr_post, argv[0]); -} - -DEFUN(cfg_nat_no_number_rewrite_post, - cfg_nat_no_number_rewrite_post_cmd, - "no number-rewrite-post", - NO_STR "Set the file with post-routing rewriting rules.\n") -{ - talloc_free(_nat->num_rewr_post_name); - _nat->num_rewr_post_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr_post, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_smsc_addr, - cfg_nat_smsc_addr_cmd, - "rewrite-smsc addr FILENAME", - SMSC_REWRITE - "The SMSC Address to match and replace in RP-DATA\n" - "File with rules for the SMSC Address replacing\n") -{ - return replace_rules(_nat, &_nat->smsc_rewr_name, - &_nat->smsc_rewr, argv[0]); -} - -DEFUN(cfg_nat_smsc_tpdest, - cfg_nat_smsc_tpdest_cmd, - "rewrite-smsc tp-dest-match FILENAME", - SMSC_REWRITE - "Match TP-Destination of a SMS.\n" - "File with rules for matching MSISDN and TP-DEST\n") -{ - return replace_rules(_nat, &_nat->tpdest_match_name, - &_nat->tpdest_match, argv[0]); -} - -DEFUN(cfg_nat_sms_clear_tpsrr, - cfg_nat_sms_clear_tpsrr_cmd, - "sms-clear-tp-srr FILENAME", - "SMS TPDU Sender Report Request clearing\n" - "Files with rules for matching MSISDN\n") -{ - return replace_rules(_nat, &_nat->sms_clear_tp_srr_name, - &_nat->sms_clear_tp_srr, argv[0]); -} - -DEFUN(cfg_nat_no_sms_clear_tpsrr, - cfg_nat_no_sms_clear_tpsrr_cmd, - "no sms-clear-tp-srr", - NO_STR - "SMS TPDU Sender Report Request clearing\n") -{ - talloc_free(_nat->sms_clear_tp_srr_name); - _nat->sms_clear_tp_srr_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->sms_clear_tp_srr, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_sms_number_rewrite, - cfg_nat_sms_number_rewrite_cmd, - "sms-number-rewrite FILENAME", - "SMS TP-DA Number rewriting\n" - "Files with rules for matching MSISDN\n") -{ - return replace_rules(_nat, &_nat->sms_num_rewr_name, - &_nat->sms_num_rewr, argv[0]); -} - -DEFUN(cfg_nat_no_sms_number_rewrite, - cfg_nat_no_sms_number_rewrite_cmd, - "no sms-number-rewrite", - NO_STR "Disable SMS TP-DA rewriting\n") -{ - talloc_free(_nat->sms_num_rewr_name); - _nat->sms_num_rewr_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->sms_num_rewr, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_prefix_trie, - cfg_nat_prefix_trie_cmd, - "prefix-tree FILENAME", - "Prefix tree for number rewriting\n" "File to load\n") -{ - /* give up the old data */ - talloc_free(_nat->num_rewr_trie); - _nat->num_rewr_trie = NULL; - - /* replace the file name */ - osmo_talloc_replace_string(_nat, &_nat->num_rewr_trie_name, argv[0]); - if (!_nat->num_rewr_trie_name) { - vty_out(vty, "%% prefix-tree no filename is present.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - _nat->num_rewr_trie = nat_rewrite_parse(_nat, _nat->num_rewr_trie_name); - if (!_nat->num_rewr_trie) { - vty_out(vty, "%% prefix-tree parsing has failed.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "%% prefix-tree loaded %zu rules.%s", - _nat->num_rewr_trie->prefixes, VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_prefix_trie, cfg_nat_no_prefix_trie_cmd, - "no prefix-tree", - NO_STR "Prefix tree for number rewriting\n") -{ - talloc_free(_nat->num_rewr_trie); - _nat->num_rewr_trie = NULL; - talloc_free(_nat->num_rewr_trie_name); - _nat->num_rewr_trie_name = NULL; - - return CMD_SUCCESS; -} - -DEFUN(show_prefix_tree, show_prefix_tree_cmd, - "show prefix-tree", - SHOW_STR "Prefix tree for number rewriting\n") -{ - if (!_nat->num_rewr_trie) { - vty_out(vty, "%% there is now prefix tree loaded.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - nat_rewrite_dump_vty(vty, _nat->num_rewr_trie); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_lst_name, - cfg_nat_ussd_lst_name_cmd, - "ussd-list-name NAME", - "Set the name of the access list to check for IMSIs for USSD message\n" - "The name of the access list for HLR USSD handling") -{ - osmo_talloc_replace_string(_nat, &_nat->ussd_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_query, - cfg_nat_ussd_query_cmd, - "ussd-query REGEXP", - "Set the USSD query to match with the ussd-list-name\n" - "The query to match") -{ - if (gsm_parse_reg(_nat, &_nat->ussd_query_re, &_nat->ussd_query, argc, argv) != 0) - return CMD_WARNING; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_token, - cfg_nat_ussd_token_cmd, - "ussd-token TOKEN", - "Set the token used to identify the USSD module\n" "Secret key\n") -{ - osmo_talloc_replace_string(_nat, &_nat->ussd_token, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_local, - cfg_nat_ussd_local_cmd, - "ussd-local-ip A.B.C.D", - "Set the IP to listen for the USSD Provider\n" "IP Address\n") -{ - osmo_talloc_replace_string(_nat, &_nat->ussd_local, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_use_ipa_for_mgcp, - cfg_nat_use_ipa_for_mgcp_cmd, - "use-msc-ipa-for-mgcp", - "This needs to be set at start. Handle MGCP messages through " - "the IPA protocol and not through the UDP socket.\n") -{ - if (_nat->mgcp_cfg->data) - vty_out(vty, - "%%the setting will not be applied right now.%s", - VTY_NEWLINE); - _nat->mgcp_ipa = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_sdp_amr_mode_set, - cfg_nat_sdp_amr_mode_set_cmd, - "sdp-ensure-amr-mode-set", - "Ensure that SDP records include a mode-set\n") -{ - _nat->sdp_ensure_amr_mode_set = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_sdp_amr_mode_set, - cfg_nat_no_sdp_amr_mode_set_cmd, - "no sdp-ensure-amr-mode-set", - NO_STR "Ensure that SDP records include a mode-set\n") -{ - _nat->sdp_ensure_amr_mode_set = 0; - return CMD_SUCCESS; -} - -/* per BSC configuration */ -DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", - "BSC configuration\n" "Identifier of the BSC\n") -{ - int bsc_nr = atoi(argv[0]); - struct bsc_config *bsc = bsc_config_num(_nat, bsc_nr); - - /* allocate a new one */ - if (!bsc) - bsc = bsc_config_alloc(_nat, "unknown", bsc_nr); - - if (!bsc) - return CMD_WARNING; - - bsc->remove = false; - vty->index = bsc; - vty->node = NAT_BSC_NODE; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_token, cfg_bsc_token_cmd, "token TOKEN", - "Authentication token configuration\n" - "Token of the BSC, currently transferred in cleartext\n") -{ - struct bsc_config *conf = vty->index; - - if (strncmp(conf->token, argv[0], 128) != 0) - conf->token_updated = true; - - osmo_talloc_replace_string(conf, &conf->token, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_auth_key, cfg_bsc_auth_key_cmd, - "auth-key KEY", - "Authentication (secret) key configuration\n" - "Non null security key\n") -{ - struct bsc_config *conf = vty->index; - - memset(conf->key, 0, sizeof(conf->key)); - osmo_hexparse(argv[0], conf->key, sizeof(conf->key)); - conf->key_present = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_auth_key, cfg_bsc_no_auth_key_cmd, - "no auth-key", - NO_STR "Authentication (secret) key configuration\n") -{ - struct bsc_config *conf = vty->index; - - memset(conf->key, 0, sizeof(conf->key)); - conf->key_present = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>", - "Add the Location Area Code (LAC) of this BSC\n" "LAC\n") -{ - struct bsc_config *tmp; - struct bsc_config *conf = vty->index; - - int lac = atoi(argv[0]); - - if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) { - vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s", - lac, VTY_NEWLINE); - return CMD_WARNING; - } - - /* verify that the LACs are unique */ - llist_for_each_entry(tmp, &_nat->bsc_configs, entry) { - if (bsc_config_handles_lac(tmp, lac)) { - if (tmp->nr != conf->nr) { - vty_out(vty, "%% LAC %d is already used.%s", lac, - VTY_NEWLINE); - return CMD_ERR_INCOMPLETE; - } - } - } - - bsc_config_add_lac(conf, lac); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_lac, cfg_bsc_no_lac_cmd, - "no location_area_code <0-65535>", - NO_STR "Remove the Location Area Code (LAC) of this BSC\n" "LAC\n") -{ - int lac = atoi(argv[0]); - struct bsc_config *conf = vty->index; - - bsc_config_del_lac(conf, lac); - return CMD_SUCCESS; -} - -DEFUN(show_bar_lst, - show_bar_lst_cmd, - "show imsi-black-list", - SHOW_STR "IMSIs barred from the network\n") -{ - struct rb_node *node; - - vty_out(vty, "IMSIs barred from the network:%s", VTY_NEWLINE); - - for (node = rb_first(&_nat->imsi_black_list); node; node = rb_next(node)) { - struct bsc_filter_barr_entry *entry; - entry = rb_entry(node, struct bsc_filter_barr_entry, node); - - vty_out(vty, " IMSI(%s) CM-Reject-Cause(%d) LU-Reject-Cause(%d)%s", - entry->imsi, entry->cm_reject_cause, entry->lu_reject_cause, - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - - -DEFUN(cfg_bsc_acc_lst_name, - cfg_bsc_acc_lst_name_cmd, - "access-list-name NAME", - "Set the name of the access list to use.\n" - "The name of the to be used access list.") -{ - struct bsc_config *conf = vty->index; - - osmo_talloc_replace_string(conf, &conf->acc_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_acc_lst_name, - cfg_bsc_no_acc_lst_name_cmd, - "no access-list-name", - NO_STR "Do not use an access-list for the BSC.\n") -{ - struct bsc_config *conf = vty->index; - - if (conf->acc_lst_name) { - talloc_free(conf->acc_lst_name); - conf->acc_lst_name = NULL; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_max_endps, cfg_bsc_max_endps_cmd, - "max-endpoints <1-1024>", - "Highest endpoint to use (exclusively)\n" "Number of ports\n") -{ - struct bsc_config *conf = vty->index; - - conf->max_endpoints = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_paging, - cfg_bsc_paging_cmd, - "paging forbidden (0|1)", - PAGING_STR "Forbid sending PAGING REQUESTS to the BSC.\n" - "Do not forbid\n" "Forbid\n") -{ - struct bsc_config *conf = vty->index; - - if (strcmp("1", argv[0]) == 0) - conf->forbid_paging = 1; - else - conf->forbid_paging = 0; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_desc, - cfg_bsc_desc_cmd, - "description DESC", - "Provide a description for the given BSC.\n" "Description\n") -{ - struct bsc_config *conf = vty->index; - - osmo_talloc_replace_string(conf, &conf->description, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_paging_grp, - cfg_bsc_paging_grp_cmd, - "paging group <0-1000>", - PAGING_STR "Use a paging group\n" "Paging Group to use\n") -{ - struct bsc_config *conf = vty->index; - conf->paging_group = atoi(argv[0]); - return CMD_SUCCESS; -} - -ALIAS_DEPRECATED(cfg_bsc_paging_grp, cfg_bsc_old_grp_cmd, - "paging-group <0-1000>", - "Use a paging group\n" "Paging Group to use\n") - -DEFUN(cfg_bsc_no_paging_grp, - cfg_bsc_no_paging_grp_cmd, - "no paging group", - NO_STR PAGING_STR "Disable the usage of a paging group.\n") -{ - struct bsc_config *conf = vty->index; - conf->paging_group = PAGIN_GROUP_UNASSIGNED; - return CMD_SUCCESS; -} - -DEFUN(test_regex, test_regex_cmd, - "test regex PATTERN STRING", - "Test utilities\n" - "Regexp testing\n" "The regexp pattern\n" - "The string to match\n") -{ - regex_t reg; - char *str = NULL; - - memset(®, 0, sizeof(reg)); - if (gsm_parse_reg(_nat, ®, &str, 1, argv) != 0) - return CMD_WARNING; - - vty_out(vty, "String matches allow pattern: %d%s", - regexec(®, argv[1], 0, NULL, 0) == 0, VTY_NEWLINE); - - talloc_free(str); - regfree(®); - return CMD_SUCCESS; -} - -DEFUN(set_last_endp, set_last_endp_cmd, - "set bsc last-used-endpoint <0-9999999999> <0-1024>", - "Set a value\n" "Operate on a BSC\n" - "Last used endpoint for an assignment\n" "BSC configuration number\n" - "Endpoint number used\n") -{ - struct bsc_connection *con; - int nr = atoi(argv[0]); - int endp = atoi(argv[1]); - - - llist_for_each_entry(con, &_nat->bsc_connections, list_entry) { - if (!con->cfg) - continue; - if (con->cfg->nr != nr) - continue; - - con->last_endpoint = endp; - vty_out(vty, "Updated the last endpoint for %d to %d.%s", - con->cfg->nr, con->last_endpoint, VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(block_new_conn, block_new_conn_cmd, - "nat-block (block|unblock)", - "Block the NAT for new connections\n" - "Block\n" "Unblock\n") -{ - _nat->blocked = argv[0][0] == 'b'; - vty_out(vty, "%%Going to %s the NAT.%s", - _nat->blocked ? "block" : "unblock", VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* paging group */ -DEFUN(cfg_nat_pgroup, cfg_nat_pgroup_cmd, - "paging-group <0-1000>", - "Create a Paging Group\n" "Number of the Group\n") -{ - int group = atoi(argv[0]); - struct bsc_nat_paging_group *pgroup; - pgroup = bsc_nat_paging_group_num(_nat, group); - if (!pgroup) - pgroup = bsc_nat_paging_group_create(_nat, group); - if (!pgroup) { - vty_out(vty, "Failed to create the group.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty->index = pgroup; - vty->node = PGROUP_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_pgroup, cfg_nat_no_pgroup_cmd, - "no paging-group <0-1000>", - NO_STR "Delete paging-group\n" "Paging-group number\n") -{ - int group = atoi(argv[0]); - struct bsc_nat_paging_group *pgroup; - pgroup = bsc_nat_paging_group_num(_nat, group); - if (!pgroup) { - vty_out(vty, "No such paging group %d.%s", group, VTY_NEWLINE); - return CMD_WARNING; - } - - bsc_nat_paging_group_delete(pgroup); - return CMD_SUCCESS; -} - -DEFUN(cfg_pgroup_lac, cfg_pgroup_lac_cmd, - "location_area_code <0-65535>", - "Add the Location Area Code (LAC)\n" "LAC\n") -{ - struct bsc_nat_paging_group *pgroup = vty->index; - - int lac = atoi(argv[0]); - if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) { - vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s", - lac, VTY_NEWLINE); - return CMD_WARNING; - } - - bsc_nat_paging_group_add_lac(pgroup, lac); - return CMD_SUCCESS; -} - -DEFUN(cfg_pgroup_no_lac, cfg_pgroup_no_lac_cmd, - "no location_area_code <0-65535>", - NO_STR "Remove the Location Area Code (LAC)\n" "LAC\n") -{ - int lac = atoi(argv[0]); - struct bsc_nat_paging_group *pgroup = vty->index; - - bsc_nat_paging_group_del_lac(pgroup, lac); - return CMD_SUCCESS; -} - -DEFUN(show_ussd_connection, - show_ussd_connection_cmd, - "show ussd-connection", - SHOW_STR "USSD connection related information\n") -{ - vty_out(vty, "The USSD side channel provider is %sconnected and %sauthorized.%s", - _nat->ussd_con ? "" : "not ", - _nat->ussd_con && _nat->ussd_con->authorized? "" : "not ", - VTY_NEWLINE); - return CMD_SUCCESS; -} - -#define OSMUX_STR "RTP multiplexing\n" -DEFUN(cfg_bsc_osmux, - cfg_bsc_osmux_cmd, - "osmux (on|off|only)", - OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only OSMUX\n") -{ - struct bsc_config *conf = vty->index; - int old = conf->osmux; - - if (strcmp(argv[0], "on") == 0) - conf->osmux = OSMUX_USAGE_ON; - else if (strcmp(argv[0], "off") == 0) - conf->osmux = OSMUX_USAGE_OFF; - else if (strcmp(argv[0], "only") == 0) - conf->osmux = OSMUX_USAGE_ONLY; - - if (old == 0 && conf->osmux > 0 && !conf->nat->mgcp_cfg->osmux_init) { - LOGP(DLMGCP, LOGL_NOTICE, "Setting up OSMUX socket\n"); - if (osmux_init(OSMUX_ROLE_BSC_NAT, conf->nat->mgcp_cfg) < 0) { - LOGP(DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n"); - vty_out(vty, "%% failed to create Osmux socket%s", - VTY_NEWLINE); - return CMD_WARNING; - } - } else if (old > 0 && conf->osmux == 0) { - LOGP(DLMGCP, LOGL_NOTICE, "Disabling OSMUX socket\n"); - /* Don't stop the socket, we may already have ongoing voice - * flows already using Osmux. This just switch indicates that - * new upcoming flows should use RTP. - */ - } - - return CMD_SUCCESS; -} - -int bsc_nat_vty_init(struct bsc_nat *nat) -{ - _nat = nat; - - /* show commands */ - install_element_ve(&show_sccp_cmd); - install_element_ve(&show_bsc_cmd); - install_element_ve(&show_nat_bsc_cmd); - install_element_ve(&show_bsc_cfg_cmd); - install_element_ve(&show_stats_cmd); - install_element_ve(&show_stats_lac_cmd); - install_element_ve(&close_bsc_cmd); - install_element_ve(&show_msc_cmd); - install_element_ve(&test_regex_cmd); - install_element_ve(&show_bsc_mgcp_cmd); - install_element_ve(&show_bscs_cmd); - install_element_ve(&show_bar_lst_cmd); - install_element_ve(&show_prefix_tree_cmd); - install_element_ve(&show_ussd_connection_cmd); - - install_element(ENABLE_NODE, &set_last_endp_cmd); - install_element(ENABLE_NODE, &block_new_conn_cmd); - - /* nat group */ - install_element(CONFIG_NODE, &cfg_nat_cmd); - install_node(&nat_node, config_write_nat); - vty_install_default(NAT_NODE); - install_element(NAT_NODE, &cfg_nat_msc_ip_cmd); - install_element(NAT_NODE, &cfg_nat_msc_port_cmd); - install_element(NAT_NODE, &cfg_nat_auth_time_cmd); - install_element(NAT_NODE, &cfg_nat_ping_time_cmd); - install_element(NAT_NODE, &cfg_nat_pong_time_cmd); - install_element(NAT_NODE, &cfg_nat_token_cmd); - install_element(NAT_NODE, &cfg_nat_bsc_ip_dscp_cmd); - install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd); - install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd); - install_element(NAT_NODE, &cfg_nat_no_acc_lst_name_cmd); - install_element(NAT_NODE, &cfg_nat_include_cmd); - install_element(NAT_NODE, &cfg_nat_imsi_black_list_fn_cmd); - install_element(NAT_NODE, &cfg_nat_no_imsi_black_list_fn_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_query_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_token_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_local_cmd); - install_element(NAT_NODE, &cfg_nat_use_ipa_for_mgcp_cmd); - - bsc_msg_lst_vty_init(nat, &nat->access_lists, NAT_NODE); - - /* number rewriting */ - install_element(NAT_NODE, &cfg_nat_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_no_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_number_rewrite_post_cmd); - install_element(NAT_NODE, &cfg_nat_no_number_rewrite_post_cmd); - install_element(NAT_NODE, &cfg_nat_smsc_addr_cmd); - install_element(NAT_NODE, &cfg_nat_smsc_tpdest_cmd); - install_element(NAT_NODE, &cfg_nat_sms_clear_tpsrr_cmd); - install_element(NAT_NODE, &cfg_nat_no_sms_clear_tpsrr_cmd); - install_element(NAT_NODE, &cfg_nat_sms_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_no_sms_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_prefix_trie_cmd); - install_element(NAT_NODE, &cfg_nat_no_prefix_trie_cmd); - - install_element(NAT_NODE, &cfg_nat_sdp_amr_mode_set_cmd); - install_element(NAT_NODE, &cfg_nat_no_sdp_amr_mode_set_cmd); - - install_element(NAT_NODE, &cfg_nat_pgroup_cmd); - install_element(NAT_NODE, &cfg_nat_no_pgroup_cmd); - install_node(&pgroup_node, config_write_pgroup); - vty_install_default(PGROUP_NODE); - install_element(PGROUP_NODE, &cfg_pgroup_lac_cmd); - install_element(PGROUP_NODE, &cfg_pgroup_no_lac_cmd); - - /* BSC subgroups */ - install_element(NAT_NODE, &cfg_bsc_cmd); - install_node(&bsc_node, NULL); - vty_install_default(NAT_BSC_NODE); - install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_auth_key_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_auth_key_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_lac_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_lac_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_paging_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_desc_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_acc_lst_name_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_acc_lst_name_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_max_endps_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_old_grp_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_paging_grp_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_paging_grp_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_osmux_cmd); - - mgcp_vty_init(); - - return 0; -} - - -/* called by the telnet interface... we have our own init above */ -int bsc_vty_init(struct gsm_network *network) -{ - logging_vty_add_cmds(NULL); - return 0; -} diff --git a/src/osmo-bsc_nat/bsc_sccp.c b/src/osmo-bsc_nat/bsc_sccp.c deleted file mode 100644 index c6c265f7a..000000000 --- a/src/osmo-bsc_nat/bsc_sccp.c +++ /dev/null @@ -1,247 +0,0 @@ -/* SCCP patching and handling routines */ -/* - * (C) 2010 by Holger Hans Peter Freyther - * (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 . - * - */ - -#include -#include -#include - -#include - -#include - -#include -#include - -static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2) -{ - return memcmp(ref1, ref2, sizeof(*ref1)) == 0; -} - -/* - * SCCP patching below - */ - -/* check if we are using this ref for patched already */ -static int sccp_ref_is_free(struct sccp_source_reference *ref, struct bsc_nat *nat) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &nat->sccp_connections, list_entry) { - if (equal(ref, &conn->patched_ref)) - return -1; - } - - return 0; -} - -/* copied from sccp.c */ -static int assign_src_local_reference(struct sccp_source_reference *ref, struct bsc_nat *nat) -{ - static uint32_t last_ref = 0x50000; - int wrapped = 0; - - do { - struct sccp_source_reference reference; - reference.octet1 = (last_ref >> 0) & 0xff; - reference.octet2 = (last_ref >> 8) & 0xff; - reference.octet3 = (last_ref >> 16) & 0xff; - - ++last_ref; - /* do not use the reversed word and wrap around */ - if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) { - LOGP(DNAT, LOGL_NOTICE, "Wrapped searching for a free code\n"); - last_ref = 0; - ++wrapped; - } - - if (sccp_ref_is_free(&reference, nat) == 0) { - *ref = reference; - return 0; - } - } while (wrapped != 2); - - LOGP(DNAT, LOGL_ERROR, "Finding a free reference failed\n"); - return -1; -} - -struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc, - struct bsc_nat_parsed *parsed) -{ - struct nat_sccp_connection *conn; - - /* Some commercial BSCs like to reassign there SRC ref */ - llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) { - if (conn->bsc != bsc) - continue; - if (!equal(parsed->src_local_ref, &conn->real_ref)) - continue; - - /* the BSC has reassigned the SRC ref and we failed to keep track */ - memset(&conn->remote_ref, 0, sizeof(conn->remote_ref)); - if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) { - LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n", - bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref)); - bsc_mgcp_dlcx(conn); - llist_del(&conn->list_entry); - talloc_free(conn); - return NULL; - } else { - clock_gettime(CLOCK_MONOTONIC, &conn->creation_time); - bsc_mgcp_dlcx(conn); - return conn; - } - } - - - conn = talloc_zero(bsc->nat, struct nat_sccp_connection); - if (!conn) { - LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n"); - return NULL; - } - - conn->bsc = bsc; - clock_gettime(CLOCK_MONOTONIC, &conn->creation_time); - conn->real_ref = *parsed->src_local_ref; - if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n"); - talloc_free(conn); - return NULL; - } - - bsc_mgcp_init(conn); - llist_add_tail(&conn->list_entry, &bsc->nat->sccp_connections); - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_SCCP_CONN]); - osmo_counter_inc(bsc->cfg->nat->stats.sccp.conn); - - LOGP(DNAT, LOGL_DEBUG, "Created 0x%x <-> 0x%x mapping for con %p\n", - sccp_src_ref_to_int(&conn->real_ref), - sccp_src_ref_to_int(&conn->patched_ref), bsc); - - return conn; -} - -int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed) -{ - if (!parsed->dest_local_ref || !parsed->src_local_ref) { - LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n"); - return -1; - } - - sccp->remote_ref = *parsed->src_local_ref; - sccp->has_remote_ref = 1; - LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n", - sccp_src_ref_to_int(&sccp->patched_ref), - sccp_src_ref_to_int(&sccp->remote_ref), sccp->bsc); - - return 0; -} - -void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) { - if (equal(parsed->src_local_ref, &conn->patched_ref)) { - sccp_connection_destroy(conn); - return; - } - } - - LOGP(DNAT, LOGL_ERROR, "Can not remove connection: 0x%x\n", - sccp_src_ref_to_int(parsed->src_local_ref)); -} - -/* - * We have a message from the MSC to the BSC. The MSC is using - * an address that was assigned by the MUX, we need to update the - * dest reference to the real network. - */ -struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg, - struct bsc_nat_parsed *parsed, - struct bsc_nat *nat) -{ - struct nat_sccp_connection *conn; - - if (!parsed->dest_local_ref) { - LOGP(DNAT, LOGL_ERROR, "MSG should contain dest_local_ref.\n"); - return NULL; - } - - - llist_for_each_entry(conn, &nat->sccp_connections, list_entry) { - if (!equal(parsed->dest_local_ref, &conn->patched_ref)) - continue; - - /* Change the dest address to the real one */ - *parsed->dest_local_ref = conn->real_ref; - return conn; - } - - return NULL; -} - -/* - * These are message to the MSC. We will need to find the BSC - * Connection by either the SRC or the DST local reference. - * - * In case of a CR we need to work by the SRC local reference - * in all other cases we need to work by the destination local - * reference.. - */ -struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *msg, - struct bsc_nat_parsed *parsed, - struct bsc_connection *bsc) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) { - if (conn->bsc != bsc) - continue; - - if (parsed->src_local_ref) { - if (equal(parsed->src_local_ref, &conn->real_ref)) { - *parsed->src_local_ref = conn->patched_ref; - return conn; - } - } else if (parsed->dest_local_ref) { - if (equal(parsed->dest_local_ref, &conn->remote_ref)) - return conn; - } else { - LOGP(DNAT, LOGL_ERROR, "Header has neither loc/dst ref.\n"); - return NULL; - } - } - - return NULL; -} - -struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *nat, - struct sccp_source_reference *ref) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &nat->sccp_connections, list_entry) { - if (equal(ref, &conn->real_ref)) - return conn; - } - - return NULL; -} diff --git a/src/osmo-bsc_nat/bsc_ussd.c b/src/osmo-bsc_nat/bsc_ussd.c deleted file mode 100644 index 9769bbd39..000000000 --- a/src/osmo-bsc_nat/bsc_ussd.c +++ /dev/null @@ -1,454 +0,0 @@ -/* USSD Filter Code */ - -/* - * (C) 2010-2011 by Holger Hans Peter Freyther - * (C) 2010-2011 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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#define USSD_LAC_IE 0 -#define USSD_CI_IE 1 - -static void ussd_auth_con(struct tlv_parsed *, struct bsc_nat_ussd_con *); - -static struct bsc_nat_ussd_con *bsc_nat_ussd_alloc(struct bsc_nat *nat) -{ - struct bsc_nat_ussd_con *con; - - con = talloc_zero(nat, struct bsc_nat_ussd_con); - if (!con) - return NULL; - - con->nat = nat; - return con; -} - -static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con) -{ - if (con->nat->ussd_con == con) { - bsc_ussd_close_connections(con->nat); - con->nat->ussd_con = NULL; - } - - close(con->queue.bfd.fd); - osmo_fd_unregister(&con->queue.bfd); - osmo_timer_del(&con->auth_timeout); - osmo_wqueue_clear(&con->queue); - - msgb_free(con->pending_msg); - talloc_free(con); -} - -static void ussd_pong(struct bsc_nat_ussd_con *conn) -{ - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "pong message"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate pong msg\n"); - return; - } - - msgb_v_put(msg, IPAC_MSGT_PONG); - bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS); -} - -static int forward_sccp(struct bsc_nat *nat, struct msgb *msg) -{ - struct nat_sccp_connection *con; - struct bsc_nat_parsed *parsed; - - - parsed = bsc_nat_parse(msg); - if (!parsed) { - LOGP(DNAT, LOGL_ERROR, "Can not parse msg from USSD.\n"); - msgb_free(msg); - return -1; - } - - if (!parsed->dest_local_ref) { - LOGP(DNAT, LOGL_ERROR, "No destination local reference.\n"); - msgb_free(msg); - return -1; - } - - con = bsc_nat_find_con_by_bsc(nat, parsed->dest_local_ref); - if (!con || !con->bsc) { - LOGP(DNAT, LOGL_ERROR, "No active connection found.\n"); - msgb_free(msg); - return -1; - } - - talloc_free(parsed); - bsc_write_msg(&con->bsc->write_queue, msg); - return 0; -} - -static int ussd_read_cb(struct osmo_fd *bfd) -{ - struct bsc_nat_ussd_con *conn = bfd->data; - struct msgb *msg = NULL; - struct ipaccess_head *hh; - int ret; - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &conn->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); - bsc_nat_ussd_destroy(conn); - return -1; - } - - LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n", - osmo_hexdump(msg->data, msg->len), msg->l2h[0]); - hh = (struct ipaccess_head *) msg->data; - - if (hh->proto == IPAC_PROTO_IPACCESS) { - if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { - struct tlv_parsed tvp; - int ret; - ret = ipa_ccm_idtag_parse(&tvp, - (unsigned char *) msg->l2h + 2, - msgb_l2len(msg) - 2); - if (ret < 0) { - LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " - "message with malformed TLVs\n"); - msgb_free(msg); - return ret; - } - if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) - ussd_auth_con(&tvp, conn); - } else if (msg->l2h[0] == IPAC_MSGT_PING) { - LOGP(DNAT, LOGL_DEBUG, "Got USSD ping request.\n"); - ussd_pong(conn); - } else { - LOGP(DNAT, LOGL_NOTICE, "Got unknown IPACCESS message 0x%02x.\n", msg->l2h[0]); - } - - msgb_free(msg); - } else if (hh->proto == IPAC_PROTO_SCCP) { - forward_sccp(conn->nat, msg); - } else { - msgb_free(msg); - } - - return 0; -} - -static void ussd_auth_cb(void *_data) -{ - LOGP(DNAT, LOGL_ERROR, "USSD module didn't authenticate\n"); - bsc_nat_ussd_destroy((struct bsc_nat_ussd_con *) _data); -} - -static void ussd_auth_con(struct tlv_parsed *tvp, struct bsc_nat_ussd_con *conn) -{ - const char *token; - int len; - if (!conn->nat->ussd_token) { - LOGP(DNAT, LOGL_ERROR, "No USSD token set. Closing\n"); - bsc_nat_ussd_destroy(conn); - return; - } - - token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME); - len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); - - /* last byte should be a NULL */ - if (strlen(conn->nat->ussd_token) != len - 1) - goto disconnect; - /* compare everything including the null byte */ - if (memcmp(conn->nat->ussd_token, token, len) != 0) - goto disconnect; - - /* it is authenticated now */ - if (conn->nat->ussd_con && conn->nat->ussd_con != conn) - bsc_nat_ussd_destroy(conn->nat->ussd_con); - - LOGP(DNAT, LOGL_ERROR, "USSD token specified. USSD provider is connected.\n"); - osmo_timer_del(&conn->auth_timeout); - conn->authorized = 1; - conn->nat->ussd_con = conn; - return; - -disconnect: - LOGP(DNAT, LOGL_ERROR, "Wrong USSD token by client: %d\n", - conn->queue.bfd.fd); - bsc_nat_ussd_destroy(conn); -} - -static void ussd_start_auth(struct bsc_nat_ussd_con *conn) -{ - struct msgb *msg; - - osmo_timer_setup(&conn->auth_timeout, ussd_auth_cb, conn); - osmo_timer_schedule(&conn->auth_timeout, conn->nat->auth_timeout, 0); - - msg = msgb_alloc_headroom(4096, 128, "auth message"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate auth msg\n"); - return; - } - - msgb_v_put(msg, IPAC_MSGT_ID_GET); - bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS); -} - -static int ussd_listen_cb(struct osmo_fd *bfd, unsigned int what) -{ - struct bsc_nat_ussd_con *conn; - struct bsc_nat *nat; - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - int fd; - - if (!(what & BSC_FD_READ)) - return 0; - - fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len); - if (fd < 0) { - perror("accept"); - return fd; - } - - nat = (struct bsc_nat *) bfd->data; - osmo_counter_inc(nat->stats.ussd.reconn); - - conn = bsc_nat_ussd_alloc(nat); - if (!conn) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate USSD con struct.\n"); - close(fd); - return -1; - } - - osmo_wqueue_init(&conn->queue, 10); - conn->queue.bfd.data = conn; - conn->queue.bfd.fd = fd; - conn->queue.bfd.when = BSC_FD_READ; - conn->queue.read_cb = ussd_read_cb; - conn->queue.write_cb = bsc_write_cb; - - if (osmo_fd_register(&conn->queue.bfd) < 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to register USSD fd.\n"); - bsc_nat_ussd_destroy(conn); - return -1; - } - - LOGP(DNAT, LOGL_NOTICE, "USSD Connection on %d with IP: %s\n", - fd, inet_ntoa(sa.sin_addr)); - - /* do authentication */ - ussd_start_auth(conn); - return 0; -} - -int bsc_ussd_init(struct bsc_nat *nat) -{ - struct in_addr addr; - - addr.s_addr = INADDR_ANY; - if (nat->ussd_local) - inet_aton(nat->ussd_local, &addr); - - nat->ussd_listen.data = nat; - return make_sock(&nat->ussd_listen, IPPROTO_TCP, - ntohl(addr.s_addr), 5001, 0, ussd_listen_cb, nat); -} - -static int forward_ussd_simple(struct nat_sccp_connection *con, struct msgb *input) -{ - struct msgb *copy; - struct bsc_nat_ussd_con *ussd; - - if (!con->bsc->nat->ussd_con) - return -1; - - copy = msgb_alloc_headroom(4096, 128, "forward bts"); - if (!copy) { - LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); - return -1; - } - - /* copy the data into the copy */ - copy->l2h = msgb_put(copy, msgb_l2len(input)); - memcpy(copy->l2h, input->l2h, msgb_l2len(input)); - - /* send it out */ - ussd = con->bsc->nat->ussd_con; - bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP); - return 0; -} - -static int forward_ussd(struct nat_sccp_connection *con, const struct ussd_request *req, - struct msgb *input) -{ - struct msgb *msg, *copy; - struct ipac_msgt_sccp_state *state; - struct bsc_nat_ussd_con *ussd; - uint16_t lac, ci; - - if (!con->bsc->nat->ussd_con) - return -1; - - msg = msgb_alloc_headroom(4096, 128, "forward ussd"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); - return -1; - } - - copy = msgb_alloc_headroom(4096, 128, "forward bts"); - if (!copy) { - LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); - msgb_free(msg); - return -1; - } - - copy->l2h = msgb_put(copy, msgb_l2len(input)); - memcpy(copy->l2h, input->l2h, msgb_l2len(input)); - - msg->l2h = msgb_put(msg, 1); - msg->l2h[0] = IPAC_MSGT_SCCP_OLD; - - /* fill out the data */ - state = (struct ipac_msgt_sccp_state *) msgb_put(msg, sizeof(*state)); - state->trans_id = req->transaction_id; - state->invoke_id = req->invoke_id; - memcpy(&state->src_ref, &con->remote_ref, sizeof(con->remote_ref)); - memcpy(&state->dst_ref, &con->real_ref, sizeof(con->real_ref)); - memcpy(state->imsi, con->filter_state.imsi, strlen(con->filter_state.imsi)); - - /* add additional tag/values */ - lac = htons(con->lac); - ci = htons(con->ci); - msgb_tv_fixed_put(msg, USSD_LAC_IE, sizeof(lac), (const uint8_t *) &lac); - msgb_tv_fixed_put(msg, USSD_CI_IE, sizeof(ci), (const uint8_t *) &ci); - - ussd = con->bsc->nat->ussd_con; - bsc_do_write(&ussd->queue, msg, IPAC_PROTO_IPACCESS); - bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP); - - return 0; -} - -int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct msgb *msg) -{ - uint32_t len; - uint8_t msg_type; - uint8_t proto; - uint8_t ti; - struct gsm48_hdr *hdr48; - struct bsc_msg_acc_lst *lst; - struct ussd_request req; - - /* - * various checks to avoid the decoding work. Right now we only want to - * decode if the connection was created for USSD, we do have a USSD access - * list, a query, a IMSI and such... - */ - if (con->filter_state.con_type != FLT_CON_TYPE_SSA) - return 0; - - if (!con->filter_state.imsi) - return 0; - - /* We have not verified the IMSI yet */ - if (!con->authorized) - return 0; - - if (!con->bsc->nat->ussd_lst_name) - return 0; - if (!con->bsc->nat->ussd_query) - return 0; - - if (parsed->bssap != BSSAP_MSG_DTAP) - return 0; - - if (strlen(con->filter_state.imsi) > GSM23003_IMSI_MAX_DIGITS) - return 0; - - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return 0; - - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - ti = gsm48_hdr_trans_id_no_ti(hdr48); - if (proto != GSM48_PDISC_NC_SS) - return 0; - - if (msg_type == GSM0480_MTYPE_REGISTER) { - - /* now check if it is a IMSI we care about */ - lst = bsc_msg_acc_lst_find(&con->bsc->nat->access_lists, - con->bsc->nat->ussd_lst_name); - if (!lst) - return 0; - - if (bsc_msg_acc_lst_check_allow(lst, con->filter_state.imsi) != 0) - return 0; - - /* now decode the message and see if we really want to handle it */ - memset(&req, 0, sizeof(req)); - if (gsm0480_decode_ussd_request(hdr48, len, &req) != 1) - return 0; - if (req.text[0] == 0xff) - return 0; - - if (regexec(&con->bsc->nat->ussd_query_re, - req.text, 0, NULL, 0) == REG_NOMATCH) - return 0; - - /* found a USSD query for our subscriber */ - LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", - con->filter_state.imsi); - con->ussd_ti[ti] = 1; - if (forward_ussd(con, &req, msg) != 0) - return 0; - return 1; - } else if (msg_type == GSM0480_MTYPE_FACILITY && con->ussd_ti[ti]) { - LOGP(DNAT, LOGL_NOTICE, "Forwarding message part of TI: %d %s\n", - ti, con->filter_state.imsi); - if (forward_ussd_simple(con, msg) != 0) - return 0; - return 1; - } - - return 0; -} diff --git a/src/osmo-msc/Makefile.am b/src/osmo-msc/Makefile.am index 0d4876fa9..a26b4bdc0 100644 --- a/src/osmo-msc/Makefile.am +++ b/src/osmo-msc/Makefile.am @@ -36,7 +36,6 @@ osmo_msc_LDADD = \ $(top_builddir)/src/libmsc/libmsc.a \ $(top_builddir)/src/libvlr/libvlr.a \ $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOGSM_LIBS) \ $(LIBOSMOVTY_LIBS) \ diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index 26494e13d..07b30d983 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -23,8 +23,6 @@ noinst_HEADERS = \ $(NULL) bin_PROGRAMS = \ - bs11_config \ - isdnsync \ meas_json \ $(NULL) if HAVE_SQLITE3 @@ -49,24 +47,6 @@ noinst_PROGRAMS = \ $(NULL) endif -bs11_config_SOURCES = \ - bs11_config.c \ - $(NULL) - -bs11_config_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(NULL) - -isdnsync_SOURCES = \ - isdnsync.c \ - $(NULL) - smpp_mirror_SOURCES = \ smpp_mirror.c \ $(NULL) diff --git a/src/utils/bs11_config.c b/src/utils/bs11_config.c deleted file mode 100644 index a0f3cb757..000000000 --- a/src/utils/bs11_config.c +++ /dev/null @@ -1,953 +0,0 @@ -/* Siemens BS-11 microBTS configuration tool */ - -/* (C) 2009-2010 by Harald Welte - * All Rights Reserved - * - * This software is based on ideas (but not code) of BS11Config - * (C) 2009 by Dieter Spaar - * - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void *tall_bs11cfg_ctx; -static struct e1inp_sign_link *oml_link; - -/* state of our bs11_config application */ -enum bs11cfg_state { - STATE_NONE, - STATE_LOGON_WAIT, - STATE_LOGON_ACK, - STATE_SWLOAD, - STATE_QUERY, -}; -static enum bs11cfg_state bs11cfg_state = STATE_NONE; -static char *command, *value; -struct osmo_timer_list status_timer; - -static const uint8_t obj_li_attr[] = { - NM_ATT_BS11_BIT_ERR_THESH, 0x09, 0x00, - NM_ATT_BS11_L1_PROT_TYPE, 0x00, - NM_ATT_BS11_LINE_CFG, 0x00, -}; -static const uint8_t obj_bbsig0_attr[] = { - NM_ATT_BS11_RSSI_OFFS, 0x02, 0x00, 0x00, - NM_ATT_BS11_DIVERSITY, 0x01, 0x00, -}; -static const uint8_t obj_pa0_attr[] = { - NM_ATT_BS11_TXPWR, 0x01, BS11_TRX_POWER_GSM_30mW, -}; -static const char *trx1_password = "1111111111"; -#define TEI_OML 25 - -/* dummy function to keep gsm_data.c happy */ -struct osmo_counter *osmo_counter_alloc(const char *name) -{ - return NULL; -} - -int handle_serial_msg(struct msgb *rx_msg); - -/* create all objects for an initial configuration */ -static int create_objects(struct gsm_bts *bts) -{ - fprintf(stdout, "Crating Objects for minimal config\n"); - abis_nm_bs11_create_object(bts, BS11_OBJ_LI, 0, sizeof(obj_li_attr), - obj_li_attr); - abis_nm_bs11_create_object(bts, BS11_OBJ_GPSU, 0, 0, NULL); - abis_nm_bs11_create_object(bts, BS11_OBJ_ALCO, 0, 0, NULL); - abis_nm_bs11_create_object(bts, BS11_OBJ_CCLK, 0, 0, NULL); - abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 0, - sizeof(obj_bbsig0_attr), obj_bbsig0_attr); - abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 0, - sizeof(obj_pa0_attr), obj_pa0_attr); - abis_nm_bs11_create_envaBTSE(bts, 0); - abis_nm_bs11_create_envaBTSE(bts, 1); - abis_nm_bs11_create_envaBTSE(bts, 2); - abis_nm_bs11_create_envaBTSE(bts, 3); - - abis_nm_bs11_conn_oml_tei(bts, 0, 1, 0xff, TEI_OML); - - abis_nm_bs11_set_trx_power(bts->c0, BS11_TRX_POWER_GSM_30mW); - - sleep(1); - - abis_nm_bs11_set_trx1_pw(bts, trx1_password); - - sleep(1); - - return 0; -} - -static int create_trx1(struct gsm_bts *bts) -{ - uint8_t bbsig1_attr[sizeof(obj_bbsig0_attr)+12]; - uint8_t *cur = bbsig1_attr; - struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, 1); - - if (!trx) - trx = gsm_bts_trx_alloc(bts); - - fprintf(stdout, "Crating Objects for TRX1\n"); - - abis_nm_bs11_set_trx1_pw(bts, trx1_password); - - sleep(1); - - cur = tlv_put(cur, NM_ATT_BS11_PASSWORD, 10, - (uint8_t *)trx1_password); - memcpy(cur, obj_bbsig0_attr, sizeof(obj_bbsig0_attr)); - abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 1, - sizeof(bbsig1_attr), bbsig1_attr); - abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 1, - sizeof(obj_pa0_attr), obj_pa0_attr); - abis_nm_bs11_set_trx_power(trx, BS11_TRX_POWER_GSM_30mW); - - return 0; -} - -static char *serial_port = "/dev/ttyUSB0"; -static char *fname_safety = "BTSBMC76.SWI"; -static char *fname_software = "HS011106.SWL"; -static int delay_ms = 0; -static int win_size = 8; -static int param_disconnect = 0; -static int param_restart = 0; -static int param_forced = 0; -static struct gsm_bts *g_bts; - -static int file_is_readable(const char *fname) -{ - int rc; - struct stat st; - - rc = stat(fname, &st); - if (rc < 0) - return 0; - - if (S_ISREG(st.st_mode) && (st.st_mode & S_IRUSR)) - return 1; - - return 0; -} - -static int percent; -static int percent_old; - -/* callback function passed to the ABIS OML code */ -static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg, - void *data, void *param) -{ - if (hook != GSM_HOOK_NM_SWLOAD) - return 0; - - switch (event) { - case NM_MT_LOAD_INIT_ACK: - fprintf(stdout, "Software Load Initiate ACK\n"); - break; - case NM_MT_LOAD_INIT_NACK: - fprintf(stderr, "ERROR: Software Load Initiate NACK\n"); - exit(5); - break; - case NM_MT_LOAD_END_ACK: - if (data) { - /* we did a safety load and must activate it */ - abis_nm_software_activate(g_bts, fname_safety, - swload_cbfn, g_bts); - sleep(5); - } - break; - case NM_MT_LOAD_END_NACK: - fprintf(stderr, "ERROR: Software Load End NACK\n"); - exit(3); - break; - case NM_MT_ACTIVATE_SW_NACK: - fprintf(stderr, "ERROR: Activate Software NACK\n"); - exit(4); - break; - case NM_MT_ACTIVATE_SW_ACK: - bs11cfg_state = STATE_NONE; - - break; - case NM_MT_LOAD_SEG_ACK: - percent = abis_nm_software_load_status(g_bts); - if (percent > percent_old) - printf("Software Download Progress: %d%%\n", percent); - percent_old = percent; - break; - } - return 0; -} - -static const struct value_string bs11_linkst_names[] = { - { 0, "Down" }, - { 1, "Up" }, - { 2, "Restoring" }, - { 0, NULL } -}; - -static const char *linkstate_name(uint8_t linkstate) -{ - return get_value_string(bs11_linkst_names, linkstate); -} - -static const struct value_string mbccu_load_names[] = { - { 0, "No Load" }, - { 1, "Load BTSCAC" }, - { 2, "Load BTSDRX" }, - { 3, "Load BTSBBX" }, - { 4, "Load BTSARC" }, - { 5, "Load" }, - { 0, NULL } -}; - -static const char *mbccu_load_name(uint8_t linkstate) -{ - return get_value_string(mbccu_load_names, linkstate); -} - -static const char *bts_phase_name(uint8_t phase) -{ - switch (phase) { - case BS11_STATE_WARM_UP: - case BS11_STATE_WARM_UP_2: - return "Warm Up"; - break; - case BS11_STATE_LOAD_SMU_SAFETY: - return "Load SMU Safety"; - break; - case BS11_STATE_LOAD_SMU_INTENDED: - return "Load SMU Intended"; - break; - case BS11_STATE_LOAD_MBCCU: - return "Load MBCCU"; - break; - case BS11_STATE_SOFTWARE_RQD: - return "Software required"; - break; - case BS11_STATE_WAIT_MIN_CFG: - case BS11_STATE_WAIT_MIN_CFG_2: - return "Wait minimal config"; - break; - case BS11_STATE_MAINTENANCE: - return "Maintenance"; - break; - case BS11_STATE_NORMAL: - return "Normal"; - break; - case BS11_STATE_ABIS_LOAD: - return "Abis load"; - break; - default: - return "Unknown"; - break; - } -} - -static const char *trx_power_name(uint8_t pwr) -{ - switch (pwr) { - case BS11_TRX_POWER_GSM_2W: - return "2W (GSM)"; - case BS11_TRX_POWER_GSM_250mW: - return "250mW (GSM)"; - case BS11_TRX_POWER_GSM_80mW: - return "80mW (GSM)"; - case BS11_TRX_POWER_GSM_30mW: - return "30mW (GSM)"; - case BS11_TRX_POWER_DCS_3W: - return "3W (DCS)"; - case BS11_TRX_POWER_DCS_1W6: - return "1.6W (DCS)"; - case BS11_TRX_POWER_DCS_500mW: - return "500mW (DCS)"; - case BS11_TRX_POWER_DCS_160mW: - return "160mW (DCS)"; - default: - return "unknown value"; - } -} - -static const char *pll_mode_name(uint8_t mode) -{ - switch (mode) { - case BS11_LI_PLL_LOCKED: - return "E1 Locked"; - case BS11_LI_PLL_STANDALONE: - return "Standalone"; - default: - return "unknown"; - } -} - -static const char *cclk_acc_name(uint8_t acc) -{ - switch (acc) { - case 0: - /* Out of the demanded +/- 0.05ppm */ - return "Medium"; - case 1: - /* Synchronized with Abis, within demanded tolerance +/- 0.05ppm */ - return "High"; - default: - return "unknown"; - } -} - -static const char *bport_lcfg_name(uint8_t lcfg) -{ - switch (lcfg) { - case BS11_LINE_CFG_STAR: - return "Star"; - case BS11_LINE_CFG_MULTIDROP: - return "Multi-Drop"; - default: - return "unknown"; - } -} - -static const char *obj_name(struct abis_om_fom_hdr *foh) -{ - static char retbuf[256]; - - retbuf[0] = 0; - - switch (foh->obj_class) { - case NM_OC_BS11: - strcat(retbuf, "BS11 "); - switch (foh->obj_inst.bts_nr) { - case BS11_OBJ_PA: - sprintf(retbuf+strlen(retbuf), "Power Amplifier %d ", - foh->obj_inst.ts_nr); - break; - case BS11_OBJ_LI: - sprintf(retbuf+strlen(retbuf), "Line Interface "); - break; - case BS11_OBJ_CCLK: - sprintf(retbuf+strlen(retbuf), "CCLK "); - break; - } - break; - case NM_OC_SITE_MANAGER: - strcat(retbuf, "SITE MANAGER "); - break; - case NM_OC_BS11_BPORT: - sprintf(retbuf+strlen(retbuf), "BPORT%u ", - foh->obj_inst.bts_nr); - break; - } - return retbuf; -} - -static void print_state(struct tlv_parsed *tp) -{ - if (TLVP_PRESENT(tp, NM_ATT_BS11_BTS_STATE)) { - uint8_t phase, mbccu; - if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 1) { - phase = *TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE); - printf("PHASE: %u %-20s ", phase & 0xf, - bts_phase_name(phase)); - } - if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 2) { - mbccu = *(TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE)+1); - printf("MBCCU0: %-11s MBCCU1: %-11s ", - mbccu_load_name(mbccu & 0xf), mbccu_load_name(mbccu >> 4)); - } - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_E1_STATE) && - TLVP_LEN(tp, NM_ATT_BS11_E1_STATE) >= 1) { - uint8_t e1_state = *TLVP_VAL(tp, NM_ATT_BS11_E1_STATE); - printf("Abis-link: %-9s ", linkstate_name(e1_state & 0xf)); - } - printf("\n"); -} - -static int print_attr(struct tlv_parsed *tp) -{ - if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_PCB_SERIAL)) { - printf("\tBS-11 ESN PCB Serial Number: %s\n", - TLVP_VAL(tp, NM_ATT_BS11_ESN_PCB_SERIAL)); - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_HW_CODE_NO)) { - printf("\tBS-11 ESN Hardware Code Number: %s\n", - TLVP_VAL(tp, NM_ATT_BS11_ESN_HW_CODE_NO)+6); - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_FW_CODE_NO)) { - printf("\tBS-11 ESN Firmware Code Number: %s\n", - TLVP_VAL(tp, NM_ATT_BS11_ESN_FW_CODE_NO)+6); - } -#if 0 - if (TLVP_PRESENT(tp, NM_ATT_BS11_BOOT_SW_VERS)) { - printf("BS-11 Boot Software Version: %s\n", - TLVP_VAL(tp, NM_ATT_BS11_BOOT_SW_VERS)+6); - } -#endif - if (TLVP_PRESENT(tp, NM_ATT_ABIS_CHANNEL) && - TLVP_LEN(tp, NM_ATT_ABIS_CHANNEL) >= 3) { - const uint8_t *chan = TLVP_VAL(tp, NM_ATT_ABIS_CHANNEL); - printf("\tE1 Channel: Port=%u Timeslot=%u ", - chan[0], chan[1]); - if (chan[2] == 0xff) - printf("(Full Slot)\n"); - else - printf("Subslot=%u\n", chan[2]); - } - if (TLVP_PRESENT(tp, NM_ATT_TEI)) - printf("\tTEI: %d\n", *TLVP_VAL(tp, NM_ATT_TEI)); - if (TLVP_PRESENT(tp, NM_ATT_BS11_TXPWR) && - TLVP_LEN(tp, NM_ATT_BS11_TXPWR) >= 1) { - printf("\tTRX Power: %s\n", - trx_power_name(*TLVP_VAL(tp, NM_ATT_BS11_TXPWR))); - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_PLL_MODE) && - TLVP_LEN(tp, NM_ATT_BS11_PLL_MODE) >= 1) { - printf("\tPLL Mode: %s\n", - pll_mode_name(*TLVP_VAL(tp, NM_ATT_BS11_PLL_MODE))); - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_PLL) && - TLVP_LEN(tp, NM_ATT_BS11_PLL) >= 4) { - const uint8_t *vp = TLVP_VAL(tp, NM_ATT_BS11_PLL); - printf("\tPLL Set Value=%d, Work Value=%d\n", - vp[0] << 8 | vp[1], vp[2] << 8 | vp[3]); - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_CCLK_ACCURACY) && - TLVP_LEN(tp, NM_ATT_BS11_CCLK_ACCURACY) >= 1) { - const uint8_t *acc = TLVP_VAL(tp, NM_ATT_BS11_CCLK_ACCURACY); - printf("\tCCLK Accuracy: %s (%d)\n", cclk_acc_name(*acc), *acc); - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_CCLK_TYPE) && - TLVP_LEN(tp, NM_ATT_BS11_CCLK_TYPE) >= 1) { - const uint8_t *acc = TLVP_VAL(tp, NM_ATT_BS11_CCLK_TYPE); - printf("\tCCLK Type=%d\n", *acc); - } - if (TLVP_PRESENT(tp, NM_ATT_BS11_LINE_CFG) && - TLVP_LEN(tp, NM_ATT_BS11_LINE_CFG) >= 1) { - const uint8_t *lcfg = TLVP_VAL(tp, NM_ATT_BS11_LINE_CFG); - printf("\tLine Configuration: %s (%d)\n", - bport_lcfg_name(*lcfg), *lcfg); - } - - - - return 0; -} - -static void cmd_query(void) -{ - struct gsm_bts_trx *trx = g_bts->c0; - - bs11cfg_state = STATE_QUERY; - abis_nm_bs11_get_serno(g_bts); - abis_nm_bs11_get_oml_tei_ts(g_bts); - abis_nm_bs11_get_pll_mode(g_bts); - abis_nm_bs11_get_cclk(g_bts); - abis_nm_bs11_get_trx_power(trx); - trx = gsm_bts_trx_num(g_bts, 1); - if (trx) - abis_nm_bs11_get_trx_power(trx); - abis_nm_bs11_get_bport_line_cfg(g_bts, 0); - abis_nm_bs11_get_bport_line_cfg(g_bts, 1); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; -} - -/* handle a response from the BTS to a GET STATE command */ -static int handle_state_resp(enum abis_bs11_phase state) -{ - int rc = 0; - - switch (state) { - case BS11_STATE_WARM_UP: - case BS11_STATE_LOAD_SMU_SAFETY: - case BS11_STATE_LOAD_SMU_INTENDED: - case BS11_STATE_LOAD_MBCCU: - break; - case BS11_STATE_SOFTWARE_RQD: - bs11cfg_state = STATE_SWLOAD; - /* send safety load. Use g_bts as private 'param' - * argument, so our swload_cbfn can distinguish - * a safety load from a regular software */ - if (file_is_readable(fname_safety)) - rc = abis_nm_software_load(g_bts, 0xff, fname_safety, - win_size, param_forced, - swload_cbfn, g_bts); - else - fprintf(stderr, "No valid Safety Load file \"%s\"\n", - fname_safety); - break; - case BS11_STATE_WAIT_MIN_CFG: - case BS11_STATE_WAIT_MIN_CFG_2: - bs11cfg_state = STATE_SWLOAD; - rc = create_objects(g_bts); - break; - case BS11_STATE_MAINTENANCE: - if (command) { - if (!strcmp(command, "disconnect")) - abis_nm_bs11_factory_logon(g_bts, 0); - else if (!strcmp(command, "reconnect")) - rc = abis_nm_bs11_bsc_disconnect(g_bts, 1); - else if (!strcmp(command, "software") - && bs11cfg_state != STATE_SWLOAD) { - bs11cfg_state = STATE_SWLOAD; - /* send software (FIXME: over A-bis?) */ - if (file_is_readable(fname_software)) - rc = abis_nm_bs11_load_swl(g_bts, fname_software, - win_size, param_forced, - swload_cbfn); - else - fprintf(stderr, "No valid Software file \"%s\"\n", - fname_software); - } else if (!strcmp(command, "delete-trx1")) { - printf("Locing BBSIG and PA objects of TRX1\n"); - abis_nm_chg_adm_state(g_bts, NM_OC_BS11, - BS11_OBJ_BBSIG, 0, 1, - NM_STATE_LOCKED); - abis_nm_chg_adm_state(g_bts, NM_OC_BS11, - BS11_OBJ_PA, 0, 1, - NM_STATE_LOCKED); - sleep(1); - printf("Deleting BBSIG and PA objects of TRX1\n"); - abis_nm_bs11_delete_object(g_bts, BS11_OBJ_BBSIG, 1); - abis_nm_bs11_delete_object(g_bts, BS11_OBJ_PA, 1); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "create-trx1")) { - create_trx1(g_bts); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "pll-e1-locked")) { - abis_nm_bs11_set_pll_locked(g_bts, 1); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "pll-standalone")) { - abis_nm_bs11_set_pll_locked(g_bts, 0); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "pll-setvalue")) { - abis_nm_bs11_set_pll(g_bts, atoi(value)); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "pll-workvalue")) { - /* To set the work value we need to login as FIELD */ - abis_nm_bs11_factory_logon(g_bts, 0); - sleep(1); - abis_nm_bs11_infield_logon(g_bts, 1); - sleep(1); - abis_nm_bs11_set_pll(g_bts, atoi(value)); - sleep(1); - abis_nm_bs11_infield_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "oml-tei")) { - abis_nm_bs11_conn_oml_tei(g_bts, 0, 1, 0xff, TEI_OML); - command = NULL; - } else if (!strcmp(command, "restart")) { - abis_nm_bs11_restart(g_bts); - command = NULL; - } else if (!strcmp(command, "query")) { - cmd_query(); - } else if (!strcmp(command, "create-bport1")) { - abis_nm_bs11_create_bport(g_bts, 1); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "delete-bport1")) { - abis_nm_chg_adm_state(g_bts, NM_OC_BS11_BPORT, 1, 0xff, 0xff, NM_STATE_LOCKED); - sleep(1); - abis_nm_bs11_delete_bport(g_bts, 1); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "bport0-star")) { - abis_nm_bs11_set_bport_line_cfg(g_bts, 0, BS11_LINE_CFG_STAR); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "bport0-multidrop")) { - abis_nm_bs11_set_bport_line_cfg(g_bts, 0, BS11_LINE_CFG_MULTIDROP); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } else if (!strcmp(command, "bport1-multidrop")) { - abis_nm_bs11_set_bport_line_cfg(g_bts, 1, BS11_LINE_CFG_MULTIDROP); - sleep(1); - abis_nm_bs11_factory_logon(g_bts, 0); - command = NULL; - } - - } - break; - case BS11_STATE_NORMAL: - if (command) { - if (!strcmp(command, "reconnect")) - abis_nm_bs11_factory_logon(g_bts, 0); - else if (!strcmp(command, "disconnect")) - abis_nm_bs11_bsc_disconnect(g_bts, 0); - else if (!strcmp(command, "query")) { - cmd_query(); - } - } else if (param_disconnect) { - param_disconnect = 0; - abis_nm_bs11_bsc_disconnect(g_bts, 0); - if (param_restart) { - param_restart = 0; - abis_nm_bs11_restart(g_bts); - } - } - break; - default: - break; - } - return rc; -} - -/* handle a fully-received message/packet from the RS232 port */ -static int abis_nm_bs11cfg_rcvmsg(struct msgb *rx_msg) -{ - struct e1inp_sign_link *link = rx_msg->dst; - struct abis_om_hdr *oh; - struct abis_om_fom_hdr *foh; - struct tlv_parsed tp; - int rc = -1; - -#if 0 - const uint8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 }; - - if (rx_msg->len < LAPD_HDR_LEN - + sizeof(struct abis_om_fom_hdr) - + sizeof(struct abis_om_hdr)) { - if (!memcmp(rx_msg->data + 2, too_fast, - sizeof(too_fast))) { - fprintf(stderr, "BS11 tells us we're too " - "fast, try --delay bigger than %u\n", - delay_ms); - return -E2BIG; - } else - fprintf(stderr, "unknown BS11 message\n"); - } -#endif - - oh = (struct abis_om_hdr *) msgb_l2(rx_msg); - foh = (struct abis_om_fom_hdr *) oh->data; - switch (foh->msg_type) { - case NM_MT_BS11_LMT_LOGON_ACK: - printf("LMT LOGON: ACK\n\n"); - if (bs11cfg_state == STATE_NONE) - bs11cfg_state = STATE_LOGON_ACK; - rc = abis_nm_bs11_get_state(g_bts); - break; - case NM_MT_BS11_LMT_LOGOFF_ACK: - printf("LMT LOGOFF: ACK\n"); - exit(0); - break; - case NM_MT_BS11_GET_STATE_ACK: - rc = abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh)); - print_state(&tp); - if (TLVP_PRESENT(&tp, NM_ATT_BS11_BTS_STATE) && - TLVP_LEN(&tp, NM_ATT_BS11_BTS_STATE) >= 1) - rc = handle_state_resp(*TLVP_VAL(&tp, NM_ATT_BS11_BTS_STATE)); - break; - case NM_MT_GET_ATTR_RESP: - printf("\n%sATTRIBUTES:\n", obj_name(foh)); - abis_nm_tlv_parse(&tp, g_bts, foh->data, oh->length-sizeof(*foh)); - rc = print_attr(&tp); - //osmo_hexdump(foh->data, oh->length-sizeof(*foh)); - break; - case NM_MT_BS11_SET_ATTR_ACK: - printf("SET ATTRIBUTE ObjClass=0x%02x ObjInst=(%d,%d,%d) ACK\n", - foh->obj_class, foh->obj_inst.bts_nr, - foh->obj_inst.trx_nr, foh->obj_inst.ts_nr); - rc = 0; - break; - case NM_MT_BS11_SET_ATTR_NACK: - printf("SET ATTRIBUTE ObjClass=0x%02x ObjInst=(%d,%d,%d) NACK\n", - foh->obj_class, foh->obj_inst.bts_nr, - foh->obj_inst.trx_nr, foh->obj_inst.ts_nr); - break; - case NM_MT_GET_ATTR_NACK: - printf("\n%sGET ATTR NACK\n", obj_name(foh)); - break; - case NM_MT_BS11_CREATE_OBJ_ACK: - printf("\n%sCREATE OBJECT ACK\n", obj_name(foh)); - break; - case NM_MT_BS11_CREATE_OBJ_NACK: - printf("\n%sCREATE OBJECT NACK\n", obj_name(foh)); - break; - case NM_MT_BS11_DELETE_OBJ_ACK: - printf("\n%sDELETE OBJECT ACK\n", obj_name(foh)); - break; - case NM_MT_BS11_DELETE_OBJ_NACK: - printf("\n%sDELETE OBJECT NACK\n", obj_name(foh)); - break; - default: - rc = abis_nm_rcvmsg(rx_msg); - } - if (rc < 0) { - perror("ERROR in main loop"); - //break; - } - /* flush the queue of pending messages to be sent. */ - abis_nm_queue_send_next(link->trx->bts); - if (rc == 1) - return rc; - - switch (bs11cfg_state) { - case STATE_NONE: - abis_nm_bs11_factory_logon(g_bts, 1); - break; - case STATE_LOGON_ACK: - osmo_timer_schedule(&status_timer, 5, 0); - break; - default: - break; - } - - return rc; -} - -void status_timer_cb(void *data) -{ - abis_nm_bs11_get_state(g_bts); -} - -static void print_banner(void) -{ - printf("bs11_config (C) 2009-2010 by Harald Welte and Dieter Spaar\n"); - printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); -} - -static void print_help(void) -{ - printf("bs11_config [options] [command]\n"); - printf("\nSupported options:\n"); - printf("\t-h --help\t\t\tPrint this help text\n"); - printf("\t-p --port \t\tSpecify serial port\n"); - printf("\t-s --software \t\tSpecify Software file\n"); - printf("\t-S --safety \t\tSpecify Safety Load file\n"); - printf("\t-d --delay \t\t\tSpecify delay in milliseconds\n"); - printf("\t-D --disconnect\t\t\tDisconnect BTS from BSC\n"); - printf("\t-w --win-size \t\tSpecify Window Size\n"); - printf("\t-f --forced\t\t\tForce Software Load\n"); - printf("\nSupported commands:\n"); - printf("\tquery\t\t\tQuery the BS-11 about serial number and configuration\n"); - printf("\tdisconnect\t\tDisconnect A-bis link (go into administrative state)\n"); - printf("\tresconnect\t\tReconnect A-bis link (go into normal state)\n"); - printf("\trestart\t\t\tRestart the BTS\n"); - printf("\tsoftware\t\tDownload Software (only in administrative state)\n"); - printf("\tcreate-trx1\t\tCreate objects for TRX1 (Danger: Your BS-11 might overheat)\n"); - printf("\tdelete-trx1\t\tDelete objects for TRX1\n"); - printf("\tpll-e1-locked\t\tSet the PLL to be locked to E1 clock\n"); - printf("\tpll-standalone\t\tSet the PLL to be in standalone mode\n"); - printf("\tpll-setvalue \tSet the PLL set value\n"); - printf("\tpll-workvalue \tSet the PLL work value\n"); - printf("\toml-tei\t\t\tSet OML E1 TS and TEI\n"); - printf("\tbport0-star\t\tSet BPORT0 line config to star\n"); - printf("\tbport0-multidrop\tSet BPORT0 line config to multidrop\n"); - printf("\tbport1-multidrop\tSet BPORT1 line config to multidrop\n"); - printf("\tcreate-bport1\t\tCreate BPORT1 object\n"); - printf("\tdelete-bport1\t\tDelete BPORT1 object\n"); -} - -static void handle_options(int argc, char **argv) -{ - int option_index = 0; - print_banner(); - - while (1) { - int c; - static struct option long_options[] = { - { "help", 0, 0, 'h' }, - { "port", 1, 0, 'p' }, - { "software", 1, 0, 's' }, - { "safety", 1, 0, 'S' }, - { "delay", 1, 0, 'd' }, - { "disconnect", 0, 0, 'D' }, - { "win-size", 1, 0, 'w' }, - { "forced", 0, 0, 'f' }, - { "restart", 0, 0, 'r' }, - { "debug", 1, 0, 'b'}, - }; - - c = getopt_long(argc, argv, "hp:s:S:td:Dw:fra:", - long_options, &option_index); - - if (c == -1) - break; - - switch (c) { - case 'h': - print_help(); - exit(0); - case 'p': - serial_port = optarg; - break; - case 'b': - log_parse_category_mask(osmo_stderr_target, optarg); - break; - case 's': - fname_software = optarg; - break; - case 'S': - fname_safety = optarg; - break; - case 'd': - delay_ms = atoi(optarg); - break; - case 'w': - win_size = atoi(optarg); - break; - case 'D': - param_disconnect = 1; - break; - case 'f': - param_forced = 1; - break; - case 'r': - param_disconnect = 1; - param_restart = 1; - break; - default: - break; - } - } - if (optind < argc) { - command = argv[optind]; - if (optind+1 < argc) - value = argv[optind+1]; - } - -} - -static int num_sigint; - -static void signal_handler(int signal) -{ - fprintf(stdout, "\nsignal %u received\n", signal); - - switch (signal) { - case SIGINT: - num_sigint++; - abis_nm_bs11_factory_logon(g_bts, 0); - if (num_sigint >= 3) - exit(0); - break; - } -} - -static int bs11cfg_sign_link(struct msgb *msg) -{ - msg->dst = oml_link; - return abis_nm_bs11cfg_rcvmsg(msg); -} - -struct e1inp_line_ops bs11cfg_e1inp_line_ops = { - .sign_link = bs11cfg_sign_link, -}; - -extern int bts_model_bs11_init(void); -int main(int argc, char **argv) -{ - struct gsm_network *gsmnet; - struct e1inp_line *line; - - tall_bs11cfg_ctx = talloc_named_const(NULL, 0, "bs11-config"); - msgb_talloc_ctx_init(tall_bs11cfg_ctx, 0); - - osmo_init_logging(&log_info); - handle_options(argc, argv); - bts_model_bs11_init(); - - gsmnet = bsc_network_init(tall_bs11cfg_ctx, 1, 1, NULL); - if (!gsmnet) { - fprintf(stderr, "Unable to allocate gsm network\n"); - exit(1); - } - g_bts = gsm_bts_alloc_register(gsmnet, GSM_BTS_TYPE_BS11, - HARDCODED_BSIC); - - /* Override existing OML callback handler to set our own. */ - g_bts->model->oml_rcvmsg = abis_nm_bs11cfg_rcvmsg; - - libosmo_abis_init(tall_bs11cfg_ctx); - - /* Initialize virtual E1 line over rs232. */ - line = talloc_zero(tall_bs11cfg_ctx, struct e1inp_line); - if (!line) { - fprintf(stderr, "Unable to allocate memory for virtual E1 line\n"); - exit(1); - } - /* set the serial port. */ - bs11cfg_e1inp_line_ops.cfg.rs232.port = serial_port; - bs11cfg_e1inp_line_ops.cfg.rs232.delay = delay_ms; - - line->driver = e1inp_driver_find("rs232"); - if (!line->driver) { - fprintf(stderr, "cannot find `rs232' driver, giving up.\n"); - exit(1); - } - e1inp_line_bind_ops(line, &bs11cfg_e1inp_line_ops); - - /* configure and create signalling link for OML. */ - e1inp_ts_config_sign(&line->ts[0], line); - g_bts->oml_link = oml_link = - e1inp_sign_link_create(&line->ts[0], E1INP_SIGN_OML, - g_bts->c0, TEI_OML, 0); - - e1inp_line_update(line); - - signal(SIGINT, &signal_handler); - - abis_nm_bs11_factory_logon(g_bts, 1); - //abis_nm_bs11_get_serno(g_bts); - - osmo_timer_setup(&status_timer, status_timer_cb, NULL); - - while (1) { - if (osmo_select_main(0) < 0) - break; - } - - abis_nm_bs11_factory_logon(g_bts, 0); - - exit(0); -} diff --git a/src/utils/isdnsync.c b/src/utils/isdnsync.c deleted file mode 100644 index cc8ff6723..000000000 --- a/src/utils/isdnsync.c +++ /dev/null @@ -1,189 +0,0 @@ -/* isdnsync.c - * - * Author Andreas Eversberg - * - * 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 . - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mISDNif.h" -#define MISDN_OLD_AF_COMPATIBILITY -#define AF_COMPATIBILITY_FUNC -#include "compat_af_isdn.h" - -int card = 0; -int sock = -1; - -int mISDN_open(void) -{ - int fd, ret; - struct mISDN_devinfo devinfo; - struct sockaddr_mISDN l2addr; - - fd = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE); - if (fd < 0) { - fprintf(stderr, "could not open socket (%s)\n", strerror(errno)); - return fd; - } - devinfo.id = card; - ret = ioctl(fd, IMGETDEVINFO, &devinfo); - if (ret < 0) { - fprintf(stderr,"could not send IOCTL IMGETCOUNT (%s)\n", strerror(errno)); - close(fd); - return ret; - } - close(fd); - if (!(devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) - && !(devinfo.Dprotocols & (1 << ISDN_P_TE_E1))) { - fprintf(stderr,"Interface does not support TE mode (%s)\n", strerror(errno)); - return ret; - } - fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_TE); - if (fd < 0) { - fprintf(stderr,"could not open ISDN_P_LAPD_TE socket (%s)\n", strerror(errno)); - return fd; - } - l2addr.family = AF_ISDN; - l2addr.dev = card; - l2addr.channel = 0; - l2addr.sapi = 0; - l2addr.tei = 0; - ret = bind(fd, (struct sockaddr *)&l2addr, sizeof(l2addr)); - if (ret < 0) { - fprintf(stderr,"could not bind socket for card %d (%s)\n", card, strerror(errno)); - close(fd); - return ret; - } - sock = fd; - - return sock; -} - - -void mISDN_handle(void) -{ - int ret; - fd_set rfd; - struct timeval tv; - struct sockaddr_mISDN addr; - socklen_t alen; - unsigned char buffer[2048]; - struct mISDNhead *hh = (struct mISDNhead *)buffer; - int l1 = 0, l2 = 0, tei = 0; - - while(1) { -again: - FD_ZERO(&rfd); - FD_SET(sock, &rfd); - tv.tv_sec = 2; - tv.tv_usec = 0; - ret = select(sock+1, &rfd, NULL, NULL, &tv); - if (ret < 0) { - if (errno == EINTR) - continue; - fprintf(stderr, "%s aborted: %s\n", __FUNCTION__, strerror(errno)); - break; - } - if (FD_ISSET(sock, &rfd)) { - alen = sizeof(addr); - ret = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &addr, &alen); - if (ret < 0) { - fprintf(stderr, "%s read socket error %s\n", __FUNCTION__, strerror(errno)); - } else if (ret < MISDN_HEADER_LEN) { - fprintf(stderr, "%s read socket shor frame\n", __FUNCTION__); - } else { - switch(hh->prim) { - case MPH_ACTIVATE_IND: - case PH_ACTIVATE_IND: - if (!l1) { - printf("PH_ACTIVATE\n"); - printf("*** Sync available from interface :-)\n"); - l1 = 1; - } - goto again; - break; - case MPH_DEACTIVATE_IND: - case PH_DEACTIVATE_IND: - if (l1) { - printf("PH_DEACTIVATE\n"); - printf("*** Lost sync on interface :-(\n"); - l1 = 0; - } - goto again; - break; - case DL_ESTABLISH_IND: - case DL_ESTABLISH_CNF: - printf("DL_ESTABLISH\n"); - l2 = 1; - goto again; - break; - case DL_RELEASE_IND: - case DL_RELEASE_CNF: - printf("DL_RELEASE\n"); - l2 = 0; - goto again; - break; - case DL_INFORMATION_IND: - printf("DL_INFORMATION (tei %d sapi %d)\n", addr.tei, addr.sapi); - tei = 1; - break; - default: -// printf("prim %x\n", hh->prim); - goto again; - } - } - } - if (tei && !l2) { - hh->prim = DL_ESTABLISH_REQ; - printf("-> activating layer 2\n"); - sendto(sock, buffer, MISDN_HEADER_LEN, 0, (struct sockaddr *) &addr, alen); - } - } -} - -int main(int argc, char *argv[]) -{ - int ret; - - if (argc <= 1) - { - printf("Usage: %s \n\n", argv[0]); - printf("Opens given card number in TE-mode PTP and tries to keep layer 2 established.\n"); - printf("This keeps layer 1 activated to retrieve a steady sync signal from network.\n"); - return(0); - } - - card = atoi(argv[1]); - - init_af_isdn(); - - if ((ret = mISDN_open() < 0)) - return(ret); - - mISDN_handle(); - - close(sock); - - return 0; -} diff --git a/tests/Makefile.am b/tests/Makefile.am index 7e17ad8de..c225afab9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,48 +1,13 @@ SUBDIRS = \ - gsm0408 \ - channel \ - gprs \ - abis \ - gbproxy \ - trau \ - subscr \ - nanobts_omlattr \ sms_queue \ msc_vlr \ $(NULL) -if BUILD_NAT -SUBDIRS += \ - bsc-nat \ - bsc-nat-trie \ - $(NULL) -endif -if BUILD_BSC -SUBDIRS += \ - bsc \ - $(NULL) -endif if BUILD_SMPP SUBDIRS += \ smpp \ $(NULL) endif -if HAVE_LIBGTP -SUBDIRS += \ - gtphub \ - $(NULL) - -if HAVE_LIBCARES -SUBDIRS += \ - sgsn \ - oap \ - xid \ - sndcp_xid \ - slhc \ - v42bis \ - $(NULL) -endif -endif # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac @@ -86,7 +51,7 @@ python-tests: $(BUILT_SOURCES) if BUILD_SMPP $(PYTHON) $(srcdir)/smpp_test_runner.py -w $(abs_top_builddir) -v endif - rm -f $(top_builddir)/sms.db $(top_builddir)/gsn_restart $(top_builddir)/gtphub_restart_count + rm -f $(top_builddir)/sms.db else python-tests: $(BUILT_SOURCES) echo "Not running python-based tests (determined at configure-time)" diff --git a/tests/abis/Makefile.am b/tests/abis/Makefile.am deleted file mode 100644 index 1c5dede3b..000000000 --- a/tests/abis/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - abis_test.ok \ - $(NULL) - -noinst_PROGRAMS = \ - abis_test \ - $(NULL) - -abis_test_SOURCES = \ - abis_test.c \ - $(NULL) - -abis_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(NULL) diff --git a/tests/abis/abis_test.c b/tests/abis/abis_test.c deleted file mode 100644 index 591f8350f..000000000 --- a/tests/abis/abis_test.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * (C) 2012 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 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 . - * - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include - -static const uint8_t load_config[] = { - 0x42, 0x12, 0x00, 0x08, 0x31, 0x36, 0x38, 0x64, - 0x34, 0x37, 0x32, 0x00, 0x13, 0x00, 0x0b, 0x76, - 0x32, 0x30, 0x30, 0x62, 0x31, 0x34, 0x33, 0x64, - 0x30, 0x00, 0x42, 0x12, 0x00, 0x08, 0x31, 0x36, - 0x38, 0x64, 0x34, 0x37, 0x32, 0x00, 0x13, 0x00, - 0x0b, 0x76, 0x32, 0x30, 0x30, 0x62, 0x31, 0x34, - 0x33, 0x64, 0x31, 0x00 -}; - -static void test_sw_selection(void) -{ - struct abis_nm_sw_desc descr[8], tmp; - uint16_t len0, len1; - int rc, pos; - - rc = abis_nm_get_sw_conf(load_config, ARRAY_SIZE(load_config), - &descr[0], ARRAY_SIZE(descr)); - if (rc != 2) { - printf("%s(): FAILED to parse the File Id/File version: %d\n", - __func__, rc); - abort(); - } - - len0 = abis_nm_sw_desc_len(&descr[0], true); - printf("len: %u\n", len0); - printf("file_id: %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len)); - printf("file_ver: %s\n", osmo_hexdump(descr[0].file_version, descr[0].file_version_len)); - - len1 = abis_nm_sw_desc_len(&descr[1], true); - printf("len: %u\n", len1); - printf("file_id: %s\n", osmo_hexdump(descr[1].file_id, descr[1].file_id_len)); - printf("file_ver: %s\n", osmo_hexdump(descr[1].file_version, descr[1].file_version_len)); - - /* start */ - pos = abis_nm_select_newest_sw(descr, rc); - if (pos != 1) { - printf("Selected the wrong version: %d\n", pos); - abort(); - } - printf("SELECTED: %d\n", pos); - - /* shuffle */ - tmp = descr[0]; - descr[0] = descr[1]; - descr[1] = tmp; - pos = abis_nm_select_newest_sw(descr, rc); - if (pos != 0) { - printf("Selected the wrong version: %d\n", pos); - abort(); - } - printf("SELECTED: %d\n", pos); - printf("%s(): OK\n", __func__); -} - -int main(int argc, char **argv) -{ - osmo_init_logging(&log_info); - - test_sw_selection(); - - return EXIT_SUCCESS; -} diff --git a/tests/abis/abis_test.ok b/tests/abis/abis_test.ok deleted file mode 100644 index 8418cad87..000000000 --- a/tests/abis/abis_test.ok +++ /dev/null @@ -1,9 +0,0 @@ -len: 26 -file_id: 31 36 38 64 34 37 32 00 -file_ver: 76 32 30 30 62 31 34 33 64 30 00 -len: 26 -file_id: 31 36 38 64 34 37 32 00 -file_ver: 76 32 30 30 62 31 34 33 64 31 00 -SELECTED: 1 -SELECTED: 0 -test_sw_selection(): OK diff --git a/tests/bsc-nat-trie/Makefile.am b/tests/bsc-nat-trie/Makefile.am deleted file mode 100644 index 6663897bf..000000000 --- a/tests/bsc-nat-trie/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) \ - $(LIBOSMOLEGACYMGCP_CFLAGS) \ - $(NULL) -AM_LDFLAGS = $(COVERAGE_LDFLAGS) - -EXTRA_DIST = bsc_nat_trie_test.ok prefixes.csv - -noinst_PROGRAMS = bsc_nat_trie_test - -bsc_nat_trie_test_SOURCES = bsc_nat_trie_test.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c -bsc_nat_trie_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -lrt \ - $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOLEGACYMGCP_LIBS) \ - $(LIBRARY_GSM) \ - $(NULL) diff --git a/tests/bsc-nat-trie/bsc_nat_trie_test.c b/tests/bsc-nat-trie/bsc_nat_trie_test.c deleted file mode 100644 index 4b4df2faf..000000000 --- a/tests/bsc-nat-trie/bsc_nat_trie_test.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * (C) 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 . - * - */ - -#include -#include - -#include -#include -#include -#include - -#include - -int main(int argc, char **argv) -{ - struct nat_rewrite *trie; - - osmo_init_logging(&log_info); - - printf("Testing the trie\n"); - - trie = nat_rewrite_parse(NULL, "prefixes.csv"); - OSMO_ASSERT(trie); - - /* verify that it has been parsed */ - OSMO_ASSERT(trie->prefixes == 17); - printf("Dumping the internal trie\n"); - nat_rewrite_dump(trie); - - /* now do the matching... */ - OSMO_ASSERT(!nat_rewrite_lookup(trie, "")); - OSMO_ASSERT(!nat_rewrite_lookup(trie, "2")); - - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1")->rewrite, "1") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12")->rewrite, "2") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123")->rewrite, "3") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234")->rewrite, "4") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345")->rewrite, "5") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123456")->rewrite, "6") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234567")->rewrite, "7") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678")->rewrite, "8") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123456789")->rewrite, "9") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234567890")->rewrite, "10") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "13")->rewrite, "11") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "14")->rewrite, "12") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "15")->rewrite, "13") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "16")->rewrite, "14") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "823455")->rewrite, "15") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "82")->rewrite, "16") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "+49123445")->rewrite, "17") == 0); - - /* match a prefix */ - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "121")->rewrite, "2") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1292323")->rewrite, "2") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678901")->rewrite, "10") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "160")->rewrite, "14") == 0); - - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678901123452123123")->rewrite, "10") == 0); - - /* invalid input */ - OSMO_ASSERT(!nat_rewrite_lookup(trie, "12abc")); - - talloc_free(trie); - - trie = nat_rewrite_parse(NULL, "does_not_exist.csv"); - OSMO_ASSERT(!trie); - - printf("Done with the tests.\n"); - return 0; -} diff --git a/tests/bsc-nat-trie/bsc_nat_trie_test.ok b/tests/bsc-nat-trie/bsc_nat_trie_test.ok deleted file mode 100644 index 4d4cc9949..000000000 --- a/tests/bsc-nat-trie/bsc_nat_trie_test.ok +++ /dev/null @@ -1,20 +0,0 @@ -Testing the trie -Dumping the internal trie -1,1 -12,2 -123,3 -1234,4 -12345,5 -123456,6 -1234567,7 -12345678,8 -123456789,9 -1234567890,10 -13,11 -14,12 -15,13 -16,14 -82,16 -823455,15 -+49123,17 -Done with the tests. diff --git a/tests/bsc-nat-trie/prefixes.csv b/tests/bsc-nat-trie/prefixes.csv deleted file mode 100644 index 35485b1a3..000000000 --- a/tests/bsc-nat-trie/prefixes.csv +++ /dev/null @@ -1,25 +0,0 @@ -1,1 -12,2 -123,3 -1234,4 -12345,5 -123456,6 -1234567,7 -12345678,8 -123456789,9 -1234567890,10 -13,11 -14,12 -15,13 -16,14 -823455,15 -82,16 -+49123,17 -1ABC,18 -12345678901234567890,19 -,20 -14A,21 -124,324324324234 -1234567890,10 -no line -99, diff --git a/tests/bsc-nat/Makefile.am b/tests/bsc-nat/Makefile.am deleted file mode 100644 index 74838a984..000000000 --- a/tests/bsc-nat/Makefile.am +++ /dev/null @@ -1,61 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOCTRL_LIBS) \ - $(LIBOSMOSCCP_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMONETIF_CFLAGS) \ - $(LIBOSMOLEGACYMGCP_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - bsc_nat_test.ok \ - bsc_data.c \ - barr.cfg \ - barr_dup.cfg \ - prefixes.csv \ - $(NULL) - -noinst_PROGRAMS = \ - bsc_nat_test \ - $(NULL) - -bsc_nat_test_SOURCES = \ - bsc_nat_test.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_filter.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_sccp.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_utils.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_mgcp_utils.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_filter.c - -bsc_nat_test_LDADD = \ - $(top_builddir)/src/libfilter/libfilter.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOSCCP_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMONETIF_LIBS) \ - $(LIBOSMOCTRL_LIBS) \ - $(LIBOSMOLEGACYMGCP_LIBS) \ - $(LIBRARY_GSM) \ - -lrt \ - $(NULL) diff --git a/tests/bsc-nat/barr.cfg b/tests/bsc-nat/barr.cfg deleted file mode 100644 index a9a4a2b31..000000000 --- a/tests/bsc-nat/barr.cfg +++ /dev/null @@ -1,12 +0,0 @@ -12123124:3:2: -12123123:3:1: -12123128:3:6: -12123125:3:3: -12123127:3:5: -12123126:3:4: -12123120:3:4: -12123119:3:4: -12123118:3:4: -12123117:3:4: -12123116:3:4: -12123115:3:4: diff --git a/tests/bsc-nat/barr_dup.cfg b/tests/bsc-nat/barr_dup.cfg deleted file mode 100644 index ea94631ce..000000000 --- a/tests/bsc-nat/barr_dup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -12123124:3:2: -12123124:3:2: diff --git a/tests/bsc-nat/bsc_data.c b/tests/bsc-nat/bsc_data.c deleted file mode 100644 index 3a9f1da62..000000000 --- a/tests/bsc-nat/bsc_data.c +++ /dev/null @@ -1,275 +0,0 @@ -/* test data */ - -/* BSC -> MSC, CR */ -static const uint8_t bsc_cr[] = { -0x00, 0x2e, 0xfd, -0x01, 0x00, 0x00, 0x15, 0x02, 0x02, 0x04, 0x02, -0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05, -0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3, -0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4, -0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80, -0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; - -static const uint8_t bsc_cr_patched[] = { -0x00, 0x2e, 0xfd, -0x01, 0x00, 0x00, 0x05, 0x02, 0x02, 0x04, 0x02, -0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05, -0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3, -0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4, -0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80, -0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; - -/* CC, MSC -> BSC */ -static const uint8_t msc_cc[] = { -0x00, 0x0a, 0xfd, -0x02, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x02, -0x01, 0x00 }; -static const uint8_t msc_cc_patched[] = { -0x00, 0x0a, 0xfd, -0x02, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x02, -0x01, 0x00 }; - -/* Classmark, BSC -> MSC */ -static const uint8_t bsc_dtap[] = { -0x00, 0x17, 0xfd, -0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00, -0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13, -0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 }; - -static const uint8_t bsc_dtap_patched[] = { -0x00, 0x17, 0xfd, -0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00, -0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13, -0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 }; - -/* Clear command, MSC -> BSC */ -static const uint8_t msc_dtap[] = { -0x00, 0x0d, 0xfd, -0x06, 0x00, 0x00, 0x05, 0x00, 0x01, 0x06, 0x00, -0x04, 0x20, 0x04, 0x01, 0x09 }; -static const uint8_t msc_dtap_patched[] = { -0x00, 0x0d, 0xfd, -0x06, 0x00, 0x00, 0x15, 0x00, 0x01, 0x06, 0x00, -0x04, 0x20, 0x04, 0x01, 0x09 }; - -/*RLSD, MSC -> BSC */ -static const uint8_t msc_rlsd[] = { -0x00, 0x0a, 0xfd, -0x04, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x00, -0x01, 0x00 }; -static const uint8_t msc_rlsd_patched[] = { -0x00, 0x0a, 0xfd, -0x04, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x00, -0x01, 0x00 }; - -/* RLC, BSC -> MSC */ -static const uint8_t bsc_rlc[] = { -0x00, 0x07, 0xfd, -0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x15 }; - -static const uint8_t bsc_rlc_patched[] = { -0x00, 0x07, 0xfd, -0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x05 }; - - -/* a paging command */ -static const uint8_t paging_by_lac_cmd[] = { -0x00, 0x22, 0xfd, 0x09, -0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x02, 0x00, -0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x12, 0x00, -0x10, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, 0x02, -0x01, 0x50, 0x02, 0x30, 0x1a, 0x03, 0x05, 0x20, -0x15 }; - -/* an assignment command */ -static const uint8_t ass_cmd[] = { -0x00, 0x12, 0xfd, 0x06, -0x00, 0x00, 0x49, 0x00, 0x01, 0x0b, 0x00, 0x09, -0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00, -0x01 }; - -/* identity response */ -static const uint8_t id_resp[] = { -0x00, 0x15, 0xfd, 0x06, 0x01, 0x1c, 0xdc, -0x00, 0x01, 0x0e, 0x01, 0x00, 0x0b, 0x05, 0x59, -0x08, 0x29, 0x40, 0x21, 0x03, 0x07, 0x48, 0x66, -0x31 -}; - -/* sms code msg */ -static const uint8_t smsc_rewrite[] = { -0x00, 0x30, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x29, 0x01, 0x03, 0x26, 0x09, 0x01, 0x23, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x17, 0x21, 0x0c, 0x0f, 0x81, -0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_patched[] = { -0x00, 0x31, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x2a, 0x01, 0x03, 0x27, 0x09, 0x01, 0x24, -0x00, 0x0c, 0x00, 0x08, 0x91, 0x66, 0x66, 0x66, -0x66, 0x66, 0x66, 0xf7, 0x17, 0x01, 0x0c, 0x0f, -0x81, 0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, -0xf5, 0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, -0xca, 0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_patched_hdr[] = { -0x00, 0x30, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x29, 0x01, 0x03, 0x26, 0x09, 0x01, 0x23, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x17, 0x01, 0x0c, 0x0f, 0x81, -0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_num_patched[] = { -0x00, 0x2f, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x28, 0x01, 0x03, 0x25, 0x09, 0x01, 0x22, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x16, 0x21, 0x0c, 0x0d, 0x91, - 0x23, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_num_patched_tp_srr[] = { -0x00, 0x2f, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x28, 0x01, 0x03, 0x25, 0x09, 0x01, 0x22, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x16, 0x01, 0x0c, 0x0d, 0x91, - 0x23, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -/* - * MGCP messages - */ - -/* nothing to patch */ -static const char crcx[] = "CRCX 23265295 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n"; -static const char crcx_patched[] = "CRCX 23265295 1e@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n"; - - -/* patch the ip and port */ -static const char crcx_resp[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98 3\r\na=rtpmap:98 AMR/8000\r\n"; -static const char crcx_resp_patched[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 10.0.0.1\r\nm=audio 999 RTP/AVP 98 3\r\na=rtpmap:98 AMR/8000\r\na=fmtp:98 mode-set=2\r\n"; - -/* patch the ip and port */ -static const char mdcx[] = "MDCX 23330829 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 172.16.18.2\r\nt=0 0\r\nm=audio 4410 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"; -static const char mdcx_patched[] = "MDCX 23330829 1e@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 10.0.0.23\r\nt=0 0\r\nm=audio 6666 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"; - - -static const char mdcx_resp[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n"; -static const char mdcx_resp_patched[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 10.0.0.23\r\nm=audio 5555 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\na=fmtp:98 mode-set=2\r\n"; - -/* different line ending */ -static const char mdcx_resp2[] = "200 33330829\n\nv=0\nc=IN IP4 172.16.18.2\nm=audio 4002 RTP/AVP 98\na=rtpmap:98 AMR/8000\n"; -static const char mdcx_resp_patched2[] = "200 33330829\n\nv=0\nc=IN IP4 10.0.0.23\nm=audio 5555 RTP/AVP 98\na=rtpmap:98 AMR/8000\na=fmtp:98 mode-set=2\n"; -static const char mdcx_resp_patched2_noamr[] = "200 33330829\n\nv=0\nc=IN IP4 10.0.0.23\nm=audio 5555 RTP/AVP 98\na=rtpmap:98 AMR/8000\n"; - -struct mgcp_patch_test { - const char *orig; - const char *patch; - const char *ip; - const int port; - const int payload_type; - const int ensure_mode_set; -}; - -static const struct mgcp_patch_test mgcp_messages[] = { - { - .orig = crcx, - .patch = crcx_patched, - .ip = "0.0.0.0", - .port = 2323, - .ensure_mode_set = 1, - }, - { - .orig = crcx_resp, - .patch = crcx_resp_patched, - .ip = "10.0.0.1", - .port = 999, - .payload_type = 98, - .ensure_mode_set = 1, - }, - { - .orig = mdcx, - .patch = mdcx_patched, - .ip = "10.0.0.23", - .port = 6666, - .payload_type = 126, - .ensure_mode_set = 1, - }, - { - .orig = mdcx_resp, - .patch = mdcx_resp_patched, - .ip = "10.0.0.23", - .port = 5555, - .payload_type = 98, - .ensure_mode_set = 1, - }, - { - .orig = mdcx_resp2, - .patch = mdcx_resp_patched2, - .ip = "10.0.0.23", - .port = 5555, - .payload_type = 98, - .ensure_mode_set = 1, - }, - { - .orig = mdcx_resp2, - .patch = mdcx_resp_patched2_noamr, - .ip = "10.0.0.23", - .port = 5555, - .payload_type = 98, - .ensure_mode_set = 0, - }, -}; - -/* CC Setup messages */ -static const uint8_t cc_setup_national[] = { - 0x00, 0x20, 0xfd, 0x06, 0x01, 0x12, - 0x6d, 0x00, 0x01, 0x19, 0x01, 0x00, 0x16, 0x03, - 0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x06, 0x81, 0x10, 0x27, 0x33, 0x63, - 0x66, 0x15, 0x02, 0x11, 0x01 -}; - -static const uint8_t cc_setup_national_patched[] = { - 0x00, 0x21, 0xfd, 0x06, 0x01, 0x12, - 0x6d, 0x00, 0x01, 0x1a, 0x01, 0x00, 0x17, 0x03, - 0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x07, 0x91, 0x94, 0x71, 0x32, 0x33, - 0x66, 0xf6, 0x15, 0x02, 0x11, 0x01 -}; - -/* patch the phone number of cc_setup_national_patched */ -static const uint8_t cc_setup_national_patched_patched[] = { - 0x00, 0x21, 0xfd, 0x06, 0x01, 0x12, - 0x6d, 0x00, 0x01, 0x1a, 0x01, 0x00, 0x17, 0x03, - 0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x07, 0x91, 0x63, 0x71, 0x32, 0x33, - 0x66, 0xf6, 0x15, 0x02, 0x11, 0x01 -}; - -static const uint8_t cc_setup_international[] = { - 0x00, 0x22, 0xfd, 0x06, 0x01, 0x13, - 0xe7, 0x00, 0x01, 0x1b, 0x01, 0x00, 0x18, 0x03, - 0x45, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x08, 0x81, 0x00, 0x94, 0x71, 0x33, - 0x63, 0x66, 0x03, 0x15, 0x02, 0x11, 0x01 -}; - -static const uint8_t cc_setup_national_again[] = { - 0x00, 0x22, 0xfd, 0x06, 0x01, 0x12, 0x6d, 0x00, - 0x01, 0x1b, 0x01, 0x00, 0x18, 0x03, 0x05, 0x04, - 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, 0x81, 0x5e, - 0x08, 0x81, 0x63, 0x94, 0x71, 0x32, 0x33, 0x66, - 0xf6, 0x15, 0x02, 0x11, 0x01 -}; diff --git a/tests/bsc-nat/bsc_nat_test.c b/tests/bsc-nat/bsc_nat_test.c deleted file mode 100644 index 2914a01b5..000000000 --- a/tests/bsc-nat/bsc_nat_test.c +++ /dev/null @@ -1,1584 +0,0 @@ -/* - * BSC NAT Message filtering - * - * (C) 2010-2013 by Holger Hans Peter Freyther - * (C) 2010-2013 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 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 . - * - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -/* test messages for ipa */ -static uint8_t ipa_id[] = { - 0x00, 0x01, 0xfe, 0x06, -}; - -/* SCCP messages are below */ -static uint8_t gsm_reset[] = { - 0x00, 0x12, 0xfd, - 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, - 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04, - 0x01, 0x20, -}; - -static const uint8_t gsm_reset_ack[] = { - 0x00, 0x13, 0xfd, - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03, - 0x00, 0x01, 0x31, -}; - -static const uint8_t gsm_paging[] = { - 0x00, 0x20, 0xfd, - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10, - 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, - 0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06, -}; - -/* BSC -> MSC connection open */ -static const uint8_t bssmap_cr[] = { - 0x00, 0x2c, 0xfd, - 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02, - 0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, - 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3, - 0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33, - 0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, - 0x31, 0x97, 0x61, 0x00 -}; - -/* MSC -> BSC connection confirm */ -static const uint8_t bssmap_cc[] = { - 0x00, 0x0a, 0xfd, - 0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, -}; - -/* MSC -> BSC released */ -static const uint8_t bssmap_released[] = { - 0x00, 0x0e, 0xfd, - 0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f, - 0x02, 0x23, 0x42, 0x00, -}; - -/* BSC -> MSC released */ -static const uint8_t bssmap_release_complete[] = { - 0x00, 0x07, 0xfd, - 0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03 -}; - -/* both directions IT timer */ -static const uint8_t connnection_it[] = { - 0x00, 0x0b, 0xfd, - 0x10, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, - 0x00, 0x00, 0x00, 0x00, -}; - -/* error in both directions */ -static const uint8_t proto_error[] = { - 0x00, 0x05, 0xfd, - 0x0f, 0x22, 0x33, 0x44, 0x00, -}; - -/* MGCP wrap... */ -static const uint8_t mgcp_msg[] = { - 0x00, 0x03, 0xfc, - 0x20, 0x20, 0x20, -}; - -/* location updating request */ -static const uint8_t bss_lu[] = { - 0x00, 0x2e, 0xfd, - 0x01, 0x91, 0x45, 0x14, 0x02, 0x02, 0x04, 0x02, - 0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05, - 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x14, 0xc3, - 0x50, 0x17, 0x12, 0x05, 0x08, 0x70, 0x72, 0xf4, - 0x80, 0xff, 0xfe, 0x30, 0x08, 0x29, 0x44, 0x50, - 0x12, 0x03, 0x24, 0x01, 0x95, 0x00 -}; - -/* paging response */ -static const uint8_t pag_resp[] = { - 0x00, 0x2c, 0xfd, 0x01, 0xe5, 0x68, - 0x14, 0x02, 0x02, 0x04, 0x02, 0x42, 0xfe, 0x0f, - 0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00, 0x72, - 0xf4, 0x80, 0x20, 0x16, 0xc3, 0x50, 0x17, 0x10, - 0x06, 0x27, 0x01, 0x03, 0x30, 0x18, 0x96, 0x08, - 0x29, 0x26, 0x30, 0x32, 0x11, 0x42, 0x01, 0x19, - 0x00 -}; - -struct filter_result { - const uint8_t *data; - const uint16_t length; - const int dir; - const int result; -}; - -static const struct filter_result results[] = { - { - .data = ipa_id, - .length = ARRAY_SIZE(ipa_id), - .dir = DIR_MSC, - .result = 1, - }, - { - .data = gsm_reset, - .length = ARRAY_SIZE(gsm_reset), - .dir = DIR_MSC, - .result = 1, - }, - { - .data = gsm_reset_ack, - .length = ARRAY_SIZE(gsm_reset_ack), - .dir = DIR_BSC, - .result = 1, - }, - { - .data = gsm_paging, - .length = ARRAY_SIZE(gsm_paging), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = bssmap_cr, - .length = ARRAY_SIZE(bssmap_cr), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = bssmap_cc, - .length = ARRAY_SIZE(bssmap_cc), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = bssmap_released, - .length = ARRAY_SIZE(bssmap_released), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = bssmap_release_complete, - .length = ARRAY_SIZE(bssmap_release_complete), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = mgcp_msg, - .length = ARRAY_SIZE(mgcp_msg), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = connnection_it, - .length = ARRAY_SIZE(connnection_it), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = connnection_it, - .length = ARRAY_SIZE(connnection_it), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = proto_error, - .length = ARRAY_SIZE(proto_error), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = proto_error, - .length = ARRAY_SIZE(proto_error), - .dir = DIR_MSC, - .result = 0, - }, - -}; - -static void test_filter(void) -{ - int i; - - - /* start testinh with proper messages */ - printf("Testing BSS Filtering.\n"); - for (i = 0; i < ARRAY_SIZE(results); ++i) { - int result; - struct bsc_nat_parsed *parsed; - struct msgb *msg = msgb_alloc(4096, "test-message"); - - printf("Going to test item: %d\n", i); - memcpy(msg->data, results[i].data, results[i].length); - msg->l2h = msgb_put(msg, results[i].length); - - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Failed to parse the message\n"); - continue; - } - - result = bsc_nat_filter_ipa(results[i].dir, msg, parsed); - if (result != results[i].result) { - printf("FAIL: Not the expected result got: %d wanted: %d\n", - result, results[i].result); - } - - msgb_free(msg); - } -} - -#include "bsc_data.c" - -static void copy_to_msg(struct msgb *msg, const uint8_t *data, unsigned int length) -{ - msgb_reset(msg); - msg->l2h = msgb_put(msg, length); - memcpy(msg->l2h, data, msgb_l2len(msg)); -} - -static void verify_msg(struct msgb *out, const uint8_t *ref, int ref_len) -{ - if (out->len != ref_len) { - printf("FAIL: The size should match: %d vs. %d\n", - out->len, ref_len); - printf("%s\n", osmo_hexdump(out->data, out->len)); - printf("Wanted\n"); - printf("%s\n", osmo_hexdump(ref, ref_len)); - abort(); - } - - if (memcmp(out->data, ref, out->len) != 0) { - printf("FAIL: the data should be changed.\n"); - printf("%s\n", osmo_hexdump(out->data, out->len)); - printf("Wanted\n"); - printf("%s\n", osmo_hexdump(ref, ref_len)); - abort(); - } -} - - -#define VERIFY(con_found, con, msg, ver, str) \ - if (!con_found) { \ - printf("Failed to find connection.\n"); \ - abort(); \ - } \ - if (con_found->bsc != con) { \ - printf("Got connection of the wrong BSC: %d\n", \ - con_found->bsc->cfg->nr); \ - abort(); \ - } \ - if (memcmp(msg->data, ver, sizeof(ver)) != 0) { \ - printf("Failed to patch the %s msg.\n", str); \ - abort(); \ - } - -/* test conn tracking once */ -static void test_contrack() -{ - struct bsc_nat *nat; - struct bsc_connection *con; - struct nat_sccp_connection *con_found; - struct nat_sccp_connection *rc_con; - struct bsc_nat_parsed *parsed; - struct msgb *msg; - - printf("Testing connection tracking.\n"); - nat = bsc_nat_alloc(); - con = bsc_connection_alloc(nat); - con->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(con->cfg, 23); - bsc_config_add_lac(con->cfg, 49); - bsc_config_add_lac(con->cfg, 42); - bsc_config_del_lac(con->cfg, 49); - bsc_config_add_lac(con->cfg, 1111); - msg = msgb_alloc(4096, "test"); - - /* 1.) create a connection */ - copy_to_msg(msg, bsc_cr, sizeof(bsc_cr)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - if (con_found != NULL) { - printf("Con should not exist realref(%u)\n", - sccp_src_ref_to_int(&con_found->real_ref)); - abort(); - } - rc_con = create_sccp_src_ref(con, parsed); - if (!rc_con) { - printf("Failed to create a ref\n"); - abort(); - } - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - if (!con_found) { - printf("Failed to find connection.\n"); - abort(); - } - if (con_found->bsc != con) { - printf("Got connection of the wrong BSC: %d\n", - con_found->bsc->cfg->nr); - abort(); - } - if (con_found != rc_con) { - printf("Failed to find the right connection.\n"); - abort(); - } - if (memcmp(msg->data, bsc_cr_patched, sizeof(bsc_cr_patched)) != 0) { - printf("Failed to patch the BSC CR msg.\n"); - abort(); - } - talloc_free(parsed); - - /* 2.) get the cc */ - copy_to_msg(msg, msc_cc, sizeof(msc_cc)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - VERIFY(con_found, con, msg, msc_cc_patched, "MSC CC"); - if (update_sccp_src_ref(con_found, parsed) != 0) { - printf("Failed to update the SCCP con.\n"); - abort(); - } - - /* 3.) send some data */ - copy_to_msg(msg, bsc_dtap, sizeof(bsc_dtap)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - VERIFY(con_found, con, msg, bsc_dtap_patched, "BSC DTAP"); - - /* 4.) receive some data */ - copy_to_msg(msg, msc_dtap, sizeof(msc_dtap)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - VERIFY(con_found, con, msg, msc_dtap_patched, "MSC DTAP"); - - /* 5.) close the connection */ - copy_to_msg(msg, msc_rlsd, sizeof(msc_rlsd)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - VERIFY(con_found, con, msg, msc_rlsd_patched, "MSC RLSD"); - - /* 6.) confirm the connection close */ - copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - if (!con_found) { - printf("Failed to find connection.\n"); - abort(); - } - if (con_found->bsc != con) { - printf("Got connection of the wrong BSC: %d\n", - con_found->bsc->cfg->nr); - abort(); - } - if (memcmp(msg->data, bsc_rlc_patched, sizeof(bsc_rlc_patched)) != 0) { - printf("Failed to patch the BSC CR msg.\n"); - abort(); - } - remove_sccp_src_ref(con, msg, parsed); - talloc_free(parsed); - - copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - - /* verify that it is gone */ - if (con_found != NULL) { - printf("Con should not exist real_ref(%u)\n", - sccp_src_ref_to_int(&con_found->real_ref)); - abort(); - } - talloc_free(parsed); - - - bsc_config_free(con->cfg); - bsc_nat_free(nat); - msgb_free(msg); -} - -static void test_paging(void) -{ - struct bsc_nat *nat; - struct bsc_connection *con; - struct bsc_config *cfg; - - printf("Testing paging by lac.\n"); - - nat = bsc_nat_alloc(); - con = bsc_connection_alloc(nat); - cfg = bsc_config_alloc(nat, "unknown", 0); - con->cfg = cfg; - bsc_config_add_lac(cfg, 23); - con->authenticated = 1; - llist_add(&con->list_entry, &nat->bsc_connections); - - /* Test it by not finding it */ - if (bsc_config_handles_lac(cfg, 8213) != 0) { - printf("Should not be handled.\n"); - abort(); - } - - /* Test by finding it */ - bsc_config_del_lac(cfg, 23); - bsc_config_add_lac(cfg, 8213); - if (bsc_config_handles_lac(cfg, 8213) == 0) { - printf("Should have found it.\n"); - abort(); - } - - bsc_nat_free(nat); -} - -static void test_mgcp_allocations(void) -{ -#if 0 - struct bsc_connection *bsc; - struct bsc_nat *nat; - struct nat_sccp_connection con; - int i, j, multiplex; - - printf("Testing MGCP.\n"); - memset(&con, 0, sizeof(con)); - - nat = bsc_nat_alloc(); - nat->bsc_endpoints = talloc_zero_array(nat, - struct bsc_endpoint, - 65); - nat->mgcp_cfg = mgcp_config_alloc(); - nat->mgcp_cfg->trunk.number_endpoints = 64; - - bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc->cfg->max_endpoints = 60; - bsc_config_add_lac(bsc->cfg, 2323); - bsc->last_endpoint = 0x22; - con.bsc = bsc; - - bsc_init_endps_if_needed(bsc); - - i = 1; - do { - if (bsc_assign_endpoint(bsc, &con) != 0) { - printf("failed to allocate... on iteration %d\n", i); - break; - } - ++i; - } while(1); - - multiplex = bsc_mgcp_nr_multiplexes(bsc->cfg->max_endpoints); - for (i = 0; i < multiplex; ++i) { - for (j = 0; j < 32; ++j) - printf("%d", bsc->_endpoint_status[i*32 + j]); - printf(": %d of %d\n", i*32 + 32, 32 * 8); - } -#endif -} - -static void test_mgcp_ass_tracking(void) -{ - struct bsc_connection *bsc; - struct bsc_nat *nat; - struct nat_sccp_connection con; - struct bsc_nat_parsed *parsed; - struct msgb *msg; - - printf("Testing MGCP.\n"); - memset(&con, 0, sizeof(con)); - - nat = bsc_nat_alloc(); - nat->bsc_endpoints = talloc_zero_array(nat, - struct bsc_endpoint, - 33); - nat->mgcp_cfg = mgcp_config_alloc(); - nat->mgcp_cfg->trunk.number_endpoints = 64; - mgcp_endpoints_allocate(&nat->mgcp_cfg->trunk); - - bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(bsc->cfg, 2323); - bsc->last_endpoint = 0x1e; - con.bsc = bsc; - - msg = msgb_alloc(4096, "foo"); - copy_to_msg(msg, ass_cmd, sizeof(ass_cmd)); - parsed = bsc_nat_parse(msg); - - if (msg->l2h[16] != 0 || - msg->l2h[17] != 0x1) { - printf("Input is not as expected.. %s 0x%x\n", - osmo_hexdump(msg->l2h, msgb_l2len(msg)), - msg->l2h[17]); - abort(); - } - - if (bsc_mgcp_assign_patch(&con, msg) != 0) { - printf("Failed to handle assignment.\n"); - abort(); - } - - if (con.msc_endp != 1) { - printf("Timeslot should be 1.\n"); - abort(); - } - - if (con.bsc_endp != 0x1) { - printf("Assigned timeslot should have been 1.\n"); - abort(); - } - if (con.bsc->_endpoint_status[0x1] != 1) { - printf("The status on the BSC is wrong.\n"); - abort(); - } - - int multiplex, timeslot; - mgcp_endpoint_to_timeslot(0x1, &multiplex, ×lot); - - uint16_t cic = htons(timeslot & 0x1f); - if (memcmp(&cic, &msg->l2h[16], sizeof(cic)) != 0) { - printf("Message was not patched properly\n"); - printf("data cic: 0x%x %s\n", cic, osmo_hexdump(msg->l2h, msgb_l2len(msg))); - abort(); - } - - talloc_free(parsed); - - bsc_mgcp_dlcx(&con); - if (con.bsc_endp != -1 || con.msc_endp != -1 || - con.bsc->_endpoint_status[1] != 0 || con.bsc->last_endpoint != 0x1) { - printf("Clearing should remove the mapping.\n"); - abort(); - } - - bsc_config_free(bsc->cfg); - bsc_nat_free(nat); -} - -/* test the code to find a given connection */ -static void test_mgcp_find(void) -{ - struct bsc_nat *nat; - struct bsc_connection *con; - struct nat_sccp_connection *sccp_con; - - printf("Testing finding of a BSC Connection\n"); - - nat = bsc_nat_alloc(); - con = bsc_connection_alloc(nat); - llist_add(&con->list_entry, &nat->bsc_connections); - - sccp_con = talloc_zero(con, struct nat_sccp_connection); - sccp_con->msc_endp = 12; - sccp_con->bsc_endp = 12; - sccp_con->bsc = con; - llist_add(&sccp_con->list_entry, &nat->sccp_connections); - - if (bsc_mgcp_find_con(nat, 11) != NULL) { - printf("Found the wrong connection.\n"); - abort(); - } - - if (bsc_mgcp_find_con(nat, 12) != sccp_con) { - printf("Didn't find the connection\n"); - abort(); - } - - /* free everything */ - bsc_nat_free(nat); -} - -static void test_mgcp_rewrite(void) -{ - int i; - struct msgb *output; - printf("Testing rewriting MGCP messages.\n"); - - for (i = 0; i < ARRAY_SIZE(mgcp_messages); ++i) { - const char *orig = mgcp_messages[i].orig; - const char *patc = mgcp_messages[i].patch; - const char *ip = mgcp_messages[i].ip; - const int port = mgcp_messages[i].port; - const int expected_payload_type = mgcp_messages[i].payload_type; - const int ensure_mode_set = mgcp_messages[i].ensure_mode_set; - int payload_type = -1; - - char *input = strdup(orig); - - output = bsc_mgcp_rewrite(input, strlen(input), 0x1e, - ip, port, -1, &payload_type, ensure_mode_set); - - if (payload_type != -1) { - fprintf(stderr, "Found media payload type %d in SDP data\n", - payload_type); - if (payload_type != expected_payload_type) { - printf("Wrong payload type %d (expected %d)\n", - payload_type, expected_payload_type); - abort(); - } - } - - if (msgb_l2len(output) != strlen(patc)) { - printf("Wrong sizes for test: %d %u != %zu != %zu\n", i, msgb_l2len(output), strlen(patc), strlen(orig)); - printf("String '%s' vs '%s'\n", (const char *) output->l2h, patc); - abort(); - } - - if (memcmp(output->l2h, patc, msgb_l2len(output)) != 0) { - printf("Broken on %d msg: '%s'\n", i, (const char *) output->l2h); - abort(); - } - - msgb_free(output); - free(input); - } -} - -static void test_mgcp_parse(void) -{ - int code, ci; - char transaction[60]; - - printf("Testing MGCP response parsing.\n"); - - if (bsc_mgcp_parse_response(crcx_resp, &code, transaction) != 0) { - printf("Failed to parse CRCX resp.\n"); - abort(); - } - - if (code != 200) { - printf("Failed to parse the CODE properly. Got: %d\n", code); - abort(); - } - - if (strcmp(transaction, "23265295") != 0) { - printf("Failed to parse transaction id: '%s'\n", transaction); - abort(); - } - - ci = bsc_mgcp_extract_ci(crcx_resp); - if (ci != 1) { - printf("Failed to parse the CI. Got: %d\n", ci); - abort(); - } -} - -struct cr_filter { - const uint8_t *data; - int length; - int result; - int contype; - - const char *bsc_imsi_allow; - const char *bsc_imsi_deny; - const char *nat_imsi_deny; - int nat_cm_reject_cause; - int nat_lu_reject_cause; - int bsc_cm_reject_cause; - int bsc_lu_reject_cause; - int want_cm_reject_cause; - int want_lu_reject_cause; -}; - -static struct cr_filter cr_filter[] = { - { - .data = bssmap_cr, - .length = sizeof(bssmap_cr), - .result = 1, - .contype = FLT_CON_TYPE_CM_SERV_REQ, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - .data = pag_resp, - .length = sizeof(pag_resp), - .result = 1, - .contype = FLT_CON_TYPE_PAG_RESP, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* nat deny is before blank/null BSC */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -3, - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* BSC allow is before NAT deny */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .nat_imsi_deny = "[0-9]*", - .bsc_imsi_allow = "2440[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* BSC allow is before NAT deny */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .bsc_imsi_allow = "[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* filter as deny is first */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .bsc_imsi_deny = "[0-9]*", - .bsc_imsi_allow = "[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* deny by nat rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -3, - .bsc_imsi_deny = "000[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* deny by nat rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -3, - .bsc_imsi_deny = "000[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = 0x23, - .nat_lu_reject_cause = 0x42, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = 0x42, - .want_cm_reject_cause = 0x23, - }, - { - /* deny by bsc rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -2, - .bsc_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* deny by bsc rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -2, - .bsc_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = 0x42, - .bsc_lu_reject_cause = 0x23, - .want_lu_reject_cause = 0x23, - .want_cm_reject_cause = 0x42, - }, -}; - -static void test_cr_filter() -{ - int i, res, contype; - struct msgb *msg = msgb_alloc(4096, "test_cr_filter"); - struct bsc_nat_parsed *parsed; - struct bsc_msg_acc_lst *nat_lst, *bsc_lst; - struct bsc_msg_acc_lst_entry *nat_entry, *bsc_entry; - struct bsc_filter_reject_cause cause; - - struct bsc_nat *nat = bsc_nat_alloc(); - struct bsc_connection *bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(bsc->cfg, 1234); - bsc->cfg->acc_lst_name = "bsc"; - nat->acc_lst_name = "nat"; - - nat_lst = bsc_msg_acc_lst_get(nat, &nat->access_lists, "nat"); - bsc_lst = bsc_msg_acc_lst_get(nat, &nat->access_lists, "bsc"); - - bsc_entry = bsc_msg_acc_lst_entry_create(bsc_lst); - nat_entry = bsc_msg_acc_lst_entry_create(nat_lst); - - /* test the default value as we are going to overwrite it */ - OSMO_ASSERT(bsc_entry->cm_reject_cause == GSM48_REJECT_PLMN_NOT_ALLOWED); - OSMO_ASSERT(bsc_entry->lu_reject_cause == GSM48_REJECT_PLMN_NOT_ALLOWED); - - for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) { - char *imsi; - msgb_reset(msg); - copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length); - - bsc_entry->cm_reject_cause = cr_filter[i].bsc_cm_reject_cause; - bsc_entry->lu_reject_cause = cr_filter[i].bsc_lu_reject_cause; - nat_entry->cm_reject_cause = cr_filter[i].nat_cm_reject_cause; - nat_entry->lu_reject_cause = cr_filter[i].nat_lu_reject_cause; - - if (gsm_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny, - cr_filter[i].nat_imsi_deny ? 1 : 0, - &cr_filter[i].nat_imsi_deny) != 0) - abort(); - if (gsm_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow, - cr_filter[i].bsc_imsi_allow ? 1 : 0, - &cr_filter[i].bsc_imsi_allow) != 0) - abort(); - if (gsm_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny, - cr_filter[i].bsc_imsi_deny ? 1 : 0, - &cr_filter[i].bsc_imsi_deny) != 0) - abort(); - - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Failed to parse the message\n"); - abort(); - } - - memset(&cause, 0, sizeof(cause)); - res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype, &imsi, &cause); - if (res != cr_filter[i].result) { - printf("FAIL: Wrong result %d for test %d.\n", res, i); - abort(); - } - - - OSMO_ASSERT(cause.cm_reject_cause == cr_filter[i].want_cm_reject_cause); - OSMO_ASSERT(cause.lu_reject_cause == cr_filter[i].want_lu_reject_cause); - - if (contype != cr_filter[i].contype) { - printf("FAIL: Wrong contype %d for test %d.\n", res, contype); - abort(); - } - - talloc_steal(parsed, imsi); - talloc_free(parsed); - } - - msgb_free(msg); - bsc_nat_free(nat); -} - -static void test_dt_filter() -{ - int i; - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct bsc_nat_parsed *parsed; - struct bsc_filter_reject_cause cause; - - struct bsc_nat *nat = bsc_nat_alloc(); - struct bsc_connection *bsc = bsc_connection_alloc(nat); - struct nat_sccp_connection *con = talloc_zero(0, struct nat_sccp_connection); - - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(bsc->cfg, 23); - con->bsc = bsc; - - msgb_reset(msg); - copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp)); - - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - if (parsed->bssap != BSSAP_MSG_DTAP) { - printf("FAIL: It should be dtap\n"); - abort(); - } - - /* gsm_type is actually the size of the dtap */ - if (parsed->gsm_type < msgb_l3len(msg) - 3) { - printf("FAIL: Not enough space for the content\n"); - abort(); - } - - memset(&cause, 0, sizeof(cause)); - OSMO_ASSERT(!con->filter_state.imsi); - if (bsc_nat_filter_dt(bsc, msg, con, parsed, &cause) != 1) { - printf("FAIL: Should have passed..\n"); - abort(); - } - OSMO_ASSERT(con->filter_state.imsi); - OSMO_ASSERT(talloc_parent(con->filter_state.imsi) == con); - - /* just some basic length checking... */ - for (i = ARRAY_SIZE(id_resp); i >= 0; --i) { - msgb_reset(msg); - copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp)); - - parsed = bsc_nat_parse(msg); - if (!parsed) - continue; - - con->filter_state.imsi_checked = 0; - memset(&cause, 0, sizeof(cause)); - bsc_nat_filter_dt(bsc, msg, con, parsed, &cause); - } - - msgb_free(msg); - bsc_nat_free(nat); -} - -static void test_setup_rewrite() -{ - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct msgb *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "27408000001234"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list entries; - struct osmo_config_entry entry; - - INIT_LLIST_HEAD(&entries.entry); - entry.mcc = "274"; - entry.mnc = "08"; - entry.option = "^0([1-9])"; - entry.text = "0049"; - llist_add_tail(&entry.list, &entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - - /* verify that nothing changed */ - msgb_reset(msg); - copy_to_msg(msg, cc_setup_international, ARRAY_SIZE(cc_setup_international)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (msg != out) { - printf("FAIL: The message should not have been changed\n"); - abort(); - } - - verify_msg(out, cc_setup_international, ARRAY_SIZE(cc_setup_international)); - talloc_free(parsed); - - /* verify that something in the message changes */ - msgb_reset(msg); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - msgb_free(out); - - /* Make sure that a wildcard is matching */ - entry.mnc = "*"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - msgb_free(out); - - /* Make sure that a wildcard is matching */ - entry.mnc = "09"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out != msg) { - printf("FAIL: The message should be unchanged.\n"); - abort(); - } - - verify_msg(out, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - msgb_free(out); - - /* Now see what happens to an international number */ - entry.mnc = "*"; - entry.option = "^\\+[0-9][0-9]([1-9])"; - entry.text = "0036"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp %d\n", __LINE__); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created %d.\n", __LINE__); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed %d\n", __LINE__); - abort(); - } - - verify_msg(out, cc_setup_national_patched_patched, - ARRAY_SIZE(cc_setup_national_patched_patched)); - msgb_free(out); - - /* go from international back to national */ - entry.mnc = "*"; - entry.option = "^\\+([0-9])"; - entry.text = "36"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp %d\n", __LINE__); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created %d.\n", __LINE__); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed %d\n", __LINE__); - abort(); - } - - verify_msg(out, cc_setup_national_again, - ARRAY_SIZE(cc_setup_national_again)); - msgb_free(out); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); - bsc_nat_free(nat); -} - -static void test_setup_rewrite_prefix(void) -{ - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct msgb *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "27408000001234"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list entries; - struct osmo_config_entry entry; - - INIT_LLIST_HEAD(&entries.entry); - entry.mcc = "274"; - entry.mnc = "08"; - entry.option = "^0([1-9])"; - entry.text = "prefix_lookup"; - llist_add_tail(&entry.list, &entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - - nat->num_rewr_trie = nat_rewrite_parse(nat, "prefixes.csv"); - - msgb_reset(msg); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - msgb_free(out); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); - bsc_nat_free(nat); -} - -static void test_setup_rewrite_post(void) -{ - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct msgb *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "27408000001234"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list entries; - struct osmo_config_entry entry; - struct osmo_config_list entries_post; - struct osmo_config_entry entry_post; - - INIT_LLIST_HEAD(&entries.entry); - entry.mcc = "274"; - entry.mnc = "08"; - entry.option = "^0([1-9])"; - entry.text = "0049"; - llist_add_tail(&entry.list, &entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - - /* attempt to undo the previous one */ - INIT_LLIST_HEAD(&entries_post.entry); - entry_post.mcc = "274"; - entry_post.mnc = "08"; - entry_post.option = "^\\+49([1-9])"; - entry_post.text = "prefix_lookup"; - llist_add_tail(&entry_post.list, &entries_post.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, &entries_post); - - nat->num_rewr_trie = nat_rewrite_parse(nat, "prefixes.csv"); - - msgb_reset(msg); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - msgb_free(out); - - bsc_nat_free(nat); -} - -static void test_sms_smsc_rewrite() -{ - struct msgb *msg = msgb_alloc(4096, "SMSC rewrite"), *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "515039900406700"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list smsc_entries, dest_entries, clear_entries; - struct osmo_config_entry smsc_entry, dest_entry, clear_entry; - - INIT_LLIST_HEAD(&smsc_entries.entry); - INIT_LLIST_HEAD(&dest_entries.entry); - INIT_LLIST_HEAD(&clear_entries.entry); - smsc_entry.mcc = "^515039"; - smsc_entry.option = "639180000105()"; - smsc_entry.text = "6666666666667"; - llist_add_tail(&smsc_entry.list, &smsc_entries.entry); - dest_entry.mcc = "515"; - dest_entry.mnc = "03"; - dest_entry.option = "^0049"; - dest_entry.text = ""; - llist_add_tail(&dest_entry.list, &dest_entries.entry); - clear_entry.mcc = "^515039"; - clear_entry.option = "^0049"; - clear_entry.text = ""; - llist_add_tail(&clear_entry.list, &clear_entries.entry); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->smsc_rewr, &smsc_entries); - bsc_nat_num_rewr_entry_adapt(nat, &nat->tpdest_match, &dest_entries); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, &clear_entries); - - printf("Testing SMSC rewriting.\n"); - - /* - * Check if the SMSC address is changed - */ - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_patched, ARRAY_SIZE(smsc_rewrite_patched)); - msgb_free(out); - - /* clear out the filter for SMSC */ - printf("Attempting to only rewrite the HDR\n"); - bsc_nat_num_rewr_entry_adapt(nat, &nat->smsc_rewr, NULL); - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_patched_hdr, ARRAY_SIZE(smsc_rewrite_patched_hdr)); - msgb_free(out); - - /* clear out the next filter */ - printf("Attempting to change nothing.\n"); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, NULL); - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out != msg) { - printf("FAIL: This should not have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - msgb_free(out); - bsc_nat_free(nat); -} - -static void test_sms_number_rewrite(void) -{ - struct msgb *msg, *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "515039900406700"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list num_entries, clear_entries; - struct osmo_config_entry num_entry, clear_entry; - - INIT_LLIST_HEAD(&num_entries.entry); - num_entry.mcc = "^515039"; - num_entry.option = "^0049()"; - num_entry.text = "0032"; - llist_add_tail(&num_entry.list, &num_entries.entry); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_num_rewr, &num_entries); - - printf("Testing SMS TP-DA rewriting.\n"); - - /* - * Check if the SMSC address is changed - */ - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_num_patched, - ARRAY_SIZE(smsc_rewrite_num_patched)); - msgb_free(out); - - /* - * Now with TP-SRR rewriting enabled - */ - INIT_LLIST_HEAD(&clear_entries.entry); - clear_entry.mcc = "^515039"; - clear_entry.option = ""; - clear_entry.text = ""; - llist_add_tail(&clear_entry.list, &clear_entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, &clear_entries); - - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_num_patched_tp_srr, - ARRAY_SIZE(smsc_rewrite_num_patched_tp_srr)); - msgb_free(out); - bsc_nat_free(nat); -} - -static void test_barr_list_parsing(void) -{ - int rc; - int cm, lu; - struct rb_node *node; - struct rb_root root = RB_ROOT; - struct osmo_config_list *lst = osmo_config_list_parse(NULL, "barr.cfg"); - if (lst == NULL) - abort(); - - rc = bsc_filter_barr_adapt(NULL, &root, lst); - if (rc != 0) - abort(); - talloc_free(lst); - - - for (node = rb_first(&root); node; node = rb_next(node)) { - struct bsc_filter_barr_entry *entry; - entry = rb_entry(node, struct bsc_filter_barr_entry, node); - printf("IMSI: %s CM: %d LU: %d\n", entry->imsi, - entry->cm_reject_cause, entry->lu_reject_cause); - } - - /* do the look up now.. */ - rc = bsc_filter_barr_find(&root, "12123119", &cm, &lu); - if (!rc) { - printf("Failed to find the IMSI.\n"); - abort(); - } - - if (cm != 3 || lu != 4) { - printf("Found CM(%d) and LU(%d)\n", cm, lu); - abort(); - } - - /* empty and check that it is empty */ - bsc_filter_barr_adapt(NULL, &root, NULL); - if (!RB_EMPTY_ROOT(&root)) { - printf("Failed to empty the list.\n"); - abort(); - } - - /* check that dup results in an error */ - lst = osmo_config_list_parse(NULL, "barr_dup.cfg"); - if (lst == NULL) { - printf("Failed to parse list with dups\n"); - abort(); - } - - rc = bsc_filter_barr_adapt(NULL, &root, lst); - if (rc != -1) { - printf("It should have failed due dup\n"); - abort(); - } - talloc_free(lst); - - /* dump for reference */ - for (node = rb_first(&root); node; node = rb_next(node)) { - struct bsc_filter_barr_entry *entry; - entry = rb_entry(node, struct bsc_filter_barr_entry, node); - printf("IMSI: %s CM: %d LU: %d\n", entry->imsi, - entry->cm_reject_cause, entry->lu_reject_cause); - - } - rc = bsc_filter_barr_adapt(NULL, &root, NULL); -} - -static void test_nat_extract_lac() -{ - int res; - struct bsc_connection *bsc; - struct bsc_nat *nat; - struct nat_sccp_connection con; - struct bsc_nat_parsed *parsed; - struct msgb *msg = msgb_alloc(4096, "test-message"); - - printf("Testing LAC extraction from SCCP CR\n"); - - /* initialize the testcase */ - nat = bsc_nat_alloc(); - bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - - memset(&con, 0, sizeof(con)); - con.bsc = bsc; - - /* create the SCCP CR */ - msg->l2h = msgb_put(msg, ARRAY_SIZE(bssmap_cr)); - memcpy(msg->l2h, bssmap_cr, ARRAY_SIZE(bssmap_cr)); - - /* parse it and pass it on */ - parsed = bsc_nat_parse(msg); - res = bsc_nat_extract_lac(bsc, &con, parsed, msg); - OSMO_ASSERT(res == 0); - - /* verify the LAC */ - OSMO_ASSERT(con.lac == 8210); - OSMO_ASSERT(con.ci == 50000); - - bsc_nat_free(nat); -} - -int main(int argc, char **argv) -{ - msgb_talloc_ctx_init(NULL, 0); - sccp_set_log_area(DSCCP); - osmo_init_logging(&log_info); - - test_filter(); - test_contrack(); - test_paging(); - test_mgcp_ass_tracking(); - test_mgcp_find(); - test_mgcp_rewrite(); - test_mgcp_parse(); - test_cr_filter(); - test_dt_filter(); - test_setup_rewrite(); - test_setup_rewrite_prefix(); - test_setup_rewrite_post(); - test_sms_smsc_rewrite(); - test_sms_number_rewrite(); - test_mgcp_allocations(); - test_barr_list_parsing(); - test_nat_extract_lac(); - - printf("Testing execution completed.\n"); - return 0; -} - -/* stub */ -void bsc_nat_send_mgcp_to_msc(struct bsc_nat *nat, struct msgb *msg) -{ - abort(); -} diff --git a/tests/bsc-nat/bsc_nat_test.ok b/tests/bsc-nat/bsc_nat_test.ok deleted file mode 100644 index ab04f4273..000000000 --- a/tests/bsc-nat/bsc_nat_test.ok +++ /dev/null @@ -1,39 +0,0 @@ -Testing BSS Filtering. -Going to test item: 0 -Going to test item: 1 -Going to test item: 2 -Going to test item: 3 -Going to test item: 4 -Going to test item: 5 -Going to test item: 6 -Going to test item: 7 -Going to test item: 8 -Going to test item: 9 -Going to test item: 10 -Going to test item: 11 -Going to test item: 12 -Testing connection tracking. -Testing paging by lac. -Testing MGCP. -Testing finding of a BSC Connection -Testing rewriting MGCP messages. -Testing MGCP response parsing. -Testing SMSC rewriting. -Attempting to only rewrite the HDR -Attempting to change nothing. -Testing SMS TP-DA rewriting. -IMSI: 12123115 CM: 3 LU: 4 -IMSI: 12123116 CM: 3 LU: 4 -IMSI: 12123117 CM: 3 LU: 4 -IMSI: 12123118 CM: 3 LU: 4 -IMSI: 12123119 CM: 3 LU: 4 -IMSI: 12123120 CM: 3 LU: 4 -IMSI: 12123123 CM: 3 LU: 1 -IMSI: 12123124 CM: 3 LU: 2 -IMSI: 12123125 CM: 3 LU: 3 -IMSI: 12123126 CM: 3 LU: 4 -IMSI: 12123127 CM: 3 LU: 5 -IMSI: 12123128 CM: 3 LU: 6 -IMSI: 12123124 CM: 3 LU: 2 -Testing LAC extraction from SCCP CR -Testing execution completed. diff --git a/tests/bsc-nat/prefixes.csv b/tests/bsc-nat/prefixes.csv deleted file mode 100644 index 0c7660f10..000000000 --- a/tests/bsc-nat/prefixes.csv +++ /dev/null @@ -1,2 +0,0 @@ -0172,0049 -+49,0 diff --git a/tests/bsc/Makefile.am b/tests/bsc/Makefile.am deleted file mode 100644 index 90bbb4ac7..000000000 --- a/tests/bsc/Makefile.am +++ /dev/null @@ -1,47 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOSCCP_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMOLEGACYMGCP_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - bsc_test.ok \ - $(NULL) - -noinst_PROGRAMS = \ - bsc_test \ - $(NULL) - -bsc_test_SOURCES = \ - bsc_test.c \ - $(top_srcdir)/src/osmo-bsc/osmo_bsc_filter.c \ - $(NULL) - -bsc_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOSCCP_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOLEGACYMGCP_LIBS) \ - $(LIBRARY_GSM) \ - -lrt \ - $(NULL) diff --git a/tests/bsc/bsc_test.c b/tests/bsc/bsc_test.c deleted file mode 100644 index 20ed5b43b..000000000 --- a/tests/bsc/bsc_test.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * BSC Message filtering - * - * (C) 2013 by sysmocom s.f.m.c. GmbH - * Written by Jacob Erlbeck - * (C) 2010-2013 by Holger Hans Peter Freyther - * (C) 2010-2013 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 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 . - * - */ - - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -enum test { - TEST_SCAN_TO_BTS, - TEST_SCAN_TO_MSC, -}; - -/* GSM 04.08 MM INFORMATION test message */ -static uint8_t gsm48_mm_info_nn_tzt[] = { - 0x05, 0x32, 0x45, 0x08, 0x80, 0x4f, 0x77, 0xeb, - 0x1a, 0xb6, 0x97, 0xe7, 0x47, 0x31, 0x90, 0x61, - 0x11, 0x02, 0x73, 0x00, -}; - -static uint8_t gsm48_mm_info_nn_tzt_out[] = { - 0x05, 0x32, 0x45, 0x08, 0x80, 0x4f, 0x77, 0xeb, - 0x1a, 0xb6, 0x97, 0xe7, 0x47, 0x31, 0x90, 0x61, - 0x11, 0x02, 0x73, 0x1a, -}; - -static uint8_t gsm48_mm_info_nn_tzt_dst[] = { - 0x05, 0x32, 0x45, 0x08, 0x80, 0x4f, 0x77, 0xeb, - 0x1a, 0xb6, 0x97, 0xe7, 0x47, 0x31, 0x90, 0x61, - 0x11, 0x02, 0x73, 0x00, 0x49, 0x01, 0x00, -}; - -static uint8_t gsm48_mm_info_nn_tzt_dst_out[] = { - 0x05, 0x32, 0x45, 0x08, 0x80, 0x4f, 0x77, 0xeb, - 0x1a, 0xb6, 0x97, 0xe7, 0x47, 0x31, 0x90, 0x61, - 0x11, 0x02, 0x73, 0x1a, 0x49, 0x01, 0x02, -}; - -struct test_definition { - const uint8_t *data; - const uint16_t length; - const int dir; - const int result; - const uint8_t *out_data; - const uint16_t out_length; - const char* params; - const int n_params; -}; - -static int get_int(const char *params, size_t nmemb, const char *key, int def, int *is_set) -{ - const char *kv = NULL; - - kv = strstr(params, key); - if (kv) { - kv += strlen(key) + 1; - fprintf(stderr, "get_int(%s) -> %d\n", key, atoi(kv)); - if (is_set) - *is_set = 1; - } - - return kv ? atoi(kv) : def; -} - -static const struct test_definition test_scan_defs[] = { - { - .data = gsm48_mm_info_nn_tzt_dst, - .length = ARRAY_SIZE(gsm48_mm_info_nn_tzt), - .dir = TEST_SCAN_TO_BTS, - .result = 0, - .out_data = gsm48_mm_info_nn_tzt_dst_out, - .out_length = ARRAY_SIZE(gsm48_mm_info_nn_tzt_out), - .params = "tz_hr=-5 tz_mn=15 tz_dst=2", - .n_params = 3, - }, - { - .data = gsm48_mm_info_nn_tzt_dst, - .length = ARRAY_SIZE(gsm48_mm_info_nn_tzt_dst), - .dir = TEST_SCAN_TO_BTS, - .result = 0, - .out_data = gsm48_mm_info_nn_tzt_dst_out, - .out_length = ARRAY_SIZE(gsm48_mm_info_nn_tzt_dst_out), - .params = "tz_hr=-5 tz_mn=15 tz_dst=2", - .n_params = 3, - }, -}; - -static void test_scan(void) -{ - int i; - - struct gsm_network *net; - struct gsm_bts *bts; - struct osmo_bsc_sccp_con *sccp_con; - struct bsc_msc_data *msc; - struct gsm_subscriber_connection *conn; - - net = talloc_zero(NULL, struct gsm_network); - bts = talloc_zero(net, struct gsm_bts); - sccp_con = talloc_zero(net, struct osmo_bsc_sccp_con); - msc = talloc_zero(net, struct bsc_msc_data); - conn = talloc_zero(net, struct gsm_subscriber_connection); - - bts->network = net; - sccp_con->msc = msc; - conn->bts = bts; - conn->sccp_con = sccp_con; - - /* start testing with proper messages */ - printf("Testing BTS<->MSC message scan.\n"); - for (i = 0; i < ARRAY_SIZE(test_scan_defs); ++i) { - const struct test_definition *test_def = &test_scan_defs[i]; - int result; - struct msgb *msg = msgb_alloc(4096, "test-message"); - int is_set = 0; - - net->tz.hr = get_int(test_def->params, test_def->n_params, "tz_hr", 0, &is_set); - net->tz.mn = get_int(test_def->params, test_def->n_params, "tz_mn", 0, &is_set); - net->tz.dst = get_int(test_def->params, test_def->n_params, "tz_dst", 0, &is_set); - net->tz.override = 1; - - printf("Going to test item: %d\n", i); - msg->l3h = msgb_put(msg, test_def->length); - memcpy(msg->l3h, test_def->data, test_def->length); - - switch (test_def->dir) { - case TEST_SCAN_TO_BTS: - /* override timezone of msg coming from the MSC */ - result = bsc_scan_msc_msg(conn, msg); - break; - case TEST_SCAN_TO_MSC: - /* override timezone of msg coming from the BSC */ - /* FIXME: no test for this case is defined in - * test_scan_defs[], so this is never used. */ - result = bsc_scan_bts_msg(conn, msg); - break; - default: - abort(); - break; - } - - if (result != test_def->result) { - printf("FAIL: Not the expected result, got: %d wanted: %d\n", - result, test_def->result); - goto out; - } - - if (msgb_l3len(msg) != test_def->out_length) { - printf("FAIL: Not the expected message size, got: %d wanted: %d\n", - msgb_l3len(msg), test_def->out_length); - goto out; - } - - if (memcmp(msgb_l3(msg), test_def->out_data, test_def->out_length) != 0) { - printf("FAIL: Not the expected message\n"); - goto out; - } - -out: - msgb_free(msg); - } - - talloc_free(net); -} - - -int main(int argc, char **argv) -{ - msgb_talloc_ctx_init(NULL, 0); - osmo_init_logging(&log_info); - - test_scan(); - - printf("Testing execution completed.\n"); - return 0; -} diff --git a/tests/bsc/bsc_test.ok b/tests/bsc/bsc_test.ok deleted file mode 100644 index 0564bf0cd..000000000 --- a/tests/bsc/bsc_test.ok +++ /dev/null @@ -1,4 +0,0 @@ -Testing BTS<->MSC message scan. -Going to test item: 0 -Going to test item: 1 -Testing execution completed. diff --git a/tests/channel/Makefile.am b/tests/channel/Makefile.am deleted file mode 100644 index dd78bdcf9..000000000 --- a/tests/channel/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - channel_test.ok \ - $(NULL) - -noinst_PROGRAMS = \ - channel_test \ - $(NULL) - -channel_test_SOURCES = \ - channel_test.c \ - $(NULL) - -channel_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libvlr/libvlr.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBCRYPTO_LIBS) \ - -ldbi \ - $(NULL) diff --git a/tests/channel/channel_test.c b/tests/channel/channel_test.c deleted file mode 100644 index beae658e9..000000000 --- a/tests/channel/channel_test.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * (C) 2009 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 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 . - * - */ - -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include - -void test_bts_debug_print(void) -{ - struct gsm_network *network; - struct gsm_bts *bts; - struct gsm_bts_trx *trx; - - printf("Testing the lchan printing:"); - - /* Create a dummy network */ - network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); - if (!network) - exit(1); - /* Add a BTS with some reasonanbly non-zero id */ - bts = gsm_bts_alloc(network, 45); - /* Add a second TRX to test on multiple TRXs */ - gsm_bts_trx_alloc(bts); - - llist_for_each_entry(trx, &bts->trx_list, list) { - char *name = gsm_lchan_name(&trx->ts[3].lchan[4]); - - if (name) - printf(" %s", name); - else - printf("NULL name"); - } - printf("\n"); -} - - -void test_dyn_ts_subslots(void) -{ - struct gsm_bts_trx_ts ts; - - printf("Testing subslot numbers for pchan types\n"); - - ts.pchan = GSM_PCHAN_TCH_F; - OSMO_ASSERT(ts_subslots(&ts) == 1); - - ts.pchan = GSM_PCHAN_TCH_H; - OSMO_ASSERT(ts_subslots(&ts) == 2); - - ts.pchan = GSM_PCHAN_PDCH; - OSMO_ASSERT(ts_subslots(&ts) == 0); - - ts.pchan = GSM_PCHAN_TCH_F_PDCH; - ts.flags = 0; /* TCH_F mode */ - OSMO_ASSERT(ts_subslots(&ts) == 1); - ts.flags = TS_F_PDCH_ACTIVE; - OSMO_ASSERT(ts_subslots(&ts) == 0); - - ts.pchan = GSM_PCHAN_TCH_F_TCH_H_PDCH; - ts.dyn.pchan_is = GSM_PCHAN_TCH_F; - OSMO_ASSERT(ts_subslots(&ts) == 1); - ts.dyn.pchan_is = GSM_PCHAN_TCH_H; - OSMO_ASSERT(ts_subslots(&ts) == 2); - ts.dyn.pchan_is = GSM_PCHAN_PDCH; - OSMO_ASSERT(ts_subslots(&ts) == 0); -} - -int main(int argc, char **argv) -{ - osmo_init_logging(&log_info); - - test_dyn_ts_subslots(); - test_bts_debug_print(); - - return EXIT_SUCCESS; -} - -void _abis_nm_sendmsg() {} -void sms_alloc() {} -void sms_free() {} -void gsm_net_update_ctype(struct gsm_network *network) {} -void gsm48_secure_channel() {} -void paging_request_stop() {} -void vty_out() {} - -void ipa_client_conn_clear_queue() {} -void ipa_client_conn_close() {} -void ipa_client_conn_create() {} -void ipa_client_conn_destroy() {} -void ipa_client_conn_open() {} -void ipa_client_conn_send() {} -void ipa_msg_push_header() {} -void ipaccess_bts_handle_ccm() {} - -struct tlv_definition nm_att_tlvdef; diff --git a/tests/channel/channel_test.ok b/tests/channel/channel_test.ok deleted file mode 100644 index 81d656927..000000000 --- a/tests/channel/channel_test.ok +++ /dev/null @@ -1,2 +0,0 @@ -Testing subslot numbers for pchan types -Testing the lchan printing: (bts=45,trx=0,ts=3,ss=4) (bts=45,trx=1,ts=3,ss=4) diff --git a/tests/gbproxy/Makefile.am b/tests/gbproxy/Makefile.am deleted file mode 100644 index 2dd66dfd4..000000000 --- a/tests/gbproxy/Makefile.am +++ /dev/null @@ -1,54 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - gbproxy_test.ok \ - $(NULL) - -noinst_PROGRAMS = \ - gbproxy_test \ - $(NULL) - -gbproxy_test_SOURCES = \ - gbproxy_test.c \ - $(NULL) - -gbproxy_test_LDFLAGS = \ - -Wl,--wrap=RAND_bytes \ - $(NULL) - -gbproxy_test_LDADD = \ - $(top_builddir)/src/gprs/gb_proxy.o \ - $(top_builddir)/src/gprs/gb_proxy_patch.o \ - $(top_builddir)/src/gprs/gb_proxy_peer.o \ - $(top_builddir)/src/gprs/gb_proxy_tlli.o \ - $(top_builddir)/src/gprs/gprs_gb_parse.o \ - $(top_builddir)/src/gprs/gprs_llc_parse.o \ - $(top_builddir)/src/gprs/crc24.o \ - $(top_builddir)/src/gprs/gprs_utils.o \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGB_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBRARY_DL) \ - $(LIBCRYPTO_LIBS) \ - -lrt \ - $(NULL) diff --git a/tests/gbproxy/gbproxy_test.c b/tests/gbproxy/gbproxy_test.c deleted file mode 100644 index 577daa95e..000000000 --- a/tests/gbproxy/gbproxy_test.c +++ /dev/null @@ -1,4971 +0,0 @@ -/* test routines for gbproxy - * send NS messages to the gbproxy and dumps what happens - * (C) 2013 by sysmocom s.f.m.c. GmbH - * Author: Jacob Erlbeck - */ - -#undef _GNU_SOURCE -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#define REMOTE_BSS_ADDR 0x01020304 -#define REMOTE_SGSN_ADDR 0x05060708 - -#define SGSN_NSEI 0x0100 - -#define REMOTE_SGSN2_ADDR 0x15161718 -#define SGSN2_NSEI 0x0102 - -#define MATCH_ANY (-1) - -struct gbproxy_config gbcfg = {0}; - -struct llist_head *received_messages = NULL; - -/* override, requires '-Wl,--wrap=RAND_bytes' */ -int __real_RAND_bytes(unsigned char *buf, int num); -int mock_RAND_bytes(unsigned char *buf, int num); -int (*RAND_bytes_cb)(unsigned char *, int) = - &mock_RAND_bytes; - -int __wrap_RAND_bytes(unsigned char *buf, int num) -{ - return (*RAND_bytes_cb)(buf, num); -} - -static int rand_seq_num = 0; -int mock_RAND_bytes(unsigned char *buf, int num) -{ - uint32_t val; - - OSMO_ASSERT(num == sizeof(val)); - OSMO_ASSERT(__real_RAND_bytes(buf, num) == 1); - - val = 0x00dead00 + rand_seq_num; - - rand_seq_num++; - - memcpy(buf, &val, num); - - return 1; -} - -static void cleanup_test() -{ - rand_seq_num = 0; -} - -static int dump_global(FILE *stream, int indent) -{ - unsigned int i; - const struct rate_ctr_group_desc *desc; - int rc; - - rc = fprintf(stream, "%*sGbproxy global:\n", indent, ""); - if (rc < 0) - return rc; - - desc = gbcfg.ctrg->desc; - - for (i = 0; i < desc->num_ctr; i++) { - struct rate_ctr *ctr = &gbcfg.ctrg->ctr[i]; - if (ctr->current) { - rc = fprintf(stream, "%*s %s: %llu\n", - indent, "", - desc->ctr_desc[i].description, - (long long)ctr->current); - - if (rc < 0) - return rc; - } - } - - return 0; -} - -static int dump_peers(FILE *stream, int indent, time_t now, - struct gbproxy_config *cfg) -{ - struct gbproxy_peer *peer; - struct gprs_ra_id raid; - unsigned int i; - const struct rate_ctr_group_desc *desc; - int rc; - - rc = fprintf(stream, "%*sPeers:\n", indent, ""); - if (rc < 0) - return rc; - - llist_for_each_entry(peer, &cfg->bts_peers, list) { - struct gbproxy_link_info *link_info; - struct gbproxy_patch_state *state = &peer->patch_state; - gsm48_parse_ra(&raid, peer->ra); - - rc = fprintf(stream, "%*s NSEI %u, BVCI %u, %sblocked, " - "RAI %u-%u-%u-%u\n", - indent, "", - peer->nsei, peer->bvci, - peer->blocked ? "" : "not ", - raid.mcc, raid.mnc, raid.lac, raid.rac); - - if (rc < 0) - return rc; - - desc = peer->ctrg->desc; - - for (i = 0; i < desc->num_ctr; i++) { - struct rate_ctr *ctr = &peer->ctrg->ctr[i]; - if (ctr->current) { - rc = fprintf(stream, "%*s %s: %llu\n", - indent, "", - desc->ctr_desc[i].description, - (long long)ctr->current); - - if (rc < 0) - return rc; - } - } - - fprintf(stream, "%*s TLLI-Cache: %d\n", - indent, "", state->logical_link_count); - llist_for_each_entry(link_info, &state->logical_links, list) { - char mi_buf[200]; - time_t age = now ? now - link_info->timestamp : 0; - int stored_msgs = 0; - struct llist_head *iter; - enum gbproxy_match_id match_id; - llist_for_each(iter, &link_info->stored_msgs) - stored_msgs++; - - if (link_info->imsi_len > 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)"); - } - fprintf(stream, "%*s TLLI %08x", - indent, "", link_info->tlli.current); - if (link_info->tlli.assigned) - fprintf(stream, "/%08x", link_info->tlli.assigned); - if (link_info->sgsn_tlli.current) { - fprintf(stream, " -> %08x", - link_info->sgsn_tlli.current); - if (link_info->sgsn_tlli.assigned) - fprintf(stream, "/%08x", - link_info->sgsn_tlli.assigned); - } - fprintf(stream, ", IMSI %s, AGE %d", - mi_buf, (int)age); - - if (stored_msgs) - fprintf(stream, ", STORED %d", stored_msgs); - - for (match_id = 0; match_id < ARRAY_SIZE(cfg->matches); - ++match_id) { - if (cfg->matches[match_id].enable && - link_info->is_matching[match_id]) { - fprintf(stream, ", IMSI matches"); - break; - } - } - - if (link_info->imsi_acq_pending) - fprintf(stream, ", IMSI acquisition in progress"); - - if (cfg->route_to_sgsn2) - fprintf(stream, ", SGSN NSEI %d", - link_info->sgsn_nsei); - - if (link_info->is_deregistered) - fprintf(stream, ", DE-REGISTERED"); - - rc = fprintf(stream, "\n"); - if (rc < 0) - return rc; - } - } - - return 0; -} - -const uint8_t *convert_ra(struct gprs_ra_id *raid) -{ - static uint8_t buf[6]; - gsm48_construct_ra(buf, raid); - return buf; -} - -/* DTAP - Attach Request */ -static const unsigned char dtap_attach_req[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, - 0x05, 0xf4, 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22, - 0x33, 0x40, 0x50, 0x60, 0x19, 0x18, 0xb3, 0x43, - 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, 0x9a, - 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, - 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, -}; - -/* DTAP - Attach Request (invalid RAI) */ -static const unsigned char dtap_attach_req2[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, - 0x05, 0xf4, 0xfb, 0x00, 0xbe, 0xef, 0x99, 0x99, - 0x99, 0x40, 0x50, 0x60, 0x19, 0x18, 0xb3, 0x43, - 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, 0x9a, - 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, - 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, -}; - -/* DTAP - Attach Request (P-TMSI 0x3f32b700) */ -static const unsigned char dtap_attach_req3[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, - 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x11, 0x22, - 0x33, 0x40, 0x50, 0x60, 0x19, 0x18, 0xb3, 0x43, - 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, 0x80, 0x9a, - 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, - 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00, -}; - -/* DTAP - Attach Request (IMSI 12131415161718) */ -static const unsigned char dtap_attach_req4[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, - 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, 0x19, - 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, - 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, - 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, - 0x00, -}; - -/* DTAP - Identity Request */ -static const unsigned char dtap_identity_req[] = { - 0x08, 0x15, 0x01 -}; - -/* DTAP - Identity Response */ -static const unsigned char dtap_identity_resp[] = { - 0x08, 0x16, 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, - 0x16, 0x17, 0x18 -}; - -/* DTAP - Identity Response, IMSI 2 */ -static const unsigned char dtap_identity2_resp[] = { - 0x08, 0x16, 0x08, 0x11, 0x12, 0x99, 0x99, 0x99, - 0x16, 0x17, 0x18 -}; - -/* DTAP - Identity Response, IMSI 3 */ -static const unsigned char dtap_identity3_resp[] = { - 0x08, 0x16, 0x08, 0x11, 0x12, 0x99, 0x99, 0x99, - 0x26, 0x27, 0x28 -}; - -/* DTAP - Attach Accept */ -static const unsigned char dtap_attach_acc[] = { - 0x08, 0x02, 0x01, 0x49, 0x04, 0x21, 0x63, 0x54, - 0x40, 0x50, 0x60, 0x19, 0xcd, 0xd7, 0x08, 0x17, - 0x16, 0x18, 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00 -}; - -/* DTAP - Attach Accept, P-TMSI 2 */ -static const unsigned char dtap_attach_acc2[] = { - 0x08, 0x02, 0x01, 0x49, 0x04, 0x21, 0x63, 0x54, - 0x40, 0x50, 0x60, 0x19, 0xcd, 0xd7, 0x08, 0x17, - 0x16, 0x18, 0x05, 0xf4, 0xe0, 0x98, 0x76, 0x54 -}; - -/* DTAP - Attach Complete */ -static const unsigned char dtap_attach_complete[] = { - 0x08, 0x03 -}; - -/* DTAP - Attach Reject (GPRS services not allowed) */ -static const unsigned char dtap_attach_rej7[] = { - 0x08, 0x04, 0x07 -}; - -/* DTAP - GMM Information */ -static const unsigned char dtap_gmm_information[] = { - 0x08, 0x21 -}; - -/* DTAP - Routing Area Update Request */ -static const unsigned char dtap_ra_upd_req[] = { - 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, - 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 -}; - -/* DTAP - Routing Area Update Accept */ -static const unsigned char dtap_ra_upd_acc[] = { - 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54, - 0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18, - 0x05, 0xf4, 0xef, 0xe2, 0xb7, 0x00, 0x17, 0x16, -}; - -/* DTAP - Routing Area Update Accept, P-TMSI 2 */ -static const unsigned char dtap_ra_upd_acc2[] = { - 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54, - 0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18, - 0x05, 0xf4, 0xe0, 0x98, 0x76, 0x54, 0x17, 0x16, -}; - -/* DTAP - Routing Area Update Accept, P-TMSI 3 */ -static const unsigned char dtap_ra_upd_acc3[] = { - 0x08, 0x09, 0x00, 0x49, 0x21, 0x63, 0x54, - 0x40, 0x50, 0x60, 0x19, 0x54, 0xab, 0xb3, 0x18, - 0x05, 0xf4, 0xe0, 0x54, 0x32, 0x10, 0x17, 0x16, -}; - -/* DTAP - Routing Area Update Complete */ -static const unsigned char dtap_ra_upd_complete[] = { - 0x08, 0x0a -}; - -/* DTAP - Routing Area Update Reject */ -/* cause = 10 ("Implicitly detached"), force_standby = 0 */ -static const unsigned char dtap_ra_upd_rej[] = { - 0x08, 0x0b, 0x0a, 0x00, -}; - -/* DTAP - Activate PDP Context Request */ -static const unsigned char dtap_act_pdp_ctx_req[] = { - 0x0a, 0x41, 0x05, 0x03, 0x0c, 0x00, - 0x00, 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x01, 0x21, 0x28, 0x03, - 0x02, 0x61, 0x62, 0x27, 0x14, 0x80, 0x80, 0x21, - 0x10, 0x01, 0x00, 0x00, 0x10, 0x81, 0x06, 0x00, - 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00, 0x00, - 0x00 -}; - -/* DTAP - Detach Request (MO) */ -/* normal detach, power_off = 1 */ -static const unsigned char dtap_detach_po_req[] = { - 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb -}; - -/* DTAP - Detach Request (MO) */ -/* normal detach, power_off = 0 */ -static const unsigned char dtap_detach_req[] = { - 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb -}; - -/* DTAP - Detach Accept (MO) */ -static const unsigned char dtap_detach_acc[] = { - 0x08, 0x06, 0x00 -}; - -/* DTAP - Detach Request (MT) */ -/* normal detach, reattach required, implicitly detached */ -static const unsigned char dtap_mt_detach_rea_req[] = { - 0x08, 0x05, 0x01, 0x25, 0x0a -}; - -/* DTAP - Detach Request (MT) */ -/* normal detach, reattach not required, implicitly detached */ -static const unsigned char dtap_mt_detach_req[] = { - 0x08, 0x05, 0x02, 0x25, 0x0a -}; - -/* DTAP - Detach Accept (MT) */ -static const unsigned char dtap_mt_detach_acc[] = { - 0x08, 0x06 -}; - -/* GPRS-LLC - SAPI: LLGMM, U, XID */ -static const unsigned char llc_u_xid_ul[] = { - 0x41, 0xfb, 0x01, 0x00, 0x0e, 0x00, 0x64, 0x11, - 0x05, 0x16, 0x01, 0x90, 0x66, 0xb3, 0x28 -}; - -/* GPRS-LLC - SAPI: LLGMM, U, XID */ -static const unsigned char llc_u_xid_dl[] = { - 0x41, 0xfb, 0x30, 0x84, 0x10, 0x61, 0xb6, 0x64, - 0xe4, 0xa9, 0x1a, 0x9e -}; - -/* GPRS-LLC - SAPI: LL11, UI, NSAPI 5, DNS query */ -static const unsigned char llc_ui_ll11_dns_query_ul[] = { - 0x0b, 0xc0, 0x01, 0x65, 0x00, 0x00, 0x00, 0x45, - 0x00, 0x00, 0x38, 0x95, 0x72, 0x00, 0x00, 0x45, - 0x11, 0x20, 0x85, 0x0a, 0xc0, 0x07, 0xe4, 0xac, - 0x10, 0x01, 0x0a, 0xad, 0xab, 0x00, 0x35, 0x00, - 0x24, 0x0e, 0x1c, 0x3b, 0xe0, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x6d, 0x05, 0x68, 0x65, 0x69, 0x73, 0x65, 0x02, - 0x64, 0x65, 0x00, 0x00, 0x01, 0x00, 0x01, 0x47, - 0x8f, 0x07 -}; - -/* GPRS-LLC - SAPI: LL11, UI, NSAPI 5, DNS query */ -static const unsigned char llc_ui_ll11_dns_resp_dl[] = { - 0x4b, 0xc0, 0x01, 0x65, 0x00, 0x00, 0x00, 0x45, - 0x00, 0x00, 0xc6, 0x00, 0x00, 0x40, 0x00, 0x3e, - 0x11, 0x7c, 0x69, 0xac, 0x10, 0x01, 0x0a, 0x0a, - 0xc0, 0x07, 0xe4, 0x00, 0x35, 0xad, 0xab, 0x00, - 0xb2, 0x74, 0x4e, 0x3b, 0xe0, 0x81, 0x80, 0x00, - 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x01, - 0x6d, 0x05, 0x68, 0x65, 0x69, 0x73, 0x65, 0x02, - 0x64, 0x65, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, - 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, - 0x10, 0x00, 0x04, 0xc1, 0x63, 0x90, 0x58, 0xc0, - 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, - 0x10, 0x00, 0x16, 0x03, 0x6e, 0x73, 0x32, 0x0c, - 0x70, 0x6f, 0x70, 0x2d, 0x68, 0x61, 0x6e, 0x6e, - 0x6f, 0x76, 0x65, 0x72, 0x03, 0x6e, 0x65, 0x74, - 0x00, 0xc0, 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, - 0x00, 0x0e, 0x10, 0x00, 0x10, 0x02, 0x6e, 0x73, - 0x01, 0x73, 0x08, 0x70, 0x6c, 0x75, 0x73, 0x6c, - 0x69, 0x6e, 0x65, 0xc0, 0x14, 0xc0, 0x0e, 0x00, - 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 0x00, - 0x05, 0x02, 0x6e, 0x73, 0xc0, 0x0e, 0xc0, 0x0e, - 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, - 0x00, 0x05, 0x02, 0x6e, 0x73, 0xc0, 0x5f, 0xc0, - 0x0e, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x0e, - 0x10, 0x00, 0x12, 0x02, 0x6e, 0x73, 0x0c, 0x70, - 0x6f, 0x70, 0x2d, 0x68, 0x61, 0x6e, 0x6e, 0x6f, - 0x76, 0x65, 0x72, 0xc0, 0x14, 0xaa, 0xdf, 0x31 -}; - -static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text, - struct sockaddr_in *peer, const unsigned char* data, - size_t data_len); - -static void send_ns_reset(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr, - enum ns_cause cause, uint16_t nsvci, uint16_t nsei) -{ - /* GPRS Network Service, PDU type: NS_RESET, - */ - unsigned char msg[12] = { - 0x02, 0x00, 0x81, 0x01, 0x01, 0x82, 0x11, 0x22, - 0x04, 0x82, 0x11, 0x22 - }; - - msg[3] = cause; - msg[6] = nsvci / 256; - msg[7] = nsvci % 256; - msg[10] = nsei / 256; - msg[11] = nsei % 256; - - gprs_process_message(nsi, "RESET", src_addr, msg, sizeof(msg)); -} - -static void send_ns_reset_ack(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr, - uint16_t nsvci, uint16_t nsei) -{ - /* GPRS Network Service, PDU type: NS_RESET_ACK, - */ - unsigned char msg[9] = { - 0x03, 0x01, 0x82, 0x11, 0x22, - 0x04, 0x82, 0x11, 0x22 - }; - - msg[3] = nsvci / 256; - msg[4] = nsvci % 256; - msg[7] = nsei / 256; - msg[8] = nsei % 256; - - gprs_process_message(nsi, "RESET_ACK", src_addr, msg, sizeof(msg)); -} - -static void send_ns_alive(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr) -{ - /* GPRS Network Service, PDU type: NS_ALIVE */ - unsigned char msg[1] = { - 0x0a - }; - - gprs_process_message(nsi, "ALIVE", src_addr, msg, sizeof(msg)); -} - -static void send_ns_alive_ack(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr) -{ - /* GPRS Network Service, PDU type: NS_ALIVE_ACK */ - unsigned char msg[1] = { - 0x0b - }; - - gprs_process_message(nsi, "ALIVE_ACK", src_addr, msg, sizeof(msg)); -} - -static void send_ns_unblock(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr) -{ - /* GPRS Network Service, PDU type: NS_UNBLOCK */ - unsigned char msg[1] = { - 0x06 - }; - - gprs_process_message(nsi, "UNBLOCK", src_addr, msg, sizeof(msg)); -} - -static void send_ns_unblock_ack(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr) -{ - /* GPRS Network Service, PDU type: NS_UNBLOCK_ACK */ - unsigned char msg[1] = { - 0x07 - }; - - gprs_process_message(nsi, "UNBLOCK_ACK", src_addr, msg, sizeof(msg)); -} - -static void send_ns_unitdata(struct gprs_ns_inst *nsi, const char *text, - struct sockaddr_in *src_addr, uint16_t nsbvci, - const unsigned char *bssgp_msg, size_t bssgp_msg_size) -{ - /* GPRS Network Service, PDU type: NS_UNITDATA */ - unsigned char msg[4096] = { - 0x00, 0x00, 0x00, 0x00 - }; - - OSMO_ASSERT(bssgp_msg_size <= sizeof(msg) - 4); - - msg[2] = nsbvci / 256; - msg[3] = nsbvci % 256; - memcpy(msg + 4, bssgp_msg, bssgp_msg_size); - - gprs_process_message(nsi, text ? text : "UNITDATA", src_addr, msg, bssgp_msg_size + 4); -} - -static void send_bssgp_ul_unitdata( - struct gprs_ns_inst *nsi, const char *text, - struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, - struct gprs_ra_id *raid, uint16_t cell_id, - const uint8_t *llc_msg, size_t llc_msg_size) -{ - /* GPRS Network Service, PDU type: NS_UNITDATA */ - /* Base Station Subsystem GPRS Protocol: UL_UNITDATA */ - unsigned char msg[4096] = { - 0x01, /* TLLI */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, - 0x08, 0x88, /* RAI */ 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - /* CELL ID */ 0x00, 0x00, 0x00, 0x80, 0x0e, /* LLC LEN */ 0x00, 0x00, - }; - - size_t bssgp_msg_size = 23 + llc_msg_size; - - OSMO_ASSERT(bssgp_msg_size <= sizeof(msg)); - - gsm48_construct_ra(msg + 10, raid); - msg[1] = (uint8_t)(tlli >> 24); - msg[2] = (uint8_t)(tlli >> 16); - msg[3] = (uint8_t)(tlli >> 8); - msg[4] = (uint8_t)(tlli >> 0); - msg[16] = cell_id / 256; - msg[17] = cell_id % 256; - msg[21] = llc_msg_size / 256; - msg[22] = llc_msg_size % 256; - memcpy(msg + 23, llc_msg, llc_msg_size); - - send_ns_unitdata(nsi, text ? text : "BSSGP UL UNITDATA", - src_addr, nsbvci, msg, bssgp_msg_size); -} - -static void send_bssgp_dl_unitdata( - struct gprs_ns_inst *nsi, const char *text, - struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, - int with_racap_drx, const uint8_t *imsi, size_t imsi_size, - const uint8_t *llc_msg, size_t llc_msg_size) -{ - /* Base Station Subsystem GPRS Protocol: DL_UNITDATA */ - unsigned char msg[4096] = { - 0x00, /* TLLI */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x20, - 0x16, 0x82, 0x02, 0x58, - }; - unsigned char racap_drx[] = { - 0x13, 0x99, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, - 0x62, 0x00, 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, - 0x00, 0x60, 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, - 0x60, 0x80, 0x00, 0x0a, 0x82, 0x08, 0x02 - }; - - size_t bssgp_msg_size = 0; - - OSMO_ASSERT(51 + imsi_size + llc_msg_size <= sizeof(msg)); - - msg[1] = (uint8_t)(tlli >> 24); - msg[2] = (uint8_t)(tlli >> 16); - msg[3] = (uint8_t)(tlli >> 8); - msg[4] = (uint8_t)(tlli >> 0); - - bssgp_msg_size = 12; - - if (with_racap_drx) { - memcpy(msg + bssgp_msg_size, racap_drx, sizeof(racap_drx)); - bssgp_msg_size += sizeof(racap_drx); - } - - if (imsi) { - OSMO_ASSERT(imsi_size <= 127); - msg[bssgp_msg_size] = BSSGP_IE_IMSI; - msg[bssgp_msg_size + 1] = 0x80 | imsi_size; - memcpy(msg + bssgp_msg_size + 2, imsi, imsi_size); - bssgp_msg_size += 2 + imsi_size; - } - - if ((bssgp_msg_size % 4) != 0) { - size_t abytes = (4 - (bssgp_msg_size + 2) % 4) % 4; - msg[bssgp_msg_size] = BSSGP_IE_ALIGNMENT; - msg[bssgp_msg_size + 1] = 0x80 | abytes; - memset(msg + bssgp_msg_size + 2, 0, abytes); - bssgp_msg_size += 2 + abytes; - } - - msg[bssgp_msg_size] = BSSGP_IE_LLC_PDU; - if (llc_msg_size < 128) { - msg[bssgp_msg_size + 1] = 0x80 | llc_msg_size; - bssgp_msg_size += 2; - } else { - msg[bssgp_msg_size + 1] = llc_msg_size / 256; - msg[bssgp_msg_size + 2] = llc_msg_size % 256; - bssgp_msg_size += 3; - } - memcpy(msg + bssgp_msg_size, llc_msg, llc_msg_size); - bssgp_msg_size += llc_msg_size; - - - send_ns_unitdata(nsi, text ? text : "BSSGP DL UNITDATA", - src_addr, nsbvci, msg, bssgp_msg_size); -} - -static void send_bssgp_reset(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr, - uint16_t bvci) -{ - /* GPRS Network Service, PDU type: NS_UNITDATA, BVCI 0 - * BSSGP RESET */ - unsigned char msg[18] = { - 0x22, 0x04, 0x82, 0x4a, - 0x2e, 0x07, 0x81, 0x08, 0x08, 0x88, 0x11, 0x22, - 0x33, 0x40, 0x50, 0x60, 0x10, 0x00 - }; - - msg[3] = bvci / 256; - msg[4] = bvci % 256; - - send_ns_unitdata(nsi, "BVC_RESET", src_addr, 0, msg, sizeof(msg)); -} - -static void send_bssgp_reset_ack(struct gprs_ns_inst *nsi, - struct sockaddr_in *src_addr, uint16_t bvci) -{ - /* GPRS Network Service, PDU type: NS_UNITDATA, BVCI 0 - * BSSGP RESET_ACK */ - static unsigned char msg[5] = { - 0x23, 0x04, 0x82, 0x00, - 0x00 - }; - - msg[3] = bvci / 256; - msg[4] = bvci % 256; - - send_ns_unitdata(nsi, "BVC_RESET_ACK", src_addr, 0, msg, sizeof(msg)); -} - -static void send_bssgp_suspend(struct gprs_ns_inst *nsi, - struct sockaddr_in *src_addr, - uint32_t tlli, - struct gprs_ra_id *raid) -{ - /* Base Station Subsystem GPRS Protocol, BSSGP SUSPEND */ - unsigned char msg[15] = { - 0x0b, 0x1f, 0x84, /* TLLI */ 0xff, 0xff, 0xff, 0xff, 0x1b, - 0x86, /* RAI */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - - msg[3] = (uint8_t)(tlli >> 24); - msg[4] = (uint8_t)(tlli >> 16); - msg[5] = (uint8_t)(tlli >> 8); - msg[6] = (uint8_t)(tlli >> 0); - - gsm48_construct_ra(msg + 9, raid); - - send_ns_unitdata(nsi, "BVC_SUSPEND", src_addr, 0, msg, sizeof(msg)); -} - -static void send_bssgp_suspend_ack(struct gprs_ns_inst *nsi, - struct sockaddr_in *src_addr, - uint32_t tlli, - struct gprs_ra_id *raid) -{ - /* Base Station Subsystem GPRS Protocol, BSSGP SUSPEND ACK */ - unsigned char msg[18] = { - 0x0c, 0x1f, 0x84, /* TLLI */ 0xff, 0xff, 0xff, 0xff, 0x1b, - 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1d, - 0x81, 0x01 - }; - - msg[3] = (uint8_t)(tlli >> 24); - msg[4] = (uint8_t)(tlli >> 16); - msg[5] = (uint8_t)(tlli >> 8); - msg[6] = (uint8_t)(tlli >> 0); - - gsm48_construct_ra(msg + 9, raid); - - send_ns_unitdata(nsi, "BVC_SUSPEND_ACK", src_addr, 0, msg, sizeof(msg)); -} - -static void send_bssgp_llc_discarded(struct gprs_ns_inst *nsi, - struct sockaddr_in *src_addr, - uint16_t bvci, uint32_t tlli, - unsigned n_frames, unsigned n_octets) -{ - /* Base Station Subsystem GPRS Protocol: LLC-DISCARDED (0x2c) */ - unsigned char msg[] = { - 0x2c, 0x1f, 0x84, /* TLLI */ 0xff, 0xff, 0xff, 0xff, 0x0f, - 0x81, /* n frames */ 0xff, 0x04, 0x82, /* BVCI */ 0xff, 0xff, 0x25, 0x83, - /* n octets */ 0xff, 0xff, 0xff - }; - - msg[3] = (uint8_t)(tlli >> 24); - msg[4] = (uint8_t)(tlli >> 16); - msg[5] = (uint8_t)(tlli >> 8); - msg[6] = (uint8_t)(tlli >> 0); - msg[9] = (uint8_t)(n_frames); - msg[12] = (uint8_t)(bvci >> 8); - msg[13] = (uint8_t)(bvci >> 0); - msg[16] = (uint8_t)(n_octets >> 16); - msg[17] = (uint8_t)(n_octets >> 8); - msg[18] = (uint8_t)(n_octets >> 0); - - send_ns_unitdata(nsi, "LLC_DISCARDED", src_addr, 0, msg, sizeof(msg)); -} - -static void send_bssgp_paging(struct gprs_ns_inst *nsi, - struct sockaddr_in *src_addr, - const uint8_t *imsi, size_t imsi_size, - struct gprs_ra_id *raid, uint32_t ptmsi) -{ - /* Base Station Subsystem GPRS Protocol, BSSGP SUSPEND */ - unsigned char msg[100] = { - 0x06, - }; - - const unsigned char drx_ie[] = {0x0a, 0x82, 0x07, 0x04}; - const unsigned char qos_ie[] = {0x18, 0x83, 0x00, 0x00, 0x00}; - - size_t bssgp_msg_size = 1; - - if (imsi) { - OSMO_ASSERT(imsi_size <= 127); - msg[bssgp_msg_size] = BSSGP_IE_IMSI; - msg[bssgp_msg_size + 1] = 0x80 | imsi_size; - memcpy(msg + bssgp_msg_size + 2, imsi, imsi_size); - bssgp_msg_size += 2 + imsi_size; - } - - memcpy(msg + bssgp_msg_size, drx_ie, sizeof(drx_ie)); - bssgp_msg_size += sizeof(drx_ie); - - if (raid) { - msg[bssgp_msg_size] = BSSGP_IE_ROUTEING_AREA; - msg[bssgp_msg_size+1] = 0x86; - gsm48_construct_ra(msg + bssgp_msg_size + 2, raid); - bssgp_msg_size += 8; - } - - memcpy(msg + bssgp_msg_size, qos_ie, sizeof(qos_ie)); - bssgp_msg_size += sizeof(qos_ie); - - if (ptmsi != GSM_RESERVED_TMSI) { - const uint32_t ptmsi_be = htonl(ptmsi); - msg[bssgp_msg_size] = BSSGP_IE_TMSI; - msg[bssgp_msg_size+1] = 0x84; - memcpy(msg + bssgp_msg_size + 2, &ptmsi_be, 4); - bssgp_msg_size += 6; - } - - send_ns_unitdata(nsi, "PAGING_PS", src_addr, 0, msg, bssgp_msg_size); -} - -static void send_bssgp_flow_control_bvc(struct gprs_ns_inst *nsi, - struct sockaddr_in *src_addr, - uint16_t bvci, uint8_t tag) -{ - /* GPRS Network Service, PDU type: NS_UNITDATA, - * BSSGP FLOW_CONTROL_BVC */ - unsigned char msg[] = { - 0x26, 0x1e, 0x81, /* Tag */ 0xff, 0x05, 0x82, 0x01, 0xdc, - 0x03, 0x82, 0x02, 0x76, 0x01, 0x82, 0x00, 0x50, - 0x1c, 0x82, 0x02, 0x58, 0x06, 0x82, 0x00, 0x03 - }; - - msg[3] = tag; - - send_ns_unitdata(nsi, "FLOW_CONTROL_BVC", src_addr, bvci, - msg, sizeof(msg)); -} - -static void send_bssgp_flow_control_bvc_ack(struct gprs_ns_inst *nsi, - struct sockaddr_in *src_addr, - uint16_t bvci, uint8_t tag) -{ - /* GPRS Network Service, PDU type: NS_UNITDATA, - * BSSGP FLOW_CONTROL_BVC_ACK */ - unsigned char msg[] = { - 0x27, 0x1e, 0x81, /* Tag */ 0xce - }; - - msg[3] = tag; - - send_ns_unitdata(nsi, "FLOW_CONTROL_BVC_ACK", src_addr, bvci, - msg, sizeof(msg)); -} - -static void send_llc_ul_ui( - struct gprs_ns_inst *nsi, const char *text, - struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, - struct gprs_ra_id *raid, uint16_t cell_id, - unsigned sapi, unsigned nu, - const uint8_t *msg, size_t msg_size) -{ - unsigned char llc_msg[4096] = { - 0x00, 0xc0, 0x01 - }; - - size_t llc_msg_size = 3 + msg_size + 3; - uint8_t e_bit = 0; - uint8_t pm_bit = 1; - unsigned fcs; - - nu &= 0x01ff; - - OSMO_ASSERT(llc_msg_size <= sizeof(llc_msg)); - - llc_msg[0] = (sapi & 0x0f); - llc_msg[1] = 0xc0 | (nu >> 6); /* UI frame */ - llc_msg[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1); - - memcpy(llc_msg + 3, msg, msg_size); - - fcs = gprs_llc_fcs(llc_msg, msg_size + 3); - llc_msg[3 + msg_size + 0] = (uint8_t)(fcs >> 0); - llc_msg[3 + msg_size + 1] = (uint8_t)(fcs >> 8); - llc_msg[3 + msg_size + 2] = (uint8_t)(fcs >> 16); - - send_bssgp_ul_unitdata(nsi, text ? text : "LLC UI", - src_addr, nsbvci, tlli, raid, cell_id, - llc_msg, llc_msg_size); -} - -static void send_llc_dl_ui( - struct gprs_ns_inst *nsi, const char *text, - struct sockaddr_in *src_addr, uint16_t nsbvci, uint32_t tlli, - int with_racap_drx, const uint8_t *imsi, size_t imsi_size, - unsigned sapi, unsigned nu, - const uint8_t *msg, size_t msg_size) -{ - /* GPRS Network Service, PDU type: NS_UNITDATA */ - /* Base Station Subsystem GPRS Protocol: UL_UNITDATA */ - unsigned char llc_msg[4096] = { - 0x00, 0x00, 0x01 - }; - - size_t llc_msg_size = 3 + msg_size + 3; - uint8_t e_bit = 0; - uint8_t pm_bit = 1; - unsigned fcs; - - nu &= 0x01ff; - - OSMO_ASSERT(llc_msg_size <= sizeof(llc_msg)); - - llc_msg[0] = 0x40 | (sapi & 0x0f); - llc_msg[1] = 0xc0 | (nu >> 6); /* UI frame */ - llc_msg[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1); - - memcpy(llc_msg + 3, msg, msg_size); - - fcs = gprs_llc_fcs(llc_msg, msg_size + 3); - llc_msg[3 + msg_size + 0] = (uint8_t)(fcs >> 0); - llc_msg[3 + msg_size + 1] = (uint8_t)(fcs >> 8); - llc_msg[3 + msg_size + 2] = (uint8_t)(fcs >> 16); - - send_bssgp_dl_unitdata(nsi, text ? text : "LLC UI", - src_addr, nsbvci, tlli, - with_racap_drx, imsi, imsi_size, - llc_msg, llc_msg_size); -} - - -static void setup_ns(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr, - uint16_t nsvci, uint16_t nsei) -{ - printf("Setup NS-VC: remote 0x%08x:%d, " - "NSVCI 0x%04x(%d), NSEI 0x%04x(%d)\n\n", - ntohl(src_addr->sin_addr.s_addr), ntohs(src_addr->sin_port), - nsvci, nsvci, nsei, nsei); - - send_ns_reset(nsi, src_addr, NS_CAUSE_OM_INTERVENTION, nsvci, nsei); - send_ns_alive(nsi, src_addr); - send_ns_unblock(nsi, src_addr); - send_ns_alive_ack(nsi, src_addr); -} - -static void setup_bssgp(struct gprs_ns_inst *nsi, struct sockaddr_in *src_addr, - uint16_t bvci) -{ - printf("Setup BSSGP: remote 0x%08x:%d, " - "BVCI 0x%04x(%d)\n\n", - ntohl(src_addr->sin_addr.s_addr), ntohs(src_addr->sin_port), - bvci, bvci); - - send_bssgp_reset(nsi, src_addr, bvci); -} - -static void connect_sgsn(struct gprs_ns_inst *nsi, struct sockaddr_in *sgsn_peer, - uint32_t sgsn_nsei) -{ - gprs_ns_nsip_connect(nsi, sgsn_peer, sgsn_nsei, sgsn_nsei+1); - send_ns_reset_ack(nsi, sgsn_peer, sgsn_nsei+1, sgsn_nsei); - send_ns_alive_ack(nsi, sgsn_peer); - send_ns_unblock_ack(nsi, sgsn_peer); - send_ns_alive(nsi, sgsn_peer); -} - -static void configure_sgsn_peer(struct sockaddr_in *sgsn_peer) -{ - sgsn_peer->sin_family = AF_INET; - sgsn_peer->sin_port = htons(32000); - sgsn_peer->sin_addr.s_addr = htonl(REMOTE_SGSN_ADDR); -} - -static void configure_sgsn2_peer(struct sockaddr_in *sgsn_peer) -{ - sgsn_peer->sin_family = AF_INET; - sgsn_peer->sin_port = htons(32001); - sgsn_peer->sin_addr.s_addr = htonl(REMOTE_SGSN2_ADDR); -} - -static void configure_bss_peers(struct sockaddr_in *bss_peers, size_t size) -{ - size_t i; - - for (i = 0; i < size; ++i) { - bss_peers[i].sin_family = AF_INET; - bss_peers[i].sin_port = htons((i + 1) * 1111); - bss_peers[i].sin_addr.s_addr = htonl(REMOTE_BSS_ADDR); - } -} - -int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, - struct sockaddr_in *saddr, enum gprs_ns_ll ll); - -/* override */ -int gprs_ns_callback(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, uint16_t bvci) -{ - printf("CALLBACK, event %d, msg length %zu, bvci 0x%04x\n%s\n\n", - event, msgb_bssgp_len(msg), bvci, - osmo_hexdump(msgb_l2(msg), msgb_l2len(msg))); - - switch (event) { - case GPRS_NS_EVT_UNIT_DATA: - return gbprox_rcvmsg(&gbcfg, msg, nsvc->nsei, bvci, nsvc->nsvci); - default: - break; - } - return 0; -} - -/* override */ -ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, - const struct sockaddr *dest_addr, socklen_t addrlen) -{ - typedef ssize_t (*sendto_t)(int, const void *, size_t, int, - const struct sockaddr *, socklen_t); - static sendto_t real_sendto = NULL; - uint32_t dest_host = htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr); - int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port); - - if (!real_sendto) - real_sendto = dlsym(RTLD_NEXT, "sendto"); - - if (dest_host == REMOTE_BSS_ADDR) - printf("MESSAGE to BSS at 0x%08x:%d, msg length %zu\n%s\n\n", - dest_host, dest_port, - len, osmo_hexdump(buf, len)); - else if (dest_host == REMOTE_SGSN_ADDR) - printf("MESSAGE to SGSN at 0x%08x:%d, msg length %zu\n%s\n\n", - dest_host, dest_port, - len, osmo_hexdump(buf, len)); - else if (dest_host == REMOTE_SGSN2_ADDR) - printf("MESSAGE to SGSN 2 at 0x%08x:%d, msg length %zu\n%s\n\n", - dest_host, dest_port, - len, osmo_hexdump(buf, len)); - else - return real_sendto(sockfd, buf, len, flags, dest_addr, addrlen); - - return len; -} - -/* override */ -int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) -{ - typedef int (*gprs_ns_sendmsg_t)(struct gprs_ns_inst *nsi, struct msgb *msg); - static gprs_ns_sendmsg_t real_gprs_ns_sendmsg = NULL; - uint16_t bvci = msgb_bvci(msg); - uint16_t nsei = msgb_nsei(msg); - - size_t len = msgb_length(msg); - - if (!real_gprs_ns_sendmsg) - real_gprs_ns_sendmsg = dlsym(RTLD_NEXT, "gprs_ns_sendmsg"); - - if (nsei == SGSN_NSEI) - printf("NS UNITDATA MESSAGE to SGSN, BVCI 0x%04x, " - "msg length %zu (%s)\n", - bvci, len, __func__); - else if (nsei == SGSN2_NSEI) - printf("NS UNITDATA MESSAGE to SGSN 2, BVCI 0x%04x, " - "msg length %zu (%s)\n", - bvci, len, __func__); - else - printf("NS UNITDATA MESSAGE to BSS, BVCI 0x%04x, " - "msg length %zu (%s)\n", - bvci, len, __func__); - - if (received_messages) { - struct msgb *msg_copy; - msg_copy = gprs_msgb_copy(msg, "received_messages"); - llist_add_tail(&msg_copy->list, received_messages); - } - - return real_gprs_ns_sendmsg(nsi, msg); -} - -/* Get the next message from the receive FIFO - * - * \returns a pointer to the message which will be invalidated at the next call - * to expect_msg. Returns NULL, if there is no message left. - */ -static struct msgb *expect_msg(void) -{ - static struct msgb *msg = NULL; - - msgb_free(msg); - msg = NULL; - - if (!received_messages) - return NULL; - - if (llist_empty(received_messages)) - return NULL; - - msg = llist_entry(received_messages->next, struct msgb, list); - llist_del(&msg->list); - - return msg; -} - -struct expect_result { - struct msgb *msg; - struct gprs_gb_parse_context parse_ctx; -}; - -static struct expect_result *expect_bssgp_msg( - int match_nsei, int match_bvci, int match_pdu_type) -{ - static struct expect_result result; - static const struct expect_result empty_result = {0,}; - static struct msgb *msg; - uint16_t nsei; - int rc; - - memcpy(&result, &empty_result, sizeof(result)); - - msg = expect_msg(); - if (!msg) - return NULL; - - nsei = msgb_nsei(msg); - - if (match_nsei != MATCH_ANY && match_nsei != nsei) { - fprintf(stderr, "%s: NSEI mismatch (expected %u, got %u)\n", - __func__, match_nsei, nsei); - return NULL; - } - - if (match_bvci != MATCH_ANY && match_bvci != msgb_bvci(msg)) { - fprintf(stderr, "%s: BVCI mismatch (expected %u, got %u)\n", - __func__, match_bvci, msgb_bvci(msg)); - return NULL; - } - - result.msg = msg; - - result.parse_ctx.to_bss = nsei != SGSN_NSEI && nsei != SGSN2_NSEI; - result.parse_ctx.peer_nsei = nsei; - - if (!msgb_bssgph(msg)) { - fprintf(stderr, "%s: Expected BSSGP\n", __func__); - return NULL; - } - - rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg), - &result.parse_ctx); - - if (!rc) { - fprintf(stderr, "%s: Failed to parse message\n", __func__); - return NULL; - } - - if (match_pdu_type != MATCH_ANY && - match_pdu_type != result.parse_ctx.pdu_type) { - fprintf(stderr, "%s: PDU type mismatch (expected %u, got %u)\n", - __func__, match_pdu_type, result.parse_ctx.pdu_type); - return NULL; - } - - return &result; -} - -static struct expect_result *expect_llc_msg( - int match_nsei, int match_bvci, int match_sapi, int match_type) -{ - static struct expect_result *result; - - result = expect_bssgp_msg(match_nsei, match_bvci, MATCH_ANY); - if (!result) - return NULL; - - if (!result->parse_ctx.llc) { - fprintf(stderr, "%s: Expected LLC message\n", __func__); - return NULL; - } - - if (match_sapi != MATCH_ANY && - match_sapi != result->parse_ctx.llc_hdr_parsed.sapi) { - fprintf(stderr, "%s: LLC SAPI mismatch (expected %u, got %u)\n", - __func__, match_sapi, result->parse_ctx.llc_hdr_parsed.sapi); - return NULL; - } - - if (match_type != MATCH_ANY && - match_type != result->parse_ctx.llc_hdr_parsed.cmd) { - fprintf(stderr, - "%s: LLC command/type mismatch (expected %u, got %u)\n", - __func__, match_type, result->parse_ctx.llc_hdr_parsed.cmd); - return NULL; - } - - return result; -} - -static struct expect_result *expect_gmm_msg(int match_nsei, int match_bvci, - int match_type) -{ - static struct expect_result *result; - - result = expect_llc_msg(match_nsei, match_bvci, GPRS_SAPI_GMM, GPRS_LLC_UI); - if (!result) - return NULL; - - if (!result->parse_ctx.g48_hdr) { - fprintf(stderr, "%s: Expected GSM 04.08 message\n", __func__); - return NULL; - } - - if (match_type != MATCH_ANY && - match_type != result->parse_ctx.g48_hdr->msg_type) { - fprintf(stderr, - "%s: GSM 04.08 message type mismatch (expected %u, got %u)\n", - __func__, match_type, result->parse_ctx.g48_hdr->msg_type); - return NULL; - } - - return result; -} - -static void dump_rate_ctr_group(FILE *stream, const char *prefix, - struct rate_ctr_group *ctrg) -{ - unsigned int i; - - for (i = 0; i < ctrg->desc->num_ctr; i++) { - struct rate_ctr *ctr = &ctrg->ctr[i]; - if (ctr->current && !strchr(ctrg->desc->ctr_desc[i].name, '.')) - fprintf(stream, " %s%s: %llu%s", - prefix, ctrg->desc->ctr_desc[i].description, - (long long)ctr->current, - "\n"); - }; -} - -/* Signal handler for signals from NS layer */ -static int test_signal(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct ns_signal_data *nssd = signal_data; - int rc; - - if (subsys != SS_L_NS) - return 0; - - switch (signal) { - case S_NS_RESET: - printf("==> got signal NS_RESET, NS-VC 0x%04x/%s\n", - nssd->nsvc->nsvci, - gprs_ns_ll_str(nssd->nsvc)); - break; - - case S_NS_ALIVE_EXP: - printf("==> got signal NS_ALIVE_EXP, NS-VC 0x%04x/%s\n", - nssd->nsvc->nsvci, - gprs_ns_ll_str(nssd->nsvc)); - break; - - case S_NS_BLOCK: - printf("==> got signal NS_BLOCK, NS-VC 0x%04x/%s\n", - nssd->nsvc->nsvci, - gprs_ns_ll_str(nssd->nsvc)); - break; - - case S_NS_UNBLOCK: - printf("==> got signal NS_UNBLOCK, NS-VC 0x%04x/%s\n", - nssd->nsvc->nsvci, - gprs_ns_ll_str(nssd->nsvc)); - break; - - case S_NS_REPLACED: - printf("==> got signal NS_REPLACED: 0x%04x/%s", - nssd->nsvc->nsvci, - gprs_ns_ll_str(nssd->nsvc)); - printf(" -> 0x%04x/%s\n", - nssd->old_nsvc->nsvci, - gprs_ns_ll_str(nssd->old_nsvc)); - break; - - default: - printf("==> got signal %d, NS-VC 0x%04x/%s\n", signal, - nssd->nsvc->nsvci, - gprs_ns_ll_str(nssd->nsvc)); - break; - } - printf("\n"); - rc = gbprox_signal(subsys, signal, handler_data, signal_data); - return rc; -} - -static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text, struct sockaddr_in *peer, const unsigned char* data, size_t data_len) -{ - struct msgb *msg; - int ret; - if (data_len > NS_ALLOC_SIZE - NS_ALLOC_HEADROOM) { - fprintf(stderr, "message too long: %zu\n", data_len); - return -1; - } - - msg = gprs_ns_msgb_alloc(); - OSMO_ASSERT(msg); - memmove(msg->data, data, data_len); - msg->l2h = msg->data; - msgb_put(msg, data_len); - - printf("PROCESSING %s from 0x%08x:%d\n%s\n\n", - text, ntohl(peer->sin_addr.s_addr), ntohs(peer->sin_port), - osmo_hexdump(data, data_len)); - - ret = gprs_ns_rcvmsg(nsi, msg, peer, GPRS_NS_LL_UDP); - - printf("result (%s) = %d\n\n", text, ret); - - msgb_free(msg); - - return ret; -} - -static void gprs_dump_nsi(struct gprs_ns_inst *nsi) -{ - struct gprs_nsvc *nsvc; - - printf("Current NS-VCIs:\n"); - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - struct sockaddr_in *peer = &(nsvc->ip.bts_addr); - printf(" VCI 0x%04x, NSEI 0x%04x, peer 0x%08x:%d%s%s\n", - nsvc->nsvci, nsvc->nsei, - ntohl(peer->sin_addr.s_addr), ntohs(peer->sin_port), - nsvc->state & NSE_S_BLOCKED ? ", blocked" : "", - nsvc->state & NSE_S_ALIVE ? "" : ", dead" - ); - dump_rate_ctr_group(stdout, " ", nsvc->ctrg); - } - printf("\n"); -} - -static void test_gbproxy() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[4] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - gprs_dump_nsi(nsi); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - printf("--- Initialise BSS 2 ---\n\n"); - - setup_ns(nsi, &bss_peer[1], 0x2001, 0x2000); - setup_bssgp(nsi, &bss_peer[1], 0x2002); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x2002); - - printf("--- Move BSS 1 to new port ---\n\n"); - - setup_ns(nsi, &bss_peer[2], 0x1001, 0x1000); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Move BSS 2 to former BSS 1 port ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x2001, 0x2000); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Move BSS 1 to current BSS 2 port ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x2001, 0x2000); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Move BSS 2 to new port ---\n\n"); - - setup_ns(nsi, &bss_peer[3], 0x2001, 0x2000); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Move BSS 2 to former BSS 1 port ---\n\n"); - - setup_ns(nsi, &bss_peer[2], 0x2001, 0x2000); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Move BSS 1 to original BSS 1 port ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Reset BSS 1 with a new BVCI ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], 0x1012); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1012); - - printf("--- Reset BSS 1 with the old BVCI ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], 0x1002); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - printf("--- Reset BSS 1 with the old BVCI again ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], 0x1002); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1012 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], 0x1012, (uint8_t *)"", 0); - - printf("--- Send message from SGSN to BSS 1, BVCI 0x1012 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &sgsn_peer, 0x1012, (uint8_t *)"", 0); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], 0x1012, (uint8_t *)"", 0); - - printf("--- Send message from SGSN to BSS 1, BVCI 0x1002 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &sgsn_peer, 0x1012, (uint8_t *)"", 0); - - printf("--- Send message from BSS 2 to SGSN, BVCI 0x2002 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], 0x2002, (uint8_t *)"", 0); - - printf("--- Send message from SGSN to BSS 2, BVCI 0x2002 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &sgsn_peer, 0x2002, (uint8_t *)"", 0); - - printf("--- Reset BSS 1 with the old BVCI on BSS2's link ---\n\n"); - - setup_bssgp(nsi, &bss_peer[2], 0x1002); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - dump_global(stdout, 0); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], 0x1012, (uint8_t *)"", 0); - - printf("--- Send message from SGSN to BSS 1, BVCI 0x1002 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &sgsn_peer, 0x1012, (uint8_t *)"", 0); - - printf("--- Send message from SGSN to BSS 1, BVCI 0x10ff (invalid) ---\n\n"); - - send_ns_unitdata(nsi, NULL, &sgsn_peer, 0x10ff, (uint8_t *)"", 0); - - /* Find peer */ - OSMO_ASSERT(gbproxy_peer_by_bvci(&gbcfg, 0xeeee) == NULL); - OSMO_ASSERT(gbproxy_peer_by_bvci(&gbcfg, 0x1000) == NULL); - OSMO_ASSERT(gbproxy_peer_by_bvci(&gbcfg, 0x1012) != NULL); - OSMO_ASSERT(gbproxy_peer_by_nsei(&gbcfg, 0xeeee) == NULL); - OSMO_ASSERT(gbproxy_peer_by_nsei(&gbcfg, 0x1012) == NULL); - OSMO_ASSERT(gbproxy_peer_by_nsei(&gbcfg, 0x1000) != NULL); - - - /* Cleanup */ - OSMO_ASSERT(gbproxy_cleanup_peers(&gbcfg, 0, 0) == 0); - OSMO_ASSERT(gbproxy_cleanup_peers(&gbcfg, 0x1000, 0xeeee) == 0); - OSMO_ASSERT(gbproxy_cleanup_peers(&gbcfg, 0, 0x1002) == 0); - OSMO_ASSERT(gbproxy_cleanup_peers(&gbcfg, 0x1000, 0x1012) == 1); - OSMO_ASSERT(gbproxy_cleanup_peers(&gbcfg, 0x1000, 0x1012) == 0); - - dump_peers(stdout, 0, 0, &gbcfg); - - dump_global(stdout, 0); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; -} - -static void test_gbproxy_ident_changes() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - uint16_t nsei[2] = {0x1000, 0x2000}; - uint16_t nsvci[2] = {0x1001, 0x2001}; - uint16_t bvci[4] = {0x1002, 0x2002, 0x3002, 0x4002}; - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - gprs_dump_nsi(nsi); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], nsvci[0], nsei[0]); - gprs_dump_nsi(nsi); - - printf("--- Setup BVCI 1 ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], bvci[0]); - send_bssgp_reset_ack(nsi, &sgsn_peer, bvci[0]); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Setup BVCI 2 ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], bvci[1]); - send_bssgp_reset_ack(nsi, &sgsn_peer, bvci[1]); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 1 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[0], (uint8_t *)"", 0); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[0], (uint8_t *)"", 0); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 2 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[1], (uint8_t *)"", 0); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[1], (uint8_t *)"", 0); - - printf("--- Change NSEI ---\n\n"); - - setup_ns(nsi, &bss_peer[0], nsvci[0], nsei[1]); - gprs_dump_nsi(nsi); - - printf("--- Setup BVCI 1 ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], bvci[0]); - send_bssgp_reset_ack(nsi, &sgsn_peer, bvci[0]); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Setup BVCI 3 ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], bvci[2]); - send_bssgp_reset_ack(nsi, &sgsn_peer, bvci[2]); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 1 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[0], (uint8_t *)"", 0); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[0], (uint8_t *)"", 0); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 2 " - " (should fail) ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[1], (uint8_t *)"", 0); - dump_peers(stdout, 0, 0, &gbcfg); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[1], (uint8_t *)"", 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 3 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[2], (uint8_t *)"", 0); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[2], (uint8_t *)"", 0); - - printf("--- Change NSVCI ---\n\n"); - - setup_ns(nsi, &bss_peer[0], nsvci[1], nsei[1]); - gprs_dump_nsi(nsi); - - printf("--- Setup BVCI 1 ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], bvci[0]); - send_bssgp_reset_ack(nsi, &sgsn_peer, bvci[0]); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Setup BVCI 4 ---\n\n"); - - setup_bssgp(nsi, &bss_peer[0], bvci[3]); - send_bssgp_reset_ack(nsi, &sgsn_peer, bvci[3]); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 1 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[0], (uint8_t *)"", 0); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[0], (uint8_t *)"", 0); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 2 " - " (should fail) ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[1], (uint8_t *)"", 0); - dump_peers(stdout, 0, 0, &gbcfg); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[1], (uint8_t *)"", 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 3 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[2], (uint8_t *)"", 0); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[2], (uint8_t *)"", 0); - - printf("--- Send message from BSS 1 to SGSN and back, BVCI 4 ---\n\n"); - - send_ns_unitdata(nsi, NULL, &bss_peer[0], bvci[3], (uint8_t *)"", 0); - send_ns_unitdata(nsi, NULL, &sgsn_peer, bvci[3], (uint8_t *)"", 0); - - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; -} - -static void test_gbproxy_ra_patching() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_sgsn = - {.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_unknown = - {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; - uint16_t cell_id = 0x7530; - const char *err_msg = NULL; - const uint32_t ptmsi = 0xefe2b700; - const uint32_t local_tlli = 0xefe2b700; - const uint32_t foreign_tlli = 0xbbc54679; - const uint32_t foreign_tlli2 = 0xbb00beef; - const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - const char *patch_re = "^9898|^121314"; - struct gbproxy_link_info *link_info; - struct gbproxy_peer *peer; - LLIST_HEAD(rcv_list); - struct expect_result *expect_res; - - OSMO_ASSERT(local_tlli == gprs_tmsi2tlli(ptmsi, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.core_mcc = 123; - gbcfg.core_mnc = 456; - gbcfg.core_apn = talloc_zero_size(NULL, 100); - gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); - gbcfg.patch_ptmsi = 0; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - if (gbproxy_set_patch_filter(&gbcfg.matches[GBPROX_MATCH_PATCHING], - patch_re, &err_msg) != 0) { - fprintf(stderr, "Failed to compile RE '%s': %s\n", - patch_re, err_msg); - exit(1); - } - - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - gprs_dump_nsi(nsi); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - - received_messages = &rcv_list; - - setup_bssgp(nsi, &bss_peer[0], 0x1002); - gprs_dump_nsi(nsi); - dump_peers(stdout, 0, 0, &gbcfg); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - OSMO_ASSERT(expect_bssgp_msg(SGSN_NSEI, 0, BSSGP_PDUT_BVC_RESET)); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - OSMO_ASSERT(expect_bssgp_msg(0x1000, 0, BSSGP_PDUT_BVC_RESET_ACK)); - - send_bssgp_suspend(nsi, &bss_peer[0], 0xccd1758b, &rai_bss); - - OSMO_ASSERT(expect_bssgp_msg(SGSN_NSEI, 0, BSSGP_PDUT_SUSPEND)); - - send_bssgp_suspend_ack(nsi, &sgsn_peer, 0xccd1758b, &rai_sgsn); - - OSMO_ASSERT(expect_bssgp_msg(0x1000, 0, BSSGP_PDUT_SUSPEND_ACK)); - - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(2 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - OSMO_ASSERT(1 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_SGSN].current); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 0, - dtap_attach_req, sizeof(dtap_attach_req)); - - OSMO_ASSERT(4 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - foreign_tlli, 0, NULL, 0, - GPRS_SAPI_GMM, 0, - dtap_identity_req, sizeof(dtap_identity_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ID_REQ)); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 3, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ID_RESP)); - - OSMO_ASSERT(5 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - OSMO_ASSERT(1 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_SGSN].current); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, 1, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - OSMO_ASSERT(2 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_SGSN].current); - - OSMO_ASSERT(gbproxy_peer_by_rai(&gbcfg, convert_ra(&rai_bss)) != NULL); - OSMO_ASSERT(gbproxy_peer_by_rai(&gbcfg, convert_ra(&rai_sgsn)) == NULL); - OSMO_ASSERT(gbproxy_peer_by_rai(&gbcfg, convert_ra(&rai_unknown)) == NULL); - - OSMO_ASSERT(gbproxy_peer_by_lai(&gbcfg, convert_ra(&rai_bss)) != NULL); - OSMO_ASSERT(gbproxy_peer_by_lai(&gbcfg, convert_ra(&rai_sgsn)) == NULL); - OSMO_ASSERT(gbproxy_peer_by_lai(&gbcfg, convert_ra(&rai_unknown)) == NULL); - - OSMO_ASSERT(gbproxy_peer_by_lac(&gbcfg, convert_ra(&rai_bss)) != NULL); - OSMO_ASSERT(gbproxy_peer_by_lac(&gbcfg, convert_ra(&rai_sgsn)) != NULL); - OSMO_ASSERT(gbproxy_peer_by_lac(&gbcfg, convert_ra(&rai_unknown)) == NULL); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->tlli.current != local_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current != local_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 4, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - OSMO_ASSERT(6 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->tlli.current != local_tlli); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current != local_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - /* Replace APN (1) */ - send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 3, - dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GSM_ACT_PDP_REQ)); - - OSMO_ASSERT(7 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->tlli.current != local_tlli); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current != local_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, 2, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_INFO)); - - OSMO_ASSERT(2 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_SGSN].current); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->tlli.current == local_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_tlli); - - /* Replace APN (2) */ - send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 3, - dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - - expect_res = expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GSM_ACT_PDP_REQ); - OSMO_ASSERT(expect_res != NULL); - OSMO_ASSERT(expect_res->parse_ctx.apn_ie_len == gbcfg.core_apn_size + 2); - - OSMO_ASSERT(8 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - gbcfg.core_apn[0] = 0; - gbcfg.core_apn_size = 0; - - /* Remove APN */ - send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REMOVE APN)", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 3, - dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - - expect_res = expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GSM_ACT_PDP_REQ); - OSMO_ASSERT(expect_res != NULL); - OSMO_ASSERT(expect_res->parse_ctx.apn_ie_len == 0); - - OSMO_ASSERT(9 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach */ - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 6, - dtap_detach_req, sizeof(dtap_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - OSMO_ASSERT(10 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - OSMO_ASSERT(2 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_SGSN].current); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, 5, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- RA update ---\n\n"); - - send_llc_ul_ui(nsi, "RA UPD REQ", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, 0x7080, - GPRS_SAPI_GMM, 5, - dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_RA_UPD_REQ)); - - OSMO_ASSERT(12 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - send_llc_dl_ui(nsi, "RA UPD ACC", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, 6, - dtap_ra_upd_acc, sizeof(dtap_ra_upd_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_RA_UPD_ACK)); - - OSMO_ASSERT(3 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_SGSN].current); - - /* Remove APN */ - send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REMOVE APN)", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 3, - dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - - expect_res = expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GSM_ACT_PDP_REQ); - OSMO_ASSERT(expect_res != NULL); - OSMO_ASSERT(expect_res->parse_ctx.apn_ie_len == 0); - - OSMO_ASSERT(13 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (power off -> no Detach Accept) */ - send_llc_ul_ui(nsi, "DETACH REQ (PWR OFF)", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 6, - dtap_detach_po_req, sizeof(dtap_detach_po_req)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - OSMO_ASSERT(14 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Bad cases ---\n\n"); - - /* The RAI in the Attach Request message differs from the RAI in the - * BSSGP message, only patch the latter */ - - send_llc_ul_ui(nsi, "ATTACH REQUEST (foreign RAI)", &bss_peer[0], 0x1002, - foreign_tlli2, &rai_bss, cell_id, - GPRS_SAPI_GMM, 0, - dtap_attach_req2, sizeof(dtap_attach_req2)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - OSMO_ASSERT(15 == peer->ctrg->ctr[GBPROX_PEER_CTR_RAID_PATCHED_BSS].current); - - printf("TLLI is already detached, shouldn't patch\n"); - send_llc_ul_ui(nsi, "ACT PDP CTX REQ", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, 3, - dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GSM_ACT_PDP_REQ)); - - printf("Invalid RAI, shouldn't patch\n"); - send_bssgp_suspend_ack(nsi, &sgsn_peer, 0xccd1758b, &rai_unknown); - - /* TODO: The following breaks with the current libosmocore, enable it - * again (and remove the plain expect_msg), when the msgb_bssgph patch - * is integrated */ - /* OSMO_ASSERT(expect_bssgp_msg(SGSN_NSEI, 0, BSSGP_PDUT_STATUS)); */ - OSMO_ASSERT(expect_msg()); - - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!expect_msg()); - received_messages = NULL; - - gbproxy_clear_patch_filter(&gbcfg.matches[GBPROX_MATCH_PATCHING]); - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; -} - -static void test_gbproxy_ptmsi_assignment() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_unknown = - {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; - uint16_t cell_id = 0x1234; - - const uint32_t ptmsi = 0xefe2b700; - const uint32_t local_tlli = 0xefe2b700; - - const uint32_t foreign_tlli1 = 0x8000dead; - const uint32_t foreign_tlli2 = 0x8000beef; - - const uint8_t imsi1[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - const uint8_t imsi2[] = {0x11, 0x12, 0x99, 0x99, 0x99, 0x16, 0x17, 0x18}; - - struct gbproxy_link_info *link_info, *link_info2; - struct gbproxy_peer *peer; - unsigned bss_nu = 0; - unsigned sgsn_nu = 0; - - OSMO_ASSERT(local_tlli == gprs_tmsi2tlli(ptmsi, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.core_mcc = 0; - gbcfg.core_mnc = 0; - gbcfg.core_apn = talloc_zero_size(NULL, 100); - gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); - gbcfg.patch_ptmsi = 0; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - gprs_dump_nsi(nsi); - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Establish first LLC connection ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli1, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - foreign_tlli1, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli1, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli1, 1, imsi1, sizeof(imsi1), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli1); - link_info2 = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_tlli1); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_tlli1); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_tlli, 1, imsi1, sizeof(imsi1), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_imsi(peer, imsi1, ARRAY_SIZE(imsi1)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - OSMO_ASSERT(!gbproxy_link_info_by_imsi(peer, imsi2, ARRAY_SIZE(imsi2))); - - link_info2 = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->tlli.current == local_tlli); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - - printf("--- Establish second LLC connection with the same P-TMSI ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli2, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - foreign_tlli2, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli2, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity2_resp, sizeof(dtap_identity2_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli2, 1, imsi2, sizeof(imsi2), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli2); - link_info2 = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_tlli2); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_tlli2); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_tlli, 1, imsi2, sizeof(imsi2), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_imsi(peer, imsi2, ARRAY_SIZE(imsi2)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - OSMO_ASSERT(!gbproxy_link_info_by_imsi(peer, imsi1, ARRAY_SIZE(imsi1))); - - link_info2 = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->tlli.current == local_tlli); - OSMO_ASSERT(link_info->tlli.ptmsi == ptmsi); - - dump_global(stdout, 0); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; - - cleanup_test(); -} - -static void test_gbproxy_ptmsi_patching() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_sgsn = - {.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_wrong_mcc_sgsn = - {.mcc = 999, .mnc = 456, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_unknown = - {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; - uint16_t cell_id = 0x1234; - - const uint32_t sgsn_ptmsi = 0xefe2b700; - const uint32_t sgsn_ptmsi2 = 0xe0987654; - const uint32_t sgsn_ptmsi3 = 0xe0543210; - const uint32_t local_sgsn_tlli = 0xefe2b700; - const uint32_t local_sgsn_tlli2 = 0xe0987654; - const uint32_t local_sgsn_tlli3 = 0xe0543210; - const uint32_t random_sgsn_tlli = 0x78dead00; - const uint32_t unknown_sgsn_tlli = 0xeebadbad; - - const uint32_t bss_ptmsi = 0xc0dead01; - const uint32_t bss_ptmsi2 = 0xc0dead02; - const uint32_t bss_ptmsi3 = 0xc0dead03; - const uint32_t local_bss_tlli = 0xc0dead01; - const uint32_t local_bss_tlli2 = 0xc0dead02; - const uint32_t local_bss_tlli3 = 0xc0dead03; - const uint32_t foreign_bss_tlli = 0x8000dead; - - - const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - struct gbproxy_link_info *link_info; - struct gbproxy_peer *peer; - unsigned bss_nu = 0; - unsigned sgsn_nu = 0; - int old_ctr; - - OSMO_ASSERT(local_sgsn_tlli == gprs_tmsi2tlli(sgsn_ptmsi, TLLI_LOCAL)); - OSMO_ASSERT(local_sgsn_tlli2 == gprs_tmsi2tlli(sgsn_ptmsi2, TLLI_LOCAL)); - OSMO_ASSERT(local_sgsn_tlli3 == gprs_tmsi2tlli(sgsn_ptmsi3, TLLI_LOCAL)); - OSMO_ASSERT(local_bss_tlli == gprs_tmsi2tlli(bss_ptmsi, TLLI_LOCAL)); - OSMO_ASSERT(local_bss_tlli2 == gprs_tmsi2tlli(bss_ptmsi2, TLLI_LOCAL)); - OSMO_ASSERT(local_bss_tlli3 == gprs_tmsi2tlli(bss_ptmsi3, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.core_mcc = 123; - gbcfg.core_mnc = 456; - gbcfg.core_apn = talloc_zero_size(NULL, 100); - gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); - gbcfg.patch_ptmsi = 1; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - gprs_dump_nsi(nsi); - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - random_sgsn_tlli, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - random_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - send_llc_ul_ui(nsi, "ACT PDP CTX REQ (REPLACE APN)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_act_pdp_ctx_req, sizeof(dtap_act_pdp_ctx_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Non-DTAP */ - send_bssgp_ul_unitdata(nsi, "XID (UL)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - llc_u_xid_ul, sizeof(llc_u_xid_ul)); - - send_bssgp_dl_unitdata(nsi, "XID (DL)", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - llc_u_xid_dl, sizeof(llc_u_xid_dl)); - - send_bssgp_ul_unitdata(nsi, "LL11 DNS QUERY (UL)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - llc_ui_ll11_dns_query_ul, - sizeof(llc_ui_ll11_dns_query_ul)); - - send_bssgp_dl_unitdata(nsi, "LL11 DNS RESP (DL)", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - llc_ui_ll11_dns_resp_dl, - sizeof(llc_ui_ll11_dns_resp_dl)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Repeated RA Update Requests */ - send_llc_ul_ui(nsi, "RA UPD REQ (P-TMSI 2)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, 0x7080, - GPRS_SAPI_GMM, bss_nu++, - dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - - send_llc_dl_ui(nsi, "RA UDP ACC (P-TMSI 2)", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_ra_upd_acc2, sizeof(dtap_ra_upd_acc2)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli2, SGSN_NSEI) != NULL); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli2); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi2); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli2); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi2); - - send_llc_ul_ui(nsi, "RA UPD REQ (P-TMSI 3)", &bss_peer[0], 0x1002, - local_bss_tlli2, &rai_bss, 0x7080, - GPRS_SAPI_GMM, bss_nu++, - dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - - send_llc_dl_ui(nsi, "RA UDP ACC (P-TMSI 3)", &sgsn_peer, 0x1002, - local_sgsn_tlli2, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_ra_upd_acc3, sizeof(dtap_ra_upd_acc3)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli2, SGSN_NSEI) == NULL); - OSMO_ASSERT(gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli3, SGSN_NSEI) != NULL); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli3); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi3); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli3); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi3); - - send_llc_ul_ui(nsi, "RA UPD COMPLETE", &bss_peer[0], 0x1002, - local_bss_tlli3, &rai_bss, 0x7080, - GPRS_SAPI_GMM, bss_nu++, - dtap_ra_upd_complete, sizeof(dtap_ra_upd_complete)); - - link_info = gbproxy_link_info_by_tlli(peer, local_bss_tlli3); - - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_sgsn_tlli3, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli3, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli3); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli3); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - /* Other messages */ - send_bssgp_llc_discarded(nsi, &bss_peer[0], 0x1002, - local_bss_tlli3, 1, 12); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend(nsi, &bss_peer[0], local_bss_tlli3, &rai_bss); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend_ack(nsi, &sgsn_peer, local_sgsn_tlli3, &rai_sgsn); - - dump_peers(stdout, 0, 0, &gbcfg); - - old_ctr = peer->ctrg->ctr[GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN].current; - - send_bssgp_paging(nsi, &sgsn_peer, imsi, sizeof(imsi), &rai_bss, sgsn_ptmsi3); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(old_ctr + 1 == - peer->ctrg->ctr[GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN].current); - - /* Bad case: Invalid BVCI */ - send_bssgp_llc_discarded(nsi, &bss_peer[0], 0xeee1, - local_bss_tlli3, 1, 12); - dump_global(stdout, 0); - - /* Bad case: Invalid RAI */ - send_bssgp_suspend_ack(nsi, &sgsn_peer, local_sgsn_tlli3, &rai_unknown); - - dump_global(stdout, 0); - - /* Bad case: Invalid MCC (LAC ok) */ - send_bssgp_suspend_ack(nsi, &sgsn_peer, local_sgsn_tlli3, - &rai_wrong_mcc_sgsn); - - dump_global(stdout, 0); - - /* Bad case: Invalid TLLI from SGSN (IMSI unknown) */ - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - unknown_sgsn_tlli, 1, NULL, 0, - GPRS_SAPI_GMM, 2, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - /* Bad case: Invalid TLLI from SGSN (IMSI known) */ - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - unknown_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, 3, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - /* Detach */ - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_bss_tlli3, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - local_sgsn_tlli3, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - dump_global(stdout, 0); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; - - cleanup_test(); -} - -static void test_gbproxy_ptmsi_patching_bad_cases() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_unknown = - {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; - uint16_t cell_id = 0x1234; - - const uint32_t sgsn_ptmsi = 0xefe2b700; - const uint32_t local_sgsn_tlli = 0xefe2b700; - const uint32_t random_sgsn_tlli = 0x78dead00; - - const uint32_t bss_ptmsi = 0xc0dead01; - const uint32_t local_bss_tlli = 0xc0dead01; - const uint32_t foreign_bss_tlli = 0x8000dead; - - - const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - struct gbproxy_link_info *link_info; - struct gbproxy_peer *peer; - unsigned bss_nu = 0; - unsigned sgsn_nu = 0; - - OSMO_ASSERT(local_sgsn_tlli == gprs_tmsi2tlli(sgsn_ptmsi, TLLI_LOCAL)); - OSMO_ASSERT(local_bss_tlli == gprs_tmsi2tlli(bss_ptmsi, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.core_mcc = 123; - gbcfg.core_mnc = 456; - gbcfg.core_apn = talloc_zero_size(NULL, 100); - gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); - gbcfg.patch_ptmsi = 1; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - gprs_dump_nsi(nsi); - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - random_sgsn_tlli, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - random_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT (duplicated)", &sgsn_peer, 0x1002, - random_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - /* Detach */ - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - dump_global(stdout, 0); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; - - cleanup_test(); -} - - -static void test_gbproxy_imsi_acquisition() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_sgsn = - {.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_wrong_mcc_sgsn = - {.mcc = 999, .mnc = 456, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_unknown = - {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; - uint16_t cell_id = 0x1234; - - const uint32_t sgsn_ptmsi = 0xefe2b700; - const uint32_t local_sgsn_tlli = 0xefe2b700; - const uint32_t random_sgsn_tlli = 0x78dead00; - const uint32_t random_sgsn_tlli2 = 0x78dead02; - - const uint32_t bss_ptmsi = 0xc0dead01; - const uint32_t local_bss_tlli = 0xc0dead01; - const uint32_t foreign_bss_tlli = 0x8000dead; - const uint32_t other_bss_tlli = 0x8000beef; - - const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - struct gbproxy_link_info *link_info; - struct gbproxy_peer *peer; - unsigned bss_nu = 0; - unsigned sgsn_nu = 0; - - OSMO_ASSERT(local_sgsn_tlli == gprs_tmsi2tlli(sgsn_ptmsi, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.core_mcc = 123; - gbcfg.core_mnc = 456; - gbcfg.core_apn = talloc_zero_size(NULL, 100); - gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); - gbcfg.patch_ptmsi = 1; - gbcfg.acquire_imsi = 1; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - gprs_dump_nsi(nsi); - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - random_sgsn_tlli, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - random_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - /* Non-DTAP */ - send_bssgp_ul_unitdata(nsi, "XID (UL)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - llc_u_xid_ul, sizeof(llc_u_xid_ul)); - - send_bssgp_dl_unitdata(nsi, "XID (DL)", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - llc_u_xid_dl, sizeof(llc_u_xid_dl)); - - send_bssgp_ul_unitdata(nsi, "LL11 DNS QUERY (UL)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - llc_ui_ll11_dns_query_ul, - sizeof(llc_ui_ll11_dns_query_ul)); - - send_bssgp_dl_unitdata(nsi, "LL11 DNS RESP (DL)", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - llc_ui_ll11_dns_resp_dl, - sizeof(llc_ui_ll11_dns_resp_dl)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Other messages */ - send_bssgp_llc_discarded(nsi, &bss_peer[0], 0x1002, - local_bss_tlli, 1, 12); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_llc_discarded(nsi, &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, 12); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend(nsi, &bss_peer[0], local_bss_tlli, &rai_bss); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend_ack(nsi, &sgsn_peer, local_sgsn_tlli, &rai_sgsn); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Bad case: Invalid BVCI */ - send_bssgp_llc_discarded(nsi, &bss_peer[0], 0xeee1, - local_bss_tlli, 1, 12); - dump_global(stdout, 0); - - /* Bad case: Invalid RAI */ - send_bssgp_suspend_ack(nsi, &sgsn_peer, local_sgsn_tlli, &rai_unknown); - - dump_global(stdout, 0); - - /* Bad case: Invalid MCC (LAC ok) */ - send_bssgp_suspend_ack(nsi, &sgsn_peer, local_sgsn_tlli, - &rai_wrong_mcc_sgsn); - - dump_global(stdout, 0); - - /* Detach */ - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* RA Update request */ - - send_llc_ul_ui(nsi, "RA UPD REQ", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, 0x7080, - GPRS_SAPI_GMM, bss_nu++, - dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "RA UDP ACC", &sgsn_peer, 0x1002, - random_sgsn_tlli2, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_ra_upd_acc, sizeof(dtap_ra_upd_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach */ - - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - local_sgsn_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Special case: Repeated Attach Requests */ - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Special case: Detach from an unknown TLLI */ - - send_llc_ul_ui(nsi, "DETACH REQ (unknown TLLI)", &bss_peer[0], 0x1002, - other_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Special case: Repeated RA Update Requests */ - - send_llc_ul_ui(nsi, "RA UPD REQ", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, 0x7080, - GPRS_SAPI_GMM, bss_nu++, - dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - - send_llc_ul_ui(nsi, "RA UPD REQ", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, 0x7080, - GPRS_SAPI_GMM, bss_nu++, - dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - dump_global(stdout, 0); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; - - cleanup_test(); -} - -static void test_gbproxy_secondary_sgsn() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer[2]= {{0},}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_sgsn = - {.mcc = 123, .mnc = 456, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_unknown = - {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; - uint16_t cell_id = 0x1234; - - const uint32_t sgsn_ptmsi = 0xefe2b700; - const uint32_t local_sgsn_tlli = 0xefe2b700; - const uint32_t random_sgsn_tlli = 0x78dead00; - - const uint32_t bss_ptmsi = 0xc0dead01; - const uint32_t local_bss_tlli = 0xc0dead01; - const uint32_t foreign_bss_tlli = 0x8000dead; - - const uint32_t sgsn_ptmsi2 = 0xe0987654; - const uint32_t local_sgsn_tlli2 = 0xe0987654; - const uint32_t random_sgsn_tlli2 = 0x78dead02; - const uint32_t bss_ptmsi2 = 0xc0dead03; - const uint32_t local_bss_tlli2 = 0xc0dead03; - const uint32_t foreign_bss_tlli2 = 0x8000beef; - - const uint32_t random_sgsn_tlli3 = 0x78dead04; - const uint32_t bss_ptmsi3 = 0xc0dead05; - const uint32_t local_bss_tlli3 = 0xc0dead05; - const uint32_t foreign_bss_tlli3 = 0x8000feed; - - const uint8_t imsi1[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - const uint8_t imsi2[] = {0x11, 0x12, 0x99, 0x99, 0x99, 0x16, 0x17, 0x18}; - const uint8_t imsi3[] = {0x11, 0x12, 0x99, 0x99, 0x99, 0x26, 0x27, 0x28}; - struct gbproxy_link_info *link_info; - struct gbproxy_link_info *other_info; - struct gbproxy_peer *peer; - unsigned bss_nu = 0; - unsigned sgsn_nu = 0; - - const char *err_msg = NULL; - const char *filter_re = "999999"; - - OSMO_ASSERT(local_sgsn_tlli == gprs_tmsi2tlli(sgsn_ptmsi, TLLI_LOCAL)); - OSMO_ASSERT(local_sgsn_tlli2 == gprs_tmsi2tlli(sgsn_ptmsi2, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.core_mcc = 123; - gbcfg.core_mnc = 456; - gbcfg.core_apn = talloc_zero_size(NULL, 100); - gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); - gbcfg.patch_ptmsi = 1; - gbcfg.acquire_imsi = 1; - - gbcfg.route_to_sgsn2 = 1; - gbcfg.nsip_sgsn2_nsei = SGSN2_NSEI; - - if (gbproxy_set_patch_filter(&gbcfg.matches[GBPROX_MATCH_ROUTING], - filter_re, &err_msg) != 0) { - fprintf(stderr, "gbprox_set_patch_filter: got error: %s\n", - err_msg); - OSMO_ASSERT(err_msg == NULL); - } - - configure_sgsn_peer(&sgsn_peer[0]); - configure_sgsn2_peer(&sgsn_peer[1]); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN 1 ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer[0], SGSN_NSEI); - - printf("--- Initialise SGSN 2 ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer[1], SGSN2_NSEI); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x0); - send_bssgp_reset_ack(nsi, &sgsn_peer[0], 0x0); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - send_bssgp_reset_ack(nsi, &sgsn_peer[0], 0x1002); - send_bssgp_reset_ack(nsi, &sgsn_peer[1], 0x1002); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - gprs_dump_nsi(nsi); - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Flow control ---\n\n"); - - send_bssgp_flow_control_bvc(nsi, &bss_peer[0], 0x1002, 1); - send_bssgp_flow_control_bvc_ack(nsi, &sgsn_peer[0], 0x1002, 1); - send_bssgp_flow_control_bvc_ack(nsi, &sgsn_peer[1], 0x1002, 1); - - printf("--- Establish GPRS connection (SGSN 1) ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer[0], 0x1002, - random_sgsn_tlli, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer[0], 0x1002, - random_sgsn_tlli, 1, imsi1, sizeof(imsi1), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN2_NSEI)); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN2_NSEI)); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer[0], 0x1002, - local_sgsn_tlli, 1, imsi1, sizeof(imsi1), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN2_NSEI)); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - /* Non-DTAP */ - send_bssgp_ul_unitdata(nsi, "XID (UL)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - llc_u_xid_ul, sizeof(llc_u_xid_ul)); - - send_bssgp_dl_unitdata(nsi, "XID (DL)", &sgsn_peer[0], 0x1002, - local_sgsn_tlli, 1, imsi1, sizeof(imsi1), - llc_u_xid_dl, sizeof(llc_u_xid_dl)); - - send_bssgp_ul_unitdata(nsi, "LL11 DNS QUERY (UL)", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - llc_ui_ll11_dns_query_ul, - sizeof(llc_ui_ll11_dns_query_ul)); - - send_bssgp_dl_unitdata(nsi, "LL11 DNS RESP (DL)", &sgsn_peer[0], 0x1002, - local_sgsn_tlli, 1, imsi1, sizeof(imsi1), - llc_ui_ll11_dns_resp_dl, - sizeof(llc_ui_ll11_dns_resp_dl)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Other messages */ - send_bssgp_llc_discarded(nsi, &bss_peer[0], 0x1002, - local_bss_tlli, 1, 12); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_llc_discarded(nsi, &sgsn_peer[0], 0x1002, - local_sgsn_tlli, 1, 12); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend(nsi, &bss_peer[0], local_bss_tlli, &rai_bss); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend_ack(nsi, &sgsn_peer[0], local_sgsn_tlli, &rai_sgsn); - - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Establish GPRS connection (SGSN 2) ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli2, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli2, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity2_resp, sizeof(dtap_identity2_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer[1], 0x1002, - random_sgsn_tlli2, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli2, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity2_resp, sizeof(dtap_identity2_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer[1], 0x1002, - random_sgsn_tlli2, 1, imsi2, sizeof(imsi2), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc2, sizeof(dtap_attach_acc2)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli2, SGSN_NSEI)); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli2, SGSN2_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli2); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli2); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi2); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli2); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli2); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi2); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_bss_tlli2, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli2, SGSN_NSEI)); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli2, SGSN2_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli2); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli2); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli2); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli2); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer[1], 0x1002, - local_sgsn_tlli2, 1, imsi2, sizeof(imsi2), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli2, SGSN_NSEI)); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli2, SGSN2_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli2); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli2); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - /* Non-DTAP */ - send_bssgp_ul_unitdata(nsi, "XID (UL)", &bss_peer[0], 0x1002, - local_bss_tlli2, &rai_bss, cell_id, - llc_u_xid_ul, sizeof(llc_u_xid_ul)); - - send_bssgp_dl_unitdata(nsi, "XID (DL)", &sgsn_peer[1], 0x1002, - local_sgsn_tlli2, 1, imsi2, sizeof(imsi2), - llc_u_xid_dl, sizeof(llc_u_xid_dl)); - - send_bssgp_ul_unitdata(nsi, "LL11 DNS QUERY (UL)", &bss_peer[0], 0x1002, - local_bss_tlli2, &rai_bss, cell_id, - llc_ui_ll11_dns_query_ul, - sizeof(llc_ui_ll11_dns_query_ul)); - - send_bssgp_dl_unitdata(nsi, "LL11 DNS RESP (DL)", &sgsn_peer[1], 0x1002, - local_sgsn_tlli2, 1, imsi2, sizeof(imsi2), - llc_ui_ll11_dns_resp_dl, - sizeof(llc_ui_ll11_dns_resp_dl)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Other messages */ - send_bssgp_llc_discarded(nsi, &bss_peer[0], 0x1002, - local_bss_tlli2, 1, 12); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_llc_discarded(nsi, &sgsn_peer[1], 0x1002, - local_sgsn_tlli2, 1, 12); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend(nsi, &bss_peer[0], local_bss_tlli2, &rai_bss); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_bssgp_suspend_ack(nsi, &sgsn_peer[1], local_sgsn_tlli2, &rai_sgsn); - - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Establish GPRS connection (SGSN 2, P-TMSI collision) ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_bss_tlli3, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli3, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity3_resp, sizeof(dtap_identity3_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer[1], 0x1002, - random_sgsn_tlli3, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_bss_tlli3, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity3_resp, sizeof(dtap_identity3_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT (P-TMSI 1)", &sgsn_peer[1], 0x1002, - random_sgsn_tlli3, 1, imsi3, sizeof(imsi3), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli3, SGSN_NSEI)); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, random_sgsn_tlli3, SGSN2_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli3); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli3); - OSMO_ASSERT(!link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->tlli.ptmsi == bss_ptmsi3); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli3); - OSMO_ASSERT(!link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.ptmsi == sgsn_ptmsi); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_bss_tlli3, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - dump_peers(stdout, 0, 0, &gbcfg); - - other_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(other_info); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN2_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info != other_info); - OSMO_ASSERT(link_info->tlli.assigned == local_bss_tlli3); - OSMO_ASSERT(link_info->tlli.current == foreign_bss_tlli3); - OSMO_ASSERT(link_info->tlli.bss_validated); - OSMO_ASSERT(!link_info->tlli.net_validated); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.current == random_sgsn_tlli3); - OSMO_ASSERT(link_info->sgsn_tlli.bss_validated); - OSMO_ASSERT(!link_info->sgsn_tlli.net_validated); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer[1], 0x1002, - local_sgsn_tlli, 1, imsi3, sizeof(imsi3), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - dump_peers(stdout, 0, 0, &gbcfg); - - other_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN_NSEI); - OSMO_ASSERT(other_info); - link_info = gbproxy_link_info_by_sgsn_tlli(peer, local_sgsn_tlli, SGSN2_NSEI); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info != other_info); - OSMO_ASSERT(link_info->tlli.current == local_bss_tlli3); - OSMO_ASSERT(link_info->tlli.assigned == 0); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_sgsn_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - - printf("--- Shutdown GPRS connection (SGSN 1) ---\n\n"); - - /* Detach */ - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_bss_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer[0], 0x1002, - local_sgsn_tlli, 1, imsi1, sizeof(imsi1), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Shutdown GPRS connection (SGSN 2) ---\n\n"); - - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_bss_tlli2, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer[1], 0x1002, - local_sgsn_tlli2, 1, imsi2, sizeof(imsi2), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Shutdown GPRS connection (SGSN 2, P-TMSI 1) ---\n\n"); - - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_bss_tlli3, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer[1], 0x1002, - local_sgsn_tlli, 1, imsi3, sizeof(imsi3), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - dump_global(stdout, 0); - - gbproxy_clear_patch_filter(&gbcfg.matches[GBPROX_MATCH_ROUTING]); - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; - - cleanup_test(); -} - -static void test_gbproxy_keep_info() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - uint16_t cell_id = 0x1234; - - const uint32_t ptmsi = 0xefe2b700; - const uint32_t local_tlli = 0xefe2b700; - const uint32_t foreign_tlli = 0xafe2b700; - - const uint8_t imsi[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; - struct gbproxy_link_info *link_info, *link_info2; - struct gbproxy_peer *peer; - unsigned bss_nu = 0; - unsigned sgsn_nu = 0; - - LLIST_HEAD(rcv_list); - - OSMO_ASSERT(local_tlli == gprs_tmsi2tlli(ptmsi, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.patch_ptmsi = 0; - gbcfg.acquire_imsi = 1; - gbcfg.core_mcc = 0; - gbcfg.core_mnc = 0; - gbcfg.core_apn = NULL; - gbcfg.core_apn_size = 0; - gbcfg.route_to_sgsn2 = 0; - gbcfg.nsip_sgsn2_nsei = 0xffff; - gbcfg.keep_link_infos = GBPROX_KEEP_ALWAYS; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - gprs_dump_nsi(nsi); - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Send message from BSS 1 to SGSN, BVCI 0x1002 ---\n\n"); - - received_messages = &rcv_list; - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ID_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->imsi_len == 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(link_info->imsi_acq_pending); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->imsi_len > 0); - OSMO_ASSERT(!link_info->imsi_acq_pending); - OSMO_ASSERT(gprs_tlli_type(link_info->sgsn_tlli.current) == TLLI_FOREIGN); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - foreign_tlli, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ID_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ID_RESP)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->imsi_len > 0); - OSMO_ASSERT(gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi))); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_INFO)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - /* Detach (MO) */ - send_llc_ul_ui(nsi, "DETACH REQ", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "DETACH ACC", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - OSMO_ASSERT(!expect_msg()); - - /* Re-Attach */ - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req3, sizeof(dtap_attach_req3)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - OSMO_ASSERT(gprs_tlli_type(link_info->sgsn_tlli.current) == TLLI_FOREIGN); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (MT) */ - send_llc_dl_ui(nsi, "DETACH REQ (re-attach)", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_rea_req, sizeof(dtap_mt_detach_rea_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - OSMO_ASSERT(!expect_msg()); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - /* Re-Attach */ - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req3, sizeof(dtap_attach_req3)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (MT) */ - send_llc_dl_ui(nsi, "DETACH REQ", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_req, sizeof(dtap_mt_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - OSMO_ASSERT(!expect_msg()); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - /* Re-Attach with IMSI */ - send_llc_ul_ui(nsi, "ATTACH REQUEST (IMSI)", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req4, sizeof(dtap_attach_req4)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - OSMO_ASSERT(link_info->sgsn_tlli.current == foreign_tlli); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (MT) */ - send_llc_dl_ui(nsi, "DETACH REQ", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_req, sizeof(dtap_mt_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - OSMO_ASSERT(!expect_msg()); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - /* Re-Attach */ - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req3, sizeof(dtap_attach_req3)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* RA update procedure (reject -> Detach) */ - send_llc_ul_ui(nsi, "RA UPD REQ", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, 0x7080, - GPRS_SAPI_GMM, bss_nu++, - dtap_ra_upd_req, sizeof(dtap_ra_upd_req)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_RA_UPD_REQ)); - - send_llc_dl_ui(nsi, "RA UDP REJ", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_ra_upd_rej, sizeof(dtap_ra_upd_rej)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_RA_UPD_REJ)); - OSMO_ASSERT(!expect_msg()); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - /* Bad case: Re-Attach with wrong (initial) P-TMSI */ - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ID_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info != link_info2); - OSMO_ASSERT(link_info->imsi_len == 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(link_info->imsi_acq_pending); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len > 0); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (MT) */ - send_llc_dl_ui(nsi, "DETACH REQ", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_req, sizeof(dtap_mt_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - OSMO_ASSERT(!expect_msg()); - - /* Bad case: Re-Attach with local TLLI */ - send_llc_ul_ui(nsi, "ATTACH REQUEST (local TLLI)", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req3, sizeof(dtap_attach_req3)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - OSMO_ASSERT(link_info->sgsn_tlli.current == local_tlli); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (MT) */ - send_llc_dl_ui(nsi, "DETACH REQ (re-attach)", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_rea_req, sizeof(dtap_mt_detach_rea_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - OSMO_ASSERT(!expect_msg()); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - /* Bad case: Unexpected Re-Attach with IMSI after completed attachment - * procedure */ - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req3, sizeof(dtap_attach_req3)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_INFO)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH REQUEST (unexpected, IMSI)", - &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req4, sizeof(dtap_attach_req4)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - OSMO_ASSERT(link_info->sgsn_tlli.current == foreign_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (MT) */ - send_llc_dl_ui(nsi, "DETACH REQ", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_req, sizeof(dtap_mt_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - OSMO_ASSERT(!expect_msg()); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - /* Bad case: Unexpected Re-Attach with P-TMSI after completed attachment - * procedure */ - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req3, sizeof(dtap_attach_req3)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "GMM INFO", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_gmm_information, sizeof(dtap_gmm_information)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_INFO)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH REQUEST (unexpected)", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req3, sizeof(dtap_attach_req3)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - OSMO_ASSERT(link_info->sgsn_tlli.current == foreign_tlli); - OSMO_ASSERT(link_info->sgsn_tlli.assigned == 0); - - send_llc_dl_ui(nsi, "ATTACH ACCEPT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_acc, sizeof(dtap_attach_acc)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "ATTACH COMPLETE", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_complete, sizeof(dtap_attach_complete)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_COMPL)); - - dump_peers(stdout, 0, 0, &gbcfg); - - /* Detach (MT) */ - send_llc_dl_ui(nsi, "DETACH REQ", &sgsn_peer, 0x1002, - local_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_req, sizeof(dtap_mt_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, local_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - local_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - OSMO_ASSERT(!expect_msg()); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, local_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - - /* Attach rejected */ - - gbproxy_delete_link_infos(peer); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ID_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->imsi_len == 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(link_info->imsi_acq_pending); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info2 = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info == link_info2); - OSMO_ASSERT(link_info->imsi_len != 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(!link_info->imsi_acq_pending); - - send_llc_dl_ui(nsi, "ATTACH REJECT", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_attach_rej7, sizeof(dtap_attach_rej7)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ATTACH_REJ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, foreign_tlli)); - - OSMO_ASSERT(!expect_msg()); - - /* Attach (incomplete) and Detach (MO) */ - - gbproxy_delete_link_infos(peer); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ID_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->imsi_len == 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(link_info->imsi_acq_pending); - - send_llc_ul_ui(nsi, "DETACH REQ (MO)", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_req, sizeof(dtap_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!expect_msg()); - - /* Attach (incomplete) and Detach (MT) */ - - gbproxy_delete_link_infos(peer); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_ID_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->imsi_len == 0); - OSMO_ASSERT(!link_info->is_deregistered); - OSMO_ASSERT(link_info->imsi_acq_pending); - - send_llc_dl_ui(nsi, "DETACH REQ (MT)", &sgsn_peer, 0x1002, - foreign_tlli, 1, imsi, sizeof(imsi), - GPRS_SAPI_GMM, sgsn_nu++, - dtap_mt_detach_req, sizeof(dtap_mt_detach_req)); - - OSMO_ASSERT(expect_gmm_msg(0x1000, 0x1002, GSM48_MT_GMM_DETACH_REQ)); - - dump_peers(stdout, 0, 0, &gbcfg); - - link_info = gbproxy_link_info_by_tlli(peer, foreign_tlli); - OSMO_ASSERT(link_info); - - send_llc_ul_ui(nsi, "DETACH ACC", &bss_peer[0], 0x1002, - foreign_tlli, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_mt_detach_acc, sizeof(dtap_mt_detach_acc)); - - /* TODO: The stored messaged should be cleaned when receiving a Detach - * Ack. Remove the first OSMO_ASSERT when this is fixed. */ - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_ATTACH_REQ)); - OSMO_ASSERT(expect_gmm_msg(SGSN_NSEI, 0x1002, GSM48_MT_GMM_DETACH_ACK)); - - dump_peers(stdout, 0, 0, &gbcfg); - - OSMO_ASSERT(!gbproxy_link_info_by_tlli(peer, foreign_tlli)); - link_info = gbproxy_link_info_by_imsi(peer, imsi, sizeof(imsi)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->is_deregistered); - - OSMO_ASSERT(!expect_msg()); - received_messages = NULL; - - dump_global(stdout, 0); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; - - cleanup_test(); -} - -struct gbproxy_link_info *register_tlli( - struct gbproxy_peer *peer, uint32_t tlli, - const uint8_t *imsi, size_t imsi_len, time_t now) -{ - struct gbproxy_link_info *link_info; - int imsi_matches = -1; - int tlli_already_known = 0; - struct gbproxy_config *cfg = peer->cfg; - - /* Check, whether the IMSI matches */ - if (gprs_is_mi_imsi(imsi, imsi_len)) { - imsi_matches = gbproxy_check_imsi( - &cfg->matches[GBPROX_MATCH_PATCHING], imsi, imsi_len); - if (imsi_matches < 0) - return NULL; - } - - link_info = gbproxy_link_info_by_tlli(peer, tlli); - - if (!link_info) { - link_info = gbproxy_link_info_by_imsi(peer, imsi, imsi_len); - - if (link_info) { - /* TLLI has changed somehow, adjust it */ - LOGP(DGPRS, LOGL_INFO, - "The TLLI has changed from %08x to %08x\n", - link_info->tlli.current, tlli); - link_info->tlli.current = tlli; - } - } - - if (!link_info) { - link_info = gbproxy_link_info_alloc(peer); - link_info->tlli.current = tlli; - } else { - gbproxy_detach_link_info(peer, link_info); - tlli_already_known = 1; - } - - OSMO_ASSERT(link_info != NULL); - - if (!tlli_already_known) - LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n", tlli); - - gbproxy_attach_link_info(peer, now, link_info); - gbproxy_update_link_info(link_info, imsi, imsi_len); - - if (imsi_matches >= 0) - link_info->is_matching[GBPROX_MATCH_PATCHING] = imsi_matches; - - return link_info; -} - -static void test_gbproxy_tlli_expire(void) -{ - struct gbproxy_config cfg = {0}; - struct gbproxy_peer *peer; - const char *err_msg = NULL; - const uint8_t imsi1[] = { GSM_MI_TYPE_IMSI, 0x23, 0x24, 0x25, 0x26 }; - const uint8_t imsi2[] = { GSM_MI_TYPE_IMSI, 0x26, 0x27, 0x28, 0x29 }; - const uint8_t imsi3[] = { GSM_MI_TYPE_IMSI | 0x10, 0x32, 0x54, 0x76, 0xf8 }; - const uint32_t tlli1 = 1234 | 0xc0000000; - const uint32_t tlli2 = 5678 | 0xc0000000; - const uint32_t tlli3 = 3456 | 0xc0000000; - const char *filter_re = ".*"; - time_t now = 1407479214; - - printf("Test TLLI info expiry\n\n"); - - gbproxy_init_config(&cfg); - - if (gbproxy_set_patch_filter(&cfg.matches[GBPROX_MATCH_PATCHING], - filter_re, &err_msg) != 0) { - fprintf(stderr, "gbprox_set_patch_filter: got error: %s\n", - err_msg); - OSMO_ASSERT(err_msg == NULL); - } - - { - struct gbproxy_link_info *link_info; - - printf("Test TLLI replacement:\n"); - - cfg.tlli_max_len = 0; - cfg.tlli_max_age = 0; - peer = gbproxy_peer_alloc(&cfg, 20); - OSMO_ASSERT(peer->patch_state.logical_link_count == 0); - - printf(" Add TLLI 1, IMSI 1\n"); - link_info = register_tlli(peer, tlli1, - imsi1, ARRAY_SIZE(imsi1), now); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli1); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - /* replace the old entry */ - printf(" Add TLLI 2, IMSI 1 (should replace TLLI 1)\n"); - link_info = register_tlli(peer, tlli2, - imsi1, ARRAY_SIZE(imsi1), now); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli2); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - dump_peers(stdout, 2, now, &cfg); - - /* verify that 5678 has survived */ - link_info = gbproxy_link_info_by_imsi(peer, imsi1, ARRAY_SIZE(imsi1)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli2); - link_info = gbproxy_link_info_by_imsi(peer, imsi2, ARRAY_SIZE(imsi2)); - OSMO_ASSERT(!link_info); - - printf("\n"); - - gbproxy_peer_free(peer); - } - - { - struct gbproxy_link_info *link_info; - - printf("Test IMSI replacement:\n"); - - cfg.tlli_max_len = 0; - cfg.tlli_max_age = 0; - peer = gbproxy_peer_alloc(&cfg, 20); - OSMO_ASSERT(peer->patch_state.logical_link_count == 0); - - printf(" Add TLLI 1, IMSI 1\n"); - link_info = register_tlli(peer, tlli1, - imsi1, ARRAY_SIZE(imsi1), now); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli1); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - /* try to replace the old entry */ - printf(" Add TLLI 1, IMSI 2 (should replace IMSI 1)\n"); - link_info = register_tlli(peer, tlli1, - imsi2, ARRAY_SIZE(imsi2), now); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli1); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - dump_peers(stdout, 2, now, &cfg); - - /* verify that 5678 has survived */ - link_info = gbproxy_link_info_by_imsi(peer, imsi1, ARRAY_SIZE(imsi1)); - OSMO_ASSERT(!link_info); - link_info = gbproxy_link_info_by_imsi(peer, imsi2, ARRAY_SIZE(imsi2)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli1); - - printf("\n"); - - gbproxy_peer_free(peer); - } - - { - struct gbproxy_link_info *link_info; - int num_removed; - - printf("Test TLLI expiry, max_len == 1:\n"); - - cfg.tlli_max_len = 1; - cfg.tlli_max_age = 0; - peer = gbproxy_peer_alloc(&cfg, 20); - OSMO_ASSERT(peer->patch_state.logical_link_count == 0); - - printf(" Add TLLI 1, IMSI 1\n"); - register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - /* replace the old entry */ - printf(" Add TLLI 2, IMSI 2 (should replace IMSI 1)\n"); - register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), now); - OSMO_ASSERT(peer->patch_state.logical_link_count == 2); - - num_removed = gbproxy_remove_stale_link_infos(peer, now + 2); - OSMO_ASSERT(num_removed == 1); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - dump_peers(stdout, 2, now, &cfg); - - /* verify that 5678 has survived */ - link_info = gbproxy_link_info_by_imsi(peer, imsi1, ARRAY_SIZE(imsi1)); - OSMO_ASSERT(!link_info); - link_info = gbproxy_link_info_by_imsi(peer, imsi2, ARRAY_SIZE(imsi2)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli2); - - printf("\n"); - - gbproxy_peer_free(peer); - } - - { - struct gbproxy_link_info *link_info; - int num_removed; - - printf("Test TLLI expiry, max_age == 1:\n"); - - cfg.tlli_max_len = 0; - cfg.tlli_max_age = 1; - peer = gbproxy_peer_alloc(&cfg, 20); - OSMO_ASSERT(peer->patch_state.logical_link_count == 0); - - printf(" Add TLLI 1, IMSI 1 (should expire after timeout)\n"); - register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - printf(" Add TLLI 2, IMSI 2 (should not expire after timeout)\n"); - register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), - now + 1); - OSMO_ASSERT(peer->patch_state.logical_link_count == 2); - - num_removed = gbproxy_remove_stale_link_infos(peer, now + 2); - OSMO_ASSERT(num_removed == 1); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - dump_peers(stdout, 2, now + 2, &cfg); - - /* verify that 5678 has survived */ - link_info = gbproxy_link_info_by_imsi(peer, imsi1, ARRAY_SIZE(imsi1)); - OSMO_ASSERT(!link_info); - link_info = gbproxy_link_info_by_imsi(peer, imsi2, ARRAY_SIZE(imsi2)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli2); - - printf("\n"); - - gbproxy_peer_free(peer); - } - - { - struct gbproxy_link_info *link_info; - int num_removed; - - printf("Test TLLI expiry, max_len == 2, max_age == 1:\n"); - - cfg.tlli_max_len = 0; - cfg.tlli_max_age = 1; - peer = gbproxy_peer_alloc(&cfg, 20); - OSMO_ASSERT(peer->patch_state.logical_link_count == 0); - - printf(" Add TLLI 1, IMSI 1 (should expire)\n"); - register_tlli(peer, tlli1, imsi1, ARRAY_SIZE(imsi1), now); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - printf(" Add TLLI 2, IMSI 2 (should expire after timeout)\n"); - register_tlli(peer, tlli2, imsi2, ARRAY_SIZE(imsi2), - now + 1); - OSMO_ASSERT(peer->patch_state.logical_link_count == 2); - - printf(" Add TLLI 3, IMSI 3 (should not expire after timeout)\n"); - register_tlli(peer, tlli3, imsi3, ARRAY_SIZE(imsi3), - now + 2); - OSMO_ASSERT(peer->patch_state.logical_link_count == 3); - - dump_peers(stdout, 2, now + 2, &cfg); - - printf(" Remove stale TLLIs\n"); - num_removed = gbproxy_remove_stale_link_infos(peer, now + 3); - OSMO_ASSERT(num_removed == 2); - OSMO_ASSERT(peer->patch_state.logical_link_count == 1); - - dump_peers(stdout, 2, now + 2, &cfg); - - /* verify that tlli3 has survived */ - link_info = gbproxy_link_info_by_imsi(peer, imsi1, ARRAY_SIZE(imsi1)); - OSMO_ASSERT(!link_info); - link_info = gbproxy_link_info_by_imsi(peer, imsi2, ARRAY_SIZE(imsi2)); - OSMO_ASSERT(!link_info); - link_info = gbproxy_link_info_by_imsi(peer, imsi3, ARRAY_SIZE(imsi3)); - OSMO_ASSERT(link_info); - OSMO_ASSERT(link_info->tlli.current == tlli3); - - printf("\n"); - - gbproxy_peer_free(peer); - } - gbproxy_clear_patch_filter(&cfg.matches[GBPROX_MATCH_PATCHING]); - gbprox_reset(&cfg); - - cleanup_test(); -} - -static void test_gbproxy_imsi_matching(void) -{ - const char *err_msg = NULL; - const uint8_t imsi1[] = { GSM_MI_TYPE_IMSI | 0x10, 0x32, 0x54, 0xf6 }; - const uint8_t imsi2[] = { GSM_MI_TYPE_IMSI | GSM_MI_ODD | 0x10, 0x32, 0x54, 0x76 }; - const uint8_t imsi3_bad[] = { GSM_MI_TYPE_IMSI | 0x10, 0xee, 0x54, 0xff }; - const uint8_t tmsi1[] = { GSM_MI_TYPE_TMSI | 0xf0, 0x11, 0x22, 0x33, 0x44 }; - const uint8_t tmsi2_bad[] = { GSM_MI_TYPE_TMSI | 0xf0, 0x11, 0x22 }; - const uint8_t imei1[] = { GSM_MI_TYPE_IMEI | 0x10, 0x32, 0x54, 0xf6 }; - const uint8_t imei2[] = { GSM_MI_TYPE_IMEI | GSM_MI_ODD | 0x10, 0x32, 0x54, 0x76 }; - const char *filter_re1 = ".*"; - const char *filter_re2 = "^1234"; - const char *filter_re3 = "^4321"; - const char *filter_re4_bad = "^12["; - struct gbproxy_match match = {0,}; - - printf("=== Test IMSI/TMSI matching ===\n\n"); - - OSMO_ASSERT(match.enable == 0); - - OSMO_ASSERT(gbproxy_set_patch_filter(&match, filter_re1, &err_msg) == 0); - OSMO_ASSERT(match.enable == 1); - - OSMO_ASSERT(gbproxy_set_patch_filter(&match, filter_re2, &err_msg) == 0); - OSMO_ASSERT(match.enable == 1); - - err_msg = NULL; - OSMO_ASSERT(gbproxy_set_patch_filter(&match, filter_re4_bad, &err_msg) == -1); - OSMO_ASSERT(err_msg != NULL); - OSMO_ASSERT(match.enable == 0); - - OSMO_ASSERT(gbproxy_set_patch_filter(&match, filter_re2, &err_msg) == 0); - OSMO_ASSERT(match.enable == 1); - - OSMO_ASSERT(gbproxy_set_patch_filter(&match, NULL, &err_msg) == 0); - OSMO_ASSERT(match.enable == 0); - - OSMO_ASSERT(gbproxy_set_patch_filter(&match, filter_re2, &err_msg) == 0); - OSMO_ASSERT(match.enable == 1); - - gbproxy_clear_patch_filter(&match); - OSMO_ASSERT(match.enable == 0); - - OSMO_ASSERT(gbproxy_set_patch_filter(&match, filter_re2, &err_msg) == 0); - OSMO_ASSERT(match.enable == 1); - - OSMO_ASSERT(gbproxy_check_imsi(&match, imsi1, ARRAY_SIZE(imsi1)) == 1); - OSMO_ASSERT(gbproxy_check_imsi(&match, imsi2, ARRAY_SIZE(imsi2)) == 1); - /* imsi3_bad contains 0xE and 0xF digits, but the conversion function - * doesn't complain, so gbproxy_check_imsi() doesn't return -1 in this - * case. */ - OSMO_ASSERT(gbproxy_check_imsi(&match, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0); - OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi1, ARRAY_SIZE(tmsi1)) == -1); - OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1); - OSMO_ASSERT(gbproxy_check_imsi(&match, imei1, ARRAY_SIZE(imei1)) == -1); - OSMO_ASSERT(gbproxy_check_imsi(&match, imei2, ARRAY_SIZE(imei2)) == -1); - - OSMO_ASSERT(gbproxy_set_patch_filter(&match, filter_re3, &err_msg) == 0); - OSMO_ASSERT(match.enable == 1); - - OSMO_ASSERT(gbproxy_check_imsi(&match, imsi1, ARRAY_SIZE(imsi1)) == 0); - OSMO_ASSERT(gbproxy_check_imsi(&match, imsi2, ARRAY_SIZE(imsi2)) == 0); - OSMO_ASSERT(gbproxy_check_imsi(&match, imsi3_bad, ARRAY_SIZE(imsi3_bad)) == 0); - OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi1, ARRAY_SIZE(tmsi1)) == -1); - OSMO_ASSERT(gbproxy_check_imsi(&match, tmsi2_bad, ARRAY_SIZE(tmsi2_bad)) == -1); - OSMO_ASSERT(gbproxy_check_imsi(&match, imei1, ARRAY_SIZE(imei1)) == -1); - OSMO_ASSERT(gbproxy_check_imsi(&match, imei2, ARRAY_SIZE(imei2)) == -1); - - /* TODO: Check correct length but wrong type with is_mi_tmsi */ - - gbproxy_clear_patch_filter(&match); - OSMO_ASSERT(match.enable == 0); - - cleanup_test(); -} - -static void test_gbproxy_stored_messages() -{ - struct gprs_ns_inst *nsi = gprs_ns_instantiate(gprs_ns_callback, NULL); - struct sockaddr_in bss_peer[1] = {{0},}; - struct sockaddr_in sgsn_peer= {0}; - struct gprs_ra_id rai_bss = - {.mcc = 112, .mnc = 332, .lac = 16464, .rac = 96}; - struct gprs_ra_id rai_unknown = - {.mcc = 1, .mnc = 99, .lac = 99, .rac = 96}; - uint16_t cell_id = 0x1234; - - const uint32_t ptmsi = 0xefe2b700; - const uint32_t local_tlli = 0xefe2b700; - - const uint32_t foreign_tlli1 = 0x8000dead; - - struct gbproxy_peer *peer; - unsigned bss_nu = 0; - unsigned sgsn_nu = 0; - - OSMO_ASSERT(local_tlli == gprs_tmsi2tlli(ptmsi, TLLI_LOCAL)); - - bssgp_nsi = nsi; - gbcfg.nsi = bssgp_nsi; - gbcfg.nsip_sgsn_nsei = SGSN_NSEI; - gbcfg.core_mcc = 0; - gbcfg.core_mnc = 0; - gbcfg.core_apn = talloc_zero_size(NULL, 100); - gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar"); - gbcfg.patch_ptmsi = 0; - gbcfg.acquire_imsi = 1; - gbcfg.keep_link_infos = 0; - - configure_sgsn_peer(&sgsn_peer); - configure_bss_peers(bss_peer, ARRAY_SIZE(bss_peer)); - - printf("=== %s ===\n", __func__); - printf("--- Initialise SGSN ---\n\n"); - - connect_sgsn(nsi, &sgsn_peer, SGSN_NSEI); - - printf("--- Initialise BSS 1 ---\n\n"); - - setup_ns(nsi, &bss_peer[0], 0x1001, 0x1000); - setup_bssgp(nsi, &bss_peer[0], 0x1002); - - peer = gbproxy_peer_by_nsei(&gbcfg, 0x1000); - OSMO_ASSERT(peer != NULL); - - send_bssgp_reset_ack(nsi, &sgsn_peer, 0x1002); - - gprs_dump_nsi(nsi); - dump_global(stdout, 0); - dump_peers(stdout, 0, 0, &gbcfg); - - printf("--- Establish first LLC connection ---\n\n"); - - send_llc_ul_ui(nsi, "ATTACH REQUEST", &bss_peer[0], 0x1002, - foreign_tlli1, &rai_unknown, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_attach_req, sizeof(dtap_attach_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002, - foreign_tlli1, 0, NULL, 0, - GPRS_SAPI_GMM, sgsn_nu++, - dtap_identity_req, sizeof(dtap_identity_req)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "DETACH ACCEPT", &bss_peer[0], 0x1002, - foreign_tlli1, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_detach_acc, sizeof(dtap_detach_acc)); - - dump_peers(stdout, 0, 0, &gbcfg); - - send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002, - foreign_tlli1, &rai_bss, cell_id, - GPRS_SAPI_GMM, bss_nu++, - dtap_identity_resp, sizeof(dtap_identity_resp)); - - dump_peers(stdout, 0, 0, &gbcfg); - - dump_global(stdout, 0); - - gbprox_reset(&gbcfg); - gprs_ns_destroy(nsi); - nsi = NULL; - - cleanup_test(); -} - -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 struct log_info info = { - .cat = gprs_categories, - .num_cat = ARRAY_SIZE(gprs_categories), -}; - -int main(int argc, char **argv) -{ - msgb_talloc_ctx_init(NULL, 0); - - osmo_init_logging(&info); - log_set_use_color(osmo_stderr_target, 0); - log_set_print_filename(osmo_stderr_target, 0); - osmo_signal_register_handler(SS_L_NS, &test_signal, &gbcfg); - - log_set_print_filename(osmo_stderr_target, 0); - log_set_log_level(osmo_stderr_target, LOGL_DEBUG); - log_set_all_filter(osmo_stderr_target, 1); - - rate_ctr_init(NULL); - - setlinebuf(stdout); - - printf("===== GbProxy test START\n"); - gbproxy_init_config(&gbcfg); - test_gbproxy(); - test_gbproxy_ident_changes(); - test_gbproxy_imsi_matching(); - test_gbproxy_ptmsi_assignment(); - test_gbproxy_ra_patching(); - test_gbproxy_ptmsi_patching(); - test_gbproxy_ptmsi_patching_bad_cases(); - test_gbproxy_imsi_acquisition(); - test_gbproxy_secondary_sgsn(); - test_gbproxy_keep_info(); - test_gbproxy_tlli_expire(); - test_gbproxy_stored_messages(); - printf("===== GbProxy test END\n\n"); - - exit(EXIT_SUCCESS); -} diff --git a/tests/gbproxy/gbproxy_test.ok b/tests/gbproxy/gbproxy_test.ok deleted file mode 100644 index 737aec0ba..000000000 --- a/tests/gbproxy/gbproxy_test.ok +++ /dev/null @@ -1,7244 +0,0 @@ -===== GbProxy test START -=== test_gbproxy === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - -Current NS-VCIs: - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - ---- Initialise BSS 2 --- - -Setup NS-VC: remote 0x01020304:2222, NSVCI 0x2001(8193), NSEI 0x2000(8192) - -PROCESSING RESET from 0x01020304:2222 -02 00 81 01 01 82 20 01 04 82 20 00 - -==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:2222 - -MESSAGE to BSS at 0x01020304:2222, msg length 9 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS at 0x01020304:2222, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:2222 -0a - -MESSAGE to BSS at 0x01020304:2222, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:2222 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:2222 - -MESSAGE to BSS at 0x01020304:2222, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:2222 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:2222, BVCI 0x2002(8194) - -PROCESSING BVC_RESET from 0x01020304:2222 -00 00 00 00 22 04 82 20 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 20 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 20 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 20 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 20 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:2222, msg length 9 -00 00 00 00 23 04 82 20 02 - -result (BVC_RESET_ACK) = 9 - ---- Move BSS 1 to new port --- - -Setup NS-VC: remote 0x01020304:3333, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:3333 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:3333 - -MESSAGE to BSS at 0x01020304:3333, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:3333, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:3333 -0a - -MESSAGE to BSS at 0x01020304:3333, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:3333 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:3333 - -MESSAGE to BSS at 0x01020304:3333, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:3333 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:2222 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:3333 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Move BSS 2 to former BSS 1 port --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x2001(8193), NSEI 0x2000(8192) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 20 01 04 82 20 00 - -==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:3333 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Move BSS 1 to current BSS 2 port --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x2001(8193), NSEI 0x2000(8192) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 20 01 04 82 20 00 - -==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:3333 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Move BSS 2 to new port --- - -Setup NS-VC: remote 0x01020304:4444, NSVCI 0x2001(8193), NSEI 0x2000(8192) - -PROCESSING RESET from 0x01020304:4444 -02 00 81 01 01 82 20 01 04 82 20 00 - -==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:4444 - -MESSAGE to BSS at 0x01020304:4444, msg length 9 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS at 0x01020304:4444, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:4444 -0a - -MESSAGE to BSS at 0x01020304:4444, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:4444 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:4444 - -MESSAGE to BSS at 0x01020304:4444, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:4444 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:4444 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:3333 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Move BSS 2 to former BSS 1 port --- - -Setup NS-VC: remote 0x01020304:3333, NSVCI 0x2001(8193), NSEI 0x2000(8192) - -PROCESSING RESET from 0x01020304:3333 -02 00 81 01 01 82 20 01 04 82 20 00 - -==> got signal NS_REPLACED: 0x2001/1.2.3.4:4444 -> 0x1001/1.2.3.4:3333 - -==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:3333 - -MESSAGE to BSS at 0x01020304:3333, msg length 9 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS at 0x01020304:3333, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:3333 -0a - -MESSAGE to BSS at 0x01020304:3333, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:3333 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:3333 - -MESSAGE to BSS at 0x01020304:3333, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:3333 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:3333 - NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x00000000:0 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Move BSS 1 to original BSS 1 port --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:3333 - NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Reset BSS 1 with a new BVCI --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1012(4114) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 12 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 12 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 12 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:3333 - NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 12 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 12 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 12 - -result (BVC_RESET_ACK) = 9 - ---- Reset BSS 1 with the old BVCI --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:3333 - NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - ---- Reset BSS 1 with the old BVCI again --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:3333 - NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - ---- Send message from BSS 1 to SGSN, BVCI 0x1012 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 10 12 - -CALLBACK, event 0, msg length 0, bvci 0x1012 -00 00 10 12 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1012, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 10 12 - -result (UNITDATA) = 4 - ---- Send message from SGSN to BSS 1, BVCI 0x1012 --- - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 10 12 - -CALLBACK, event 0, msg length 0, bvci 0x1012 -00 00 10 12 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1012, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 10 12 - -result (UNITDATA) = 4 - ---- Send message from BSS 1 to SGSN, BVCI 0x1002 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 10 12 - -CALLBACK, event 0, msg length 0, bvci 0x1012 -00 00 10 12 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1012, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 10 12 - -result (UNITDATA) = 4 - ---- Send message from SGSN to BSS 1, BVCI 0x1002 --- - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 10 12 - -CALLBACK, event 0, msg length 0, bvci 0x1012 -00 00 10 12 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1012, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 10 12 - -result (UNITDATA) = 4 - ---- Send message from BSS 2 to SGSN, BVCI 0x2002 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 20 02 - -result (UNITDATA) = 4 - ---- Send message from SGSN to BSS 2, BVCI 0x2002 --- - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:3333, msg length 4 -00 00 20 02 - -result (UNITDATA) = 4 - ---- Reset BSS 1 with the old BVCI on BSS2's link --- - -Setup BSSGP: remote 0x01020304:3333, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:3333 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:3333 - NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 4096, BVCI 4114, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 -Gbproxy global: -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:3333, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - ---- Send message from BSS 1 to SGSN, BVCI 0x1002 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 10 12 - -CALLBACK, event 0, msg length 0, bvci 0x1012 -00 00 10 12 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1012, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 10 12 - -result (UNITDATA) = 4 - ---- Send message from SGSN to BSS 1, BVCI 0x1002 --- - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 10 12 - -CALLBACK, event 0, msg length 0, bvci 0x1012 -00 00 10 12 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1012, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 10 12 - -result (UNITDATA) = 4 - ---- Send message from SGSN to BSS 1, BVCI 0x10ff (invalid) --- - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 10 ff - -CALLBACK, event 0, msg length 0, bvci 0x10ff -00 00 10 ff - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 10 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 14 -00 00 00 00 41 07 81 05 04 82 10 ff 15 80 - -result (UNITDATA) = 14 - -Peers: - NSEI 8192, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 -Gbproxy global: - Invalid BVC Identifier : 1 -=== test_gbproxy_ident_changes === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - -Current NS-VCIs: - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - ---- Setup BVCI 1 --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Setup BVCI 2 --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x2002(8194) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 20 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 20 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 20 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 20 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 20 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 20 02 - -result (BVC_RESET_ACK) = 9 - -Peers: - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN and back, BVCI 1 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 10 02 - -CALLBACK, event 0, msg length 0, bvci 0x1002 -00 00 10 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 10 02 - -result (UNITDATA) = 4 - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 10 02 - -CALLBACK, event 0, msg length 0, bvci 0x1002 -00 00 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 10 02 - -result (UNITDATA) = 4 - ---- Send message from BSS 1 to SGSN and back, BVCI 2 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 20 02 - -result (UNITDATA) = 4 - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 20 02 - -result (UNITDATA) = 4 - ---- Change NSEI --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x2000(8192) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 20 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 20 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC changed NSEI count : 1 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - ---- Setup BVCI 1 --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Peers: - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 ---- Setup BVCI 3 --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x3002(12290) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 30 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 30 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 30 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 30 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 30 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 30 02 - -result (BVC_RESET_ACK) = 9 - -Peers: - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN and back, BVCI 1 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 10 02 - -CALLBACK, event 0, msg length 0, bvci 0x1002 -00 00 10 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 10 02 - -result (UNITDATA) = 4 - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 10 02 - -CALLBACK, event 0, msg length 0, bvci 0x1002 -00 00 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 10 02 - -result (UNITDATA) = 4 - ---- Send message from BSS 1 to SGSN and back, BVCI 2 (should fail) --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 20 02 - -result (UNITDATA) = 4 - -Peers: - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 -PROCESSING UNITDATA from 0x05060708:32000 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -result (UNITDATA) = -22 - -Peers: - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - NS Transmission error : 1 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN and back, BVCI 3 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 30 02 - -CALLBACK, event 0, msg length 0, bvci 0x3002 -00 00 30 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x3002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 30 02 - -result (UNITDATA) = 4 - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 30 02 - -CALLBACK, event 0, msg length 0, bvci 0x3002 -00 00 30 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x3002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 30 02 - -result (UNITDATA) = 4 - ---- Change NSVCI --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x2001(8193), NSEI 0x2000(8192) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 20 01 04 82 20 00 - -==> got signal NS_REPLACED: 0x2001/0.0.0.0:0 -> 0x1001/1.2.3.4:1111 - -==> got signal NS_RESET, NS-VC 0x2001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 20 01 04 82 20 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x2001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Current NS-VCIs: - VCI 0x2001, NSEI 0x2000, peer 0x01020304:1111 - NS-VC replaced other count: 1 - VCI 0x1001, NSEI 0x2000, peer 0x00000000:0 - NS-VC changed NSEI count : 1 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - ---- Setup BVCI 1 --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Peers: - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - NS Transmission error : 1 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 ---- Setup BVCI 4 --- - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x4002(16386) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 40 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 40 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 40 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 40 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 40 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 40 02 - -result (BVC_RESET_ACK) = 9 - -Peers: - NSEI 8192, BVCI 16386, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - NS Transmission error : 1 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN and back, BVCI 1 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 10 02 - -CALLBACK, event 0, msg length 0, bvci 0x1002 -00 00 10 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 10 02 - -result (UNITDATA) = 4 - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 10 02 - -CALLBACK, event 0, msg length 0, bvci 0x1002 -00 00 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 10 02 - -result (UNITDATA) = 4 - ---- Send message from BSS 1 to SGSN and back, BVCI 2 (should fail) --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 20 02 - -result (UNITDATA) = 4 - -Peers: - NSEI 8192, BVCI 16386, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 2 - NS Transmission error : 1 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 -PROCESSING UNITDATA from 0x05060708:32000 -00 00 20 02 - -CALLBACK, event 0, msg length 0, bvci 0x2002 -00 00 20 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x2002, msg length 0 (gprs_ns_sendmsg) -result (UNITDATA) = -22 - -Peers: - NSEI 8192, BVCI 16386, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 2 - NS Transmission error : 2 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN and back, BVCI 3 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 30 02 - -CALLBACK, event 0, msg length 0, bvci 0x3002 -00 00 30 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x3002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 30 02 - -result (UNITDATA) = 4 - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 30 02 - -CALLBACK, event 0, msg length 0, bvci 0x3002 -00 00 30 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x3002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 30 02 - -result (UNITDATA) = 4 - ---- Send message from BSS 1 to SGSN and back, BVCI 4 --- - -PROCESSING UNITDATA from 0x01020304:1111 -00 00 40 02 - -CALLBACK, event 0, msg length 0, bvci 0x4002 -00 00 40 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x4002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 4 -00 00 40 02 - -result (UNITDATA) = 4 - -PROCESSING UNITDATA from 0x05060708:32000 -00 00 40 02 - -CALLBACK, event 0, msg length 0, bvci 0x4002 -00 00 40 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x4002, msg length 0 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 4 -00 00 40 02 - -result (UNITDATA) = 4 - -Gbproxy global: -Peers: - NSEI 8192, BVCI 16386, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 8192, BVCI 12290, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 - NSEI 4096, BVCI 8194, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 2 - NS Transmission error : 2 - TLLI-Cache: 0 - NSEI 8192, BVCI 4098, not blocked, RAI 112-332-16464-96 - NSEI mismatch : 1 - TLLI-Cache: 0 -=== Test IMSI/TMSI matching === - -=== test_gbproxy_ptmsi_assignment === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Establish first LLC connection --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 8000dead, IMSI (none), AGE 0 -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 8000dead, IMSI (none), AGE 0 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -result (IDENT RESPONSE) = 44 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 8000dead, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/efe2b700 -> 8000dead/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/efe2b700 -> 8000dead/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 ---- Establish second LLC connection with the same P-TMSI --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 0d 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 46 42 6e - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 0d 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 46 42 6e - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 0d 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 46 42 6e - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef -> 8000beef, IMSI (none), AGE 0 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 89 41 c0 0d 08 15 01 0c a6 18 - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 89 41 c0 0d 08 15 01 0c a6 18 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 89 41 c0 0d 08 15 01 0c a6 18 - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef -> 8000beef, IMSI (none), AGE 0 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 11 08 16 08 11 12 99 99 99 16 17 18 bf d2 01 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 11 08 16 08 11 12 99 99 99 16 17 18 bf d2 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 11 08 16 08 11 12 99 99 99 16 17 18 bf d2 01 - -result (IDENT RESPONSE) = 44 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef -> 8000beef, IMSI 12199999961718, AGE 0 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 3a 6d d4 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 3a 6d d4 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 3a 6d d4 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000beef/efe2b700 -> 8000beef/efe2b700, IMSI 12199999961718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 15 08 03 86 ac 47 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 15 08 03 86 ac 47 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 15 08 03 86 ac 47 - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000beef/efe2b700 -> 8000beef/efe2b700, IMSI 12199999961718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12199999961718, AGE 0 -Gbproxy global: -=== test_gbproxy_ra_patching === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - -Current NS-VCIs: - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00 - -result (BVC_RESET) = 22 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 1 - TLLI-Cache: 0 -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -PROCESSING BVC_SUSPEND from 0x01020304:1111 -00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60 - -CALLBACK, event 0, msg length 15, bvci 0x0000 -00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 15 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 19 -00 00 00 00 0b 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 - -result (BVC_SUSPEND) = 19 - -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 21 63 54 40 50 60 1d 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 22 -00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 11 22 33 40 50 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 22 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 2 - RAID patched (SGSN): 1 - TLLI from SGSN unknown : 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN, BVCI 0x1002 --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 21 63 54 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 8e cd 32 - -result (ATTACH REQUEST) = 79 - -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 11 01 c0 0d 08 16 08 11 12 13 14 15 16 17 18 b7 1b 9a - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 11 01 c0 0d 08 16 08 11 12 13 14 15 16 17 18 b7 1b 9a - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 11 01 c0 0d 08 16 08 11 12 13 14 15 16 17 18 b7 1b 9a - -result (IDENT RESPONSE) = 44 - -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 be 38 c0 - -result (ATTACH ACCEPT) = 92 - -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 08 01 c0 11 08 03 ea 67 11 - -result (ATTACH COMPLETE) = 35 - -PROCESSING ACT PDP CTX REQ (REPLACE APN) from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -CALLBACK, event 0, msg length 76, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 81 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 85 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 3a 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 08 03 66 6f 6f 03 62 61 72 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 24 9d 75 - -result (ACT PDP CTX REQ (REPLACE APN)) = 85 - -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -result (GMM INFO) = 70 - -PROCESSING ACT PDP CTX REQ (REPLACE APN) from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -CALLBACK, event 0, msg length 76, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 81 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 85 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 3a 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 08 03 66 6f 6f 03 62 61 72 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 24 9d 75 - -result (ACT PDP CTX REQ (REPLACE APN)) = 85 - -PROCESSING ACT PDP CTX REQ (REMOVE APN) from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -CALLBACK, event 0, msg length 76, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 71 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 75 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 30 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 85 fa 60 - -result (ACT PDP CTX REQ (REMOVE APN)) = 75 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 9 - RAID patched (SGSN): 2 - APN patched : 3 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - PDP Activation Request count : 3 - TLLI from SGSN unknown : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0, IMSI matches -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 7e e1 41 - -result (DETACH REQ) = 48 - -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 2 - APN patched : 3 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - Detach Request count : 1 - Detach Accept count : 1 - PDP Activation Request count : 3 - TLLI from SGSN unknown : 1 - TLLI-Cache: 0 ---- RA update --- - -PROCESSING RA UPD REQ from 0x01020304:1111 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 - -CALLBACK, event 0, msg length 85, bvci 0x1002 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 85 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 89 -00 00 10 02 01 bb c5 46 79 00 00 04 08 88 21 63 54 40 50 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 21 63 54 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 1d f0 41 - -result (RA UPD REQ) = 89 - -PROCESSING RA UPD ACC from 0x05060708:32000 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 - -CALLBACK, event 0, msg length 87, bvci 0x1002 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 d7 59 65 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 87 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 91 -00 00 10 02 00 bb c5 46 79 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 19 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 3a 03 54 - -result (RA UPD ACC) = 91 - -PROCESSING ACT PDP CTX REQ (REMOVE APN) from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -CALLBACK, event 0, msg length 76, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 71 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 75 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 30 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 85 fa 60 - -result (ACT PDP CTX REQ (REMOVE APN)) = 75 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 - RAID patched (SGSN): 3 - APN patched : 4 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 1 - Detach Accept count : 1 - PDP Activation Request count : 4 - TLLI from SGSN unknown : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI bbc54679/efe2b700 -> bbc54679/efe2b700, IMSI 12131415161718, AGE 0, IMSI matches -PROCESSING DETACH REQ (PWR OFF) from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 15 01 c0 19 08 05 09 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 84 0c eb - -result (DETACH REQ (PWR OFF)) = 48 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 14 - RAID patched (SGSN): 3 - APN patched : 4 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 2 - Detach Accept count : 1 - PDP Activation Request count : 4 - TLLI from SGSN unknown : 1 - TLLI-Cache: 0 ---- Bad cases --- - -PROCESSING ATTACH REQUEST (foreign RAI) from 0x01020304:1111 -00 00 10 02 01 bb 00 be ef 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb 00 be ef 99 99 99 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 2d c7 df - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 bb 00 be ef 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb 00 be ef 99 99 99 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 2d c7 df - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 bb 00 be ef 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb 00 be ef 99 99 99 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 2d c7 df - -result (ATTACH REQUEST (foreign RAI)) = 79 - -TLLI is already detached, shouldn't patch -PROCESSING ACT PDP CTX REQ from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -CALLBACK, event 0, msg length 76, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 76 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 80 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 75 30 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -result (ACT PDP CTX REQ) = 80 - -Invalid RAI, shouldn't patch -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 00 f1 99 00 63 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 cc d1 75 8b 1b 86 00 f1 99 00 63 60 1d 81 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 24 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 28 -00 00 00 00 41 07 81 21 15 92 0c 1f 84 cc d1 75 8b 1b 86 00 f1 99 00 63 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 28 - -Gbproxy global: - Invalid Routing Area Identifier : 1 - Patch error: no peer : 1 -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 16 - RAID patched (SGSN): 3 - APN patched : 4 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 2 - Detach Accept count : 1 - PDP Activation Request count : 5 - TLLI from SGSN unknown : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI efe2b700 -> efe2b700, IMSI (none), AGE 0 - TLLI bb00beef -> bb00beef, IMSI (none), AGE 0 -=== test_gbproxy_ptmsi_patching === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN, BVCI 0x1002 --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 2 - TLLI patched (BSS ): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI (none), AGE 0 -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 2 - TLLI patched (BSS ): 1 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI (none), AGE 0 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -result (IDENT RESPONSE) = 44 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 de ad 01 0c 0a 29 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 2 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 2 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 3 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ACT PDP CTX REQ (REPLACE APN) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -CALLBACK, event 0, msg length 76, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 35 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 03 02 61 62 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 5a ff 02 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 81 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 85 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 3a 01 c0 0d 0a 41 05 03 0c 00 00 1f 10 00 00 00 00 00 00 00 00 02 01 21 28 08 03 66 6f 6f 03 62 61 72 27 14 80 80 21 10 01 00 00 10 81 06 00 00 00 00 83 06 00 00 00 00 24 9d 75 - -result (ACT PDP CTX REQ (REPLACE APN)) = 85 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 5 - RAID patched (SGSN): 1 - APN patched : 1 - TLLI patched (BSS ): 4 - TLLI patched (SGSN): 3 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING XID (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -CALLBACK, event 0, msg length 38, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 38 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 42 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -result (XID (UL)) = 42 - -PROCESSING XID (DL) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -CALLBACK, event 0, msg length 70, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 70 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 74 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -result (XID (DL)) = 74 - -PROCESSING LL11 DNS QUERY (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -CALLBACK, event 0, msg length 89, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 89 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 93 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -result (LL11 DNS QUERY (UL)) = 93 - -PROCESSING LL11 DNS RESP (DL) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -CALLBACK, event 0, msg length 267, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 267 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 271 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -result (LL11 DNS RESP (DL)) = 271 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 7 - RAID patched (SGSN): 1 - APN patched : 1 - TLLI patched (BSS ): 6 - TLLI patched (SGSN): 5 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING RA UPD REQ (P-TMSI 2) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 11 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 e2 6d 78 - -CALLBACK, event 0, msg length 85, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 11 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 e2 6d 78 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 85 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 89 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 70 80 00 80 0e 00 3e 01 c0 11 08 08 10 21 63 54 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 69 a3 ae - -result (RA UPD REQ (P-TMSI 2)) = 89 - -PROCESSING RA UDP ACC (P-TMSI 2) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 0d 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 e0 98 76 54 17 16 9f e8 ea - -CALLBACK, event 0, msg length 87, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 0d 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 e0 98 76 54 17 16 9f e8 ea - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 87 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 91 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 0d 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 c0 de ad 02 17 16 bb 4d a0 - -result (RA UDP ACC (P-TMSI 2)) = 91 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 9 - RAID patched (SGSN): 2 - APN patched : 1 - TLLI patched (BSS ): 7 - TLLI patched (SGSN): 6 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01/c0dead02 -> efe2b700/e0987654, IMSI 12131415161718, AGE 0 -PROCESSING RA UPD REQ (P-TMSI 3) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 02 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 - -CALLBACK, event 0, msg length 85, bvci 0x1002 -00 00 10 02 01 c0 de ad 02 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 85 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 89 -00 00 10 02 01 e0 98 76 54 00 00 04 08 88 21 63 54 40 50 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 21 63 54 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 1d f0 41 - -result (RA UPD REQ (P-TMSI 3)) = 89 - -PROCESSING RA UDP ACC (P-TMSI 3) from 0x05060708:32000 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 11 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 e0 54 32 10 17 16 1b a3 a8 - -CALLBACK, event 0, msg length 87, bvci 0x1002 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 11 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 e0 54 32 10 17 16 1b a3 a8 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 87 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 91 -00 00 10 02 00 c0 de ad 02 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 11 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 c0 de ad 03 17 16 6e 58 26 - -result (RA UDP ACC (P-TMSI 3)) = 91 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 11 - RAID patched (SGSN): 3 - APN patched : 1 - TLLI patched (BSS ): 8 - TLLI patched (SGSN): 7 - P-TMSI patched (SGSN): 3 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01/c0dead03 -> efe2b700/e0543210, IMSI 12131415161718, AGE 0 -PROCESSING RA UPD COMPLETE from 0x01020304:1111 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 08 01 c0 19 08 0a d5 5f 5e - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 08 01 c0 19 08 0a d5 5f 5e - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 e0 54 32 10 00 00 04 08 88 21 63 54 40 50 60 70 80 00 80 0e 00 08 01 c0 19 08 0a d5 5f 5e - -result (RA UPD COMPLETE) = 35 - -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 e0 54 32 10 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 e0 54 32 10 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 c0 de ad 03 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 12 - RAID patched (SGSN): 3 - APN patched : 1 - TLLI patched (BSS ): 9 - TLLI patched (SGSN): 8 - P-TMSI patched (SGSN): 3 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - RoutingArea Update Compltd count: 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 -PROCESSING LLC_DISCARDED from 0x01020304:1111 -00 00 00 00 2c 1f 84 c0 de ad 03 0f 81 01 04 82 10 02 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 c0 de ad 03 0f 81 01 04 82 10 02 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 19 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 23 -00 00 00 00 2c 1f 84 e0 54 32 10 0f 81 01 04 82 10 02 25 83 00 00 0c - -result (LLC_DISCARDED) = 23 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 12 - RAID patched (SGSN): 3 - APN patched : 1 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 8 - P-TMSI patched (SGSN): 3 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - RoutingArea Update Compltd count: 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 -PROCESSING BVC_SUSPEND from 0x01020304:1111 -00 00 00 00 0b 1f 84 c0 de ad 03 1b 86 11 22 33 40 50 60 - -CALLBACK, event 0, msg length 15, bvci 0x0000 -00 00 00 00 0b 1f 84 c0 de ad 03 1b 86 11 22 33 40 50 60 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 15 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 19 -00 00 00 00 0b 1f 84 e0 54 32 10 1b 86 21 63 54 40 50 60 - -result (BVC_SUSPEND) = 19 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 - RAID patched (SGSN): 3 - APN patched : 1 - TLLI patched (BSS ): 11 - TLLI patched (SGSN): 8 - P-TMSI patched (SGSN): 3 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - RoutingArea Update Compltd count: 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 e0 54 32 10 1b 86 21 63 54 40 50 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 e0 54 32 10 1b 86 21 63 54 40 50 60 1d 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 22 -00 00 00 00 0c 1f 84 c0 de ad 03 1b 86 11 22 33 40 50 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 22 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 - RAID patched (SGSN): 4 - APN patched : 1 - TLLI patched (BSS ): 11 - TLLI patched (SGSN): 9 - P-TMSI patched (SGSN): 3 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - RoutingArea Update Compltd count: 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 -PROCESSING PAGING_PS from 0x05060708:32000 -00 00 00 00 06 0d 88 11 12 13 14 15 16 17 18 0a 82 07 04 1b 86 11 22 33 40 50 60 18 83 00 00 00 20 84 e0 54 32 10 - -CALLBACK, event 0, msg length 34, bvci 0x0000 -00 00 00 00 06 0d 88 11 12 13 14 15 16 17 18 0a 82 07 04 1b 86 11 22 33 40 50 60 18 83 00 00 00 20 84 e0 54 32 10 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 34 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 38 -00 00 00 00 06 0d 88 11 12 13 14 15 16 17 18 0a 82 07 04 1b 86 11 22 33 40 50 60 18 83 00 00 00 20 84 c0 de ad 03 - -result (PAGING_PS) = 38 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 - RAID patched (SGSN): 5 - APN patched : 1 - TLLI patched (BSS ): 11 - TLLI patched (SGSN): 9 - P-TMSI patched (SGSN): 4 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - RoutingArea Update Compltd count: 1 - PDP Activation Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 -PROCESSING LLC_DISCARDED from 0x01020304:1111 -00 00 00 00 2c 1f 84 c0 de ad 03 0f 81 01 04 82 ee e1 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 c0 de ad 03 0f 81 01 04 82 ee e1 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 19 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 23 -00 00 00 00 2c 1f 84 e0 54 32 10 0f 81 01 04 82 ee e1 25 83 00 00 0c - -result (LLC_DISCARDED) = 23 - -Gbproxy global: -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 e0 54 32 10 1b 86 00 f1 99 00 63 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 e0 54 32 10 1b 86 00 f1 99 00 63 60 1d 81 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 24 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 28 -00 00 00 00 41 07 81 21 15 92 0c 1f 84 e0 54 32 10 1b 86 00 f1 99 00 63 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 28 - -Gbproxy global: - Invalid Routing Area Identifier : 1 - Patch error: no peer : 1 -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 e0 54 32 10 1b 86 99 69 54 40 50 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 e0 54 32 10 1b 86 99 69 54 40 50 60 1d 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 22 -00 00 00 00 0c 1f 84 c0 de ad 03 1b 86 11 22 33 40 50 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 22 - -Gbproxy global: - Invalid Routing Area Identifier : 1 - Patch error: no peer : 1 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ee ba db ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 00 83 00 00 00 0e 88 41 c0 09 08 21 04 ba 3d - -CALLBACK, event 0, msg length 58, bvci 0x1002 -00 00 10 02 00 ee ba db ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 00 83 00 00 00 0e 88 41 c0 09 08 21 04 ba 3d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 58 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 62 -00 00 10 02 00 ee ba db ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 00 83 00 00 00 0e 88 41 c0 09 08 21 04 ba 3d - -result (GMM INFO) = 62 - -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ee ba db ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 0d 08 21 68 71 6b - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ee ba db ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 0d 08 21 68 71 6b - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 ee ba db ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 0d 08 21 68 71 6b - -result (GMM INFO) = 70 - -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 1d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb aa cc a3 - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 1d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb aa cc a3 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 e0 54 32 10 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 1d 08 05 01 18 05 f4 e0 54 32 10 19 03 b9 97 cb ea 6d af - -result (DETACH REQ) = 48 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 14 - RAID patched (SGSN): 6 - APN patched : 1 - TLLI patched (BSS ): 13 - TLLI patched (SGSN): 10 - P-TMSI patched (BSS ): 1 - P-TMSI patched (SGSN): 4 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - RoutingArea Update Compltd count: 1 - Detach Request count : 1 - PDP Activation Request count : 1 - TLLI from SGSN unknown : 2 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead03 -> e0543210, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 e0 54 32 10 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 19 08 06 00 04 ff 52 - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 e0 54 32 10 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 19 08 06 00 04 ff 52 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 c0 de ad 03 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 19 08 06 00 04 ff 52 - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 14 - RAID patched (SGSN): 6 - APN patched : 1 - TLLI patched (BSS ): 13 - TLLI patched (SGSN): 11 - P-TMSI patched (BSS ): 1 - P-TMSI patched (SGSN): 4 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 2 - RoutingArea Update Accept count : 2 - RoutingArea Update Compltd count: 1 - Detach Request count : 1 - Detach Accept count : 1 - PDP Activation Request count : 1 - TLLI from SGSN unknown : 2 - TLLI-Cache: 0 -Gbproxy global: - Invalid Routing Area Identifier : 1 - Patch error: no peer : 1 -=== test_gbproxy_ptmsi_patching_bad_cases === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN, BVCI 0x1002 --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 2 - TLLI patched (BSS ): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI (none), AGE 0 -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 2 - TLLI patched (BSS ): 1 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI (none), AGE 0 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -result (IDENT RESPONSE) = 44 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 de ad 01 0c 0a 29 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 2 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT (duplicated) from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 09 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 1d 9e 24 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 09 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 1d 9e 24 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 09 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 de ad 01 42 f6 fc - -result (ATTACH ACCEPT (duplicated)) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 3 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 2 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 3 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 2 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 0d 08 21 68 71 6b - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 0d 08 21 68 71 6b - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 0d 08 21 68 71 6b - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 4 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 2 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6 - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6 - -result (DETACH REQ) = 48 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 5 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 4 - TLLI patched (SGSN): 4 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 2 - Attach Completed count : 1 - Detach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 11 08 06 00 cf 8a 58 - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 11 08 06 00 cf 8a 58 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 11 08 06 00 cf 8a 58 - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 5 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 4 - TLLI patched (SGSN): 5 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 2 - Attach Completed count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI-Cache: 0 -Gbproxy global: -=== test_gbproxy_imsi_acquisition === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 1 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN, BVCI 0x1002 --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 21 63 54 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 8e cd 32 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - TLLI patched (BSS ): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0 -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - TLLI patched (BSS ): 1 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -result (IDENT RESPONSE) = 44 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 de ad 01 0c 0a 29 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 2 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 5 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 2 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 5 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 3 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING XID (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -CALLBACK, event 0, msg length 38, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 38 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 42 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -result (XID (UL)) = 42 - -PROCESSING XID (DL) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -CALLBACK, event 0, msg length 70, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 70 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 74 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -result (XID (DL)) = 74 - -PROCESSING LL11 DNS QUERY (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -CALLBACK, event 0, msg length 89, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 89 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 93 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -result (LL11 DNS QUERY (UL)) = 93 - -PROCESSING LL11 DNS RESP (DL) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -CALLBACK, event 0, msg length 267, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 267 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 271 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -result (LL11 DNS RESP (DL)) = 271 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 7 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 5 - TLLI patched (SGSN): 5 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING LLC_DISCARDED from 0x01020304:1111 -00 00 00 00 2c 1f 84 c0 de ad 01 0f 81 01 04 82 10 02 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 c0 de ad 01 0f 81 01 04 82 10 02 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 19 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 23 -00 00 00 00 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -result (LLC_DISCARDED) = 23 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 7 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 6 - TLLI patched (SGSN): 5 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING LLC_DISCARDED from 0x05060708:32000 -00 00 00 00 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 25 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 29 -00 00 00 00 41 07 81 27 15 93 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -result (LLC_DISCARDED) = 29 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 7 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 6 - TLLI patched (SGSN): 6 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING BVC_SUSPEND from 0x01020304:1111 -00 00 00 00 0b 1f 84 c0 de ad 01 1b 86 11 22 33 40 50 60 - -CALLBACK, event 0, msg length 15, bvci 0x0000 -00 00 00 00 0b 1f 84 c0 de ad 01 1b 86 11 22 33 40 50 60 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 15 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 19 -00 00 00 00 0b 1f 84 ef e2 b7 00 1b 86 21 63 54 40 50 60 - -result (BVC_SUSPEND) = 19 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 8 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 7 - TLLI patched (SGSN): 6 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 21 63 54 40 50 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 21 63 54 40 50 60 1d 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 22 -00 00 00 00 0c 1f 84 c0 de ad 01 1b 86 11 22 33 40 50 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 22 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 8 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 7 - TLLI patched (SGSN): 7 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING LLC_DISCARDED from 0x01020304:1111 -00 00 00 00 2c 1f 84 c0 de ad 01 0f 81 01 04 82 ee e1 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 c0 de ad 01 0f 81 01 04 82 ee e1 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 19 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 23 -00 00 00 00 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 ee e1 25 83 00 00 0c - -result (LLC_DISCARDED) = 23 - -Gbproxy global: - BSSGP protocol error (SGSN): 1 -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 00 f1 99 00 63 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 00 f1 99 00 63 60 1d 81 01 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 24 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 28 -00 00 00 00 41 07 81 21 15 92 0c 1f 84 ef e2 b7 00 1b 86 00 f1 99 00 63 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 28 - -Gbproxy global: - Invalid Routing Area Identifier : 1 - BSSGP protocol error (SGSN): 1 - Patch error: no peer : 1 -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 99 69 54 40 50 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 99 69 54 40 50 60 1d 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 22 -00 00 00 00 0c 1f 84 c0 de ad 01 1b 86 11 22 33 40 50 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 22 - -Gbproxy global: - Invalid Routing Area Identifier : 1 - BSSGP protocol error (SGSN): 1 - Patch error: no peer : 1 -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de - -result (DETACH REQ) = 48 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 9 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 9 - TLLI patched (SGSN): 8 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - Detach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 9 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 9 - TLLI patched (SGSN): 9 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI-Cache: 0 -PROCESSING RA UPD REQ from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 - -CALLBACK, event 0, msg length 85, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (RA UPD REQ) = 0 - -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 19 08 16 08 11 12 13 14 15 16 17 18 35 23 fc - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 19 08 16 08 11 12 13 14 15 16 17 18 35 23 fc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 85 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 89 -00 00 10 02 01 78 de ad 02 00 00 04 08 88 21 63 54 00 63 60 70 80 00 80 0e 00 3e 01 c0 15 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 96 3e 97 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 9 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead02, IMSI 12131415161718, AGE 0 -PROCESSING RA UDP ACC from 0x05060708:32000 -00 00 10 02 00 78 de ad 02 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 11 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 36 98 77 - -CALLBACK, event 0, msg length 87, bvci 0x1002 -00 00 10 02 00 78 de ad 02 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 11 08 09 00 49 21 63 54 40 50 60 19 54 ab b3 18 05 f4 ef e2 b7 00 17 16 36 98 77 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 87 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 91 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9d 41 c0 11 08 09 00 49 11 22 33 40 50 60 19 54 ab b3 18 05 f4 c0 de ad 03 17 16 6e 58 26 - -result (RA UDP ACC) = 91 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 10 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead03 -> 78dead02/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 1d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb aa cc a3 - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 1d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb aa cc a3 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 06 00 11 f5 c0 - -result (DETACH REQ) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 10 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 2 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead03 -> 78dead02/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 c0 de ad 03 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 15 08 06 00 f7 35 f0 - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 11 - P-TMSI patched (SGSN): 2 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 2 - Detach Accept count : 2 - TLLI-Cache: 0 -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 b6 bb - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 b6 bb - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 25 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 1d aa 57 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 25 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 1d aa 57 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 05 08 15 01 8f 47 9e - -result (ATTACH REQUEST) = 0 - -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 29 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb d9 1d ef - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 29 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb d9 1d ef - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 09 08 06 00 da 80 ca - -result (DETACH REQ) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 11 - P-TMSI patched (SGSN): 2 - Attach Request count : 3 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 3 - Detach Accept count : 2 - TLLI-Cache: 0 -PROCESSING DETACH REQ (unknown TLLI) from 0x01020304:1111 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 2d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 0d 30 0d - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 2d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 0d 30 0d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 06 00 11 f5 c0 - -result (DETACH REQ (unknown TLLI)) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 11 - P-TMSI patched (SGSN): 2 - Attach Request count : 3 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 1 - RoutingArea Update Accept count : 1 - Detach Request count : 4 - Detach Accept count : 2 - TLLI-Cache: 0 -PROCESSING RA UPD REQ from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 31 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 d8 cf d8 - -CALLBACK, event 0, msg length 85, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 31 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 d8 cf d8 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (RA UPD REQ) = 0 - -PROCESSING RA UPD REQ from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 35 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 ac 9c 37 - -CALLBACK, event 0, msg length 85, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 70 80 00 80 0e 00 3e 01 c0 35 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 ac 9c 37 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 05 08 15 01 8f 47 9e - -result (RA UPD REQ) = 0 - -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 39 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 44 b6 8a - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 39 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 44 b6 8a - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 09 08 06 00 da 80 ca - -result (DETACH REQ) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 11 - P-TMSI patched (SGSN): 2 - Attach Request count : 3 - Attach Accept count : 1 - Attach Completed count : 1 - RoutingArea Update Request count: 3 - RoutingArea Update Accept count : 1 - Detach Request count : 5 - Detach Accept count : 2 - TLLI-Cache: 0 -Gbproxy global: - Invalid Routing Area Identifier : 1 - BSSGP protocol error (SGSN): 1 - Patch error: no peer : 1 -=== test_gbproxy_secondary_sgsn === ---- Initialise SGSN 1 --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise SGSN 2 --- - -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 12 -02 00 81 01 01 82 01 03 04 82 01 02 - -PROCESSING RESET_ACK from 0x15161718:32001 -03 01 82 01 03 04 82 01 02 - -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x15161718:32001 -0b - -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x15161718:32001 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0103/21.22.23.24:32001 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x15161718:32001 -0a - -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x0000(0) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 00 00 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 00 00 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 00 00 - -result (BVC_RESET) = 9 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 00 00 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 00 00 - -result (BVC_RESET_ACK) = -2 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 21 63 54 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -PROCESSING BVC_RESET_ACK from 0x15161718:32001 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 1 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0103, NSEI 0x0102, peer 0x15161718:32001 - NS-VC Block count : 1 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Gbproxy global: - Invalid BVC Identifier : 1 - Patch error: no peer : 1 -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 1 - TLLI-Cache: 0 ---- Flow control --- - -PROCESSING FLOW_CONTROL_BVC from 0x01020304:1111 -00 00 10 02 26 1e 81 01 05 82 01 dc 03 82 02 76 01 82 00 50 1c 82 02 58 06 82 00 03 - -CALLBACK, event 0, msg length 24, bvci 0x1002 -00 00 10 02 26 1e 81 01 05 82 01 dc 03 82 02 76 01 82 00 50 1c 82 02 58 06 82 00 03 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 28 -00 00 10 02 26 1e 81 01 05 82 01 dc 03 82 02 76 01 82 00 50 1c 82 02 58 06 82 00 03 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 28 -00 00 10 02 26 1e 81 01 05 82 01 dc 03 82 02 76 01 82 00 50 1c 82 02 58 06 82 00 03 - -result (FLOW_CONTROL_BVC) = 28 - -PROCESSING FLOW_CONTROL_BVC_ACK from 0x05060708:32000 -00 00 10 02 27 1e 81 01 - -CALLBACK, event 0, msg length 4, bvci 0x1002 -00 00 10 02 27 1e 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 4 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 8 -00 00 10 02 27 1e 81 01 - -result (FLOW_CONTROL_BVC_ACK) = 8 - -PROCESSING FLOW_CONTROL_BVC_ACK from 0x15161718:32001 -00 00 10 02 27 1e 81 01 - -CALLBACK, event 0, msg length 4, bvci 0x1002 -00 00 10 02 27 1e 81 01 - -result (FLOW_CONTROL_BVC_ACK) = 0 - ---- Establish GPRS connection (SGSN 1) --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress, SGSN NSEI 65535 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 2 - TLLI patched (BSS ): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 2 - TLLI patched (BSS ): 1 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 78 de ad 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -result (IDENT RESPONSE) = 44 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 1 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 78dead00, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 78 de ad 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 de ad 01 0c 0a 29 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 3 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 2 - TLLI patched (SGSN): 2 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 2 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead/c0dead01 -> 78dead00/efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 4 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 3 - TLLI patched (SGSN): 3 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING XID (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -CALLBACK, event 0, msg length 38, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 38 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 42 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -result (XID (UL)) = 42 - -PROCESSING XID (DL) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -CALLBACK, event 0, msg length 70, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 70 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 74 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -result (XID (DL)) = 74 - -PROCESSING LL11 DNS QUERY (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -CALLBACK, event 0, msg length 89, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 89 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 93 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -result (LL11 DNS QUERY (UL)) = 93 - -PROCESSING LL11 DNS RESP (DL) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -CALLBACK, event 0, msg length 267, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 267 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 271 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -result (LL11 DNS RESP (DL)) = 271 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 6 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 5 - TLLI patched (SGSN): 5 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING LLC_DISCARDED from 0x01020304:1111 -00 00 00 00 2c 1f 84 c0 de ad 01 0f 81 01 04 82 10 02 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 c0 de ad 01 0f 81 01 04 82 10 02 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 19 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 23 -00 00 00 00 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -result (LLC_DISCARDED) = 23 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 6 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 6 - TLLI patched (SGSN): 5 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING LLC_DISCARDED from 0x05060708:32000 -00 00 00 00 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 25 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 29 -00 00 00 00 41 07 81 27 15 93 2c 1f 84 ef e2 b7 00 0f 81 01 04 82 10 02 25 83 00 00 0c - -result (LLC_DISCARDED) = 29 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 6 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 6 - TLLI patched (SGSN): 6 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING BVC_SUSPEND from 0x01020304:1111 -00 00 00 00 0b 1f 84 c0 de ad 01 1b 86 11 22 33 40 50 60 - -CALLBACK, event 0, msg length 15, bvci 0x0000 -00 00 00 00 0b 1f 84 c0 de ad 01 1b 86 11 22 33 40 50 60 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 15 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 19 -00 00 00 00 0b 1f 84 ef e2 b7 00 1b 86 21 63 54 40 50 60 - -result (BVC_SUSPEND) = 19 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 7 - RAID patched (SGSN): 1 - TLLI patched (BSS ): 7 - TLLI patched (SGSN): 6 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING BVC_SUSPEND_ACK from 0x05060708:32000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 21 63 54 40 50 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 ef e2 b7 00 1b 86 21 63 54 40 50 60 1d 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 22 -00 00 00 00 0c 1f 84 c0 de ad 01 1b 86 11 22 33 40 50 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 22 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 7 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 7 - TLLI patched (SGSN): 7 - P-TMSI patched (SGSN): 1 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 ---- Establish GPRS connection (SGSN 2) --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 11 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 bf 00 5c - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 11 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 bf 00 5c - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 7 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 7 - TLLI patched (SGSN): 7 - P-TMSI patched (SGSN): 1 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef -> 78dead02, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress, SGSN NSEI 65535 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 15 08 16 08 11 12 99 99 99 16 17 18 b2 dd 58 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 15 08 16 08 11 12 99 99 99 16 17 18 b2 dd 58 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 79 -00 00 10 02 01 78 de ad 02 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 11 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 bf 00 5c - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 8 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 8 - TLLI patched (SGSN): 7 - P-TMSI patched (SGSN): 1 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT REQUEST from 0x15161718:32001 -00 00 10 02 00 78 de ad 02 00 50 20 16 82 02 58 0e 89 41 c0 0d 08 15 01 0c a6 18 - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 78 de ad 02 00 50 20 16 82 02 58 0e 89 41 c0 0d 08 15 01 0c a6 18 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 0e 89 41 c0 0d 08 15 01 0c a6 18 - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 8 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 8 - TLLI patched (SGSN): 8 - P-TMSI patched (SGSN): 1 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 19 08 16 08 11 12 99 99 99 16 17 18 a5 cc b3 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 be ef 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 19 08 16 08 11 12 99 99 99 16 17 18 a5 cc b3 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 44 -00 00 10 02 01 78 de ad 02 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 19 08 16 08 11 12 99 99 99 16 17 18 a5 cc b3 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 9 - RAID patched (SGSN): 2 - TLLI patched (BSS ): 9 - TLLI patched (SGSN): 8 - P-TMSI patched (SGSN): 1 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef -> 78dead02, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING ATTACH ACCEPT from 0x15161718:32001 -00 00 10 02 00 78 de ad 02 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 e0 98 76 54 cb 1c 5b - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 78 de ad 02 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 e0 98 76 54 cb 1c 5b - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 be ef 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 de ad 03 32 40 fa - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 9 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 9 - TLLI patched (SGSN): 9 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef/c0dead03 -> 78dead02/e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 1d 08 03 5e 3a ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 1d 08 03 5e 3a ea - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 35 -00 00 10 02 01 e0 98 76 54 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 1d 08 03 5e 3a ea - -result (ATTACH COMPLETE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 9 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI 8000beef/c0dead03 -> 78dead02/e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING GMM INFO from 0x15161718:32001 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 c0 de ad 03 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 88 41 c0 15 08 21 bb c1 c6 - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 10 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 10 - TLLI patched (SGSN): 10 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING XID (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -CALLBACK, event 0, msg length 38, bvci 0x1002 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 38 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 42 -00 00 10 02 01 e0 98 76 54 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 0f 41 fb 01 00 0e 00 64 11 05 16 01 90 66 b3 28 - -result (XID (UL)) = 0 - -PROCESSING XID (DL) from 0x15161718:32001 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -CALLBACK, event 0, msg length 70, bvci 0x1002 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 70 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 74 -00 00 10 02 00 c0 de ad 03 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 8c 41 fb 30 84 10 61 b6 64 e4 a9 1a 9e - -result (XID (DL)) = 74 - -PROCESSING LL11 DNS QUERY (UL) from 0x01020304:1111 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -CALLBACK, event 0, msg length 89, bvci 0x1002 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 89 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 93 -00 00 10 02 01 e0 98 76 54 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 42 0b c0 01 65 00 00 00 45 00 00 38 95 72 00 00 45 11 20 85 0a c0 07 e4 ac 10 01 0a ad ab 00 35 00 24 0e 1c 3b e0 01 00 00 01 00 00 00 00 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 47 8f 07 - -result (LL11 DNS QUERY (UL)) = 0 - -PROCESSING LL11 DNS RESP (DL) from 0x15161718:32001 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -CALLBACK, event 0, msg length 267, bvci 0x1002 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 267 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 271 -00 00 10 02 00 c0 de ad 03 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 00 d0 4b c0 01 65 00 00 00 45 00 00 c6 00 00 40 00 3e 11 7c 69 ac 10 01 0a 0a c0 07 e4 00 35 ad ab 00 b2 74 4e 3b e0 81 80 00 01 00 01 00 05 00 00 01 6d 05 68 65 69 73 65 02 64 65 00 00 01 00 01 c0 0c 00 01 00 01 00 00 0e 10 00 04 c1 63 90 58 c0 0e 00 02 00 01 00 00 0e 10 00 16 03 6e 73 32 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 03 6e 65 74 00 c0 0e 00 02 00 01 00 00 0e 10 00 10 02 6e 73 01 73 08 70 6c 75 73 6c 69 6e 65 c0 14 c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 0e c0 0e 00 02 00 01 00 00 0e 10 00 05 02 6e 73 c0 5f c0 0e 00 02 00 01 00 00 0e 10 00 12 02 6e 73 0c 70 6f 70 2d 68 61 6e 6e 6f 76 65 72 c0 14 aa df 31 - -result (LL11 DNS RESP (DL)) = 271 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 12 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 12 - TLLI patched (SGSN): 12 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING LLC_DISCARDED from 0x01020304:1111 -00 00 00 00 2c 1f 84 c0 de ad 03 0f 81 01 04 82 10 02 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 c0 de ad 03 0f 81 01 04 82 10 02 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x0000, msg length 19 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 23 -00 00 00 00 2c 1f 84 e0 98 76 54 0f 81 01 04 82 10 02 25 83 00 00 0c - -result (LLC_DISCARDED) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 12 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 13 - TLLI patched (SGSN): 12 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING LLC_DISCARDED from 0x15161718:32001 -00 00 00 00 2c 1f 84 e0 98 76 54 0f 81 01 04 82 10 02 25 83 00 00 0c - -CALLBACK, event 0, msg length 19, bvci 0x0000 -00 00 00 00 2c 1f 84 e0 98 76 54 0f 81 01 04 82 10 02 25 83 00 00 0c - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x0000, msg length 25 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 29 -00 00 00 00 41 07 81 27 15 93 2c 1f 84 e0 98 76 54 0f 81 01 04 82 10 02 25 83 00 00 0c - -result (LLC_DISCARDED) = 29 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 12 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 13 - TLLI patched (SGSN): 13 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING BVC_SUSPEND from 0x01020304:1111 -00 00 00 00 0b 1f 84 c0 de ad 03 1b 86 11 22 33 40 50 60 - -CALLBACK, event 0, msg length 15, bvci 0x0000 -00 00 00 00 0b 1f 84 c0 de ad 03 1b 86 11 22 33 40 50 60 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x0000, msg length 15 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 19 -00 00 00 00 0b 1f 84 e0 98 76 54 1b 86 21 63 54 40 50 60 - -result (BVC_SUSPEND) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 - RAID patched (SGSN): 3 - TLLI patched (BSS ): 14 - TLLI patched (SGSN): 13 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING BVC_SUSPEND_ACK from 0x15161718:32001 -00 00 00 00 0c 1f 84 e0 98 76 54 1b 86 21 63 54 40 50 60 1d 81 01 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 0c 1f 84 e0 98 76 54 1b 86 21 63 54 40 50 60 1d 81 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 22 -00 00 00 00 0c 1f 84 c0 de ad 03 1b 86 11 22 33 40 50 60 1d 81 01 - -result (BVC_SUSPEND_ACK) = 22 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 14 - TLLI patched (SGSN): 14 - P-TMSI patched (SGSN): 2 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 ---- Establish GPRS connection (SGSN 2, P-TMSI collision) --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 fe ed 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 b6 bb - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 fe ed 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 b6 bb - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 fe ed 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 13 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 14 - TLLI patched (SGSN): 14 - P-TMSI patched (SGSN): 2 - Attach Request count : 3 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI 8000feed -> 78dead04, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress, SGSN NSEI 65535 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 fe ed 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 25 08 16 08 11 12 99 99 99 26 27 28 58 c7 cb - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 fe ed 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 25 08 16 08 11 12 99 99 99 26 27 28 58 c7 cb - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 79 -00 00 10 02 01 78 de ad 04 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 b6 bb - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 14 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 15 - TLLI patched (SGSN): 14 - P-TMSI patched (SGSN): 2 - Attach Request count : 3 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT REQUEST from 0x15161718:32001 -00 00 10 02 00 78 de ad 04 00 50 20 16 82 02 58 0e 89 41 c0 19 08 15 01 a2 f2 a4 - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 78 de ad 04 00 50 20 16 82 02 58 0e 89 41 c0 19 08 15 01 a2 f2 a4 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 fe ed 00 50 20 16 82 02 58 0e 89 41 c0 19 08 15 01 a2 f2 a4 - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 14 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 15 - TLLI patched (SGSN): 15 - P-TMSI patched (SGSN): 2 - Attach Request count : 3 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 fe ed 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 29 08 16 08 11 12 99 99 99 26 27 28 4f d6 20 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 fe ed 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 29 08 16 08 11 12 99 99 99 26 27 28 4f d6 20 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 44 -00 00 10 02 01 78 de ad 04 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 29 08 16 08 11 12 99 99 99 26 27 28 4f d6 20 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 15 - RAID patched (SGSN): 4 - TLLI patched (BSS ): 16 - TLLI patched (SGSN): 15 - P-TMSI patched (SGSN): 2 - Attach Request count : 3 - Attach Accept count : 2 - Attach Completed count : 2 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI 8000feed -> 78dead04, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING ATTACH ACCEPT (P-TMSI 1) from 0x15161718:32001 -00 00 10 02 00 78 de ad 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 9e 41 c0 1d 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 74 91 01 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 78 de ad 04 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 9e 41 c0 1d 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 74 91 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 80 00 fe ed 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 9e 41 c0 1d 08 02 01 49 04 11 22 33 40 50 60 19 cd d7 08 17 16 18 05 f4 c0 de ad 05 3e 78 6e - -result (ATTACH ACCEPT (P-TMSI 1)) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 15 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 16 - TLLI patched (SGSN): 16 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 2 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI 8000feed/c0dead05 -> 78dead04/efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 c0 de ad 05 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 2d 08 03 43 50 ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 c0 de ad 05 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 2d 08 03 43 50 ea - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 2d 08 03 43 50 ea - -result (ATTACH COMPLETE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 16 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 17 - TLLI patched (SGSN): 16 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI 8000feed/c0dead05 -> 78dead04/efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 -PROCESSING GMM INFO from 0x15161718:32001 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 88 41 c0 21 08 21 ca 60 90 - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 88 41 c0 21 08 21 ca 60 90 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 c0 de ad 05 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 88 41 c0 21 08 21 ca 60 90 - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 16 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 17 - TLLI patched (SGSN): 17 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 ---- Shutdown GPRS connection (SGSN 1) --- - -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 31 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 57 e6 15 - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 c0 de ad 01 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 31 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 57 e6 15 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 31 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 57 e6 15 - -result (DETACH REQ) = 48 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 17 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 18 - TLLI patched (SGSN): 17 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 1 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI c0dead01 -> efe2b700, IMSI 12131415161718, AGE 0, SGSN NSEI 256 - TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 25 08 06 00 4d 09 cd - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 25 08 06 00 4d 09 cd - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 c0 de ad 01 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 25 08 06 00 4d 09 cd - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 17 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 18 - TLLI patched (SGSN): 18 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 ---- Shutdown GPRS connection (SGSN 2) --- - -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 35 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 83 cb f7 - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 c0 de ad 03 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 35 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 83 cb f7 - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 48 -00 00 10 02 01 e0 98 76 54 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 35 08 05 01 18 05 f4 e0 98 76 54 19 03 b9 97 cb b4 31 31 - -result (DETACH REQ) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 18 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 19 - TLLI patched (SGSN): 18 - P-TMSI patched (BSS ): 1 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 2 - Detach Accept count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI c0dead03 -> e0987654, IMSI 12199999961718, AGE 0, IMSI matches, SGSN NSEI 258 - TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 -PROCESSING DETACH ACC from 0x15161718:32001 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 89 41 c0 29 08 06 00 be c3 6f - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 e0 98 76 54 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 89 41 c0 29 08 06 00 be c3 6f - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 c0 de ad 03 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 16 17 18 00 81 00 0e 89 41 c0 29 08 06 00 be c3 6f - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 18 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 19 - TLLI patched (SGSN): 19 - P-TMSI patched (BSS ): 1 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 2 - Detach Accept count : 2 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 ---- Shutdown GPRS connection (SGSN 2, P-TMSI 1) --- - -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 c0 de ad 05 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 39 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 44 b6 8a - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 c0 de ad 05 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 39 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 44 b6 8a - -NS UNITDATA MESSAGE to SGSN 2, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN 2 at 0x15161718:32001, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 39 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 44 b6 8a - -result (DETACH REQ) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 19 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 20 - TLLI patched (SGSN): 19 - P-TMSI patched (BSS ): 1 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 3 - Detach Accept count : 2 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0dead05 -> efe2b700, IMSI 12199999962728, AGE 0, IMSI matches, SGSN NSEI 258 -PROCESSING DETACH ACC from 0x15161718:32001 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 89 41 c0 2d 08 06 00 86 7c c7 - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 89 41 c0 2d 08 06 00 86 7c c7 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 c0 de ad 05 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 99 99 99 26 27 28 00 81 00 0e 89 41 c0 2d 08 06 00 86 7c c7 - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - RAID patched (BSS ): 19 - RAID patched (SGSN): 5 - TLLI patched (BSS ): 20 - TLLI patched (SGSN): 20 - P-TMSI patched (BSS ): 1 - P-TMSI patched (SGSN): 3 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 3 - Detach Accept count : 3 - TLLI-Cache: 0 -Gbproxy global: - Invalid BVC Identifier : 1 - BSSGP protocol error (SGSN): 2 - Patch error: no peer : 1 -=== test_gbproxy_keep_info === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Send message from BSS 1 to SGSN, BVCI 0x1002 --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 44 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -result (IDENT RESPONSE) = 44 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 05 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 53 62 f1 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 09 08 21 04 ba 3d - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 48 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de - -result (DETACH REQ) = 48 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - Detach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 0d 08 06 00 aa ab ee - -result (DETACH ACC) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - Attach Accept count : 1 - Attach Completed count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 15 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e6 71 c7 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 15 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e6 71 c7 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 15 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e6 71 c7 - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 1 - Attach Completed count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 3a 6d d4 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 3a 6d d4 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 11 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 3a 6d d4 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 19 08 03 32 f1 bc - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 19 08 03 32 f1 bc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 19 08 03 32 f1 bc - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ (re-attach) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 15 08 05 01 25 0a 67 0e 96 - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 15 08 05 01 25 0a 67 0e 96 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 15 08 05 01 25 0a 67 0e 96 - -result (DETACH REQ (re-attach)) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 1d 08 06 3d 1c 8b - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 1d 08 06 3d 1c 8b - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 1d 08 06 3d 1c 8b - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 2 - Attach Accept count : 2 - Attach Completed count : 2 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 db cc - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 db cc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 21 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 44 db cc - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 3 - Attach Accept count : 2 - Attach Completed count : 2 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 19 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 27 3c 84 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 19 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 27 3c 84 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 19 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 27 3c 84 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 2 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 25 08 03 9b c6 47 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 25 08 03 9b c6 47 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 25 08 03 9b c6 47 - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 1d 08 05 02 25 0a dd 56 6c - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 1d 08 05 02 25 0a dd 56 6c - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 1d 08 05 02 25 0a dd 56 6c - -result (DETACH REQ) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 29 08 06 4c bd dd - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 29 08 06 4c bd dd - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 29 08 06 4c bd dd - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 3 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST (IMSI) from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 37 01 c0 2d 08 01 02 f5 e0 21 08 02 08 11 12 13 14 15 16 17 18 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 a5 85 76 - -CALLBACK, event 0, msg length 78, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 37 01 c0 2d 08 01 02 f5 e0 21 08 02 08 11 12 13 14 15 16 17 18 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 a5 85 76 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 78 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 82 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 37 01 c0 2d 08 01 02 f5 e0 21 08 02 08 11 12 13 14 15 16 17 18 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 a5 85 76 - -result (ATTACH REQUEST (IMSI)) = 82 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 4 - Attach Accept count : 3 - Attach Completed count : 3 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 21 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 cf 80 6e - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 21 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 cf 80 6e - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 21 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 cf 80 6e - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 4 - Attach Accept count : 4 - Attach Completed count : 3 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 31 08 03 fc 2b 11 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 31 08 03 fc 2b 11 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 31 08 03 fc 2b 11 - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 4 - Attach Accept count : 4 - Attach Completed count : 4 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 25 08 05 02 25 0a 8e ee 85 - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 25 08 05 02 25 0a 8e ee 85 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 25 08 05 02 25 0a 8e ee 85 - -result (DETACH REQ) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 4 - Attach Accept count : 4 - Attach Completed count : 4 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 35 08 06 f3 c6 26 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 35 08 06 f3 c6 26 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 35 08 06 f3 c6 26 - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 4 - Attach Accept count : 4 - Attach Completed count : 4 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 39 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e4 85 12 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 39 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e4 85 12 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 39 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e4 85 12 - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 5 - Attach Accept count : 4 - Attach Completed count : 4 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 29 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 d2 d1 3e - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 29 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 d2 d1 3e - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 29 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 d2 d1 3e - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 5 - Attach Accept count : 5 - Attach Completed count : 4 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 3d 08 03 48 76 ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 3d 08 03 48 76 ea - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 3d 08 03 48 76 ea - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 5 - Attach Accept count : 5 - Attach Completed count : 5 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING RA UPD REQ from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 41 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 30 73 32 - -CALLBACK, event 0, msg length 85, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 41 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 30 73 32 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 85 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 89 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 70 80 00 80 0e 00 3e 01 c0 41 08 08 10 11 22 33 40 50 60 1d 19 13 42 33 57 2b f7 c8 48 02 13 48 50 c8 48 02 14 48 50 c8 48 02 17 49 10 c8 48 02 00 19 8b b2 92 17 16 27 07 04 31 02 e5 e0 32 02 20 00 30 73 32 - -result (RA UPD REQ) = 89 - -PROCESSING RA UDP REJ from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8a 41 c0 2d 08 0b 0a 00 41 30 a7 - -CALLBACK, event 0, msg length 68, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8a 41 c0 2d 08 0b 0a 00 41 30 a7 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 68 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 72 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8a 41 c0 2d 08 0b 0a 00 41 30 a7 - -result (RA UDP REJ) = 72 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 5 - Attach Accept count : 5 - Attach Completed count : 5 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 45 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 50 cc c3 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 45 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 50 cc c3 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 6 - Attach Accept count : 5 - Attach Completed count : 5 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 2 - TLLI-Cache: 2 - TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 49 08 16 08 11 12 13 14 15 16 17 18 86 ca 3f - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 49 08 16 08 11 12 13 14 15 16 17 18 86 ca 3f - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 45 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 50 cc c3 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 6 - Attach Accept count : 5 - Attach Completed count : 5 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 31 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 f5 22 ce - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 31 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 f5 22 ce - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 31 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 f5 22 ce - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 6 - Attach Accept count : 6 - Attach Completed count : 5 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 4d 08 03 79 84 ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 4d 08 03 79 84 ea - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 4d 08 03 79 84 ea - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 6 - Attach Accept count : 6 - Attach Completed count : 6 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 35 08 05 02 25 0a 9b fa 57 - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 35 08 05 02 25 0a 9b fa 57 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 35 08 05 02 25 0a 9b fa 57 - -result (DETACH REQ) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 6 - Attach Accept count : 6 - Attach Completed count : 6 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 51 08 06 a5 d9 70 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 51 08 06 a5 d9 70 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 51 08 06 a5 d9 70 - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 6 - Attach Accept count : 6 - Attach Completed count : 6 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST (local TLLI) from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 55 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 f9 cc e9 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 55 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 f9 cc e9 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 55 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 f9 cc e9 - -result (ATTACH REQUEST (local TLLI)) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 7 - Attach Accept count : 6 - Attach Completed count : 6 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 39 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 e8 73 9e - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 39 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 e8 73 9e - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 39 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 e8 73 9e - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 7 - Attach Accept count : 7 - Attach Completed count : 6 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 59 08 03 1e 69 bc - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 59 08 03 1e 69 bc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 59 08 03 1e 69 bc - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 7 - Attach Accept count : 7 - Attach Completed count : 7 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ (re-attach) from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 3d 08 05 01 25 0a 21 a2 ad - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 3d 08 05 01 25 0a 21 a2 ad - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 3d 08 05 01 25 0a 21 a2 ad - -result (DETACH REQ (re-attach)) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 7 - Attach Accept count : 7 - Attach Completed count : 7 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 5d 08 06 11 84 8b - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 5d 08 06 11 84 8b - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 5d 08 06 11 84 8b - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 7 - Attach Accept count : 7 - Attach Completed count : 7 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 61 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 5b 66 e2 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 61 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 5b 66 e2 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 61 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 5b 66 e2 - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 8 - Attach Accept count : 7 - Attach Completed count : 7 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 41 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 9e 50 40 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 41 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 9e 50 40 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 41 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 9e 50 40 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 8 - Attach Accept count : 8 - Attach Completed count : 7 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 65 08 03 b7 5e 47 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 65 08 03 b7 5e 47 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 65 08 03 b7 5e 47 - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 8 - Attach Accept count : 8 - Attach Completed count : 8 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 45 08 21 9c 7f c6 - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 45 08 21 9c 7f c6 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 45 08 21 9c 7f c6 - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 8 - Attach Accept count : 8 - Attach Completed count : 8 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH REQUEST (unexpected, IMSI) from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 37 01 c0 69 08 01 02 f5 e0 21 08 02 08 11 12 13 14 15 16 17 18 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e1 11 8e - -CALLBACK, event 0, msg length 78, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 37 01 c0 69 08 01 02 f5 e0 21 08 02 08 11 12 13 14 15 16 17 18 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e1 11 8e - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 78 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 82 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 37 01 c0 69 08 01 02 f5 e0 21 08 02 08 11 12 13 14 15 16 17 18 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 e1 11 8e - -result (ATTACH REQUEST (unexpected, IMSI)) = 82 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 9 - Attach Accept count : 8 - Attach Completed count : 8 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 49 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 83 01 10 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 49 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 83 01 10 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 49 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 83 01 10 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 9 - Attach Accept count : 9 - Attach Completed count : 8 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 6d 08 03 6f c8 ea - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 6d 08 03 6f c8 ea - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 6d 08 03 6f c8 ea - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 9 - Attach Accept count : 9 - Attach Completed count : 9 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 4d 08 05 02 25 0a 51 0e 1b - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 4d 08 05 02 25 0a 51 0e 1b - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 4d 08 05 02 25 0a 51 0e 1b - -result (DETACH REQ) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 9 - Attach Accept count : 9 - Attach Completed count : 9 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 71 08 06 b3 95 70 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 71 08 06 b3 95 70 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 71 08 06 b3 95 70 - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 9 - Attach Accept count : 9 - Attach Completed count : 9 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 75 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 ab 17 53 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 75 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 ab 17 53 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 75 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 ab 17 53 - -result (ATTACH REQUEST) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 10 - Attach Accept count : 9 - Attach Completed count : 9 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 51 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 a4 f2 e0 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 51 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 a4 f2 e0 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 51 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 a4 f2 e0 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 10 - Attach Accept count : 10 - Attach Completed count : 9 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 79 08 03 08 25 bc - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 79 08 03 08 25 bc - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 79 08 03 08 25 bc - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 10 - Attach Accept count : 10 - Attach Completed count : 10 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING GMM INFO from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 55 08 21 97 59 c6 - -CALLBACK, event 0, msg length 66, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 55 08 21 97 59 c6 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 66 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 70 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 88 41 c0 55 08 21 97 59 c6 - -result (GMM INFO) = 70 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 10 - Attach Accept count : 10 - Attach Completed count : 10 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH REQUEST (unexpected) from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 7d 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 a2 24 d0 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 7d 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 a2 24 d0 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 7d 08 01 02 f5 e0 21 08 02 05 f4 ef e2 b7 00 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 a2 24 d0 - -result (ATTACH REQUEST (unexpected)) = 79 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 11 - Attach Accept count : 10 - Attach Completed count : 10 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH ACCEPT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 59 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 b9 a3 b0 - -CALLBACK, event 0, msg length 88, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 59 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 b9 a3 b0 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 88 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 92 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 9e 41 c0 59 08 02 01 49 04 21 63 54 40 50 60 19 cd d7 08 17 16 18 05 f4 ef e2 b7 00 b9 a3 b0 - -result (ATTACH ACCEPT) = 92 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 11 - Attach Accept count : 11 - Attach Completed count : 10 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH COMPLETE from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 81 08 03 b9 71 10 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 81 08 03 b9 71 10 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 81 08 03 b9 71 10 - -result (ATTACH COMPLETE) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 11 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700/efe2b700 -> afe2b700/efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH REQ from 0x05060708:32000 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 5d 08 05 02 25 0a 44 1a c9 - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 5d 08 05 02 25 0a 44 1a c9 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 ef e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 5d 08 05 02 25 0a 44 1a c9 - -result (DETACH REQ) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 11 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI efe2b700 -> efe2b700, IMSI 12131415161718, AGE 0 -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 85 08 06 b6 9c 27 - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 85 08 06 b6 9c 27 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 85 08 06 b6 9c 27 - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 11 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 89 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 21 24 df - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 89 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 21 24 df - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 12 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 8d 08 16 08 11 12 13 14 15 16 17 18 74 ac 38 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 8d 08 16 08 11 12 13 14 15 16 17 18 74 ac 38 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 89 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 21 24 df - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 12 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0 -PROCESSING ATTACH REJECT from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 61 08 04 07 79 ba a5 - -CALLBACK, event 0, msg length 67, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 61 08 04 07 79 ba a5 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 67 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 71 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 89 41 c0 61 08 04 07 79 ba a5 - -result (ATTACH REJECT) = 71 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 12 - Attach Reject count : 1 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 91 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 81 7a 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 91 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 81 7a 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 13 - Attach Reject count : 1 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 1 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING DETACH REQ (MO) from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 95 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 9c dc fc - -CALLBACK, event 0, msg length 44, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 95 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 9c dc fc - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 00 09 41 c4 05 08 06 00 29 4a 68 - -result (DETACH REQ (MO)) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 13 - Attach Reject count : 1 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 2 - Detach Accept count : 1 - TLLI-Cache: 0 -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 99 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 88 49 82 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 99 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 88 49 82 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 14 - Attach Reject count : 1 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 2 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING DETACH REQ (MT) from 0x05060708:32000 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 65 08 05 02 25 0a 17 a2 20 - -CALLBACK, event 0, msg length 69, bvci 0x1002 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 65 08 05 02 25 0a 17 a2 20 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 69 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 73 -00 00 10 02 00 af e2 b7 00 00 50 20 16 82 02 58 13 99 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 0a 82 08 02 0d 88 11 12 13 14 15 16 17 18 00 81 00 0e 8b 41 c0 65 08 05 02 25 0a 17 a2 20 - -result (DETACH REQ (MT)) = 73 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 14 - Attach Reject count : 1 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 2 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI afe2b700 -> afe2b700, IMSI 12131415161718, AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING DETACH ACC from 0x01020304:1111 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 9d 08 06 65 2c 8a - -CALLBACK, event 0, msg length 31, bvci 0x1002 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 9d 08 06 65 2c 8a - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 34 01 c0 99 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 88 49 82 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 35 -00 00 10 02 01 af e2 b7 00 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 9d 08 06 65 2c 8a - -result (DETACH ACC) = 35 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 14 - Attach Reject count : 1 - Attach Accept count : 11 - Attach Completed count : 11 - RoutingArea Update Request count: 1 - RoutingArea Update Reject count : 1 - Detach Request count : 2 - Detach Accept count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 00000000, IMSI 12131415161718, AGE 0, DE-REGISTERED -Gbproxy global: -Test TLLI info expiry - -Test TLLI replacement: - Add TLLI 1, IMSI 1 - Add TLLI 2, IMSI 1 (should replace TLLI 1) - Peers: - NSEI 0, BVCI 20, not blocked, RAI 0-0-0-0 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c000162e, IMSI 03242526, AGE 0, IMSI matches - -Test IMSI replacement: - Add TLLI 1, IMSI 1 - Add TLLI 1, IMSI 2 (should replace IMSI 1) - Peers: - NSEI 0, BVCI 20, not blocked, RAI 0-0-0-0 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c00004d2, IMSI 06272829, AGE 0, IMSI matches - -Test TLLI expiry, max_len == 1: - Add TLLI 1, IMSI 1 - Add TLLI 2, IMSI 2 (should replace IMSI 1) - Peers: - NSEI 0, BVCI 20, not blocked, RAI 0-0-0-0 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c000162e, IMSI 06272829, AGE 0, IMSI matches - -Test TLLI expiry, max_age == 1: - Add TLLI 1, IMSI 1 (should expire after timeout) - Add TLLI 2, IMSI 2 (should not expire after timeout) - Peers: - NSEI 0, BVCI 20, not blocked, RAI 0-0-0-0 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c000162e, IMSI 06272829, AGE 1, IMSI matches - -Test TLLI expiry, max_len == 2, max_age == 1: - Add TLLI 1, IMSI 1 (should expire) - Add TLLI 2, IMSI 2 (should expire after timeout) - Add TLLI 3, IMSI 3 (should not expire after timeout) - Peers: - NSEI 0, BVCI 20, not blocked, RAI 0-0-0-0 - TLLI cache size : 3 - TLLI-Cache: 3 - TLLI c0000d80, IMSI 12345678, AGE 0, IMSI matches - TLLI c000162e, IMSI 06272829, AGE 1, IMSI matches - TLLI c00004d2, IMSI 03242526, AGE 2, IMSI matches - Remove stale TLLIs - Peers: - NSEI 0, BVCI 20, not blocked, RAI 0-0-0-0 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI c0000d80, IMSI 12345678, AGE 0, IMSI matches - -=== test_gbproxy_stored_messages === ---- Initialise SGSN --- - -MESSAGE to SGSN at 0x05060708:32000, msg length 12 -02 00 81 01 01 82 01 01 04 82 01 00 - -PROCESSING RESET_ACK from 0x05060708:32000 -03 01 82 01 01 04 82 01 00 - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0a - -result (RESET_ACK) = 1 - -PROCESSING ALIVE_ACK from 0x05060708:32000 -0b - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -06 - -result (ALIVE_ACK) = 1 - -PROCESSING UNBLOCK_ACK from 0x05060708:32000 -07 - -==> got signal NS_UNBLOCK, NS-VC 0x0101/5.6.7.8:32000 - -result (UNBLOCK_ACK) = 0 - -PROCESSING ALIVE from 0x05060708:32000 -0a - -MESSAGE to SGSN at 0x05060708:32000, msg length 1 -0b - -result (ALIVE) = 1 - ---- Initialise BSS 1 --- - -Setup NS-VC: remote 0x01020304:1111, NSVCI 0x1001(4097), NSEI 0x1000(4096) - -PROCESSING RESET from 0x01020304:1111 -02 00 81 01 01 82 10 01 04 82 10 00 - -==> got signal NS_RESET, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 9 -03 01 82 10 01 04 82 10 00 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0a - -result (RESET) = 9 - -PROCESSING ALIVE from 0x01020304:1111 -0a - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -0b - -result (ALIVE) = 1 - -PROCESSING UNBLOCK from 0x01020304:1111 -06 - -==> got signal NS_UNBLOCK, NS-VC 0x1001/1.2.3.4:1111 - -MESSAGE to BSS at 0x01020304:1111, msg length 1 -07 - -result (UNBLOCK) = 1 - -PROCESSING ALIVE_ACK from 0x01020304:1111 -0b - -result (ALIVE_ACK) = 0 - -Setup BSSGP: remote 0x01020304:1111, BVCI 0x1002(4098) - -PROCESSING BVC_RESET from 0x01020304:1111 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -CALLBACK, event 0, msg length 18, bvci 0x0000 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 18 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 22 -00 00 00 00 22 04 82 10 02 07 81 08 08 88 11 22 33 40 50 60 10 00 - -result (BVC_RESET) = 22 - -PROCESSING BVC_RESET_ACK from 0x05060708:32000 -00 00 00 00 23 04 82 10 02 - -CALLBACK, event 0, msg length 5, bvci 0x0000 -00 00 00 00 23 04 82 10 02 - -NS UNITDATA MESSAGE to BSS, BVCI 0x0000, msg length 5 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 9 -00 00 00 00 23 04 82 10 02 - -result (BVC_RESET_ACK) = 9 - -Current NS-VCIs: - VCI 0x1001, NSEI 0x1000, peer 0x01020304:1111 - VCI 0x0101, NSEI 0x0100, peer 0x05060708:32000 - NS-VC Block count : 1 - -Gbproxy global: -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - TLLI-Cache: 0 ---- Establish first LLC connection --- - -PROCESSING ATTACH REQUEST from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -CALLBACK, event 0, msg length 75, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 28 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c4 01 08 15 01 b7 f8 36 - -result (ATTACH REQUEST) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 8000dead, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING IDENT REQUEST from 0x05060708:32000 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -CALLBACK, event 0, msg length 23, bvci 0x1002 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 23 (gprs_ns_sendmsg) -MESSAGE to BSS at 0x01020304:1111, msg length 27 -00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba - -result (IDENT REQUEST) = 27 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 8000dead, IMSI (none), AGE 0, STORED 1, IMSI acquisition in progress -PROCESSING DETACH ACCEPT from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 09 01 c0 05 08 06 00 f8 92 41 - -CALLBACK, event 0, msg length 32, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 09 01 c0 05 08 06 00 f8 92 41 - -result (DETACH ACCEPT) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI cache size : 1 - TLLI-Cache: 1 - TLLI 8000dead -> 8000dead, IMSI (none), AGE 0, STORED 2, IMSI acquisition in progress -PROCESSING IDENT RESPONSE from 0x01020304:1111 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -CALLBACK, event 0, msg length 40, bvci 0x1002 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3 - -NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg) -MESSAGE to SGSN at 0x05060708:32000, msg length 79 -00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01 - -result (IDENT RESPONSE) = 0 - -Peers: - NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96 - Attach Request count : 1 - TLLI-Cache: 0 -Gbproxy global: -===== GbProxy test END - diff --git a/tests/gprs/Makefile.am b/tests/gprs/Makefile.am deleted file mode 100644 index 902313f2a..000000000 --- a/tests/gprs/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) - -EXTRA_DIST = gprs_test.ok - -noinst_PROGRAMS = gprs_test - -gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c - -gprs_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) diff --git a/tests/gprs/gprs_test.c b/tests/gprs/gprs_test.c deleted file mode 100644 index aac9bb896..000000000 --- a/tests/gprs/gprs_test.c +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#define ASSERT_FALSE(x) if (x) { printf("Should have returned false.\n"); abort(); } -#define ASSERT_TRUE(x) if (!x) { printf("Should have returned true.\n"); abort(); } - -/** - * GSM 04.64 8.4.2 Receipt of unacknowledged information - */ -static int nu_is_retransmission(uint16_t nu, uint16_t vur) -{ - int ret = gprs_llc_is_retransmit(nu, vur); - printf("N(U) = %d, V(UR) = %d => %s\n", nu, vur, - ret == 1 ? "retransmit" : "new"); - return ret; -} - -static void test_8_4_2() -{ - printf("Testing gprs_llc_is_retransmit.\n"); - - ASSERT_FALSE(nu_is_retransmission(0, 0)); - ASSERT_TRUE (nu_is_retransmission(0, 1)); - - /* expect 1... check for retransmissions */ - ASSERT_TRUE (nu_is_retransmission(0, 1)); - ASSERT_TRUE (nu_is_retransmission(511, 1)); - ASSERT_TRUE (nu_is_retransmission(483, 1)); - ASSERT_TRUE (nu_is_retransmission(482, 1)); - ASSERT_FALSE(nu_is_retransmission(481, 1)); - - /* expect 511... check for retransmissions */ - ASSERT_FALSE(nu_is_retransmission(0, 240)); // ahead - ASSERT_FALSE(nu_is_retransmission(0, 511)); // ahead - ASSERT_FALSE(nu_is_retransmission(1, 511)); // ahead - ASSERT_FALSE(nu_is_retransmission(511, 511)); // same - ASSERT_TRUE (nu_is_retransmission(510, 511)); // behind - ASSERT_TRUE (nu_is_retransmission(481, 511)); // behind - ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped -} - -static void test_gprs_timer_enc_dec(void) -{ - int i, u, secs, tmr; - const int upper_secs_test_limit = 12000; - int dec_secs, last_dec_secs = -1; - - printf("Test GPRS timer decoding/encoding\n"); - - /* Check gprs_tmr_to_secs with all 256 encoded values */ - for (u = 0; u <= GPRS_TMR_DEACTIVATED; u += 32) { - fprintf(stderr, "Testing decoding with timer value unit %u\n", - u / 32); - for (i = 0; i < 32; i++) { - switch (u) { - case GPRS_TMR_2SECONDS: - OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 2 * i); - break; - - default: - case GPRS_TMR_MINUTE: - OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 60 * i); - break; - - case GPRS_TMR_6MINUTE: - OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 360 * i); - break; - - case GPRS_TMR_DEACTIVATED: - OSMO_ASSERT(gprs_tmr_to_secs(u + i) == -1); - break; - } - - OSMO_ASSERT(gprs_tmr_to_secs(u + i) < upper_secs_test_limit); - } - } - - /* Check gprs_secs_to_tmr_floor for secs that can exactly be - * represented as GPRS timer values */ - for (i = 0; i < GPRS_TMR_DEACTIVATED; i++) { - int j; - secs = gprs_tmr_to_secs(i); - tmr = gprs_secs_to_tmr_floor(secs); - OSMO_ASSERT(secs == gprs_tmr_to_secs(tmr)); - - /* Check that the highest resolution is used */ - for (j = 0; j < tmr; j++) - OSMO_ASSERT(secs != gprs_tmr_to_secs(j)); - } - OSMO_ASSERT(GPRS_TMR_DEACTIVATED == gprs_secs_to_tmr_floor(-1)); - - /* Check properties of gprs_secs_to_tmr_floor */ - for (secs = 0; secs <= upper_secs_test_limit; secs++) { - int tmr = gprs_secs_to_tmr_floor(secs); - int delta_secs = gprs_tmr_to_secs((tmr & ~0x1f) | 1); - dec_secs = gprs_tmr_to_secs(tmr); - - /* Check floor */ - OSMO_ASSERT(dec_secs <= secs); - /* Check monotonicity */ - OSMO_ASSERT(dec_secs >= last_dec_secs); - /* Check max distance (<= resolution) */ - OSMO_ASSERT(dec_secs - last_dec_secs <= delta_secs); - - last_dec_secs = dec_secs; - } -} - -const struct log_info_cat default_categories[] = { - [DGPRS] = { - .name = "DGPRS", - .description = "GPRS Packet Service", - .enabled = 0, .loglevel = LOGL_DEBUG, - }, -}; - -static struct log_info info = { - .cat = default_categories, - .num_cat = ARRAY_SIZE(default_categories), -}; - -int main(int argc, char **argv) -{ - osmo_init_logging(&info); - - test_8_4_2(); - test_gprs_timer_enc_dec(); - - printf("Done.\n"); - return EXIT_SUCCESS; -} diff --git a/tests/gprs/gprs_test.ok b/tests/gprs/gprs_test.ok deleted file mode 100644 index da7888c6a..000000000 --- a/tests/gprs/gprs_test.ok +++ /dev/null @@ -1,17 +0,0 @@ -Testing gprs_llc_is_retransmit. -N(U) = 0, V(UR) = 0 => new -N(U) = 0, V(UR) = 1 => retransmit -N(U) = 0, V(UR) = 1 => retransmit -N(U) = 511, V(UR) = 1 => retransmit -N(U) = 483, V(UR) = 1 => retransmit -N(U) = 482, V(UR) = 1 => retransmit -N(U) = 481, V(UR) = 1 => new -N(U) = 0, V(UR) = 240 => new -N(U) = 0, V(UR) = 511 => new -N(U) = 1, V(UR) = 511 => new -N(U) = 511, V(UR) = 511 => new -N(U) = 510, V(UR) = 511 => retransmit -N(U) = 481, V(UR) = 511 => retransmit -N(U) = 479, V(UR) = 511 => new -Test GPRS timer decoding/encoding -Done. diff --git a/tests/gsm0408/Makefile.am b/tests/gsm0408/Makefile.am deleted file mode 100644 index ae81c2c7c..000000000 --- a/tests/gsm0408/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(NULL) - -noinst_PROGRAMS = \ - gsm0408_test \ - $(NULL) - -EXTRA_DIST = \ - gsm0408_test.ok \ - $(NULL) - -gsm0408_test_SOURCES = \ - gsm0408_test.c \ - $(NULL) - -gsm0408_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - -ldbi \ - $(NULL) diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c deleted file mode 100644 index fcdc8f8ed..000000000 --- a/tests/gsm0408/gsm0408_test.c +++ /dev/null @@ -1,697 +0,0 @@ -/* simple test for the gsm0408 formatting functions */ -/* - * (C) 2008 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 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 . - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define COMPARE(result, op, value) \ - if (!((result) op (value))) {\ - fprintf(stderr, "Compare failed. Was %x should be %x in %s:%d\n",result, value, __FILE__, __LINE__); \ - exit(-1); \ - } - -#define COMPARE_STR(result, value) \ - if (strcmp(result, value) != 0) { \ - fprintf(stderr, "Compare failed. Was %s should be %s in %s:%d\n",result, value, __FILE__, __LINE__); \ - exit(-1); \ - } - -#define DBG(...) - -#define VERIFY(res, cmp, wanted) \ - if (!(res cmp wanted)) { \ - printf("ASSERT failed: %s:%d Wanted: %d %s %d\n", \ - __FILE__, __LINE__, (int) res, # cmp, (int) wanted); \ - } - - - -/* - * Test Location Area Identifier formatting. Table 10.5.3 of 04.08 - */ -static void test_location_area_identifier(void) -{ - struct gsm48_loc_area_id lai48; - - printf("Testing test location area identifier\n"); - - /* - * Test the default/test setup. Coming from - * bsc_hack.c dumps - */ - gsm48_generate_lai(&lai48, 1, 1, 1); - COMPARE(lai48.digits[0], ==, 0x00); - COMPARE(lai48.digits[1], ==, 0xF1); - COMPARE(lai48.digits[2], ==, 0x10); - COMPARE(lai48.lac, ==, htons(0x0001)); - - gsm48_generate_lai(&lai48, 602, 1, 15); - COMPARE(lai48.digits[0], ==, 0x06); - COMPARE(lai48.digits[1], ==, 0xF2); - COMPARE(lai48.digits[2], ==, 0x10); - COMPARE(lai48.lac, ==, htons(0x000f)); -} - -static inline void gen(struct gsm_bts *bts, const char *s) -{ - int r; - - bts->si_valid = 0; - bts->si_valid |= (1 << SYSINFO_TYPE_2quater); - - printf("generating SI2quater for %zu EARFCNs and %zu UARFCNs...\n", - si2q_earfcn_count(&bts->si_common.si2quater_neigh_list), bts->si_common.uarfcn_length); - - r = gsm_generate_si(bts, SYSINFO_TYPE_2quater); - if (r > 0) - for (bts->si2q_index = 0; bts->si2q_index < bts->si2q_count + 1; bts->si2q_index++) - printf("generated %s SI2quater [%02u/%02u]: [%d] %s\n", - GSM_BTS_HAS_SI(bts, SYSINFO_TYPE_2quater) ? "valid" : "invalid", - bts->si2q_index, bts->si2q_count, r, - osmo_hexdump((void *)GSM_BTS_SI2Q(bts, bts->si2q_index), GSM_MACBLOCK_LEN)); - else - printf("%s() failed to generate SI2quater: %s\n", s, strerror(-r)); -} - -static inline void del_earfcn_b(struct gsm_bts *bts, uint16_t earfcn) -{ - struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; - int r = osmo_earfcn_del(e, earfcn); - if (r) - printf("failed to remove EARFCN %u: %s\n", earfcn, strerror(-r)); - else - printf("removed EARFCN %u - ", earfcn); - - gen(bts, __func__); -} - -static inline void add_earfcn_b(struct gsm_bts *bts, uint16_t earfcn, uint8_t bw) -{ - struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; - int r = osmo_earfcn_add(e, earfcn, bw); - if (r) - printf("failed to add EARFCN %u: %s\n", earfcn, strerror(-r)); - else - printf("added EARFCN %u - ", earfcn); - - gen(bts, __func__); -} - -static inline void _bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, bool diversity) -{ - int r; - - bts->u_offset = 0; - - r = bts_uarfcn_add(bts, arfcn, scramble, diversity); - if (r < 0) - printf("failed to add UARFCN to SI2quater: %s\n", strerror(-r)); - else { - bts->si2q_count = si2q_num(bts) - 1; - gen(bts, __func__); - } -} - -static inline void test_si2q_segfault(void) -{ - struct gsm_bts *bts; - struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); - printf("Test SI2quater UARFCN (same scrambling code and diversity):\n"); - - if (!network) - exit(1); - bts = gsm_bts_alloc(network, 0); - - _bts_uarfcn_add(bts, 10564, 319, 0); - _bts_uarfcn_add(bts, 10612, 319, 0); - gen(bts, __func__); -} - -static inline void test_si2q_mu(void) -{ - struct gsm_bts *bts; - struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); - printf("Test SI2quater multiple UARFCNs:\n"); - - if (!network) - exit(1); - bts = gsm_bts_alloc(network, 0); - - _bts_uarfcn_add(bts, 10564, 318, 0); - _bts_uarfcn_add(bts, 10612, 319, 0); - _bts_uarfcn_add(bts, 10612, 31, 0); - _bts_uarfcn_add(bts, 10612, 19, 0); - _bts_uarfcn_add(bts, 10613, 64, 0); - _bts_uarfcn_add(bts, 10613, 164, 0); - _bts_uarfcn_add(bts, 10613, 14, 0); -} - -static inline void test_si2q_u(void) -{ - struct gsm_bts *bts; - struct gsm_network *network = bsc_network_init(NULL, 1, 1, NULL); - printf("Testing SYSINFO_TYPE_2quater UARFCN generation:\n"); - - if (!network) - exit(1); - - bts = gsm_bts_alloc(network, 0); - - /* first generate invalid SI as no UARFCN added */ - gen(bts, __func__); - - /* subsequent calls should produce valid SI if there's enough memory */ - _bts_uarfcn_add(bts, 1982, 13, 1); - _bts_uarfcn_add(bts, 1982, 44, 0); - _bts_uarfcn_add(bts, 1982, 61, 1); - _bts_uarfcn_add(bts, 1982, 89, 1); - _bts_uarfcn_add(bts, 1982, 113, 0); - _bts_uarfcn_add(bts, 1982, 123, 0); - _bts_uarfcn_add(bts, 1982, 56, 1); - _bts_uarfcn_add(bts, 1982, 72, 1); - _bts_uarfcn_add(bts, 1982, 223, 1); - _bts_uarfcn_add(bts, 1982, 14, 0); - _bts_uarfcn_add(bts, 1982, 88, 0); -} - -static inline void test_si2q_e(void) -{ - struct gsm_bts *bts; - struct gsm_network *network = bsc_network_init(NULL, 1, 1, NULL); - printf("Testing SYSINFO_TYPE_2quater EARFCN generation:\n"); - - if (!network) - exit(1); - - bts = gsm_bts_alloc(network, 0); - - bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list; - bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list; - bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST; - bts->si_common.si2quater_neigh_list.thresh_hi = 5; - - osmo_earfcn_init(&bts->si_common.si2quater_neigh_list); - - /* first generate invalid SI as no EARFCN added */ - gen(bts, __func__); - - /* subsequent calls should produce valid SI if there's enough memory and EARFCNs */ - add_earfcn_b(bts, 1917, 5); - del_earfcn_b(bts, 1917); - add_earfcn_b(bts, 1917, 1); - add_earfcn_b(bts, 1932, OSMO_EARFCN_MEAS_INVALID); - add_earfcn_b(bts, 1937, 2); - add_earfcn_b(bts, 1945, OSMO_EARFCN_MEAS_INVALID); - add_earfcn_b(bts, 1965, OSMO_EARFCN_MEAS_INVALID); - add_earfcn_b(bts, 1967, 4); - add_earfcn_b(bts, 1982, 3); -} - -static inline void test_si2q_long(void) -{ - struct gsm_bts *bts; - struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); - printf("Testing SYSINFO_TYPE_2quater combined EARFCN & UARFCN generation:\n"); - - if (!network) - exit(1); - - bts = gsm_bts_alloc(network, 0); - - bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list; - bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list; - bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST; - bts->si_common.si2quater_neigh_list.thresh_hi = 5; - - osmo_earfcn_init(&bts->si_common.si2quater_neigh_list); - - bts_earfcn_add(bts, 1922, 11, 22, 8,32, 8); - bts_earfcn_add(bts, 1922, 11, 22, 8, 32, 8); - bts_earfcn_add(bts, 1924, 11, 12, 6, 11, 5); - bts_earfcn_add(bts, 1923, 11, 12, 6, 11, 5); - bts_earfcn_add(bts, 1925, 11, 12, 6, 11, 5); - bts_earfcn_add(bts, 2111, 11, 12, 6, 11, 5); - bts_earfcn_add(bts, 2112, 11, 12, 6, 11, 4); - bts_earfcn_add(bts, 2113, 11, 12, 6, 11, 3); - bts_earfcn_add(bts, 2114, 11, 12, 6, 11, 2); - bts_earfcn_add(bts, 2131, 11, 12, 6, 11, 5); - bts_earfcn_add(bts, 2132, 11, 12, 6, 11, 4); - bts_earfcn_add(bts, 2133, 11, 12, 6, 11, 3); - bts_earfcn_add(bts, 2134, 11, 12, 6, 11, 2); - bts_earfcn_add(bts, 2121, 11, 12, 6, 11, 5); - bts_earfcn_add(bts, 2122, 11, 12, 6, 11, 4); - bts_earfcn_add(bts, 2123, 11, 12, 6, 11, 3); - bts_earfcn_add(bts, 2124, 11, 12, 6, 11, 2); - _bts_uarfcn_add(bts, 1976, 13, 1); - _bts_uarfcn_add(bts, 1976, 38, 1); - _bts_uarfcn_add(bts, 1976, 44, 1); - _bts_uarfcn_add(bts, 1976, 120, 1); - _bts_uarfcn_add(bts, 1976, 140, 1); - _bts_uarfcn_add(bts, 1976, 163, 1); - _bts_uarfcn_add(bts, 1976, 166, 1); - _bts_uarfcn_add(bts, 1976, 217, 1); - _bts_uarfcn_add(bts, 1976, 224, 1); - _bts_uarfcn_add(bts, 1976, 225, 1); - _bts_uarfcn_add(bts, 1976, 226, 1); -} - -static void test_mi_functionality(void) -{ - const char *imsi_odd = "987654321098763"; - const char *imsi_even = "9876543210987654"; - const uint32_t tmsi = 0xfabeacd0; - uint8_t mi[128]; - unsigned int mi_len; - char mi_parsed[GSM48_MI_SIZE]; - - printf("Testing parsing and generating TMSI/IMSI\n"); - - /* tmsi code */ - mi_len = gsm48_generate_mid_from_tmsi(mi, tmsi); - gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len - 2); - COMPARE((uint32_t)strtoul(mi_parsed, NULL, 10), ==, tmsi); - - /* imsi code */ - mi_len = gsm48_generate_mid_from_imsi(mi, imsi_odd); - gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2); - printf("hex: %s\n", osmo_hexdump(mi, mi_len)); - COMPARE_STR(mi_parsed, imsi_odd); - - mi_len = gsm48_generate_mid_from_imsi(mi, imsi_even); - gsm48_mi_to_string(mi_parsed, sizeof(mi_parsed), mi + 2, mi_len -2); - printf("hex: %s\n", osmo_hexdump(mi, mi_len)); - COMPARE_STR(mi_parsed, imsi_even); -} - -struct { - int range; - int arfcns_num; - int arfcns[RANGE_ENC_MAX_ARFCNS]; -} arfcn_test_ranges[] = { - {ARFCN_RANGE_512, 12, - { 1, 12, 31, 51, 57, 91, 97, 98, 113, 117, 120, 125 }}, - {ARFCN_RANGE_512, 17, - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }}, - {ARFCN_RANGE_512, 18, - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }}, - {ARFCN_RANGE_512, 18, - { 1, 17, 31, 45, 58, 79, 81, 97, - 113, 127, 213, 277, 287, 311, 331, 391, - 417, 511 }}, - {ARFCN_RANGE_512, 6, - { 1, 17, 31, 45, 58, 79 }}, - {ARFCN_RANGE_512, 6, - { 10, 17, 31, 45, 58, 79 }}, - {ARFCN_RANGE_1024, 17, - { 0, 17, 31, 45, 58, 79, 81, 97, - 113, 127, 213, 277, 287, 311, 331, 391, - 1023 }}, - {ARFCN_RANGE_1024, 16, - { 17, 31, 45, 58, 79, 81, 97, 113, - 127, 213, 277, 287, 311, 331, 391, 1023 }}, - {-1} -}; - -static int test_single_range_encoding(int range, const int *orig_arfcns, - int arfcns_num, int silent) -{ - int arfcns[RANGE_ENC_MAX_ARFCNS]; - int w[RANGE_ENC_MAX_ARFCNS]; - int f0_included = 0; - int rc, f0; - uint8_t chan_list[16] = {0}; - struct gsm_sysinfo_freq dec_freq[1024] = {{0}}; - int dec_arfcns[RANGE_ENC_MAX_ARFCNS] = {0}; - int dec_arfcns_count = 0; - int arfcns_used = 0; - int i; - - arfcns_used = arfcns_num; - memmove(arfcns, orig_arfcns, sizeof(arfcns)); - - f0 = range == ARFCN_RANGE_1024 ? 0 : arfcns[0]; - /* - * Manipulate the ARFCN list according to the rules in J4 depending - * on the selected range. - */ - arfcns_used = range_enc_filter_arfcns(arfcns, arfcns_used, - f0, &f0_included); - - memset(w, 0, sizeof(w)); - range_enc_arfcns(range, arfcns, arfcns_used, w, 0); - - if (!silent) - fprintf(stderr, "range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", - range, arfcns_used, f0, f0_included); - - /* Select the range and the amount of bits needed */ - switch (range) { - case ARFCN_RANGE_128: - range_enc_range128(chan_list, f0, w); - break; - case ARFCN_RANGE_256: - range_enc_range256(chan_list, f0, w); - break; - case ARFCN_RANGE_512: - range_enc_range512(chan_list, f0, w); - break; - case ARFCN_RANGE_1024: - range_enc_range1024(chan_list, f0, f0_included, w); - break; - default: - return 1; - }; - - if (!silent) - printf("chan_list = %s\n", - osmo_hexdump(chan_list, sizeof(chan_list))); - - rc = gsm48_decode_freq_list(dec_freq, chan_list, sizeof(chan_list), - 0xfe, 1); - if (rc != 0) { - printf("Cannot decode freq list, rc = %d\n", rc); - return 1; - } - - for (i = 0; i < ARRAY_SIZE(dec_freq); i++) { - if (dec_freq[i].mask && - dec_arfcns_count < ARRAY_SIZE(dec_arfcns)) - dec_arfcns[dec_arfcns_count++] = i; - } - - if (!silent) { - printf("Decoded freqs %d (expected %d)\n", - dec_arfcns_count, arfcns_num); - printf("Decoded: "); - for (i = 0; i < dec_arfcns_count; i++) { - printf("%d ", dec_arfcns[i]); - if (dec_arfcns[i] != orig_arfcns[i]) - printf("(!= %d) ", orig_arfcns[i]); - } - printf("\n"); - } - - if (dec_arfcns_count != arfcns_num) { - printf("Wrong number of arfcns\n"); - return 1; - } - - if (memcmp(dec_arfcns, orig_arfcns, sizeof(dec_arfcns)) != 0) { - printf("Decoding error, got wrong freqs\n"); - fprintf(stderr, " w = "); - for (i = 0; i < ARRAY_SIZE(w); i++) - fprintf(stderr, "%d ", w[i]); - fprintf(stderr, "\n"); - return 1; - } - - return 0; -} - -static void test_random_range_encoding(int range, int max_arfcn_num) -{ - int arfcns_num = 0; - int test_idx; - int rc, max_count; - int num_tests = 1024; - - printf("Random range test: range %d, max num ARFCNs %d\n", - range, max_arfcn_num); - - srandom(1); - - for (max_count = 1; max_count < max_arfcn_num; max_count++) { - for (test_idx = 0; test_idx < num_tests; test_idx++) { - int count; - int i; - int min_freq = 0; - - int rnd_arfcns[RANGE_ENC_MAX_ARFCNS] = {0}; - char rnd_arfcns_set[1024] = {0}; - - if (range < ARFCN_RANGE_1024) - min_freq = random() % (1023 - range); - - for (count = max_count; count; ) { - int arfcn = min_freq + random() % (range + 1); - OSMO_ASSERT(arfcn < ARRAY_SIZE(rnd_arfcns_set)); - - if (!rnd_arfcns_set[arfcn]) { - rnd_arfcns_set[arfcn] = 1; - count -= 1; - } - } - - arfcns_num = 0; - for (i = 0; i < ARRAY_SIZE(rnd_arfcns_set); i++) - if (rnd_arfcns_set[i]) - rnd_arfcns[arfcns_num++] = i; - - rc = test_single_range_encoding(range, rnd_arfcns, - arfcns_num, 1); - if (rc != 0) { - printf("Failed on test %d, range %d, num ARFCNs %d\n", - test_idx, range, max_count); - test_single_range_encoding(range, rnd_arfcns, - arfcns_num, 0); - return; - } - } - } -} - -static void test_range_encoding() -{ - int *arfcns; - int arfcns_num = 0; - int test_idx; - int range; - - for (test_idx = 0; arfcn_test_ranges[test_idx].arfcns_num > 0; test_idx++) - { - arfcns_num = arfcn_test_ranges[test_idx].arfcns_num; - arfcns = &arfcn_test_ranges[test_idx].arfcns[0]; - range = arfcn_test_ranges[test_idx].range; - - printf("Range test %d: range %d, num ARFCNs %d\n", - test_idx, range, arfcns_num); - - test_single_range_encoding(range, arfcns, arfcns_num, 0); - } - - test_random_range_encoding(ARFCN_RANGE_128, 29); - test_random_range_encoding(ARFCN_RANGE_256, 22); - test_random_range_encoding(ARFCN_RANGE_512, 18); - test_random_range_encoding(ARFCN_RANGE_1024, 16); -} - -static int freqs1[] = { - 12, 70, 121, 190, 250, 320, 401, 475, 520, 574, 634, 700, 764, 830, 905, 980 -}; - -static int freqs2[] = { - 402, 460, 1, 67, 131, 197, 272, 347, -}; - -static int freqs3[] = { - 68, 128, 198, 279, 353, 398, 452, - -}; - -static int w_out[] = { - 122, 2, 69, 204, 75, 66, 60, 70, 83, 3, 24, 67, 54, 64, 70, 9, -}; - -static int range128[] = { - 1, 1 + 127, -}; - -static int range256[] = { - 1, 1 + 128, -}; - -static int range512[] = { - 1, 1+ 511, -}; - - -static void test_arfcn_filter() -{ - int arfcns[50], i, res, f0_included; - for (i = 0; i < ARRAY_SIZE(arfcns); ++i) - arfcns[i] = (i + 1) * 2; - - /* check that the arfcn is taken out. f0_included is only set for Range1024 */ - f0_included = 24; - res = range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), - arfcns[0], &f0_included); - VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); - VERIFY(f0_included, ==, 1); - for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, ((i+2) * 2) - (2+1)); - - /* check with range1024, ARFCN 0 is included */ - for (i = 0; i < ARRAY_SIZE(arfcns); ++i) - arfcns[i] = i * 2; - res = range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), - 0, &f0_included); - VERIFY(res, ==, ARRAY_SIZE(arfcns) - 1); - VERIFY(f0_included, ==, 1); - for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, (i + 1) * 2 - 1); - - /* check with range1024, ARFCN 0 not included */ - for (i = 0; i < ARRAY_SIZE(arfcns); ++i) - arfcns[i] = (i + 1) * 2; - res = range_enc_filter_arfcns(arfcns, ARRAY_SIZE(arfcns), - 0, &f0_included); - VERIFY(res, ==, ARRAY_SIZE(arfcns)); - VERIFY(f0_included, ==, 0); - for (i = 0; i < res; ++i) - VERIFY(arfcns[i], ==, ((i + 1) * 2) - 1); -} - -static void test_print_encoding() -{ - int rc; - int w[17]; - uint8_t chan_list[16]; - memset(chan_list, 0x23, sizeof(chan_list)); - - for (rc = 0; rc < ARRAY_SIZE(w); ++rc) - switch (rc % 3) { - case 0: - w[rc] = 0xAAAA; - break; - case 1: - w[rc] = 0x5555; - break; - case 2: - w[rc] = 0x9696; - break; - } - - range_enc_range512(chan_list, (1 << 9) | 0x96, w); - - printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list))); -} - -static void test_si_range_helpers() -{ - int ws[(sizeof(freqs1)/sizeof(freqs1[0]))]; - int i, f0 = 0xFFFFFF; - - memset(&ws[0], 0x23, sizeof(ws)); - - i = range_enc_find_index(1023, freqs1, ARRAY_SIZE(freqs1)); - printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs1[i] : -1); - VERIFY(i, ==, 2); - - i = range_enc_find_index(511, freqs2, ARRAY_SIZE(freqs2)); - printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs2[i] : -1); - VERIFY(i, ==, 2); - - i = range_enc_find_index(511, freqs3, ARRAY_SIZE(freqs3)); - printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs3[i] : -1); - VERIFY(i, ==, 0); - - range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0); - - for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) { - printf("w[%d]=%d\n", i, ws[i]); - VERIFY(ws[i], ==, w_out[i]); - } - - i = range_enc_determine_range(range128, ARRAY_SIZE(range128), &f0); - VERIFY(i, ==, ARFCN_RANGE_128); - VERIFY(f0, ==, 1); - - i = range_enc_determine_range(range256, ARRAY_SIZE(range256), &f0); - VERIFY(i, ==, ARFCN_RANGE_256); - VERIFY(f0, ==, 1); - - i = range_enc_determine_range(range512, ARRAY_SIZE(range512), &f0); - VERIFY(i, ==, ARFCN_RANGE_512); - VERIFY(f0, ==, 1); -} - -static void test_gsm411_rp_ref_wrap(void) -{ - struct gsm_subscriber_connection conn; - int res; - - printf("testing RP-Reference wrap\n"); - - memset(&conn, 0, sizeof(conn)); - conn.next_rp_ref = 255; - - res = sms_next_rp_msg_ref(&conn.next_rp_ref); - printf("Allocated reference: %d\n", res); - OSMO_ASSERT(res == 255); - - res = sms_next_rp_msg_ref(&conn.next_rp_ref); - printf("Allocated reference: %d\n", res); - OSMO_ASSERT(res == 0); - - res = sms_next_rp_msg_ref(&conn.next_rp_ref); - printf("Allocated reference: %d\n", res); - OSMO_ASSERT(res == 1); -} - -int main(int argc, char **argv) -{ - osmo_init_logging(&log_info); - log_set_log_level(osmo_stderr_target, LOGL_INFO); - - test_location_area_identifier(); - test_mi_functionality(); - - test_si_range_helpers(); - test_arfcn_filter(); - test_print_encoding(); - test_range_encoding(); - test_gsm411_rp_ref_wrap(); - - test_si2q_segfault(); - test_si2q_e(); - test_si2q_u(); - test_si2q_mu(); - test_si2q_long(); - - printf("Done.\n"); - - return EXIT_SUCCESS; -} diff --git a/tests/gsm0408/gsm0408_test.ok b/tests/gsm0408/gsm0408_test.ok deleted file mode 100644 index d30f42155..000000000 --- a/tests/gsm0408/gsm0408_test.ok +++ /dev/null @@ -1,204 +0,0 @@ -Testing test location area identifier -Testing parsing and generating TMSI/IMSI -hex: 17 08 99 78 56 34 12 90 78 36 -hex: 17 09 91 78 56 34 12 90 78 56 f4 -Element is: 2 => freqs[i] = 121 -Element is: 2 => freqs[i] = 1 -Element is: 0 => freqs[i] = 68 -w[0]=122 -w[1]=2 -w[2]=69 -w[3]=204 -w[4]=75 -w[5]=66 -w[6]=60 -w[7]=70 -w[8]=83 -w[9]=3 -w[10]=24 -w[11]=67 -w[12]=54 -w[13]=64 -w[14]=70 -w[15]=9 -Range512: 89 4b 2a 95 65 95 55 2c a9 55 aa 55 6a 95 59 55 -Range test 0: range 511, num ARFCNs 12 -chan_list = 88 00 98 34 85 36 7c 50 22 dc 5e ec 00 00 00 00 -Decoded freqs 12 (expected 12) -Decoded: 1 12 31 51 57 91 97 98 113 117 120 125 -Range test 1: range 511, num ARFCNs 17 -chan_list = 88 00 82 7f 01 3f 7e 04 0b ff ff fc 10 41 07 e0 -Decoded freqs 17 (expected 17) -Decoded: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 -Range test 2: range 511, num ARFCNs 18 -chan_list = 88 00 82 7f 01 7f 7e 04 0b ff ff fc 10 41 07 ff -Decoded freqs 18 (expected 18) -Decoded: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 -Range test 3: range 511, num ARFCNs 18 -chan_list = 88 00 94 3a 44 32 d7 2a 43 2a 13 94 e5 38 39 f6 -Decoded freqs 18 (expected 18) -Decoded: 1 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 417 511 -Range test 4: range 511, num ARFCNs 6 -chan_list = 88 00 8b 3c 88 b9 6b 00 00 00 00 00 00 00 00 00 -Decoded freqs 6 (expected 6) -Decoded: 1 17 31 45 58 79 -Range test 5: range 511, num ARFCNs 6 -chan_list = 88 05 08 fc 88 b9 6b 00 00 00 00 00 00 00 00 00 -Decoded freqs 6 (expected 6) -Decoded: 10 17 31 45 58 79 -Range test 6: range 1023, num ARFCNs 17 -chan_list = 84 71 e4 ab b9 58 05 cb 39 17 fd b0 75 62 0f 2f -Decoded freqs 17 (expected 17) -Decoded: 0 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 1023 -Range test 7: range 1023, num ARFCNs 16 -chan_list = 80 71 e4 ab b9 58 05 cb 39 17 fd b0 75 62 0f 2f -Decoded freqs 16 (expected 16) -Decoded: 17 31 45 58 79 81 97 113 127 213 277 287 311 331 391 1023 -Random range test: range 127, max num ARFCNs 29 -Random range test: range 255, max num ARFCNs 22 -Random range test: range 511, max num ARFCNs 18 -Random range test: range 1023, max num ARFCNs 16 -testing RP-Reference wrap -Allocated reference: 255 -Allocated reference: 0 -Allocated reference: 1 -Test SI2quater UARFCN (same scrambling code and diversity): -generating SI2quater for 0 EARFCNs and 1 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 88 0a 7e 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 2 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 e8 0a 7f 52 88 0a 7e 0b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 2 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 e8 0a 7f 52 88 0a 7e 0b 2b 2b 2b 2b 2b 2b 2b 2b -Testing SYSINFO_TYPE_2quater EARFCN generation: -generating SI2quater for 0 EARFCNs and 0 UARFCNs... -generated invalid SI2quater [00/00]: [23] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -added EARFCN 1917 - generating SI2quater for 1 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 04 86 59 83 be e8 50 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -removed EARFCN 1917 - generating SI2quater for 0 EARFCNs and 0 UARFCNs... -generated invalid SI2quater [00/00]: [23] 59 06 07 c0 00 04 86 59 83 be e8 50 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -added EARFCN 1917 - generating SI2quater for 1 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 04 86 59 83 be c8 50 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -added EARFCN 1932 - generating SI2quater for 2 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 30 14 03 2b 2b 2b 2b 2b 2b 2b 2b -added EARFCN 1937 - generating SI2quater for 3 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a0 a0 2b 2b 2b 2b 2b 2b -added EARFCN 1945 - generating SI2quater for 4 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c c8 28 0b 2b 2b 2b -added EARFCN 1965 - generating SI2quater for 5 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c ca 0f 5a 0a 03 2b -added EARFCN 1967 - generating SI2quater for 6 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/01]: [23] 59 06 07 c0 20 04 86 59 83 be cc 1e 31 07 91 a8 3c ca 0f 5a 0a 03 2b -generated valid SI2quater [01/01]: [23] 59 06 07 c2 20 04 86 59 83 d7 e0 50 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -added EARFCN 1982 - generating SI2quater for 7 EARFCNs and 0 UARFCNs... -generated valid SI2quater [00/01]: [23] 59 06 07 c0 20 04 86 59 83 be cc 1e 31 07 91 a8 3c ca 0f 5a 0a 03 2b -generated valid SI2quater [01/01]: [23] 59 06 07 c2 20 04 86 59 83 d7 e4 1e fa c2 80 2b 2b 2b 2b 2b 2b 2b 2b -Testing SYSINFO_TYPE_2quater UARFCN generation: -generating SI2quater for 0 EARFCNs and 0 UARFCNs... -generated invalid SI2quater [00/00]: [23] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -generating SI2quater for 0 EARFCNs and 1 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 0c 1a 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 2 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 14 1a 1f 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 3 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 18 58 12 f0 83 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 4 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 20 58 2e f0 f2 03 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 5 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 28 58 2e 22 f2 4e 83 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 6 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 34 1a 64 26 5d f2 05 03 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 7 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 38 58 12 22 fd ce 8e 05 03 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 8 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 40 58 1d 22 fa ce 88 85 7b 0b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 9 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 4c 7a 34 0e 64 77 85 43 55 c8 0b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 10 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 50 1c 3b 31 fa dd 88 85 7b c4 1c 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 11 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 0f 7c 58 1c 3b 25 7a ea 08 91 fb c4 1f b0 2b 2b 2b -Test SI2quater multiple UARFCNs: -generating SI2quater for 0 EARFCNs and 1 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 88 0a 7c 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 2 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 e8 0a 7f 52 88 0a 7c 0b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 3 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 e8 12 7e e0 a9 44 05 3e 0b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 4 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 e8 18 3f f4 90 54 a2 02 9f 03 2b 2b 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 5 UARFCNs... -generated valid SI2quater [00/00]: [23] 59 06 07 c0 00 25 52 ea 08 81 52 e8 18 3f f4 90 54 a2 02 9f 03 2b 2b -generating SI2quater for 0 EARFCNs and 6 UARFCNs... -generated valid SI2quater [00/01]: [23] 59 06 07 c0 20 25 52 ea 08 81 52 e8 10 3f f4 a9 75 04 a4 0b 2b 2b 2b -generated valid SI2quater [01/01]: [23] 59 06 07 c2 20 25 52 e8 28 81 df 7f fa 32 d4 a2 02 9f 03 2b 2b 2b 2b -generating SI2quater for 0 EARFCNs and 7 UARFCNs... -generated valid SI2quater [00/01]: [23] 59 06 07 c0 20 25 52 ea 10 81 ce a9 74 08 1f fa 54 ba 82 52 03 2b 2b -generated valid SI2quater [01/01]: [23] 59 06 07 c2 20 25 52 e8 30 81 d3 7f fd b2 86 54 a2 02 9f 03 2b 2b 2b -Testing SYSINFO_TYPE_2quater combined EARFCN & UARFCN generation: -generating SI2quater for 17 EARFCNs and 1 UARFCNs... -generated valid SI2quater [00/04]: [23] 59 06 07 c0 80 25 0f 70 0c 1a 10 99 66 0f 04 83 c1 1c bb 2b 03 2b 2b -generated valid SI2quater [01/04]: [23] 59 06 07 c2 80 04 86 59 83 c2 6c 1e 0f 60 f0 bb 08 3f d7 2e ca c1 2b -generated valid SI2quater [02/04]: [23] 59 06 07 c4 80 04 86 59 84 20 64 21 06 e1 08 55 08 53 d7 2e ca c1 2b -generated valid SI2quater [03/04]: [23] 59 06 07 c6 80 04 86 59 84 2a 64 21 56 e1 0a d5 08 49 d7 2e ca c1 2b -generated valid SI2quater [04/04]: [23] 59 06 07 c8 80 04 86 59 84 25 64 21 2e e1 09 94 e5 d9 58 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 2 UARFCNs... -generated valid SI2quater [00/04]: [23] 59 06 07 c0 80 25 0f 70 14 4d e7 00 44 b3 07 82 41 e0 8e 5d 95 83 2b -generated valid SI2quater [01/04]: [23] 59 06 07 c2 80 04 86 59 83 c2 6c 1e 0f 60 f0 bb 08 3f d7 2e ca c1 2b -generated valid SI2quater [02/04]: [23] 59 06 07 c4 80 04 86 59 84 20 64 21 06 e1 08 55 08 53 d7 2e ca c1 2b -generated valid SI2quater [03/04]: [23] 59 06 07 c6 80 04 86 59 84 2a 64 21 56 e1 0a d5 08 49 d7 2e ca c1 2b -generated valid SI2quater [04/04]: [23] 59 06 07 c8 80 04 86 59 84 25 64 21 2e e1 09 94 e5 d9 58 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 3 UARFCNs... -generated valid SI2quater [00/04]: [23] 59 06 07 c0 80 25 0f 70 1c 4d e7 03 04 86 59 83 c1 20 f0 47 2e ca c1 -generated valid SI2quater [01/04]: [23] 59 06 07 c2 80 04 86 59 83 c2 6c 1e 0f 60 f0 bb 08 3f d7 2e ca c1 2b -generated valid SI2quater [02/04]: [23] 59 06 07 c4 80 04 86 59 84 20 64 21 06 e1 08 55 08 53 d7 2e ca c1 2b -generated valid SI2quater [03/04]: [23] 59 06 07 c6 80 04 86 59 84 2a 64 21 56 e1 0a d5 08 49 d7 2e ca c1 2b -generated valid SI2quater [04/04]: [23] 59 06 07 c8 80 04 86 59 84 25 64 21 2e e1 09 94 e5 d9 58 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 4 UARFCNs... -generated valid SI2quater [00/04]: [23] 59 06 07 c0 80 25 0f 70 24 59 fa 26 73 84 86 59 83 c1 1c bb 2b 03 2b -generated valid SI2quater [01/04]: [23] 59 06 07 c2 80 04 86 59 83 c1 20 f0 9b 07 83 d8 3c 2e b9 76 56 0b 2b -generated valid SI2quater [02/04]: [23] 59 06 07 c4 80 04 86 59 84 1f ec 21 03 21 08 37 08 42 a7 2e ca c1 2b -generated valid SI2quater [03/04]: [23] 59 06 07 c6 80 04 86 59 84 29 ec 21 53 21 0a b7 08 56 a7 2e ca c1 2b -generated valid SI2quater [04/04]: [23] 59 06 07 c8 80 04 86 59 84 24 ec 21 2b 21 09 77 08 4c a7 2e ca c1 2b -generating SI2quater for 17 EARFCNs and 5 UARFCNs... -generated valid SI2quater [00/04]: [23] 59 06 07 c0 80 25 0f 70 2c 59 fa 30 73 f6 04 86 59 83 c1 1c bb 2b 03 -generated valid SI2quater [01/04]: [23] 59 06 07 c2 80 04 86 59 83 c1 20 f0 9b 07 83 d8 3c 2e b9 76 56 0b 2b -generated valid SI2quater [02/04]: [23] 59 06 07 c4 80 04 86 59 84 1f ec 21 03 21 08 37 08 42 a7 2e ca c1 2b -generated valid SI2quater [03/04]: [23] 59 06 07 c6 80 04 86 59 84 29 ec 21 53 21 0a b7 08 56 a7 2e ca c1 2b -generated valid SI2quater [04/04]: [23] 59 06 07 c8 80 04 86 59 84 24 ec 21 2b 21 09 77 08 4c a7 2e ca c1 2b -generating SI2quater for 17 EARFCNs and 6 UARFCNs... -generated valid SI2quater [00/05]: [23] 59 06 07 c0 a0 25 0f 70 34 f1 ae 15 f3 f4 83 04 86 59 72 ec ac 0b 2b -generated valid SI2quater [01/05]: [23] 59 06 07 c2 a0 04 86 59 83 c1 20 f0 48 3c 26 c1 e0 f5 cb b2 b0 2b 2b -generated valid SI2quater [02/05]: [23] 59 06 07 c4 a0 04 86 59 83 c2 ec 20 ff 61 08 19 08 41 b7 2e ca c1 2b -generated valid SI2quater [03/05]: [23] 59 06 07 c6 a0 04 86 59 84 21 54 21 4f 61 0a 99 08 55 b7 2e ca c1 2b -generated valid SI2quater [04/05]: [23] 59 06 07 c8 a0 04 86 59 84 2b 54 21 27 61 09 59 08 4b b7 2e ca c1 2b -generated valid SI2quater [05/05]: [23] 59 06 07 ca a0 04 86 59 84 26 53 97 65 60 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 7 UARFCNs... -generated valid SI2quater [00/05]: [23] 59 06 07 c0 a0 25 0f 70 3c f1 ae 15 f3 f4 83 01 84 86 59 72 ec ac 0b -generated valid SI2quater [01/05]: [23] 59 06 07 c2 a0 04 86 59 83 c1 20 f0 48 3c 26 c1 e0 f5 cb b2 b0 2b 2b -generated valid SI2quater [02/05]: [23] 59 06 07 c4 a0 04 86 59 83 c2 ec 20 ff 61 08 19 08 41 b7 2e ca c1 2b -generated valid SI2quater [03/05]: [23] 59 06 07 c6 a0 04 86 59 84 21 54 21 4f 61 0a 99 08 55 b7 2e ca c1 2b -generated valid SI2quater [04/05]: [23] 59 06 07 c8 a0 04 86 59 84 2b 54 21 27 61 09 59 08 4b b7 2e ca c1 2b -generated valid SI2quater [05/05]: [23] 59 06 07 ca a0 04 86 59 84 26 53 97 65 60 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 8 UARFCNs... -generated valid SI2quater [00/02]: [23] 59 06 07 c0 40 25 0f 70 45 19 a0 0d 7d 7e a6 19 e7 00 44 b3 07 82 41 -generated valid SI2quater [01/02]: [23] 59 06 07 c2 40 04 86 59 84 2b 54 21 27 61 09 59 08 4b b7 2e ca c1 2b -generated valid SI2quater [02/02]: [23] 59 06 07 c4 40 04 86 59 84 26 53 97 65 60 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 9 UARFCNs... -generated valid SI2quater [00/02]: [23] 59 06 07 c0 40 25 0f 70 4d 19 a0 26 fd 66 a6 03 e7 fa 10 99 66 0f 04 -generated valid SI2quater [01/02]: [23] 59 06 07 c2 40 04 86 59 84 2b 54 21 27 61 09 59 08 4b b7 2e ca c1 2b -generated valid SI2quater [02/02]: [23] 59 06 07 c4 40 04 86 59 84 26 53 97 65 60 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 10 UARFCNs... -generated valid SI2quater [00/05]: [23] 59 06 07 c0 a0 25 0f 70 55 47 89 1e fd 7c b0 00 e7 9b b0 04 12 c8 2b -generated valid SI2quater [01/05]: [23] 59 06 07 c2 a0 04 86 59 83 c1 20 f0 48 3c 26 c1 e0 f5 cb b2 b0 2b 2b -generated valid SI2quater [02/05]: [23] 59 06 07 c4 a0 04 86 59 83 c2 ec 20 ff 61 08 19 08 41 b7 2e ca c1 2b -generated valid SI2quater [03/05]: [23] 59 06 07 c6 a0 04 86 59 84 21 54 21 4f 61 0a 99 08 55 b7 2e ca c1 2b -generated valid SI2quater [04/05]: [23] 59 06 07 c8 a0 04 86 59 84 2b 54 21 27 61 09 59 08 4b b7 2e ca c1 2b -generated valid SI2quater [05/05]: [23] 59 06 07 ca a0 04 86 59 84 26 53 97 65 60 2b 2b 2b 2b 2b 2b 2b 2b 2b -generating SI2quater for 17 EARFCNs and 11 UARFCNs... -generated valid SI2quater [00/05]: [23] 59 06 07 c0 a0 25 0f 70 5d 47 89 1e fd 7c b0 01 67 9b b3 f8 2b 2b 2b -generated valid SI2quater [01/05]: [23] 59 06 07 c2 a0 04 86 59 83 c1 20 f0 48 3c 26 c1 e0 f5 cb b2 b0 2b 2b -generated valid SI2quater [02/05]: [23] 59 06 07 c4 a0 04 86 59 83 c2 ec 20 ff 61 08 19 08 41 b7 2e ca c1 2b -generated valid SI2quater [03/05]: [23] 59 06 07 c6 a0 04 86 59 84 21 54 21 4f 61 0a 99 08 55 b7 2e ca c1 2b -generated valid SI2quater [04/05]: [23] 59 06 07 c8 a0 04 86 59 84 2b 54 21 27 61 09 59 08 4b b7 2e ca c1 2b -generated valid SI2quater [05/05]: [23] 59 06 07 ca a0 04 86 59 84 26 53 97 65 60 2b 2b 2b 2b 2b 2b 2b 2b 2b -Done. diff --git a/tests/gtphub/Makefile.am b/tests/gtphub/Makefile.am deleted file mode 100644 index f2a6b888e..000000000 --- a/tests/gtphub/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBGTP_CFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - gtphub_test.ok \ - $(NULL) - -if HAVE_LIBGTP -if HAVE_LIBCARES -noinst_PROGRAMS = \ - gtphub_test \ - $(NULL) -endif -endif - -gtphub_test_SOURCES = \ - gtphub_test.c \ - $(NULL) - -gtphub_test_LDFLAGS = \ - -Wl,--wrap=gtphub_resolve_ggsn_addr \ - -Wl,--wrap=gtphub_ares_init \ - -Wl,--wrap=gtphub_write \ - $(NULL) - -gtphub_test_LDADD = \ - $(top_builddir)/src/gprs/gtphub.o \ - $(top_builddir)/src/gprs/gprs_utils.o \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBGTP_LIBS) \ - -lrt \ - $(NULL) diff --git a/tests/gtphub/gtphub_test.c b/tests/gtphub/gtphub_test.c deleted file mode 100644 index e7c27d2cb..000000000 --- a/tests/gtphub/gtphub_test.c +++ /dev/null @@ -1,1786 +0,0 @@ -/* Test the GTP hub */ - -/* (C) 2015 by sysmocom s.f.m.c. GmbH - * 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 . - * - */ - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -#define ZERO_STRUCT(struct_pointer) memset(struct_pointer, '\0', \ - sizeof(*(struct_pointer))) - -#define LVL2_ASSERT(exp) LVL2_ASSERT_R(exp, return 0) -#define LVL2_ASSERT_R(exp, ret) \ - if (!(exp)) { \ - fprintf(stderr, "LVL2 Assert failed %s %s:%d\n", #exp, \ - __FILE__, __LINE__); \ - osmo_generate_backtrace(); \ - ret; \ - } - -/* Convenience makro, note: only within this C file. */ -#define LOG(label) \ - { fprintf(stderr, "\n" label "\n"); \ - printf(label "\n"); } - -void gtphub_init(struct gtphub *hub); -void gtphub_free(struct gtphub *hub); - -void *osmo_gtphub_ctx; - -static void nr_mapping_free(struct expiring_item *e) -{ - struct nr_mapping *m = container_of(e, struct nr_mapping, - expiry_entry); - nr_mapping_del(m); - talloc_free(m); -} - -static struct nr_mapping *nr_mapping_alloc(void) -{ - struct nr_mapping *m; - m = talloc(osmo_gtphub_ctx, struct nr_mapping); - nr_mapping_init(m); - m->expiry_entry.del_cb = nr_mapping_free; - return m; -} - -static struct nr_mapping *nr_map_have(struct nr_map *map, void *origin, - nr_t orig, time_t now) -{ - struct nr_mapping *mapping; - - mapping = nr_map_get(map, origin, orig); - if (!mapping) { - mapping = nr_mapping_alloc(); - mapping->origin = origin; - mapping->orig = orig; - nr_map_add(map, mapping, now); - } - - return mapping; -} - -static nr_t nr_map_verify(const struct nr_map *map, void *origin, nr_t orig, - nr_t expect_repl) -{ - struct nr_mapping *m; - m = nr_map_get(map, origin, orig); - - if (!m) { - printf("mapping not found for %p %d\n", origin, orig); - return 0; - } - - if (m->repl != expect_repl) { - printf("mapping found, but nr mismatches: expect %d, got %d\n", - (int)expect_repl, (int)m->repl); - return 0; - } - - return 1; -} - -static int nr_map_verify_inv(const struct nr_map *map, nr_t repl, - void *expect_origin, nr_t expect_orig) -{ - struct nr_mapping *m; - m = nr_map_get_inv(map, repl); - if (!m) { - printf("mapping not found for %d\n", (int)repl); - return 0; - } - - if (m->origin != expect_origin) { - printf("mapping found, but origin mismatches:" - " expect %p, got %p\n", - expect_origin, m->origin); - return 0; - } - - if (m->orig != expect_orig) { - printf("mapping found, but nr mismatches: expect %d, got %d\n", - (int)expect_orig, (int)m->orig); - return 0; - } - - return 1; -} - - -static void test_nr_map_basic(void) -{ - struct nr_pool _pool; - struct nr_pool *pool = &_pool; - struct nr_map _map; - struct nr_map *map = &_map; - - nr_pool_init(pool, 1, 1000); - nr_map_init(map, pool, NULL); - - OSMO_ASSERT(llist_empty(&map->mappings)); - -#define TEST_N_HALF 100 -#define TEST_N (2*TEST_N_HALF) -#define TEST_I 123 - uint32_t i, check_i; - uint32_t m[TEST_N]; - struct nr_mapping *mapping; - - /* create half of TEST_N mappings from one origin */ - void *origin1 = (void*)0x1234; - for (i = 0; i < TEST_N_HALF; i++) { - nr_t orig = TEST_I + i; - mapping = nr_map_have(map, origin1, orig, 0); - m[i] = mapping->repl; - OSMO_ASSERT(m[i] != 0); - OSMO_ASSERT(llist_count(&map->mappings) == (i+1)); - for (check_i = 0; check_i < i; check_i++) - OSMO_ASSERT(m[check_i] != m[i]); - } - OSMO_ASSERT(llist_count(&map->mappings) == TEST_N_HALF); - - /* create another TEST_N mappings with the same original numbers, but - * from a different origin */ - void *origin2 = (void*)0x5678; - for (i = 0; i < TEST_N_HALF; i++) { - int i2 = TEST_N_HALF + i; - nr_t orig = TEST_I + i; - mapping = nr_map_have(map, origin2, orig, 0); - m[i2] = mapping->repl; - OSMO_ASSERT(m[i2] != 0); - OSMO_ASSERT(llist_count(&map->mappings) == (i2+1)); - for (check_i = 0; check_i < i2; check_i++) - OSMO_ASSERT(m[check_i] != m[i2]); - } - OSMO_ASSERT(llist_count(&map->mappings) == TEST_N); - - /* verify mappings */ - for (i = 0; i < TEST_N_HALF; i++) { - nr_t orig = TEST_I + i; - { - OSMO_ASSERT(nr_map_verify(map, origin1, orig, m[i])); - OSMO_ASSERT(nr_map_verify_inv(map, m[i], origin1, - orig)); - } - { - int i2 = TEST_N_HALF + i; - OSMO_ASSERT(nr_map_verify(map, origin2, orig, m[i2])); - OSMO_ASSERT(nr_map_verify_inv(map, m[i2], origin2, - orig)); - } - } - - /* remove all mappings */ - for (i = 0; i < TEST_N_HALF; i++) { - OSMO_ASSERT(llist_count(&map->mappings) == (TEST_N - 2*i)); - - nr_t orig = TEST_I + i; - nr_mapping_del(nr_map_get(map, origin1, orig)); - nr_mapping_del(nr_map_get(map, origin2, orig)); - } - OSMO_ASSERT(llist_empty(&map->mappings)); -#undef TEST_N -#undef TEST_I -} - -static int nr_map_is(struct nr_map *map, const char *str) -{ - static char buf[4096]; - char *pos = buf; - size_t len = sizeof(buf); - struct nr_mapping *m; - llist_for_each_entry(m, &map->mappings, entry) { - size_t wrote = snprintf(pos, len, "(%u->%u@%d), ", - m->orig, - m->repl, - (int)m->expiry_entry.expiry); - OSMO_ASSERT(wrote < len); - pos += wrote; - len -= wrote; - } - *pos = '\0'; - - if (strncmp(buf, str, sizeof(buf)) != 0) { - printf("FAILURE: nr_map_is() mismatches expected value:\n" - "expected: \"%s\"\n" - "is: \"%s\"\n", - str, buf); - return 0; - } - return 1; -} - -static int test_nr_map_wrap_with(nr_t nr_min, nr_t nr_max, nr_t repl_last, - nr_t orig_start, int orig_n, - const char *expect) -{ - struct nr_pool _pool; - struct nr_pool *pool = &_pool; - struct nr_map _map; - struct nr_map *map = &_map; - - nr_pool_init(pool, nr_min, nr_max); - nr_map_init(map, pool, NULL); - - pool->last_nr = repl_last; - - void *origin = (void*)0x1234; - - int i; - for (i = 0; i < orig_n; i++) - LVL2_ASSERT(nr_map_have(map, origin, orig_start + i, 0)); - - LVL2_ASSERT(nr_map_is(map, expect)); - - nr_map_clear(map); - return 1; -} - -static void test_nr_map_wrap(void) -{ - OSMO_ASSERT(test_nr_map_wrap_with( - 0, UINT_MAX, UINT_MAX - 2, - 1, 5, - "(1->4294967294@0), " - "(2->4294967295@0), " - "(3->0@0), " - "(4->1@0), " - "(5->2@0), " - )); - OSMO_ASSERT(test_nr_map_wrap_with( - 5, 10, 8, - 1, 5, - "(1->9@0), (2->10@0), (3->5@0), (4->6@0), (5->7@0), " - )); -} - -static void test_expiry(void) -{ - struct expiry expiry; - struct nr_pool pool; - struct nr_map map; - int i; - - expiry_init(&expiry, 30); - nr_pool_init(&pool, 1, 1000); - nr_map_init(&map, &pool, &expiry); - OSMO_ASSERT(nr_map_is(&map, "")); - - /* tick on empty map */ - OSMO_ASSERT(expiry_tick(&expiry, 10000) == 0); - OSMO_ASSERT(nr_map_is(&map, "")); - -#define MAP1 \ - "(10->1@10040), " \ - "" - -#define MAP2 \ - "(20->2@10050), " \ - "(21->3@10051), " \ - "(22->4@10052), " \ - "(23->5@10053), " \ - "(24->6@10054), " \ - "(25->7@10055), " \ - "(26->8@10056), " \ - "(27->9@10057), " \ - "" - -#define MAP3 \ - "(420->10@10072), " \ - "(421->11@10072), " \ - "(422->12@10072), " \ - "(423->13@10072), " \ - "(424->14@10072), " \ - "(425->15@10072), " \ - "(426->16@10072), " \ - "(427->17@10072), " \ - "" - - /* add mapping at time 10010. */ - nr_map_have(&map, 0, 10, 10010); - OSMO_ASSERT(nr_map_is(&map, MAP1)); - - /* tick on unexpired item. */ - OSMO_ASSERT(expiry_tick(&expiry, 10010) == 0); - OSMO_ASSERT(expiry_tick(&expiry, 10011) == 0); - OSMO_ASSERT(nr_map_is(&map, MAP1)); - - /* Spread mappings at 10020, 10021, ... 10027. */ - for (i = 0; i < 8; i++) - nr_map_have(&map, 0, 20 + i, 10020 + i); - OSMO_ASSERT(nr_map_is(&map, MAP1 MAP2)); - - /* tick on unexpired items. */ - OSMO_ASSERT(expiry_tick(&expiry, 10030) == 0); - OSMO_ASSERT(expiry_tick(&expiry, 10039) == 0); - OSMO_ASSERT(nr_map_is(&map, MAP1 MAP2)); - - /* expire the first item (from 10010). */ - OSMO_ASSERT(expiry_tick(&expiry, 10010 + 30) == 1); - OSMO_ASSERT(nr_map_is(&map, MAP2)); - - /* again nothing to expire */ - OSMO_ASSERT(expiry_tick(&expiry, 10041) == 0); - OSMO_ASSERT(nr_map_is(&map, MAP2)); - - /* Mappings all at the same time. */ - for (i = 0; i < 8; i++) - nr_map_have(&map, 0, 420 + i, 10042); - OSMO_ASSERT(nr_map_is(&map, MAP2 MAP3)); - - /* Eight to expire, were added further above to be chronologically - * correct, at 10020..10027. */ - OSMO_ASSERT(expiry_tick(&expiry, 10027 + 30) == 8); - OSMO_ASSERT(nr_map_is(&map, MAP3)); - - /* again nothing to expire */ - OSMO_ASSERT(expiry_tick(&expiry, 10027 + 30) == 0); - OSMO_ASSERT(nr_map_is(&map, MAP3)); - - /* Eight to expire, from 10042. Now at 10042 + 30: */ - OSMO_ASSERT(expiry_tick(&expiry, 10042 + 30) == 8); - OSMO_ASSERT(nr_map_is(&map, "")); - -#undef MAP1 -#undef MAP2 -#undef MAP3 -} - -char resolve_ggsn_got_imsi[GSM23003_IMSI_MAX_DIGITS+1]; -char resolve_ggsn_got_ni[GSM_APN_LENGTH]; - -struct osmo_sockaddr resolved_ggsn_addr; -static int resolve_to_ggsn(const char *addr, uint16_t port) -{ - LVL2_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_addr, - addr, port) - == 0); - return 1; -} - -struct osmo_sockaddr resolved_sgsn_addr; -static int resolve_to_sgsn(const char *addr, uint16_t port) -{ - LVL2_ASSERT(osmo_sockaddr_init_udp(&resolved_sgsn_addr, - addr, port) - == 0); - return 1; -} - -struct osmo_sockaddr sgsn_sender; -static int send_from_sgsn(const char *addr, uint16_t port) -{ - LVL2_ASSERT(osmo_sockaddr_init_udp(&sgsn_sender, - addr, port) - == 0); - return 1; -} - -struct osmo_sockaddr ggsn_sender; -static int send_from_ggsn(const char *addr, uint16_t port) -{ - LVL2_ASSERT(osmo_sockaddr_init_udp(&ggsn_sender, - addr, port) - == 0); - return 1; -} - - -/* override, requires '-Wl,--wrap=gtphub_resolve_ggsn_addr' */ -struct gtphub_peer_port *__real_gtphub_resolve_ggsn_addr(struct gtphub *hub, - const char *imsi_str, - const char *apn_ni_str); - -struct gtphub_peer_port *__wrap_gtphub_resolve_ggsn_addr(struct gtphub *hub, - const char *imsi_str, - const char *apn_ni_str) -{ - struct gsn_addr resolved_gsna; - uint16_t resolved_port; - - OSMO_ASSERT(gsn_addr_from_sockaddr(&resolved_gsna, &resolved_port, - &resolved_ggsn_addr) == 0); - - struct gtphub_peer_port *pp; - pp = gtphub_port_have(hub, &hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL], - &resolved_gsna, resolved_port); - printf("- __wrap_gtphub_resolve_ggsn_addr():\n" - " returning GGSN addr from imsi %s ni %s: %s\n", - imsi_str, apn_ni_str, gtphub_port_str(pp)); - - if (!imsi_str) - imsi_str = "(null)"; - osmo_strlcpy(resolve_ggsn_got_imsi, imsi_str, - sizeof(resolve_ggsn_got_imsi)); - - if (!apn_ni_str) - apn_ni_str = "(null)"; - osmo_strlcpy(resolve_ggsn_got_ni, apn_ni_str, - sizeof(resolve_ggsn_got_ni)); - - return pp; -} - -#define was_resolved_for(IMSI,NI) _was_resolved_for(IMSI, NI, __FILE__, __LINE__) -static int _was_resolved_for(const char *imsi, const char *ni, const char - *file, int line) -{ - int cmp0 = strncmp(imsi, resolve_ggsn_got_imsi, - sizeof(resolve_ggsn_got_imsi)); - - if (cmp0 != 0) { - printf("\n%s:%d: was_resolved_for(): MISMATCH for IMSI\n" - " expecting: '%s'\n" - " got: '%s'\n\n", - file, - line, - imsi, resolve_ggsn_got_imsi); - } - - int cmp1 = strncmp(ni, resolve_ggsn_got_ni, - sizeof(resolve_ggsn_got_ni)); - if (cmp1 != 0) { - printf("\n%s:%d: was_resolved_for(): MISMATCH for NI\n" - " expecting: '%s'\n" - " got: '%s'\n\n", - file, - line, - ni, resolve_ggsn_got_ni); - } - - return (cmp0 == 0) && (cmp1 == 0); -} - -/* override, requires '-Wl,--wrap=gtphub_ares_init' */ -int __real_gtphub_ares_init(struct gtphub *hub); - -int __wrap_gtphub_ares_init(struct gtphub *hub) -{ - /* Do nothing. */ - return 0; -} - -/* override, requires '-Wl,--wrap=gtphub_write' */ -int __real_gtphub_write(const struct osmo_fd *to, - const struct osmo_sockaddr *to_addr, - const uint8_t *buf, size_t buf_len); - -int __wrap_gtphub_write(const struct osmo_fd *to, - const struct osmo_sockaddr *to_addr, - const uint8_t *buf, size_t buf_len) -{ - printf("Out-of-band gtphub_write(%d):\n" - "to %s\n" - "%s\n", - (int)buf_len, - osmo_sockaddr_to_str(to_addr), - osmo_hexdump(buf, buf_len)); - return 0; -} - -#define buf_len 1024 -static uint8_t buf[buf_len]; -static uint8_t *reply_buf; - -static unsigned int msg(const char *hex) -{ - unsigned int l = osmo_hexparse(hex, buf, buf_len); - OSMO_ASSERT(l > 0); - return l; -} - -/* Compare static buf to given string constant. The amount of bytes is obtained - * from parsing the GTP header in buf. hex must match an osmo_hexdump() of the - * desired message. Return 1 if size and content match. */ -#define reply_is(MSG) _reply_is(MSG, __FILE__, __LINE__) -static int _reply_is(const char *hex, const char *file, int line) -{ - struct gtp1_header_long *h = (void*)reply_buf; - int len = ntoh16(h->length) + 8; - const char *dump = osmo_hexdump_nospc(reply_buf, len); - int cmp = strcmp(dump, hex); - - if (cmp != 0) { - printf("\n%s:%d: reply_is(): MISMATCH\n" - " expecting:\n'%s'\n" - " got:\n'%s'\n\n", - file, - line, - hex, dump); - int i; - int l = strlen(hex); - int m = strlen(dump); - if (m < l) - l = m; - for (i = 0; i < l; i++) { - if (hex[i] != dump[i]) { - printf("First mismatch at position %d:\n" - " %s\n %s\n", i, hex + i, dump + i); - break; - } - } - } - return cmp == 0; -} - -#define same_addr(GOT, EXPECTED) _same_addr((GOT),(EXPECTED), __FILE__, __LINE__) -static int _same_addr(const struct osmo_sockaddr *got, - const struct osmo_sockaddr *expected, - const char *file, int line) -{ - int cmp = osmo_sockaddr_cmp(got, expected); - if (!cmp) - return 1; - char buf[256]; - printf("\n%s:%d: addr_is(): MISMATCH\n" - " expecting: '%s'\n" - " got: '%s'\n\n", - file, line, - osmo_sockaddr_to_str(expected), - osmo_sockaddr_to_strb(got, buf, sizeof(buf))); - return 0; -} - - -time_t now; -static struct gtphub _hub; -static struct gtphub *hub = &_hub; - -static int setup_test_hub() -{ - /* Not really needed, but to make 100% sure... */ - ZERO_STRUCT(hub); - - gtphub_init(hub); - - /* Tell this mock gtphub its local address for this test. */ - LVL2_ASSERT(gsn_addr_from_str(&hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].local_addr, - "127.0.1.1") == 0); - LVL2_ASSERT(gsn_addr_from_str(&hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].local_addr, - "127.0.1.2") == 0); - LVL2_ASSERT(gsn_addr_from_str(&hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].local_addr, - "127.0.2.1") == 0); - LVL2_ASSERT(gsn_addr_from_str(&hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].local_addr, - "127.0.2.2") == 0); - - hub->restart_counter = 0x23; - now = 345; - LVL2_ASSERT(send_from_sgsn("192.168.42.23", 423)); - LVL2_ASSERT(resolve_to_ggsn("192.168.43.34", 2123)); - LVL2_ASSERT(send_from_ggsn("192.168.43.34", 434)); - LVL2_ASSERT(resolve_to_sgsn("192.168.42.23", 2123)); - -#define GGSNS_CTRL_FD 1 -#define GGSNS_USER_FD 2 -#define SGSNS_CTRL_FD 3 -#define SGSNS_USER_FD 4 - hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL].ofd.priv_nr = GGSNS_CTRL_FD; - hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER].ofd.priv_nr = GGSNS_USER_FD; - hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL].ofd.priv_nr = SGSNS_CTRL_FD; - hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER].ofd.priv_nr = SGSNS_USER_FD; - - return 1; -} - -static int clear_test_hub() -{ - /* expire all */ - gtphub_gc(hub, now + (60 * GTPH_EXPIRE_SLOWLY_MINUTES) + 1); - - int plane_idx; - plane_idx = GTPH_PLANE_CTRL; - LVL2_ASSERT(llist_empty(&hub->to_gsns[GTPH_SIDE_GGSN][plane_idx].peers)); - LVL2_ASSERT(llist_empty(&hub->to_gsns[GTPH_SIDE_SGSN][plane_idx].peers)); - plane_idx = GTPH_PLANE_USER; - LVL2_ASSERT(llist_empty(&hub->to_gsns[GTPH_SIDE_GGSN][plane_idx].peers)); - LVL2_ASSERT(llist_empty(&hub->to_gsns[GTPH_SIDE_SGSN][plane_idx].peers)); - - LVL2_ASSERT(llist_empty(&hub->tunnels)); - LVL2_ASSERT(llist_empty(&hub->pending_deletes)); - LVL2_ASSERT(llist_empty(&hub->ggsn_lookups)); - LVL2_ASSERT(llist_empty(&hub->resolved_ggsns)); - - gtphub_free(hub); - return 1; -} - -static int tunnels_are(const char *expect) -{ - static char buf[4096]; - char *pos = buf; - size_t len = sizeof(buf); - struct gtphub_tunnel *t; - llist_for_each_entry(t, &hub->tunnels, entry) { - size_t wrote = snprintf(pos, len, "%s @%d\n", - gtphub_tunnel_str(t), - (int)t->expiry_entry.expiry); - LVL2_ASSERT(wrote < len); - pos += wrote; - len -= wrote; - } - *pos = '\0'; - - if (strncmp(buf, expect, sizeof(buf)) != 0) { - fprintf(stderr, "FAILURE: tunnels_are() mismatches expected value:\n" - "EXPECTED:\n%s\n" - "IS:\n%s\n", - expect, buf); - LVL2_ASSERT("tunnels do not match expected listing."); - return 0; - } - return 1; -} - -static void test_echo(void) -{ - LOG("test_echo"); - OSMO_ASSERT(setup_test_hub()); - - now = 123; - - struct osmo_fd *to_ofd; - struct osmo_sockaddr to_addr; - struct gtphub_peer_port *pp; - int send; - - const char *gtp_ping_from_sgsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "01" /* type 01: Echo request */ - "0004" /* length of 4 after header TEI */ - "00000000" /* header TEI == 0 in Echo */ - "abcd" /* some 2 octet sequence nr */ - "0000" /* N-PDU 0, no extension header (why is this here?) */ - ; - - const char *gtp_pong_to_sgsn = - "32" - "02" /* type 02: Echo response */ - "0006" /* length of 6 after header TEI */ - "00000000" /* header TEI == 0 in Echo */ - "abcd" /* same sequence nr */ - "0000" - "0e23" /* Recovery with restart counter */ - ; - - to_ofd = NULL; - ZERO_STRUCT(&to_addr); - send = gtphub_handle_buf(hub, GTPH_SIDE_SGSN, GTPH_PLANE_CTRL, - &sgsn_sender, buf, msg(gtp_ping_from_sgsn), - now, &reply_buf, &to_ofd, &to_addr); - OSMO_ASSERT(send > 0); - OSMO_ASSERT(to_addr.l); - OSMO_ASSERT(same_addr(&to_addr, &sgsn_sender)); - OSMO_ASSERT(to_ofd && (to_ofd->priv_nr == SGSNS_CTRL_FD)); - OSMO_ASSERT(reply_is(gtp_pong_to_sgsn)); - - pp = gtphub_port_find_sa(&hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_CTRL], - &sgsn_sender); - /* We don't record Echo peers. */ - OSMO_ASSERT(!pp); - - const char *gtp_ping_from_ggsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "01" /* type 01: Echo request */ - "0004" /* length of 4 after header TEI */ - "00000000" /* header TEI == 0 in Echo */ - "cdef" /* some 2 octet sequence nr */ - "0000" /* N-PDU 0, no extension header (why is this here?) */ - ; - - const char *gtp_pong_to_ggsn = - "32" - "02" /* type 02: Echo response */ - "0006" /* length of 6 after header TEI */ - "00000000" /* header TEI == 0 in Echo */ - "cdef" /* same sequence nr */ - "0000" - "0e23" /* Recovery with restart counter */ - ; - - to_ofd = NULL; - ZERO_STRUCT(&to_addr); - send = gtphub_handle_buf(hub, GTPH_SIDE_GGSN, GTPH_PLANE_CTRL, - &ggsn_sender, buf, msg(gtp_ping_from_ggsn), - now, &reply_buf, &to_ofd, &to_addr); - OSMO_ASSERT(send > 0); - OSMO_ASSERT(same_addr(&to_addr, &ggsn_sender)); - OSMO_ASSERT(to_ofd && (to_ofd->priv_nr == GGSNS_CTRL_FD)); - OSMO_ASSERT(reply_is(gtp_pong_to_ggsn)); - - pp = gtphub_port_find_sa(&hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL], - &sgsn_sender); - OSMO_ASSERT(!pp); - - - /* And all the same on the user plane. */ - - to_ofd = NULL; - ZERO_STRUCT(&to_addr); - send = gtphub_handle_buf(hub, GTPH_SIDE_SGSN, GTPH_PLANE_USER, - &sgsn_sender, buf, msg(gtp_ping_from_sgsn), - now, &reply_buf, &to_ofd, &to_addr); - OSMO_ASSERT(send > 0); - OSMO_ASSERT(to_addr.l); - OSMO_ASSERT(same_addr(&to_addr, &sgsn_sender)); - OSMO_ASSERT(to_ofd && (to_ofd->priv_nr == SGSNS_USER_FD)); - OSMO_ASSERT(reply_is(gtp_pong_to_sgsn)); - - pp = gtphub_port_find_sa(&hub->to_gsns[GTPH_SIDE_SGSN][GTPH_PLANE_USER], - &sgsn_sender); - OSMO_ASSERT(!pp); - - to_ofd = NULL; - ZERO_STRUCT(&to_addr); - send = gtphub_handle_buf(hub, GTPH_SIDE_GGSN, GTPH_PLANE_USER, - &ggsn_sender, buf, msg(gtp_ping_from_ggsn), - now, &reply_buf, &to_ofd, &to_addr); - OSMO_ASSERT(send > 0); - OSMO_ASSERT(same_addr(&to_addr, &ggsn_sender)); - OSMO_ASSERT(to_ofd && (to_ofd->priv_nr == GGSNS_USER_FD)); - OSMO_ASSERT(reply_is(gtp_pong_to_ggsn)); - - pp = gtphub_port_find_sa(&hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_USER], - &sgsn_sender); - OSMO_ASSERT(!pp); - - - OSMO_ASSERT(clear_test_hub()); -} - - -#define MSG_PDP_CTX_REQ(len, seq, restart, imsi, tei_u, tei_c, apn, gsn_c, gsn_u) \ - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */ \ - "10" /* type 16: Create PDP Context Request */ \ - len /* msg length = 8 + len (2 octets) */ \ - "00000000" /* No TEI yet */ \ - seq /* Sequence nr (2 octets) */ \ - "00" /* N-PDU 0 */ \ - "00" /* No extensions */ \ - /* IEs */ \ - "0e" restart /* 14: Recovery (restart counter: 1 octet) */ \ - "02" /* 2 = IMSI */ \ - imsi /* (8 octets) */ \ - "0f01" /* 15: Selection mode = MS provided APN, subscription not verified*/ \ - "10" /* 16: TEI Data I */ \ - tei_u /* (4 octets) */ \ - "11" /* 17: TEI Control Plane */ \ - tei_c /* (4 octets) */ \ - "1400" /* 20: NSAPI = 0*/ \ - "1a" /* 26: Charging Characteristics */ \ - "0800" \ - "80" /* 128: End User Address */ \ - "0002" /* length = 2: empty PDP Address */ \ - "f121" /* spare 0xf0, PDP organization 1, PDP type number 0x21 = 33 */ \ - "83" /* 131: Access Point Name */ \ - apn /* (2 octets length, N octets encoded APN-NI) */ \ - "84" /* 132: Protocol Configuration Options */ \ - "0015" /* length = 21 */ \ - "80c0231101010011036d69670868656d6d656c6967" \ - "85" /* 133: GSN Address */ \ - gsn_c /* (2 octets length, N octets addr) */ \ - "85" /* 133: GSN Address (second entry) */ \ - gsn_u /* (2 octets length, N octets addr) */ \ - "86" /* 134: MS International PSTN/ISDN Number (MSISDN) */ \ - "0007" /* length */ \ - "916407123254f6" /* 1946702123456(f) */ \ - "87" /* 135: Quality of Service (QoS) Profile */ \ - "0004" /* length */ \ - "00" /* priority */ \ - "0b921f" /* QoS profile data */ - -#define MSG_PDP_CTX_RSP(len, tei_h, seq, restart, tei_u, tei_c, gsn_c, gsn_u) \ - "32" \ - "11" /* Create PDP Context Response */ \ - len /* msg length = 8 + len (2 octets) */ \ - tei_h /* destination TEI (sent in req above) */ \ - seq /* mapped seq */ \ - "00" "00" \ - /* IEs */ \ - "01" /* 1: Cause */ \ - "80" /* value = 0b10000000 = response, no rejection. */ \ - "08" /* 8: Reordering Required */ \ - "00" /* not required. */ \ - "0e" restart /* 14: Recovery */ \ - "10" /* 16: TEI Data I */ \ - tei_u \ - "11" /* 17: TEI Control */ \ - tei_c \ - "7f" /* 127: Charging ID */ \ - "00000001" \ - "80" /* 128: End User Address */ \ - "0006" /* length = 6 */ \ - "f121" /* spare 0xf0, PDP organization 1, PDP type number 0x21 = 33 */ \ - "7f000002" \ - "84" /* 132: Protocol Configuration Options */ \ - "0014" /* len = 20 */ \ - "8080211002000010810608080808830600000000" \ - "85" /* 133: GSN Address (Ctrl) */ \ - gsn_c \ - "85" /* 133: GSN Address (User) */ \ - gsn_u \ - "87" /* 135: Quality of Service (QoS) Profile */ \ - "0004" /* length */ \ - "00" /* priority */ \ - "0b921f" /* QoS profile data */ - -#define msg_from_sgsn_c(A,B,C,D) msg_from_sgsn(GTPH_PLANE_CTRL, A,B,C,D) -#define msg_from_sgsn_u(A,B,C,D) msg_from_sgsn(GTPH_PLANE_USER, A,B,C,D) -static int msg_from_sgsn(int plane_idx, - struct osmo_sockaddr *_sgsn_sender, - struct osmo_sockaddr *ggsn_receiver, - const char *hex_from_sgsn, - const char *hex_to_ggsn) -{ - struct osmo_fd *ggsn_ofd = NULL; - struct osmo_sockaddr ggsn_addr; - int send; - send = gtphub_handle_buf(hub, GTPH_SIDE_SGSN, plane_idx, _sgsn_sender, - buf, msg(hex_from_sgsn), now, - &reply_buf, &ggsn_ofd, &ggsn_addr); - LVL2_ASSERT(send > 0); - LVL2_ASSERT(same_addr(&ggsn_addr, ggsn_receiver)); - LVL2_ASSERT(reply_is(hex_to_ggsn)); - return 1; -} - -#define msg_from_ggsn_c(A,B,C,D) msg_from_ggsn(GTPH_PLANE_CTRL, A,B,C,D) -#define msg_from_ggsn_u(A,B,C,D) msg_from_ggsn(GTPH_PLANE_USER, A,B,C,D) -static int msg_from_ggsn(int plane_idx, - struct osmo_sockaddr *ggsn_sender, - struct osmo_sockaddr *sgsn_receiver, - const char *msg_from_ggsn, - const char *msg_to_sgsn) -{ - struct osmo_fd *sgsn_ofd; - struct osmo_sockaddr sgsn_addr; - int send; - send = gtphub_handle_buf(hub, GTPH_SIDE_GGSN, plane_idx, ggsn_sender, - buf, msg(msg_from_ggsn), now, - &reply_buf, &sgsn_ofd, &sgsn_addr); - if (*msg_to_sgsn) { - LVL2_ASSERT(send > 0); - LVL2_ASSERT(same_addr(&sgsn_addr, sgsn_receiver)); - LVL2_ASSERT(reply_is(msg_to_sgsn)); - } - else - LVL2_ASSERT(send == 0); - return 1; -} - -static int create_pdp_ctx() -{ - const char *gtp_req_from_sgsn = - MSG_PDP_CTX_REQ("0068", - "abcd", - "60", - "42000121436587f9", - "00000123", - "00000321", - "0009""08696e7465726e6574", /* "(8)internet" */ - "0004""c0a82a17", /* same as default sgsn_sender */ - "0004""c0a82a17" - ); - const char *gtp_req_to_ggsn = - MSG_PDP_CTX_REQ("0068", - "6d31", /* mapped seq ("abcd") */ - "23", - "42000121436587f9", - "00000001", /* Data I: tunnel's TEI */ - "00000001", /* Control: tunnel's TEI */ - "0009""08696e7465726e6574", - "0004""7f000201", /* replaced with gtphub's ggsn ctrl */ - "0004""7f000202" /* replaced with gtphub's ggsn user */ - ); - - LVL2_ASSERT(msg_from_sgsn_c(&sgsn_sender, - &resolved_ggsn_addr, - gtp_req_from_sgsn, - gtp_req_to_ggsn)); - LVL2_ASSERT(was_resolved_for("240010123456789", "internet")); - - LVL2_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21945\n")); - - const char *gtp_resp_from_ggsn = - MSG_PDP_CTX_RSP("004e", - "00000001", /* destination TEI (sent in req above) */ - "6d31", /* mapped seq */ - "01", /* restart */ - "00000567", /* TEI U */ - "00000765", /* TEI C */ - "0004""c0a82b22", /* GSN addresses */ - "0004""c0a82b22" /* (== resolved_ggsn_addr) */ - ); - const char *gtp_resp_to_sgsn = - MSG_PDP_CTX_RSP("004e", - "00000321", /* unmapped TEI ("001") */ - "abcd", /* unmapped seq ("6d31") */ - "23", - "00000001", /* mapped TEI from GGSN ("567") */ - "00000001", /* mapped TEI from GGSN ("765") */ - "0004""7f000101", /* gtphub's address towards SGSNs (Ctrl) */ - "0004""7f000102" /* gtphub's address towards SGSNs (User) */ - ); - /* The response should go back to whichever port the request came from - * (unmapped by sequence nr) */ - LVL2_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_resp_from_ggsn, - gtp_resp_to_sgsn)); - - return 1; -} - -#define MSG_DEL_PDP_CTX_REQ(tei, seq) \ - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */ \ - "14" /* type 20: Delete PDP Context Request */ \ - "0008" /* msg length = 8 + len (2 octets) */ \ - tei /* TEI Ctrl */ \ - seq /* Sequence nr (2 octets) */ \ - "00" /* N-PDU 0 */ \ - "00" /* No extensions */ \ - /* IEs */ \ - "13fe" /* 19: Teardown ind = 0 */ \ - "1400" /* 20: NSAPI = 0*/ \ - -#define MSG_DEL_PDP_CTX_RSP(tei, seq) \ - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr. */ \ - "15" /* type 21: Delete PDP Context Response */ \ - "0006" /* msg length = 8 + len (2 octets) */ \ - tei /* TEI Ctrl */ \ - seq /* Sequence nr (2 octets) */ \ - "00" /* N-PDU 0 */ \ - "00" /* No extensions */ \ - /* IEs */ \ - "01" /* 1: Cause */ \ - "80" /* value = 0b10000000 = response, no rejection. */ \ - -static int delete_pdp_ctx_from_sgsn(void) -{ - now += GTPH_EXPIRE_QUICKLY_SECS + 1; - gtphub_gc(hub, now); - - LVL2_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21945\n")); - - /* TEI Ctrl from above and next sequence after abcd. */ - const char *gtp_req_from_sgsn = MSG_DEL_PDP_CTX_REQ("00000001", "abce"); - const char *gtp_req_to_ggsn = MSG_DEL_PDP_CTX_REQ("00000765", "6d32"); - - LVL2_ASSERT(msg_from_sgsn_c(&sgsn_sender, - &resolved_ggsn_addr, - gtp_req_from_sgsn, - gtp_req_to_ggsn)); - - /* 21945 + 31 = 21976 */ - LVL2_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21976\n")); - - const char *gtp_resp_from_ggsn = - MSG_DEL_PDP_CTX_RSP("00000001", "6d32"); - const char *gtp_resp_to_sgsn = - MSG_DEL_PDP_CTX_RSP("00000321", "abce"); - - /* The response should go back to whichever port the request came from - * (unmapped by sequence nr) */ - LVL2_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_resp_from_ggsn, - gtp_resp_to_sgsn)); - - LVL2_ASSERT(tunnels_are("")); - - return 1; -} - -static int delete_pdp_ctx_from_ggsn(void) -{ - now += GTPH_EXPIRE_QUICKLY_SECS + 1; - gtphub_gc(hub, now); - - LVL2_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21945\n")); - - /* TEI Ctrl from above and next sequence after abcd. */ - const char *gtp_req_from_ggsn = MSG_DEL_PDP_CTX_REQ("00000001", "5432"); - const char *gtp_req_to_sgsn = MSG_DEL_PDP_CTX_REQ("00000321", "6d31"); - - LVL2_ASSERT(msg_from_ggsn_c(&ggsn_sender, - &resolved_sgsn_addr, - gtp_req_from_ggsn, - gtp_req_to_sgsn)); - - /* 21945 + 31 = 21976 */ - LVL2_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21976\n")); - - const char *gtp_resp_from_sgsn = - MSG_DEL_PDP_CTX_RSP("00000001", "6d31"); - const char *gtp_resp_to_ggsn = - MSG_DEL_PDP_CTX_RSP("00000765", "5432"); - - /* The response should go back to whichever port the request came from - * (unmapped by sequence nr) */ - LVL2_ASSERT(msg_from_sgsn_c(&resolved_sgsn_addr, - &ggsn_sender, - gtp_resp_from_sgsn, - gtp_resp_to_ggsn)); - - LVL2_ASSERT(tunnels_are("")); - - return 1; -} - -static void test_one_pdp_ctx(int del_from_side) -{ - if (del_from_side == GTPH_SIDE_SGSN) - LOG("test_one_pdp_ctx (del from SGSN)") - else LOG("test_one_pdp_ctx (del from GGSN)"); - OSMO_ASSERT(setup_test_hub()); - - OSMO_ASSERT(create_pdp_ctx()); - - struct gtphub_peer_port *ggsn_port = - gtphub_port_find_sa(&hub->to_gsns[GTPH_SIDE_GGSN][GTPH_PLANE_CTRL], - &resolved_ggsn_addr); - OSMO_ASSERT(ggsn_port); - struct gtphub_peer *ggsn = ggsn_port->peer_addr->peer; - /* now == 345; now + 30 == 375. - * seq mapping from above: - * 0xabcd == 43981 (sent in the packet) - * 0x6d31 == 27953 (harcoded seq mapping start val) */ - OSMO_ASSERT(nr_map_is(&ggsn->seq_map, "(43981->27953@375), ")); - - /* now == 345; now + (6 * 60 * 60) == 21600 + 345 == 21945. - * 0x00000321 == 801 (TEI from SGSN Ctrl) - * 0x00000123 == 291 (TEI from SGSN User) - * 0x00000765 == 1893 (TEI from GGSN Ctrl) - * 0x00000567 == 1383 (TEI from GGSN User) - * Mapped TEIs should be 1 and 2. */ - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21945\n")); - - if (del_from_side == GTPH_SIDE_SGSN) { - OSMO_ASSERT(delete_pdp_ctx_from_sgsn()); - } else { - OSMO_ASSERT(delete_pdp_ctx_from_ggsn()); - } - OSMO_ASSERT(tunnels_are("")); - - OSMO_ASSERT(clear_test_hub()); -} - -static void test_user_data(void) -{ - LOG("test_user_data"); - - OSMO_ASSERT(setup_test_hub()); - - OSMO_ASSERT(create_pdp_ctx()); - - /* now == 345; now + (6 * 60 * 60) == 21600 + 345 == 21945. */ - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21945\n")); - - LOG("- user data starts"); - /* Now expect default port numbers for User plane. */ - resolve_to_ggsn("192.168.43.34", 2152); - resolve_to_sgsn("192.168.42.23", 2152); - - /* 10 minutes later */ - now += 600; - - const char *u_from_ggsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000001" /* mapped TEI for SGSN from create_pdp_ctx() */ - "0070" /* seq */ - "0000" /* No extensions */ - /* User data (ICMP packet), 96 - 12 = 84 octets */ - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - const char *u_to_sgsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000123" /* unmapped User TEI */ - "6d31" /* new mapped seq */ - "0000" - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - - /* This depends on create_pdp_ctx() sending resolved_sgsn_addr as GSN - * Address IEs in the GGSN's Create PDP Ctx Response. */ - OSMO_ASSERT(msg_from_ggsn_u(&ggsn_sender, - &resolved_sgsn_addr, - u_from_ggsn, - u_to_sgsn)); - - /* Make sure the user plane messages have refreshed the TEI mapping - * timeouts: 21945 + 600 == 22545. */ - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @22545\n")); - - const char *u_from_sgsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000001" /* mapped User TEI for GGSN from create_pdp_ctx() */ - "1234" /* unknown seq */ - "0000" /* No extensions */ - /* User data (ICMP packet), 96 - 12 = 84 octets */ - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - const char *u_to_ggsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000567" /* unmapped User TEI */ - "6d31" /* unmapped seq */ - "0000" - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - - OSMO_ASSERT(msg_from_sgsn_u(&sgsn_sender, - &resolved_ggsn_addr, - u_from_sgsn, - u_to_ggsn)); - - /* Make sure the user plane messages have refreshed the TEI mapping - * timeouts: 21945 + 600 == 22545. Both timeouts refreshed: */ - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @22545\n")); - - OSMO_ASSERT(clear_test_hub()); -} - -static void test_reused_tei(void) -{ - LOG("test_reused_tei"); - - OSMO_ASSERT(setup_test_hub()); - - OSMO_ASSERT(create_pdp_ctx()); - - const char *gtp_req_from_sgsn = - MSG_PDP_CTX_REQ("0068", - "abce", /* Next seq */ - "60", - "42000121436587f9", - "00000123", /* Same TEIs as before */ - "00000321", - "0009""08696e7465726e6574", /* "(8)internet" */ - "0004""c0a82a17", /* same as default sgsn_sender */ - "0004""c0a82a17" - ); - const char *gtp_req_to_ggsn = - MSG_PDP_CTX_REQ("0068", - "6d32", /* mapped seq ("abce") */ - "23", - "42000121436587f9", - "00000002", /* mapped TEI Data I ("123") */ - "00000002", /* mapped TEI Control ("321") */ - "0009""08696e7465726e6574", - "0004""7f000201", /* replaced with gtphub's ggsn ctrl */ - "0004""7f000202" /* replaced with gtphub's ggsn user */ - ); - - OSMO_ASSERT(msg_from_sgsn_c(&sgsn_sender, - &resolved_ggsn_addr, - gtp_req_from_sgsn, - gtp_req_to_ggsn)); - OSMO_ASSERT(was_resolved_for("240010123456789", "internet")); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21945\n")); - - const char *gtp_resp_from_ggsn = - MSG_PDP_CTX_RSP("004e", - "00000002", /* destination TEI (sent in req above) */ - "6d32", /* mapped seq */ - "01", /* restart */ - "00000567", /* TEI U */ - "00000765", /* TEI C */ - "0004""c0a82b22", /* GSN addresses */ - "0004""c0a82b22" /* (== resolved_ggsn_addr) */ - ); - const char *gtp_resp_to_sgsn = - MSG_PDP_CTX_RSP("004e", - "00000321", /* unmapped TEI ("001") */ - "abce", /* unmapped seq ("6d32") */ - "23", - "00000002", /* mapped TEI from GGSN ("567") */ - "00000002", /* mapped TEI from GGSN ("765") */ - "0004""7f000101", /* gtphub's address towards SGSNs (Ctrl) */ - "0004""7f000102" /* gtphub's address towards SGSNs (User) */ - ); - /* The response should go back to whichever port the request came from - * (unmapped by sequence nr) */ - OSMO_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_resp_from_ggsn, - gtp_resp_to_sgsn)); - - OSMO_ASSERT(clear_test_hub()); -} - -static void test_peer_restarted(void) -{ - LOG("test_peer_restarted"); - - OSMO_ASSERT(setup_test_hub()); - - OSMO_ASSERT(create_pdp_ctx()); - - now += 10; - - const char *gtp_req_from_sgsn = - MSG_PDP_CTX_REQ("0068", - "1234", /* brand new seq */ - "61", /* DIFFERING restart counter */ - "42000121436587f9", - "00000abc", - "00000cba", - "0009""08696e7465726e6574", /* "(8)internet" */ - "0004""c0a82a17", /* same as default sgsn_sender */ - "0004""c0a82a17" - ); - const char *gtp_req_to_ggsn = - MSG_PDP_CTX_REQ("0068", - "6d33", /* mapped seq ("1234") */ - "23", - "42000121436587f9", - "00000002", /* mapped TEI Data I ("123") */ - "00000002", /* mapped TEI Control ("321") */ - "0009""08696e7465726e6574", - "0004""7f000201", /* replaced with gtphub's ggsn ctrl */ - "0004""7f000202" /* replaced with gtphub's ggsn user */ - ); - - OSMO_ASSERT(msg_from_sgsn_c(&sgsn_sender, - &resolved_ggsn_addr, - gtp_req_from_sgsn, - gtp_req_to_ggsn)); - OSMO_ASSERT(was_resolved_for("240010123456789", "internet")); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" - " 192.168.42.23 (TEI C=cba U=abc)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21955\n" - "TEI=1:" - " (uninitialized) (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21945\n" - )); - - const char *gtp_resp_from_ggsn = - MSG_PDP_CTX_RSP("004e", - "00000002", /* destination TEI (sent in req above) */ - "6d33", /* mapped seq */ - "01", /* restart */ - "00000def", /* TEI U */ - "00000fde", /* TEI C */ - "0004""c0a82b22", /* GSN addresses */ - "0004""c0a82b22" /* (== resolved_ggsn_addr) */ - ); - const char *gtp_resp_to_sgsn = - MSG_PDP_CTX_RSP("004e", - "00000cba", /* unmapped TEI ("005") */ - "1234", /* unmapped seq ("6d32") */ - "23", - "00000002", /* mapped TEI from GGSN ("567") */ - "00000002", /* mapped TEI from GGSN ("765") */ - "0004""7f000101", /* gtphub's address towards SGSNs (Ctrl) */ - "0004""7f000102" /* gtphub's address towards SGSNs (User) */ - ); - /* The response should go back to whichever port the request came from - * (unmapped by sequence nr) */ - OSMO_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_resp_from_ggsn, - gtp_resp_to_sgsn)); - - OSMO_ASSERT(clear_test_hub()); -} - -static void test_peer_restarted_reusing_tei(void) -{ - LOG("test_peer_restarted_reusing_tei"); - - OSMO_ASSERT(setup_test_hub()); - - OSMO_ASSERT(create_pdp_ctx()); - - now += 10; - - const char *gtp_req_from_sgsn = - MSG_PDP_CTX_REQ("0068", - "1234", /* brand new seq */ - "61", /* DIFFERING restart counter */ - "42000121436587f9", - "00000123", /* SAME TEI */ - "00000321", - "0009""08696e7465726e6574", /* "(8)internet" */ - "0004""c0a82a17", /* same as default sgsn_sender */ - "0004""c0a82a17" - ); - const char *gtp_req_to_ggsn = - MSG_PDP_CTX_REQ("0068", - "6d33", /* seq 6d31 + 2, after "out-of-band" Delete PDP Ctx - due to differing restart counter. */ - "23", - "42000121436587f9", - "00000002", /* mapped TEI Data I ("123") */ - "00000002", /* mapped TEI Control ("321") */ - "0009""08696e7465726e6574", - "0004""7f000201", /* replaced with gtphub's ggsn ctrl */ - "0004""7f000202" /* replaced with gtphub's ggsn user */ - ); - - OSMO_ASSERT(msg_from_sgsn_c(&sgsn_sender, - &resolved_ggsn_addr, - gtp_req_from_sgsn, - gtp_req_to_ggsn)); - OSMO_ASSERT(was_resolved_for("240010123456789", "internet")); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" /* being established after restart */ - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21955\n" - "TEI=1:" /* invalidated due to restart */ - " (uninitialized) (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21945\n" - )); - - /* An "out-of-band" delete request should have been sent to the GGSN - * (checked by expected log output in gtphub_test.ok), and the GGSN - * will (usually) send a Delete Response like this: */ - const char *gtp_del_resp_from_ggsn = - MSG_DEL_PDP_CTX_RSP("00000001", "6d32"); - - /* For this response (due to peer restart) we expect no forwarded - * message. */ - OSMO_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_del_resp_from_ggsn, - "")); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" /* still being established after restart */ - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21955\n" - )); - - const char *gtp_resp_from_ggsn = - MSG_PDP_CTX_RSP("004e", - "00000002", /* destination TEI (sent in req above) */ - "6d33", /* mapped seq */ - "01", /* restart */ - "00000def", /* TEI U */ - "00000fde", /* TEI C */ - "0004""c0a82b22", /* GSN addresses */ - "0004""c0a82b22" /* (== resolved_ggsn_addr) */ - ); - const char *gtp_resp_to_sgsn = - MSG_PDP_CTX_RSP("004e", - "00000321", /* unmapped TEI ("005") */ - "1234", /* unmapped seq ("6d33") */ - "23", - "00000002", /* mapped TEI from GGSN ("567") */ - "00000002", /* mapped TEI from GGSN ("765") */ - "0004""7f000101", /* gtphub's address towards SGSNs (Ctrl) */ - "0004""7f000102" /* gtphub's address towards SGSNs (User) */ - ); - /* The response should go back to whichever port the request came from - * (unmapped by sequence nr) */ - OSMO_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_resp_from_ggsn, - gtp_resp_to_sgsn)); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" /* still being established after restart */ - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=fde U=def)" - " @21955\n" - )); - - OSMO_ASSERT(clear_test_hub()); -} - -static void test_sgsn_behind_nat(void) -{ - LOG("test_user_data"); - - OSMO_ASSERT(setup_test_hub()); - hub->sgsn_use_sender = 1; /* <-- Main difference to test_user_data() */ - resolve_to_sgsn("192.168.42.23", 423); /* Same as sender */ - - OSMO_ASSERT(create_pdp_ctx()); - - /* now == 345; now + (6 * 60 * 60) == 21600 + 345 == 21945. */ - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21945\n")); - - LOG("- user data starts"); - /* Now expect default port numbers for User plane -- except SGSN. */ - resolve_to_ggsn("192.168.43.34", 2152); - - /* 10 minutes later */ - now += 600; - - const char *u_from_ggsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000001" /* mapped User TEI for SGSN from create_pdp_ctx() */ - "0070" /* seq */ - "0000" /* No extensions */ - /* User data (ICMP packet), 96 - 12 = 84 octets */ - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - const char *u_to_sgsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000123" /* unmapped User TEI */ - "6d31" /* new mapped seq */ - "0000" - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - - /* This depends on create_pdp_ctx() sending resolved_sgsn_addr as GSN - * Address IEs in the GGSN's Create PDP Ctx Response. */ - OSMO_ASSERT(msg_from_ggsn_u(&ggsn_sender, - &resolved_sgsn_addr, - u_from_ggsn, - u_to_sgsn)); - - /* Make sure the user plane messages have refreshed the TEI mapping - * timeouts: 21945 + 600 == 22545. */ - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @22545\n")); - - const char *u_from_sgsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000001" /* mapped User TEI for GGSN from create_pdp_ctx() */ - "1234" /* unknown seq */ - "0000" /* No extensions */ - /* User data (ICMP packet), 96 - 12 = 84 octets */ - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - const char *u_to_ggsn = - "32" /* 0b001'1 0010: version 1, protocol GTP, with seq nr */ - "ff" /* type 255: G-PDU */ - "0058" /* length: 88 + 8 octets == 96 */ - "00000567" /* unmapped User TEI */ - "6d31" /* unmapped seq */ - "0000" - "45000054daee40004001f7890a172a010a172a02080060d23f590071e3f8" - "4156000000007241010000000000101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f3031323334353637" - ; - - OSMO_ASSERT(msg_from_sgsn_u(&sgsn_sender, - &resolved_ggsn_addr, - u_from_sgsn, - u_to_ggsn)); - - /* Make sure the user plane messages have refreshed the TEI mapping - * timeouts: 21945 + 600 == 22545. Both timeouts refreshed: */ - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @22545\n")); - - OSMO_ASSERT(clear_test_hub()); -} - -void test_parallel_context_creation(void) -{ - LOG("test_parallel_context_creation"); - - OSMO_ASSERT(setup_test_hub()); - - const char *gtp_req_from_sgsn1 = - MSG_PDP_CTX_REQ("0068", - "abcd", - "60", - "42000121436587f9", - "00000123", - "00000321", - "0009""08696e7465726e6574", /* "(8)internet" */ - "0004""c0a82a17", /* same as default sgsn_sender */ - "0004""c0a82a17" - ); - const char *gtp_req_to_ggsn1 = - MSG_PDP_CTX_REQ("0068", - "6d31", /* mapped seq ("abcd") */ - "23", - "42000121436587f9", - "00000001", /* mapped TEI Data I ("123") */ - "00000001", /* mapped TEI Control ("321") */ - "0009""08696e7465726e6574", - "0004""7f000201", /* replaced with gtphub's ggsn ctrl */ - "0004""7f000202" /* replaced with gtphub's ggsn user */ - ); - - OSMO_ASSERT(msg_from_sgsn_c(&sgsn_sender, - &resolved_ggsn_addr, - gtp_req_from_sgsn1, - gtp_req_to_ggsn1)); - - OSMO_ASSERT(tunnels_are( - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21945\n")); - - now ++; - - const char *gtp_req_from_sgsn2 = - MSG_PDP_CTX_REQ("0068", - "abce", - "60", - "42000121436588f9", - "00000124", - "00000322", - "0009""08696e7465726e6574", /* "(8)internet" */ - "0004""c0a82a17", /* same as default sgsn_sender */ - "0004""c0a82a17" - ); - const char *gtp_req_to_ggsn2 = - MSG_PDP_CTX_REQ("0068", - "6d32", /* mapped seq ("abce") */ - "23", - "42000121436588f9", - "00000002", /* mapped TEI Data I ("124") */ - "00000002", /* mapped TEI Control ("322") */ - "0009""08696e7465726e6574", - "0004""7f000201", /* replaced with gtphub's ggsn ctrl */ - "0004""7f000202" /* replaced with gtphub's ggsn user */ - ); - - OSMO_ASSERT(msg_from_sgsn_c(&sgsn_sender, - &resolved_ggsn_addr, - gtp_req_from_sgsn2, - gtp_req_to_ggsn2)); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" - " 192.168.42.23 (TEI C=322 U=124)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21946\n" - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21945\n" - )); - - now ++; - - const char *gtp_resp_from_ggsn1 = - MSG_PDP_CTX_RSP("004e", - "00000001", /* destination TEI (sent in req above) */ - "6d31", /* mapped seq */ - "01", /* restart */ - "00000567", /* TEI U */ - "00000765", /* TEI C */ - "0004""c0a82b22", /* GSN addresses */ - "0004""c0a82b22" /* (== resolved_ggsn_addr) */ - ); - const char *gtp_resp_to_sgsn1 = - MSG_PDP_CTX_RSP("004e", - "00000321", /* unmapped TEI ("001") */ - "abcd", /* unmapped seq ("6d31") */ - "23", - "00000001", /* mapped TEI from GGSN ("567") */ - "00000001", /* mapped TEI from GGSN ("765") */ - "0004""7f000101", /* gtphub's address towards SGSNs (Ctrl) */ - "0004""7f000102" /* gtphub's address towards SGSNs (User) */ - ); - - OSMO_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_resp_from_ggsn1, - gtp_resp_to_sgsn1)); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" - " 192.168.42.23 (TEI C=322 U=124)" - " <-> 192.168.43.34/(uninitialized) (TEI C=0 U=0)" - " @21946\n" - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21947\n" - )); - - now ++; - - const char *gtp_resp_from_ggsn2 = - MSG_PDP_CTX_RSP("004e", - "00000002", /* destination TEI (sent in req above) */ - "6d32", /* mapped seq */ - "01", /* restart */ - "00000568", /* TEI U */ - "00000766", /* TEI C */ - "0004""c0a82b22", /* GSN addresses */ - "0004""c0a82b22" /* (== resolved_ggsn_addr) */ - ); - const char *gtp_resp_to_sgsn2 = - MSG_PDP_CTX_RSP("004e", - "00000322", /* unmapped TEI ("001") */ - "abce", /* unmapped seq ("6d31") */ - "23", - "00000002", /* mapped TEI from GGSN ("567") */ - "00000002", /* mapped TEI from GGSN ("765") */ - "0004""7f000101", /* gtphub's address towards SGSNs (Ctrl) */ - "0004""7f000102" /* gtphub's address towards SGSNs (User) */ - ); - - OSMO_ASSERT(msg_from_ggsn_c(&resolved_ggsn_addr, - &sgsn_sender, - gtp_resp_from_ggsn2, - gtp_resp_to_sgsn2)); - - OSMO_ASSERT(tunnels_are( - "TEI=2:" - " 192.168.42.23 (TEI C=322 U=124)" - " <-> 192.168.43.34 (TEI C=766 U=568)" - " @21948\n" - "TEI=1:" - " 192.168.42.23 (TEI C=321 U=123)" - " <-> 192.168.43.34 (TEI C=765 U=567)" - " @21947\n" - )); - - OSMO_ASSERT(clear_test_hub()); -} - - -static struct log_info_cat gtphub_categories[] = { - [DGTPHUB] = { - .name = "DGTPHUB", - .description = "GTP Hub", - .color = "\033[1;33m", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, -}; - -static struct log_info info = { - .cat = gtphub_categories, - .num_cat = ARRAY_SIZE(gtphub_categories), -}; - -int main(int argc, char **argv) -{ - osmo_init_logging(&info); - osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub"); - - test_nr_map_basic(); - test_nr_map_wrap(); - test_expiry(); - test_echo(); - test_one_pdp_ctx(GTPH_SIDE_SGSN); - test_one_pdp_ctx(GTPH_SIDE_GGSN); - test_user_data(); - test_reused_tei(); - test_peer_restarted(); - test_peer_restarted_reusing_tei(); - test_sgsn_behind_nat(); - test_parallel_context_creation(); - printf("Done\n"); - - talloc_report_full(osmo_gtphub_ctx, stderr); - OSMO_ASSERT(talloc_total_blocks(osmo_gtphub_ctx) == 1); - return 0; -} - diff --git a/tests/gtphub/gtphub_test.ok b/tests/gtphub/gtphub_test.ok deleted file mode 100644 index e60d5f2b2..000000000 --- a/tests/gtphub/gtphub_test.ok +++ /dev/null @@ -1,42 +0,0 @@ -test_echo -test_one_pdp_ctx (del from SGSN) -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -test_one_pdp_ctx (del from GGSN) -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -test_user_data -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -- user data starts -test_reused_tei -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -test_peer_restarted -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -Out-of-band gtphub_write(16): -to 192.168.43.34 port 2123 -32 14 00 08 00 00 07 65 6d 32 00 00 13 ff 14 00 -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -test_peer_restarted_reusing_tei -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -Out-of-band gtphub_write(16): -to 192.168.43.34 port 2123 -32 14 00 08 00 00 07 65 6d 32 00 00 13 ff 14 00 -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -test_user_data -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -- user data starts -test_parallel_context_creation -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456789 ni internet: 192.168.43.34 port 2123 -- __wrap_gtphub_resolve_ggsn_addr(): - returning GGSN addr from imsi 240010123456889 ni internet: 192.168.43.34 port 2123 -Done diff --git a/tests/msc_vlr/Makefile.am b/tests/msc_vlr/Makefile.am index 10184fa4b..70006ddca 100644 --- a/tests/msc_vlr/Makefile.am +++ b/tests/msc_vlr/Makefile.am @@ -47,8 +47,6 @@ COMMON_LDADD = \ $(top_builddir)/src/libmsc/libmsc.a \ $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ $(top_builddir)/src/libvlr/libvlr.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBSMPP34_LIBS) \ $(LIBOSMOCORE_LIBS) \ diff --git a/tests/msc_vlr/msc_vlr_tests.c b/tests/msc_vlr/msc_vlr_tests.c index 71f971352..4b10e49d5 100644 --- a/tests/msc_vlr/msc_vlr_tests.c +++ b/tests/msc_vlr/msc_vlr_tests.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #if BUILD_IU diff --git a/tests/nanobts_omlattr/Makefile.am b/tests/nanobts_omlattr/Makefile.am deleted file mode 100644 index b03d50cc1..000000000 --- a/tests/nanobts_omlattr/Makefile.am +++ /dev/null @@ -1,34 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(NULL) - -noinst_PROGRAMS = \ - nanobts_omlattr_test \ - $(NULL) - -EXTRA_DIST = \ - nanobts_omlattr_test.ok \ - $(NULL) - -nanobts_omlattr_test_SOURCES = \ - nanobts_omlattr_test.c \ - $(NULL) - -nanobts_omlattr_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libmsc/libmsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - -ldbi \ - $(NULL) diff --git a/tests/nanobts_omlattr/nanobts_omlattr_test.c b/tests/nanobts_omlattr/nanobts_omlattr_test.c deleted file mode 100644 index ee138b8f7..000000000 --- a/tests/nanobts_omlattr/nanobts_omlattr_test.c +++ /dev/null @@ -1,284 +0,0 @@ -/* Test OML attribute generator */ - -/* (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 . - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -struct gsm_bts_model bts_model_nanobts = { - .type = GSM_BTS_TYPE_NANOBTS, - .name = "nanobts", - .start = NULL, - .oml_rcvmsg = NULL, - .e1line_bind_ops = NULL, - .nm_att_tlvdef = { - .def = { - /* ip.access specifics */ - [NM_ATT_IPACC_DST_IP] = {TLV_TYPE_FIXED, 4}, - [NM_ATT_IPACC_DST_IP_PORT] = - {TLV_TYPE_FIXED, 2}, - [NM_ATT_IPACC_STREAM_ID] = {TLV_TYPE_TV,}, - [NM_ATT_IPACC_SEC_OML_CFG] = - {TLV_TYPE_FIXED, 6}, - [NM_ATT_IPACC_IP_IF_CFG] = - {TLV_TYPE_FIXED, 8}, - [NM_ATT_IPACC_IP_GW_CFG] = - {TLV_TYPE_FIXED, 12}, - [NM_ATT_IPACC_IN_SERV_TIME] = - {TLV_TYPE_FIXED, 4}, - [NM_ATT_IPACC_LOCATION] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_PAGING_CFG] = - {TLV_TYPE_FIXED, 2}, - [NM_ATT_IPACC_UNIT_ID] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_UNIT_NAME] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_SNMP_CFG] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_NV_FLAGS] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_FREQ_CTRL] = - {TLV_TYPE_FIXED, 2}, - [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_CUR_SW_CFG] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_TIMING_BUS] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_CGI] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_RAC] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_OBJ_VERSION] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_GPRS_PAGING_CFG] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_NSEI] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_BVCI] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_NSVCI] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_NS_CFG] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_BSSGP_CFG] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_NS_LINK_CFG] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_RLC_CFG] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_ALM_THRESH_LIST] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_MONIT_VAL_LIST] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_TIB_CONTROL] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_SUPP_FEATURES] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_CODING_SCHEMES] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_RLC_CFG_2] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_HEARTB_TOUT] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_UPTIME] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_RLC_CFG_3] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_SSL_CFG] = {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_SEC_POSSIBLE] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_IML_SSL_STATE] = - {TLV_TYPE_TL16V}, - [NM_ATT_IPACC_REVOC_DATE] = {TLV_TYPE_TL16V}, - }, - }, -}; - -static void test_nanobts_attr_bts_get(struct gsm_bts *bts, uint8_t *expected) -{ - struct msgb *msgb; - - printf("Testing nanobts_attr_bts_get()...\n"); - - msgb = nanobts_attr_bts_get(bts); - printf("result= %s\n", osmo_hexdump_nospc(msgb->data, msgb->len)); - printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len)); - OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0); - msgb_free(msgb); - - printf("ok.\n"); - printf("\n"); -} - -static void test_nanobts_attr_nse_get(struct gsm_bts *bts, uint8_t *expected) -{ - struct msgb *msgb; - - printf("Testing nanobts_attr_nse_get()...\n"); - - msgb = nanobts_attr_nse_get(bts); - printf("result= %s\n", osmo_hexdump_nospc(msgb->data, msgb->len)); - printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len)); - OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0); - msgb_free(msgb); - - printf("ok.\n"); - printf("\n"); -} - -static void test_nanobts_attr_cell_get(struct gsm_bts *bts, uint8_t *expected) -{ - struct msgb *msgb; - - printf("Testing nanobts_attr_cell_get()...\n"); - - msgb = nanobts_attr_cell_get(bts); - printf("result= %s\n", osmo_hexdump_nospc(msgb->data, msgb->len)); - printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len)); - OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0); - msgb_free(msgb); - - printf("ok.\n"); - printf("\n"); -} - -static void test_nanobts_attr_nscv_get(struct gsm_bts *bts, uint8_t *expected) -{ - struct msgb *msgb; - - printf("Testing nanobts_attr_nscv_get()...\n"); - - msgb = nanobts_attr_nscv_get(bts); - printf("result= %s\n", osmo_hexdump_nospc(msgb->data, msgb->len)); - printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len)); - OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0); - msgb_free(msgb); - - printf("ok.\n"); - printf("\n"); -} - -static void test_nanobts_attr_radio_get(struct gsm_bts *bts, - struct gsm_bts_trx *trx, - uint8_t *expected) -{ - struct msgb *msgb; - - printf("Testing nanobts_attr_nscv_get()...\n"); - - msgb = nanobts_attr_radio_get(bts, trx); - printf("result= %s\n", osmo_hexdump_nospc(msgb->data, msgb->len)); - printf("expected=%s\n", osmo_hexdump_nospc(expected, msgb->len)); - OSMO_ASSERT(memcmp(msgb->data, expected, msgb->len) == 0); - msgb_free(msgb); - - printf("ok.\n"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - void *ctx; - - struct gsm_bts *bts; - struct gsm_network *net; - struct gsm_bts_trx *trx; - - ctx = talloc_named_const(NULL, 0, "ctx"); - - /* Allocate environmental structs (bts, net, trx) */ - net = talloc_zero(ctx, struct gsm_network); - INIT_LLIST_HEAD(&net->bts_list); - gsm_bts_model_register(&bts_model_nanobts); - bts = gsm_bts_alloc_register(net, GSM_BTS_TYPE_NANOBTS, 63); - OSMO_ASSERT(bts); - trx = talloc_zero(ctx, struct gsm_bts_trx); - - /* Parameters needed by nanobts_attr_bts_get() */ - bts->rach_b_thresh = -1; - bts->rach_ldavg_slots = -1; - bts->c0->arfcn = 866; - bts->cell_identity = 1337; - bts->network->country_code = 1; - bts->network->network_code = 1; - bts->location_area_code = 1; - bts->gprs.rac = 0; - uint8_t attr_bts_expected[] = - { 0x19, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73, 0x18, 0x06, 0x0e, 0x00, - 0x02, 0x01, 0x20, 0x33, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, - 0xa8, 0x1f, 0x3f, 0x25, - 0x00, 0x01, 0x0a, 0x0c, 0x0a, 0x0b, 0x01, 0x2a, 0x0a, 0x2b, - 0x03, 0xe8, 0x0a, 0x80, - 0x23, 0x0a, 0x08, 0x03, 0x62, 0x09, 0x3f, 0x99, 0x00, 0x07, - 0x00, 0xf1, 0x10, 0x00, - 0x01, 0x05, 0x39 - }; - - /* Parameters needed to test nanobts_attr_nse_get() */ - bts->gprs.nse.nsei = 101; - uint8_t attr_nse_expected[] = - { 0x9d, 0x00, 0x02, 0x00, 0x65, 0xa0, 0x00, 0x07, 0x03, 0x03, 0x03, - 0x03, 0x1e, 0x03, 0x0a, 0xa1, 0x00, 0x0b, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x0a, 0x03, - 0x0a, 0x03, 0x0a, 0x03 - }; - - /* Parameters needed to test nanobts_attr_cell_get() */ - bts->gprs.rac = 0x00; - bts->gprs.cell.bvci = 2; - bts->gprs.mode = BTS_GPRS_GPRS; - uint8_t attr_cell_expected[] = - { 0x9a, 0x00, 0x01, 0x00, 0x9c, 0x00, 0x02, 0x05, 0x03, 0x9e, 0x00, - 0x02, 0x00, 0x02, 0xa3, 0x00, 0x09, 0x14, 0x05, 0x05, 0xa0, - 0x05, 0x0a, 0x04, 0x08, - 0x0f, 0xa8, 0x00, 0x02, 0x0f, 0x00, 0xa9, 0x00, 0x05, 0x00, - 0xfa, 0x00, 0xfa, 0x02 - }; - - /* Parameters needed to test nanobts_attr_nscv_get() */ - bts->gprs.nsvc[0].nsvci = 0x65; - bts->gprs.nsvc[0].remote_port = 0x59d8; - bts->gprs.nsvc[0].remote_ip = 0x0a090165; - bts->gprs.nsvc[0].local_port = 0x5a3c; - uint8_t attr_nscv_expected[] = - { 0x9f, 0x00, 0x02, 0x00, 0x65, 0xa2, 0x00, 0x08, 0x59, 0xd8, 0x0a, - 0x09, 0x01, 0x65, 0x5a, 0x3c - }; - - /* Parameters needed to test nanobts_attr_radio_get() */ - trx->arfcn = 866; - trx->max_power_red = 22; - bts->c0->max_power_red = 22; - uint8_t attr_radio_expected[] = - { 0x2d, 0x0b, 0x05, 0x00, 0x02, 0x03, 0x62 }; - - /* Run tests */ - test_nanobts_attr_bts_get(bts, attr_bts_expected); - test_nanobts_attr_nse_get(bts, attr_nse_expected); - test_nanobts_attr_cell_get(bts, attr_cell_expected); - test_nanobts_attr_nscv_get(bts, attr_nscv_expected); - test_nanobts_attr_radio_get(bts, trx, attr_radio_expected); - - printf("Done\n"); - talloc_free(bts); - talloc_free(net); - talloc_free(trx); - talloc_report_full(ctx, stderr); - OSMO_ASSERT(talloc_total_blocks(ctx) == 1); - return 0; -} - -/* stubs */ -struct osmo_prim_hdr; -int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) -{ - abort(); -} diff --git a/tests/nanobts_omlattr/nanobts_omlattr_test.ok b/tests/nanobts_omlattr/nanobts_omlattr_test.ok deleted file mode 100644 index 91b655f8f..000000000 --- a/tests/nanobts_omlattr/nanobts_omlattr_test.ok +++ /dev/null @@ -1,26 +0,0 @@ -Testing nanobts_attr_bts_get()... -result= 19555b61676d7318060e00020120331e2424a83421a81f3f2500010a0c0a0b012a0a2b03e80a80230a080362093f99000700f11000010539 -expected=19555b61676d7318060e00020120331e2424a83421a81f3f2500010a0c0a0b012a0a2b03e80a80230a080362093f99000700f11000010539 -ok. - -Testing nanobts_attr_nse_get()... -result= 9d00020065a00007030303031e030aa1000b03030303030a030a030a03 -expected=9d00020065a00007030303031e030aa1000b03030303030a030a030a03 -ok. - -Testing nanobts_attr_cell_get()... -result= 9a0001009c000205039e00020002a30009140505a0050a04080fa800020f00a9000500fa00fa02 -expected=9a0001009c000205039e00020002a30009140505a0050a04080fa800020f00a9000500fa00fa02 -ok. - -Testing nanobts_attr_nscv_get()... -result= 9f00020065a2000859d80a0901655a3c -expected=9f00020065a2000859d80a0901655a3c -ok. - -Testing nanobts_attr_nscv_get()... -result= 2d0b0500020362 -expected=2d0b0500020362 -ok. - -Done diff --git a/tests/oap/Makefile.am b/tests/oap/Makefile.am deleted file mode 100644 index 1bb672d44..000000000 --- a/tests/oap/Makefile.am +++ /dev/null @@ -1,36 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - oap_client_test.ok \ - oap_client_test.err \ - $(NULL) - -if HAVE_LIBGTP -if HAVE_LIBCARES -noinst_PROGRAMS = \ - oap_client_test \ - $(NULL) -endif -endif - -oap_client_test_SOURCES = \ - oap_client_test.c \ - $(NULL) - -oap_client_test_LDADD = \ - $(top_builddir)/src/gprs/gprs_utils.o \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - -lrt - diff --git a/tests/oap/oap_client_test.c b/tests/oap/oap_client_test.c deleted file mode 100644 index e6501cb6d..000000000 --- a/tests/oap/oap_client_test.c +++ /dev/null @@ -1,270 +0,0 @@ -/* Test Osmocom Authentication Protocol */ -/* - * (C) 2015 by sysmocom s.f.m.c. GmbH - * 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 . - * - */ - -#include -#include - -#include -#include - -#include -#include - -static void test_oap_api(void) -{ - printf("Testing OAP API\n"); - - struct oap_client_config _config; - struct oap_client_config *config = &_config; - - struct oap_client_state _state; - struct oap_client_state *state = &_state; - - struct osmo_oap_message oap_rx; - struct msgb *msg_rx; - - struct osmo_oap_message oap_tx; - struct msgb *msg_tx; - - memset(config, 0, sizeof(*config)); - memset(state, 0, sizeof(*state)); - - OSMO_ASSERT(osmo_hexparse("0102030405060708090a0b0c0d0e0f10", config->secret_k, 16) == 16); - OSMO_ASSERT(osmo_hexparse("1112131415161718191a1b1c1d1e1f20", config->secret_opc, 16) == 16); - - fprintf(stderr, "- make sure filling with zeros means uninitialized\n"); - OSMO_ASSERT(state->state == OAP_UNINITIALIZED); - - fprintf(stderr, "- reject messages in uninitialized state\n"); - memset(&oap_rx, 0, sizeof(oap_rx)); - state->client_id = 1; - oap_rx.message_type = OAP_MSGT_REGISTER_ERROR; - msg_rx = oap_client_encoded(&oap_rx); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) < 0); - OSMO_ASSERT(state->state == OAP_UNINITIALIZED); - msgb_free(msg_rx); - OSMO_ASSERT(!msg_tx); - - fprintf(stderr, "- NULL config should disable\n"); - OSMO_ASSERT( oap_client_init(NULL, state) == 0 ); - OSMO_ASSERT(state->state == OAP_DISABLED); - - fprintf(stderr, "- reject messages in disabled state\n"); - memset(state, 0, sizeof(*state)); - memset(&oap_rx, 0, sizeof(oap_rx)); - state->state = OAP_DISABLED; - state->client_id = 1; - oap_rx.message_type = OAP_MSGT_REGISTER_ERROR; - msg_rx = oap_client_encoded(&oap_rx); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) < 0); - OSMO_ASSERT(state->state == OAP_DISABLED); - msgb_free(msg_rx); - OSMO_ASSERT(!msg_tx); - - fprintf(stderr, "- invalid client_id and shared secret\n"); - memset(state, 0, sizeof(*state)); - config->client_id = 0; - config->secret_k_present = 0; - config->secret_opc_present = 0; - OSMO_ASSERT( oap_client_init(config, state) == 0 ); - OSMO_ASSERT(state->state == OAP_DISABLED); - - fprintf(stderr, "- reset state\n"); - memset(state, 0, sizeof(*state)); - - fprintf(stderr, "- only client_id is invalid\n"); - config->client_id = 0; - config->secret_k_present = 1; - config->secret_opc_present = 1; - OSMO_ASSERT( oap_client_init(config, state) == 0 ); - OSMO_ASSERT(state->state == OAP_DISABLED); - - memset(state, 0, sizeof(*state)); - - fprintf(stderr, "- valid id, but omitted shared_secret (1/2)\n"); - config->client_id = 12345; - config->secret_k_present = 0; - config->secret_opc_present = 1; - OSMO_ASSERT( oap_client_init(config, state) == 0 ); - OSMO_ASSERT(state->state == OAP_DISABLED); - - memset(state, 0, sizeof(*state)); - - fprintf(stderr, "- valid id, but omitted shared_secret (2/2)\n"); - config->client_id = 12345; - config->secret_k_present = 1; - config->secret_opc_present = 0; - OSMO_ASSERT( oap_client_init(config, state) == 0 ); - OSMO_ASSERT(state->state == OAP_DISABLED); - - memset(state, 0, sizeof(*state)); - - - fprintf(stderr, "- mint configuration\n"); - config->client_id = 12345; - config->secret_k_present = 1; - config->secret_opc_present = 1; - /*config->secret_* buffers are still set from the top */ - OSMO_ASSERT( oap_client_init(config, state) == 0 ); - OSMO_ASSERT(state->state == OAP_INITIALIZED); - - - fprintf(stderr, "- Missing challenge data\n"); - memset(&oap_rx, 0, sizeof(oap_rx)); - oap_rx.message_type = OAP_MSGT_CHALLENGE_REQUEST; - oap_rx.rand_present = 0; - oap_rx.autn_present = 0; - msg_rx = oap_client_encoded(&oap_rx); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == -2); - msgb_free(msg_rx); - OSMO_ASSERT(!msg_tx); - - fprintf(stderr, "- AUTN missing\n"); - osmo_hexparse("0102030405060708090a0b0c0d0e0f10", - oap_rx.rand, 16); - oap_rx.rand_present = 1; - msg_rx = oap_client_encoded(&oap_rx); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == -2); - msgb_free(msg_rx); - OSMO_ASSERT(!msg_tx); - - fprintf(stderr, "- RAND missing\n"); - oap_rx.rand_present = 0; - osmo_hexparse("cec4e3848a33000086781158ca40f136", - oap_rx.autn, 16); - oap_rx.autn_present = 1; - msg_rx = oap_client_encoded(&oap_rx); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == -2); - msgb_free(msg_rx); - OSMO_ASSERT(!msg_tx); - - fprintf(stderr, "- wrong autn (by one bit)\n"); - osmo_hexparse("0102030405060708090a0b0c0d0e0f10", - oap_rx.rand, 16); - osmo_hexparse("dec4e3848a33000086781158ca40f136", - oap_rx.autn, 16); - oap_rx.rand_present = 1; - oap_rx.autn_present = 1; - msg_rx = oap_client_encoded(&oap_rx); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == -2); - msgb_free(msg_rx); - OSMO_ASSERT(!msg_tx); - - fprintf(stderr, "- all data correct\n"); - osmo_hexparse("cec4e3848a33000086781158ca40f136", - oap_rx.autn, 16); - msg_rx = oap_client_encoded(&oap_rx); - - fprintf(stderr, "- but refuse to evaluate in uninitialized state\n"); - OSMO_ASSERT(state->state == OAP_INITIALIZED); - - state->state = OAP_UNINITIALIZED; - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) < 0); - OSMO_ASSERT(!msg_tx); - - state->state = OAP_DISABLED; - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) < 0); - OSMO_ASSERT(!msg_tx); - - state->state = OAP_INITIALIZED; - - fprintf(stderr, "- now everything is correct\n"); - /* a successful return value here indicates correct autn */ - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == 0); - msgb_free(msg_rx); - - fprintf(stderr, "- Expect the challenge response in msg_tx\n"); - OSMO_ASSERT(msg_tx); - OSMO_ASSERT(osmo_oap_decode(&oap_tx, msg_tx->data, msg_tx->len) == 0); - OSMO_ASSERT(oap_tx.message_type == OAP_MSGT_CHALLENGE_RESULT); - OSMO_ASSERT(strcmp("e2d05b598c61d9ba", - osmo_hexdump_nospc(oap_tx.xres, sizeof(oap_tx.xres))) - == 0); - OSMO_ASSERT(state->state == OAP_SENT_CHALLENGE_RESULT); - msgb_free(msg_tx); - msg_tx = 0; - - struct oap_client_state saved_state = _state; - - fprintf(stderr, "- Receive registration error for the first time.\n"); - - memset(&oap_rx, 0, sizeof(oap_rx)); - oap_rx.message_type = OAP_MSGT_REGISTER_ERROR; - oap_rx.cause = GMM_CAUSE_PROTO_ERR_UNSPEC; - msg_rx = oap_client_encoded(&oap_rx); - - OSMO_ASSERT(state->registration_failures == 0); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == 0); - OSMO_ASSERT(state->registration_failures == 1); - OSMO_ASSERT(msg_tx); - OSMO_ASSERT(osmo_oap_decode(&oap_tx, msg_tx->data, msg_tx->len) == 0); - OSMO_ASSERT(oap_tx.message_type == OAP_MSGT_REGISTER_REQUEST); - OSMO_ASSERT(state->state == OAP_REQUESTED_CHALLENGE); - msgb_free(msg_tx); - msg_tx = 0; - - fprintf(stderr, "- Receive registration error for the Nth time.\n"); - state->registration_failures = 999; - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == -11); - OSMO_ASSERT(!msg_tx); - OSMO_ASSERT(state->state == OAP_INITIALIZED); - msgb_free(msg_tx); - msg_tx = 0; - - msgb_free(msg_rx); - - fprintf(stderr, "- Registration success\n"); - - _state = saved_state; - memset(&oap_rx, 0, sizeof(oap_rx)); - oap_rx.message_type = OAP_MSGT_REGISTER_RESULT; - msg_rx = oap_client_encoded(&oap_rx); - OSMO_ASSERT(oap_client_handle(state, msg_rx, &msg_tx) == 0); - OSMO_ASSERT(!msg_tx); - OSMO_ASSERT(state->state == OAP_REGISTERED); - msgb_free(msg_rx); -} - -static struct log_info_cat oap_client_test_categories[] = { -}; - -static struct log_info info = { - .cat = oap_client_test_categories, - .num_cat = ARRAY_SIZE(oap_client_test_categories), -}; - -int main(int argc, char **argv) -{ - msgb_talloc_ctx_init(NULL, 0); - osmo_init_logging(&info); - - OSMO_ASSERT(osmo_stderr_target); - log_set_use_color(osmo_stderr_target, 0); - log_set_print_timestamp(osmo_stderr_target, 0); - log_set_print_filename(osmo_stderr_target, 0); - log_set_print_category(osmo_stderr_target, 1); - log_parse_category_mask(osmo_stderr_target, "DLOAP,1"); - - test_oap_api(); - printf("Done\n"); - - return 0; -} - diff --git a/tests/oap/oap_client_test.err b/tests/oap/oap_client_test.err deleted file mode 100644 index 62ddc9efa..000000000 --- a/tests/oap/oap_client_test.err +++ /dev/null @@ -1,35 +0,0 @@ -- make sure filling with zeros means uninitialized -- reject messages in uninitialized state -DLOAP Received OAP message 5, but the OAP client is not initialized -- NULL config should disable -- reject messages in disabled state -DLOAP Received OAP message 5, but the OAP client is disabled -- invalid client_id and shared secret -- reset state -- only client_id is invalid -- valid id, but omitted shared_secret (1/2) -DLOAP OAP: client ID set, but secret K missing. -- valid id, but omitted shared_secret (2/2) -DLOAP OAP: client ID set, but secret OPC missing. -- mint configuration -- Missing challenge data -DLOAP OAP challenge incomplete (rand_present: 0, autn_present: 0) -- AUTN missing -DLOAP OAP challenge incomplete (rand_present: 1, autn_present: 0) -- RAND missing -DLOAP OAP challenge incomplete (rand_present: 0, autn_present: 1) -- wrong autn (by one bit) -DLOAP OAP: AUTN mismatch! -DLOAP OAP: AUTN from server: dec4e3848a33000086781158ca40f136 -DLOAP OAP: AUTN expected: cec4e3848a33000086781158ca40f136 -- all data correct -- but refuse to evaluate in uninitialized state -DLOAP Received OAP message 8, but the OAP client is not initialized -DLOAP Received OAP message 8, but the OAP client is disabled -- now everything is correct -- Expect the challenge response in msg_tx -- Receive registration error for the first time. -DLOAP OAP registration failed -- Receive registration error for the Nth time. -DLOAP OAP registration failed -- Registration success diff --git a/tests/oap/oap_client_test.ok b/tests/oap/oap_client_test.ok deleted file mode 100644 index 59108a792..000000000 --- a/tests/oap/oap_client_test.ok +++ /dev/null @@ -1,2 +0,0 @@ -Testing OAP API -Done diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am deleted file mode 100644 index ccb8f44f4..000000000 --- a/tests/sgsn/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBCARES_CFLAGS) \ - $(NULL) -if BUILD_IU -AM_CFLAGS += \ - $(LIBASN1C_CFLAGS) \ - $(LIBOSMOSIGTRAN_CFLAGS) \ - $(LIBOSMORANAP_CFLAGS) \ - $(NULL) -endif - -EXTRA_DIST = \ - sgsn_test.ok \ - $(NULL) - -noinst_PROGRAMS = \ - sgsn_test \ - $(NULL) - -sgsn_test_SOURCES = \ - sgsn_test.c \ - $(NULL) - -sgsn_test_LDFLAGS = \ - -Wl,--wrap=RAND_bytes \ - -Wl,--wrap=sgsn_update_subscriber_data \ - -Wl,--wrap=gprs_subscr_request_update_location \ - -Wl,--wrap=gprs_subscr_request_auth_info \ - -Wl,--wrap=gsup_client_send \ - $(NULL) - -sgsn_test_LDADD = \ - $(top_builddir)/src/gprs/gprs_llc_parse.o \ - $(top_builddir)/src/gprs/gprs_llc.o \ - $(top_builddir)/src/gprs/crc24.o \ - $(top_builddir)/src/gprs/gprs_sndcp.o \ - $(top_builddir)/src/gprs/gprs_gmm.o \ - $(top_builddir)/src/gprs/gprs_sgsn.o \ - $(top_builddir)/src/gprs/sgsn_vty.o \ - $(top_builddir)/src/gprs/sgsn_libgtp.o \ - $(top_builddir)/src/gprs/sgsn_auth.o \ - $(top_builddir)/src/gprs/sgsn_ares.o \ - $(top_builddir)/src/gprs/gprs_utils.o \ - $(top_builddir)/src/gprs/gprs_subscriber.o \ - $(top_builddir)/src/gprs/gprs_gb_parse.o \ - $(top_builddir)/src/gprs/gprs_llc_xid.o \ - $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ - $(top_builddir)/src/gprs/slhc.o \ - $(top_builddir)/src/gprs/gprs_sndcp_comp.o \ - $(top_builddir)/src/gprs/gprs_sndcp_pcomp.o \ - $(top_builddir)/src/gprs/v42bis.o \ - $(top_builddir)/src/gprs/gprs_sndcp_dcomp.o \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOGB_LIBS) \ - $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) \ - $(LIBGTP_LIBS) \ - -lrt \ - -lm \ - $(NULL) - -if BUILD_IU -sgsn_test_LDADD += \ - $(LIBOSMORANAP_LIBS) \ - $(LIBOSMOSIGTRAN_LIBS) \ - $(LIBASN1C_LIBS) \ - $(NULL) -endif diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c deleted file mode 100644 index d66c5dd84..000000000 --- a/tests/sgsn/sgsn_test.c +++ /dev/null @@ -1,2487 +0,0 @@ -/* Test the SGSN */ -/* - * (C) 2014 by Holger Hans Peter Freyther - * (C) 2014 by sysmocom s.f.m.c. GmbH - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include - -#include - -void *tall_bsc_ctx; -static struct sgsn_instance sgsn_inst = { - .config_file = "osmo_sgsn.cfg", - .cfg = { - .gtp_statedir = "./", - .auth_policy = SGSN_AUTH_POLICY_CLOSED, - }, -}; -struct sgsn_instance *sgsn = &sgsn_inst; -unsigned sgsn_tx_counter = 0; -struct msgb *last_msg = NULL; -struct gprs_gb_parse_context last_dl_parse_ctx; - -static void reset_last_msg() -{ - if (last_msg) - msgb_free(last_msg); - - last_msg = NULL; - memset(&last_dl_parse_ctx, 0, sizeof(last_dl_parse_ctx)); -} - -static void cleanup_test() -{ - reset_last_msg(); -} - -static uint32_t get_new_ptmsi(const struct gprs_gb_parse_context *parse_ctx) -{ - uint32_t new_ptmsi = GSM_RESERVED_TMSI; - - if (parse_ctx->new_ptmsi_enc) - gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi); - - return new_ptmsi; -} - -/* override */ -int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime, - struct bssgp_dl_ud_par *dup) -{ - int rc; - - reset_last_msg(); - - last_msg = msg; - OSMO_ASSERT(msgb_data(last_msg) != NULL); - - rc = gprs_gb_parse_llc(msgb_data(last_msg), msgb_length(last_msg), - &last_dl_parse_ctx); - - fprintf(stderr, "Got DL LLC message: %s\n", - gprs_gb_message_name(&last_dl_parse_ctx, "UNKNOWN")); - - OSMO_ASSERT(rc > 0); - - sgsn_tx_counter += 1; - return 0; -} - -/* override, requires '-Wl,--wrap=RAND_bytes' */ -int __real_RAND_bytes(unsigned char *buf, int num); -int mock_RAND_bytes(unsigned char *buf, int num); -int (*RAND_bytes_cb)(unsigned char *, int) = - &mock_RAND_bytes; - -int __wrap_RAND_bytes(unsigned char *buf, int num) -{ - return (*RAND_bytes_cb)(buf, num); -} -/* make results of A&C ref predictable */ -int mock_RAND_bytes(unsigned char *buf, int num) -{ - if (num > 1) - return __real_RAND_bytes(buf, num); - buf[0] = 0; - return 1; -} - -/* override, requires '-Wl,--wrap=sgsn_update_subscriber_data' */ -void __real_sgsn_update_subscriber_data(struct sgsn_mm_ctx *); -void (*update_subscriber_data_cb)(struct sgsn_mm_ctx *) = - &__real_sgsn_update_subscriber_data; - -void __wrap_sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx) -{ - (*update_subscriber_data_cb)(mmctx); -} - -/* override, requires '-Wl,--wrap=gprs_subscr_request_update_location' */ -int __real_gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx); -int (*subscr_request_update_location_cb)(struct sgsn_mm_ctx *mmctx) = - &__real_gprs_subscr_request_update_location; - -int __wrap_gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx) { - return (*subscr_request_update_location_cb)(mmctx); -}; - -/* override, requires '-Wl,--wrap=gprs_subscr_request_auth_info' */ -int __real_gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand); -int (*subscr_request_auth_info_cb)(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand) = - &__real_gprs_subscr_request_auth_info; - -int __wrap_gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand) { - return (*subscr_request_auth_info_cb)(mmctx, auts, auts_rand); -}; - -/* override, requires '-Wl,--wrap=gsup_client_send' */ -int __real_gsup_client_send(struct gsup_client *gsupc, struct msgb *msg); -int (*gsup_client_send_cb)(struct gsup_client *gsupc, struct msgb *msg) = - &__real_gsup_client_send; - -int __wrap_gsup_client_send(struct gsup_client *gsupc, struct msgb *msg) -{ - return (*gsup_client_send_cb)(gsupc, msg); -}; - -static int count(struct llist_head *head) -{ - struct llist_head *cur; - int count = 0; - - llist_for_each(cur, head) - count += 1; - - return count; -} - -static struct msgb *create_msg(const uint8_t *data, size_t len) -{ - struct msgb *msg = msgb_alloc(len + 8, "test message"); - msg->l1h = msgb_put(msg, 8); - msg->l2h = msgb_put(msg, len); - memcpy(msg->l2h, data, len); - - msgb_bcid(msg) = msg->l1h; - msgb_gmmh(msg) = msg->l2h; - return msg; -} - -/* - * Create a context and search for it - */ -static struct sgsn_mm_ctx *alloc_mm_ctx(uint32_t tlli, struct gprs_ra_id *raid) -{ - struct sgsn_mm_ctx *ctx, *ictx; - struct gprs_llc_lle *lle; - int old_count = count(gprs_llme_list()); - - lle = gprs_lle_get_or_create(tlli, 3); - ctx = sgsn_mm_ctx_alloc_gb(tlli, raid); - ctx->gmm_state = GMM_REGISTERED_NORMAL; - ctx->gb.llme = lle->llme; - - ictx = sgsn_mm_ctx_by_tlli(tlli, raid); - OSMO_ASSERT(ictx == ctx); - - OSMO_ASSERT(count(gprs_llme_list()) == old_count + 1); - - return ctx; -} - -static void send_0408_message(struct gprs_llc_llme *llme, uint32_t tlli, - const struct gprs_ra_id *bssgp_raid, - const uint8_t *data, size_t data_len) -{ - struct msgb *msg; - - reset_last_msg(); - sgsn_tx_counter = 0; - - msg = create_msg(data, data_len); - msgb_tlli(msg) = tlli; - bssgp_create_cell_id(msgb_bcid(msg), bssgp_raid, 0); - gsm0408_gprs_rcvmsg_gb(msg, llme, false); - msgb_free(msg); -} - -static void test_llme(void) -{ - struct gprs_llc_lle *lle, *lle_copy; - uint32_t local_tlli; - - printf("Testing LLME allocations\n"); - local_tlli = gprs_tmsi2tlli(0x234, TLLI_LOCAL); - - /* initial state */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - - /* Create a new entry */ - lle = gprs_lle_get_or_create(local_tlli, 3); - OSMO_ASSERT(lle); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* No new entry is created */ - lle_copy = gprs_lle_get_or_create(local_tlli, 3); - OSMO_ASSERT(lle == lle_copy); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* unassign which should delete it*/ - gprs_llgmm_unassign(lle->llme); - - /* Check that everything was cleaned up */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - - cleanup_test(); -} - -struct gprs_subscr *last_updated_subscr = NULL; -void my_dummy_sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx) -{ - OSMO_ASSERT(mmctx); - fprintf(stderr, "Called %s, mmctx = %p, subscr = %p\n", - __func__, mmctx, mmctx->subscr); - last_updated_subscr = mmctx->subscr; -} - -static void assert_subscr(const struct gprs_subscr *subscr, const char *imsi) -{ - struct gprs_subscr *sfound; - OSMO_ASSERT(subscr); - OSMO_ASSERT(strcmp(subscr->imsi, imsi) == 0); - - sfound = gprs_subscr_get_by_imsi(imsi); - OSMO_ASSERT(sfound == subscr); - - gprs_subscr_put(sfound); -} - -static void show_subscrs(FILE *out) -{ - struct gprs_subscr *subscr; - - llist_for_each_entry(subscr, gprs_subscribers, entry) { - fprintf(out, " Subscriber: %s, " - "use count: %d\n", - subscr->imsi, subscr->use_count); - } -} - -static void assert_no_subscrs() -{ - show_subscrs(stdout); - fflush(stdout); - OSMO_ASSERT(llist_empty(gprs_subscribers)); -} - -#define VERBOSE_ASSERT(val, expect_op, fmt) \ - do { \ - printf(#val " == " fmt "\n", (val)); \ - OSMO_ASSERT((val) expect_op); \ - } while (0); - -static void test_subscriber(void) -{ - struct gprs_subscr *s1, *s2, *s3; - const char *imsi1 = "1234567890"; - const char *imsi2 = "9876543210"; - const char *imsi3 = "5656565656"; - - update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data; - - printf("Testing core subscriber data API\n"); - - /* Check for emptiness */ - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi3) == NULL); - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 0, "%d"); - - /* Allocate entry 1 */ - s1 = gprs_subscr_get_or_create(imsi1); - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 1, "%d"); - s1->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT; - assert_subscr(s1, imsi1); - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 1, "%d"); - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); - - /* Allocate entry 2 */ - s2 = gprs_subscr_get_or_create(imsi2); - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 2, "%d"); - s2->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT; - - /* Allocate entry 3 */ - s3 = gprs_subscr_get_or_create(imsi3); - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 3, "%d"); - - /* Check entries */ - assert_subscr(s1, imsi1); - assert_subscr(s2, imsi2); - assert_subscr(s3, imsi3); - - /* Update entry 1 */ - last_updated_subscr = NULL; - gprs_subscr_update(s1); - OSMO_ASSERT(last_updated_subscr == NULL); - OSMO_ASSERT(s1->sgsn_data->mm == NULL); - OSMO_ASSERT((s1->flags & GPRS_SUBSCRIBER_FIRST_CONTACT) == 0); - - /* There is no subscriber cache. Verify it */ - gprs_subscr_cleanup(s1); - gprs_subscr_put(s1); - s1 = NULL; - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 2, "%d"); - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); - - assert_subscr(s2, imsi2); - assert_subscr(s3, imsi3); - - /* Free entry 2 (GPRS_SUBSCRIBER_FIRST_CONTACT is set) */ - gprs_subscr_cleanup(s2); - gprs_subscr_put(s2); - s2 = NULL; - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 1, "%d"); - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi2) == NULL); - assert_subscr(s3, imsi3); - - /* Try to delete entry 3 */ - gprs_subscr_cleanup(s3); - gprs_subscr_put(s3); - s3 = NULL; - VERBOSE_ASSERT(llist_count(gprs_subscribers), == 0, "%d"); - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi3) == NULL); - - OSMO_ASSERT(llist_empty(gprs_subscribers)); - - update_subscriber_data_cb = __real_sgsn_update_subscriber_data; - - cleanup_test(); -} - -static void test_auth_triplets(void) -{ - struct gprs_subscr *s1, *s1found; - const char *imsi1 = "1234567890"; - struct gsm_auth_tuple *at; - struct sgsn_mm_ctx *ctx; - struct gprs_ra_id raid = { 0, }; - uint32_t local_tlli = 0xffeeddcc; - - printf("Testing authentication triplet handling\n"); - - /* Check for emptiness */ - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); - - /* Allocate entry 1 */ - s1 = gprs_subscr_get_or_create(imsi1); - s1->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT; - s1found = gprs_subscr_get_by_imsi(imsi1); - OSMO_ASSERT(s1found == s1); - gprs_subscr_put(s1found); - - /* Create a context */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ctx = alloc_mm_ctx(local_tlli, &raid); - - /* Attach s1 to ctx */ - ctx->subscr = gprs_subscr_get(s1); - ctx->subscr->sgsn_data->mm = ctx; - - /* Try to get auth tuple */ - at = sgsn_auth_get_tuple(ctx, GSM_KEY_SEQ_INVAL); - OSMO_ASSERT(at == NULL); - - /* Add triplets */ - s1->sgsn_data->auth_triplets[0].key_seq = 0; - s1->sgsn_data->auth_triplets[1].key_seq = 1; - s1->sgsn_data->auth_triplets[2].key_seq = 2; - - /* Try to get auth tuple */ - at = sgsn_auth_get_tuple(ctx, GSM_KEY_SEQ_INVAL); - OSMO_ASSERT(at != NULL); - OSMO_ASSERT(at->key_seq == 0); - OSMO_ASSERT(at->use_count == 1); - at = sgsn_auth_get_tuple(ctx, at->key_seq); - OSMO_ASSERT(at != NULL); - OSMO_ASSERT(at->key_seq == 1); - OSMO_ASSERT(at->use_count == 1); - at = sgsn_auth_get_tuple(ctx, at->key_seq); - OSMO_ASSERT(at != NULL); - OSMO_ASSERT(at->key_seq == 2); - OSMO_ASSERT(at->use_count == 1); - at = sgsn_auth_get_tuple(ctx, at->key_seq); - OSMO_ASSERT(at == NULL); - - /* Free MM context and subscriber */ - gprs_subscr_put(s1); - sgsn_mm_ctx_cleanup_free(ctx); - s1found = gprs_subscr_get_by_imsi(imsi1); - OSMO_ASSERT(s1found == NULL); - - cleanup_test(); -} - -#define TEST_GSUP_IMSI1_IE 0x01, 0x05, 0x21, 0x43, 0x65, 0x87, 0x09 - -static int rx_gsup_message(const uint8_t *data, size_t data_len) -{ - struct msgb *msg; - int rc; - - msg = msgb_alloc(1024, __func__); - msg->l2h = msgb_put(msg, data_len); - OSMO_ASSERT(msg->l2h != NULL); - memcpy(msg->l2h, data, data_len); - rc = gprs_subscr_rx_gsup_message(msg); - msgb_free(msg); - - return rc; -} - -static void test_subscriber_gsup(void) -{ - struct gprs_subscr *s1, *s1found; - const char *imsi1 = "1234567890"; - struct sgsn_mm_ctx *ctx; - struct gprs_ra_id raid = { 0, }; - uint32_t local_tlli = 0xffeeddcc; - struct sgsn_subscriber_pdp_data *pdpd; - int rc; - - static const uint8_t send_auth_info_res[] = { - 0x0a, - TEST_GSUP_IMSI1_IE, - 0x03, 0x22, /* Auth tuple */ - 0x20, 0x10, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x21, 0x04, - 0x21, 0x22, 0x23, 0x24, - 0x22, 0x08, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x03, 0x22, /* Auth tuple */ - 0x20, 0x10, - 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, - 0x21, 0x04, - 0xa1, 0xa2, 0xa3, 0xa4, - 0x22, 0x08, - 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, - }; - - static const uint8_t send_auth_info_err[] = { - 0x09, - TEST_GSUP_IMSI1_IE, - 0x02, 0x01, 0x07 /* GPRS not allowed */ - }; - -#define MSISDN 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 - - static const uint8_t s1_msisdn[] = { MSISDN }; - - static const uint8_t update_location_res[] = { - 0x06, - TEST_GSUP_IMSI1_IE, - 0x08, 0x09, MSISDN, - 0x04, 0x00, /* PDP info complete */ - 0x05, 0x12, - 0x10, 0x01, 0x01, - 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ - 0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n', - 0x05, 0x11, - 0x10, 0x01, 0x02, - 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ - 0x12, 0x08, 0x03, 'f', 'o', 'o', 0x03, 'a', 'p', 'n', - }; - -#undef MSISDN - - static const uint8_t update_location_err[] = { - 0x05, - TEST_GSUP_IMSI1_IE, - 0x02, 0x01, 0x07 /* GPRS not allowed */ - }; - - static const uint8_t location_cancellation_req[] = { - 0x1c, - TEST_GSUP_IMSI1_IE, - 0x06, 0x01, 0x00, - }; - - static const uint8_t location_cancellation_req_withdraw[] = { - 0x1c, - TEST_GSUP_IMSI1_IE, - 0x06, 0x01, 0x01, - }; - - static const uint8_t location_cancellation_req_other[] = { - 0x1c, - 0x01, 0x05, 0x11, 0x11, 0x11, 0x11, 0x01, - 0x06, 0x01, 0x00, - }; - - static const uint8_t purge_ms_err[] = { - 0x0d, - TEST_GSUP_IMSI1_IE, - 0x02, 0x01, 0x02, /* IMSI unknown in HLR */ - }; - - static const uint8_t purge_ms_err_no_cause[] = { - 0x0d, - TEST_GSUP_IMSI1_IE, - }; - - static const uint8_t purge_ms_res[] = { - 0x0e, - TEST_GSUP_IMSI1_IE, - 0x07, 0x00, - }; - - - static const uint8_t insert_data_req[] = { - 0x10, - TEST_GSUP_IMSI1_IE, - 0x05, 0x11, - 0x10, 0x01, 0x03, - 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ - 0x12, 0x08, 0x03, 'b', 'a', 'r', 0x03, 'a', 'p', 'n', - }; - - static const uint8_t delete_data_req[] = { - 0x14, - TEST_GSUP_IMSI1_IE, - 0x10, 0x01, 0x03, - }; - - printf("Testing subscriber GSUP handling\n"); - - update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data; - - /* Check for emptiness */ - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); - - /* Allocate entry 1 */ - s1 = gprs_subscr_get_or_create(imsi1); - s1->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT; - s1found = gprs_subscr_get_by_imsi(imsi1); - OSMO_ASSERT(s1found == s1); - gprs_subscr_put(s1found); - - /* Create a context */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ctx = alloc_mm_ctx(local_tlli, &raid); - - /* Attach s1 to ctx */ - ctx->subscr = gprs_subscr_get(s1); - ctx->subscr->sgsn_data->mm = ctx; - - /* Inject SendAuthInfoReq GSUP message */ - rc = rx_gsup_message(send_auth_info_res, sizeof(send_auth_info_res)); - OSMO_ASSERT(rc >= 0); - OSMO_ASSERT(last_updated_subscr == s1); - - /* Check triplets */ - OSMO_ASSERT(s1->sgsn_data->auth_triplets[0].key_seq == 0); - OSMO_ASSERT(s1->sgsn_data->auth_triplets[1].key_seq == 1); - OSMO_ASSERT(s1->sgsn_data->auth_triplets[2].key_seq == GSM_KEY_SEQ_INVAL); - - /* Inject SendAuthInfoErr GSUP message */ - rc = rx_gsup_message(send_auth_info_err, sizeof(send_auth_info_err)); - OSMO_ASSERT(rc == -GMM_CAUSE_GPRS_NOTALLOWED); - OSMO_ASSERT(last_updated_subscr == s1); - OSMO_ASSERT(s1->sgsn_data->error_cause == GMM_CAUSE_GPRS_NOTALLOWED); - - /* Check triplets */ - OSMO_ASSERT(s1->sgsn_data->auth_triplets[0].key_seq == GSM_KEY_SEQ_INVAL); - OSMO_ASSERT(s1->sgsn_data->auth_triplets[1].key_seq == GSM_KEY_SEQ_INVAL); - OSMO_ASSERT(s1->sgsn_data->auth_triplets[2].key_seq == GSM_KEY_SEQ_INVAL); - - /* Inject UpdateLocRes GSUP message */ - rc = rx_gsup_message(update_location_res, sizeof(update_location_res)); - OSMO_ASSERT(rc >= 0); - OSMO_ASSERT(last_updated_subscr == s1); - OSMO_ASSERT(s1->flags & GPRS_SUBSCRIBER_ENABLE_PURGE); - OSMO_ASSERT(s1->sgsn_data->error_cause == SGSN_ERROR_CAUSE_NONE); - OSMO_ASSERT(s1->sgsn_data->msisdn_len == sizeof(s1_msisdn)); - OSMO_ASSERT(memcmp(s1->sgsn_data->msisdn, s1_msisdn, sizeof(s1_msisdn)) == 0); - OSMO_ASSERT(!llist_empty(&s1->sgsn_data->pdp_list)); - pdpd = llist_entry(s1->sgsn_data->pdp_list.next, - struct sgsn_subscriber_pdp_data, list); - OSMO_ASSERT(strcmp(pdpd->apn_str, "test.apn") == 0); - pdpd = llist_entry(pdpd->list.next, - struct sgsn_subscriber_pdp_data, list); - OSMO_ASSERT(strcmp(pdpd->apn_str, "foo.apn") == 0); - - /* Check authorization */ - OSMO_ASSERT(s1->authorized == 1); - - /* Inject UpdateLocErr GSUP message */ - rc = rx_gsup_message(update_location_err, sizeof(update_location_err)); - OSMO_ASSERT(rc == -GMM_CAUSE_GPRS_NOTALLOWED); - OSMO_ASSERT(last_updated_subscr == s1); - OSMO_ASSERT(s1->sgsn_data->error_cause == GMM_CAUSE_GPRS_NOTALLOWED); - - /* Check authorization */ - OSMO_ASSERT(s1->authorized == 0); - - /* Inject InsertSubscrData GSUP message */ - last_updated_subscr = NULL; - rc = rx_gsup_message(insert_data_req, sizeof(insert_data_req)); - OSMO_ASSERT(rc == -ENOTSUP); /* not connected */ - OSMO_ASSERT(last_updated_subscr == s1); - - /* Inject DeleteSubscrData GSUP message */ - last_updated_subscr = NULL; - rc = rx_gsup_message(delete_data_req, sizeof(delete_data_req)); - if (rc != -GMM_CAUSE_SEM_INCORR_MSG) - printf("Unexpected response to DSD: %d\n", rc); - OSMO_ASSERT(last_updated_subscr == NULL); - - /* Inject wrong LocCancelReq GSUP message */ - last_updated_subscr = NULL; - rc = rx_gsup_message(location_cancellation_req_other, - sizeof(location_cancellation_req_other)); - OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN); - OSMO_ASSERT(last_updated_subscr == NULL); - - /* Check cancellation result */ - OSMO_ASSERT(!(s1->flags & GPRS_SUBSCRIBER_CANCELLED)); - OSMO_ASSERT(s1->sgsn_data->mm != NULL); - - /* Inject LocCancelReq GSUP message */ - rc = rx_gsup_message(location_cancellation_req, - sizeof(location_cancellation_req)); - OSMO_ASSERT(rc >= 0); - OSMO_ASSERT(last_updated_subscr == s1); - OSMO_ASSERT(s1->sgsn_data->error_cause == SGSN_ERROR_CAUSE_NONE); - - /* Check cancellation result */ - OSMO_ASSERT(s1->flags & GPRS_SUBSCRIBER_CANCELLED); - OSMO_ASSERT(s1->sgsn_data->mm == NULL); - - /* Inject LocCancelReq(withdraw) GSUP message */ - rc = rx_gsup_message(location_cancellation_req_withdraw, - sizeof(location_cancellation_req_withdraw)); - OSMO_ASSERT(rc >= 0); - OSMO_ASSERT(s1->sgsn_data->error_cause == GMM_CAUSE_IMPL_DETACHED); - - /* Inject PurgeMsRes GSUP message */ - rc = rx_gsup_message(purge_ms_res, - sizeof(purge_ms_res)); - OSMO_ASSERT(rc >= 0); - OSMO_ASSERT(!(s1->flags & GPRS_SUBSCRIBER_ENABLE_PURGE)); - - /* Free MM context and subscriber */ - OSMO_ASSERT(ctx->subscr == NULL); - sgsn_mm_ctx_cleanup_free(ctx); - gprs_subscr_put(s1); - s1found = gprs_subscr_get_by_imsi(imsi1); - OSMO_ASSERT(s1found == NULL); - - /* Inject PurgeMsRes GSUP message */ - rc = rx_gsup_message(purge_ms_res, - sizeof(purge_ms_res)); - OSMO_ASSERT(rc >= 0); - - /* Inject PurgeMsErr(IMSI unknown in HLR) GSUP message */ - rc = rx_gsup_message(purge_ms_err, - sizeof(purge_ms_err)); - OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN); - - /* Inject PurgeMsErr() GSUP message */ - rc = rx_gsup_message(purge_ms_err_no_cause, - sizeof(purge_ms_err_no_cause)); - OSMO_ASSERT(rc == -GMM_CAUSE_NET_FAIL); - - /* Inject InsertSubscrData GSUP message (unknown IMSI) */ - last_updated_subscr = NULL; - rc = rx_gsup_message(insert_data_req, sizeof(insert_data_req)); - OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN); - OSMO_ASSERT(last_updated_subscr == NULL); - - /* Inject DeleteSubscrData GSUP message (unknown IMSI) */ - rc = rx_gsup_message(delete_data_req, sizeof(delete_data_req)); - OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN); - OSMO_ASSERT(last_updated_subscr == NULL); - - /* Inject LocCancelReq GSUP message (unknown IMSI) */ - rc = rx_gsup_message(location_cancellation_req, - sizeof(location_cancellation_req)); - OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN); - OSMO_ASSERT(last_updated_subscr == NULL); - - update_subscriber_data_cb = __real_sgsn_update_subscriber_data; - - cleanup_test(); -} - -int my_gsup_client_send_dummy(struct gsup_client *gsupc, struct msgb *msg) -{ - msgb_free(msg); - return 0; -}; - -/* - * Test that a GMM Detach will remove the MMCTX and the - * associated LLME. - */ -static void test_gmm_detach(void) -{ - struct gprs_ra_id raid = { 0, }; - struct sgsn_mm_ctx *ctx, *ictx; - uint32_t local_tlli; - - printf("Testing GMM detach\n"); - - /* DTAP - Detach Request (MO) */ - /* normal detach, power_off = 0 */ - static const unsigned char detach_req[] = { - 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb - }; - - local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL); - - /* Create a context */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ctx = alloc_mm_ctx(local_tlli, &raid); - - /* inject the detach */ - send_0408_message(ctx->gb.llme, local_tlli, &raid, - detach_req, ARRAY_SIZE(detach_req)); - - /* verify that a single message (hopefully the Detach Accept) has been - * sent by the SGSN */ - OSMO_ASSERT(sgsn_tx_counter == 1); - - /* verify that things are gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid); - OSMO_ASSERT(!ictx); - - cleanup_test(); -} - -/* - * Test that a GMM Detach will remove the MMCTX and the associated LLME but - * will not sent a Detach Accept message (power_off = 1) - */ -static void test_gmm_detach_power_off(void) -{ - struct gprs_ra_id raid = { 0, }; - struct sgsn_mm_ctx *ctx, *ictx; - uint32_t local_tlli; - - printf("Testing GMM detach (power off)\n"); - - /* DTAP - Detach Request (MO) */ - /* normal detach, power_off = 1 */ - static const unsigned char detach_req[] = { - 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb - }; - - local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL); - - /* Create a context */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ctx = alloc_mm_ctx(local_tlli, &raid); - - /* inject the detach */ - send_0408_message(ctx->gb.llme, local_tlli, &raid, - detach_req, ARRAY_SIZE(detach_req)); - - /* verify that no message (and therefore no Detach Accept) has been - * sent by the SGSN */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - /* verify that things are gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid); - OSMO_ASSERT(!ictx); - - cleanup_test(); -} - -/* - * Test that a GMM Detach will remove the associated LLME if there is no MMCTX. - */ -static void test_gmm_detach_no_mmctx(void) -{ - struct gprs_ra_id raid = { 0, }; - struct gprs_llc_lle *lle; - uint32_t local_tlli; - - printf("Testing GMM detach (no MMCTX)\n"); - - /* DTAP - Detach Request (MO) */ - /* normal detach, power_off = 0 */ - static const unsigned char detach_req[] = { - 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb - }; - - /* Create an LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL); - lle = gprs_lle_get_or_create(local_tlli, 3); - - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* inject the detach */ - send_0408_message(lle->llme, local_tlli, &raid, - detach_req, ARRAY_SIZE(detach_req)); - - /* verify that the LLME is gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - - cleanup_test(); -} - -/* - * Test that a single GMM Detach Accept message will not cause the SGSN to send - * any message or leave an MM context at the SGSN. - */ -static void test_gmm_detach_accept_unexpected(void) -{ - struct gprs_ra_id raid = { 0, }; - struct gprs_llc_lle *lle; - uint32_t local_tlli; - - printf("Testing GMM detach accept (unexpected)\n"); - - /* DTAP - Detach Accept (MT) */ - /* normal detach */ - static const unsigned char detach_acc[] = { - 0x08, 0x06 - }; - - /* Create an LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL); - lle = gprs_lle_get_or_create(local_tlli, 3); - - /* inject the detach */ - send_0408_message(lle->llme, local_tlli, &raid, - detach_acc, ARRAY_SIZE(detach_acc)); - - /* verify that no message (and therefore no Status or XID reset) has been - * sent by the SGSN */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - /* verify that things are gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - - cleanup_test(); -} - -/* - * Test that a GMM Status will remove the associated LLME if there is no MMCTX. - */ -static void test_gmm_status_no_mmctx(void) -{ - struct gprs_ra_id raid = { 0, }; - struct gprs_llc_lle *lle; - uint32_t local_tlli; - - printf("Testing GMM Status (no MMCTX)\n"); - - /* DTAP - GMM Status, protocol error */ - static const unsigned char gmm_status[] = { - 0x08, 0x20, 0x6f - }; - - /* Create an LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - local_tlli = gprs_tmsi2tlli(0x23, TLLI_LOCAL); - lle = gprs_lle_get_or_create(local_tlli, 3); - - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* inject the detach */ - send_0408_message(lle->llme, local_tlli, &raid, - gmm_status, ARRAY_SIZE(gmm_status)); - - /* verify that no message has been sent by the SGSN */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - /* verify that the LLME is gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - - cleanup_test(); -} - -/* - * Test the GMM Attach procedure - */ -static void test_gmm_attach(int retry) -{ - struct gprs_ra_id raid = { 0, }; - struct sgsn_mm_ctx *ctx = NULL; - struct sgsn_mm_ctx *ictx; - uint32_t ptmsi1; - uint32_t foreign_tlli; - uint32_t local_tlli = 0; - struct gprs_llc_lle *lle; - - /* DTAP - Attach Request */ - /* The P-TMSI is not known by the SGSN */ - static const unsigned char attach_req[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x05, 0xf4, - 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x19, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, - 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, - 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00 - }; - - /* DTAP - Identity Response IMEI */ - static const unsigned char ident_resp_imei[] = { - 0x08, 0x16, 0x08, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, - 0x56 - }; - - /* DTAP - Identity Response IMSI */ - static const unsigned char ident_resp_imsi[] = { - 0x08, 0x16, 0x08, 0x19, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32, - 0x54 - }; - - /* DTAP - Authentication and Ciphering Resp */ - static const unsigned char auth_ciph_resp[] = { - 0x08, 0x13, 0x00, 0x22, 0x51, 0xe5, 0x51, 0xe5, 0x23, 0x09, - 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x01 - }; - - /* DTAP - Attach Complete */ - static const unsigned char attach_compl[] = { - 0x08, 0x03 - }; - - /* DTAP - Detach Request (MO) */ - /* normal detach, power_off = 0 */ - static const unsigned char detach_req[] = { - 0x08, 0x05, 0x01, 0x18, 0x05, 0xf4, 0xeb, 0x8b, - 0x45, 0x67, 0x19, 0x03, 0xb9, 0x97, 0xcb - }; - - printf("Testing GMM attach%s\n", retry ? " with retry" : ""); - - foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); - - /* Create a LLE/LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - lle = gprs_lle_get_or_create(foreign_tlli, 3); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* inject the attach request */ - send_0408_message(lle->llme, foreign_tlli, &raid, - attach_req, ARRAY_SIZE(attach_req)); - - ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid); - OSMO_ASSERT(ctx != NULL); - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - - /* we expect an identity request (IMEI) */ - OSMO_ASSERT(sgsn_tx_counter == 1); - - /* inject the identity response (IMEI) */ - send_0408_message(ctx->gb.llme, foreign_tlli, &raid, - ident_resp_imei, ARRAY_SIZE(ident_resp_imei)); - - /* we expect an identity request (IMSI) */ - OSMO_ASSERT(sgsn_tx_counter == 1); - - /* inject the identity response (IMSI) */ - send_0408_message(ctx->gb.llme, foreign_tlli, &raid, - ident_resp_imsi, ARRAY_SIZE(ident_resp_imsi)); - - /* check that the MM context has not been removed due to a failed - * authorization */ - OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid)); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - -retry_attach_req: - - if (retry && sgsn_tx_counter == 0) { - fprintf(stderr, "Retrying attach request\n"); - /* re-inject the attach request */ - send_0408_message(lle->llme, foreign_tlli, &raid, - attach_req, ARRAY_SIZE(attach_req)); - } - - if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE && sgsn_tx_counter == 1) { - /* we got an auth & ciph request */ - - /* inject the auth & ciph response */ - send_0408_message(ctx->gb.llme, foreign_tlli, &raid, - auth_ciph_resp, ARRAY_SIZE(auth_ciph_resp)); - - /* check that the MM context has not been removed due to a - * failed authorization */ - OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid)); - if (ctx->subscr && ctx->subscr->sgsn_data->msisdn_len > 0) - OSMO_ASSERT(strcmp(ctx->msisdn, "+49166213323") == 0); - } - - if (retry && sgsn_tx_counter == 0) - goto retry_attach_req; - - /* we expect an attach accept/reject */ - OSMO_ASSERT(sgsn_tx_counter == 1); - ptmsi1 = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(ptmsi1 != GSM_RESERVED_TMSI); - - /* this has been randomly assigned by the SGSN */ - local_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); - - /* inject the attach complete */ - send_0408_message(ctx->gb.llme, local_tlli, &raid, - attach_compl, ARRAY_SIZE(attach_compl)); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - /* inject the detach */ - send_0408_message(ctx->gb.llme, local_tlli, &raid, - detach_req, ARRAY_SIZE(detach_req)); - - /* verify that things are gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid); - OSMO_ASSERT(!ictx); - - cleanup_test(); -} - -static void test_gmm_attach_acl(void) -{ - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED; - sgsn_acl_add("123456789012345", &sgsn->cfg); - printf("Auth policy 'closed': "); - test_gmm_attach(0); - sgsn_acl_del("123456789012345", &sgsn->cfg); - - sgsn->cfg.auth_policy = saved_auth_policy; - - cleanup_test(); -} - -int my_subscr_request_update_location(struct sgsn_mm_ctx *mmctx) { - int rc; - rc = __real_gprs_subscr_request_update_location(mmctx); - if (rc == -ENOTSUP) { - OSMO_ASSERT(mmctx->subscr); - gprs_subscr_update(mmctx->subscr); - } - return rc; -}; - -int my_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx) { - gprs_subscr_update(mmctx->subscr); - return 0; -}; - -static void test_gmm_attach_subscr(void) -{ - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - struct gprs_subscr *subscr; - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_REMOTE; - subscr_request_update_location_cb = my_subscr_request_update_location; - subscr_request_auth_info_cb = my_subscr_request_auth_info; - - subscr = gprs_subscr_get_or_create("123456789012345"); - subscr->authorized = 1; - - printf("Auth policy 'remote': "); - test_gmm_attach(0); - gprs_subscr_put(subscr); - assert_no_subscrs(); - - sgsn->cfg.auth_policy = saved_auth_policy; - subscr_request_update_location_cb = __real_gprs_subscr_request_update_location; - subscr_request_auth_info_cb = __real_gprs_subscr_request_auth_info; - - cleanup_test(); -} - -int my_subscr_request_auth_info_fake_auth(struct sgsn_mm_ctx *mmctx) -{ - /* Fake an authentication */ - OSMO_ASSERT(mmctx->subscr); - mmctx->is_authenticated = 1; - gprs_subscr_update_auth_info(mmctx->subscr); - - return 0; -}; - -static void test_gmm_attach_subscr_fake_auth(void) -{ - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - struct gprs_subscr *subscr; - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_REMOTE; - subscr_request_update_location_cb = my_subscr_request_update_location; - subscr_request_auth_info_cb = my_subscr_request_auth_info_fake_auth; - - subscr = gprs_subscr_get_or_create("123456789012345"); - subscr->authorized = 1; - sgsn->cfg.require_authentication = 1; - sgsn->cfg.require_update_location = 1; - - printf("Auth policy 'remote', auth faked: "); - test_gmm_attach(0); - gprs_subscr_put(subscr); - assert_no_subscrs(); - - sgsn->cfg.auth_policy = saved_auth_policy; - subscr_request_update_location_cb = __real_gprs_subscr_request_update_location; - subscr_request_auth_info_cb = __real_gprs_subscr_request_auth_info; - - cleanup_test(); -} - -int my_subscr_request_auth_info_real_auth(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand) -{ - struct gsm_auth_tuple at = { - .vec.sres = {0x51, 0xe5, 0x51, 0xe5}, - .vec.auth_types = OSMO_AUTH_TYPE_GSM, - .key_seq = 0 - }; - - /* Fake an authentication */ - OSMO_ASSERT(mmctx->subscr); - mmctx->subscr->sgsn_data->auth_triplets[0] = at; - - gprs_subscr_update_auth_info(mmctx->subscr); - - return 0; -}; - -static void test_gmm_attach_subscr_real_auth(void) -{ - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - struct gprs_subscr *subscr; - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_REMOTE; - subscr_request_update_location_cb = my_subscr_request_update_location; - subscr_request_auth_info_cb = my_subscr_request_auth_info_real_auth; - - subscr = gprs_subscr_get_or_create("123456789012345"); - subscr->authorized = 1; - sgsn->cfg.require_authentication = 1; - sgsn->cfg.require_update_location = 1; - - printf("Auth policy 'remote', triplet based auth: "); - - test_gmm_attach(0); - gprs_subscr_put(subscr); - assert_no_subscrs(); - - sgsn->cfg.auth_policy = saved_auth_policy; - subscr_request_update_location_cb = __real_gprs_subscr_request_update_location; - subscr_request_auth_info_cb = __real_gprs_subscr_request_auth_info; - - cleanup_test(); -} - -#define TEST_GSUP_IMSI_LONG_IE 0x01, 0x08, \ - 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0xf5 - -static int auth_info_skip = 0; -static int upd_loc_skip = 0; - -int my_subscr_request_auth_info_gsup_auth(struct sgsn_mm_ctx *mmctx) -{ - static const uint8_t send_auth_info_res[] = { - 0x0a, - TEST_GSUP_IMSI_LONG_IE, - 0x03, 0x22, /* Auth tuple */ - 0x20, 0x10, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x21, 0x04, - 0x51, 0xe5, 0x51, 0xe5, - 0x22, 0x08, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - }; - - OSMO_ASSERT(!mmctx || mmctx->subscr); - - if (auth_info_skip > 0) { - auth_info_skip -= 1; - return -EAGAIN; - } - - /* Fake an SendAuthInfoRes */ - rx_gsup_message(send_auth_info_res, sizeof(send_auth_info_res)); - - return 0; -}; - -int my_subscr_request_update_gsup_auth(struct sgsn_mm_ctx *mmctx) { - static const uint8_t update_location_res[] = { - 0x06, - TEST_GSUP_IMSI_LONG_IE, - 0x04, 0x00, /* PDP info complete */ - 0x05, 0x12, - 0x10, 0x01, 0x01, - 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ - 0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n', - 0x08, 0x07, /* MSISDN 49166213323 encoded */ - 0x91, 0x94, 0x61, 0x26, 0x31, 0x23, 0xF3, - 0x09, 0x07, /* MSISDN 38166213323 encoded */ - 0x91, 0x83, 0x61, 0x26, 0x31, 0x23, 0xF3, - }; - - OSMO_ASSERT(!mmctx || mmctx->subscr); - - if (upd_loc_skip > 0) { - upd_loc_skip -= 1; - return -EAGAIN; - } - - /* Fake an UpdateLocRes */ - return rx_gsup_message(update_location_res, sizeof(update_location_res)); -}; - - -static void test_gmm_attach_subscr_gsup_auth(int retry) -{ - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - struct gprs_subscr *subscr; - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_REMOTE; - subscr_request_update_location_cb = my_subscr_request_update_gsup_auth; - subscr_request_auth_info_cb = my_subscr_request_auth_info_gsup_auth; - if (retry) { - upd_loc_skip = 3; - auth_info_skip = 3; - } - - subscr = gprs_subscr_get_or_create("123456789012345"); - subscr->authorized = 1; - sgsn->cfg.require_authentication = 1; - sgsn->cfg.require_update_location = 1; - gprs_subscr_put(subscr); - - printf("Auth policy 'remote', GSUP based auth: "); - test_gmm_attach(retry); - assert_no_subscrs(); - - sgsn->cfg.auth_policy = saved_auth_policy; - subscr_request_update_location_cb = __real_gprs_subscr_request_update_location; - subscr_request_auth_info_cb = __real_gprs_subscr_request_auth_info; - upd_loc_skip = 0; - auth_info_skip = 0; - - cleanup_test(); -} - -int my_gsup_client_send(struct gsup_client *gsupc, struct msgb *msg) -{ - struct osmo_gsup_message to_peer = {0}; - struct osmo_gsup_message from_peer = {0}; - struct msgb *reply_msg; - int rc; - - /* Simulate the GSUP peer */ - rc = osmo_gsup_decode(msgb_data(msg), msgb_length(msg), &to_peer); - OSMO_ASSERT(rc >= 0); - OSMO_ASSERT(to_peer.imsi[0] != 0); - osmo_strlcpy(from_peer.imsi, to_peer.imsi, sizeof(from_peer.imsi)); - - /* This invalidates the pointers in to_peer */ - msgb_free(msg); - - switch (to_peer.message_type) { - case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST: - /* Send UPDATE_LOCATION_RESULT */ - return my_subscr_request_update_gsup_auth(NULL); - - case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST: - /* Send SEND_AUTH_INFO_RESULT */ - return my_subscr_request_auth_info_gsup_auth(NULL); - - case OSMO_GSUP_MSGT_PURGE_MS_REQUEST: - from_peer.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT; - break; - - default: - if ((to_peer.message_type & 0b00000011) == 0) { - /* Unhandled request */ - /* Send error(NOT_IMPL) */ - from_peer.message_type = to_peer.message_type + 1; - from_peer.cause = GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL; - break; - } - - /* Ignore it */ - return 0; - } - - reply_msg = gsup_client_msgb_alloc(); - reply_msg->l2h = reply_msg->data; - osmo_gsup_encode(reply_msg, &from_peer); - gprs_subscr_rx_gsup_message(reply_msg); - msgb_free(reply_msg); - - return 0; -}; - -static void test_gmm_attach_subscr_real_gsup_auth(int retry) -{ - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - struct gprs_subscr *subscr; - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_REMOTE; - gsup_client_send_cb = my_gsup_client_send; - - sgsn->gsup_client = talloc_zero(tall_bsc_ctx, struct gsup_client); - - if (retry) { - upd_loc_skip = 3; - auth_info_skip = 3; - } - - printf("Auth policy 'remote', real GSUP based auth: "); - test_gmm_attach(retry); - - subscr = gprs_subscr_get_by_imsi("123456789012345"); - OSMO_ASSERT(subscr == NULL); - assert_no_subscrs(); - - sgsn->cfg.auth_policy = saved_auth_policy; - gsup_client_send_cb = __real_gsup_client_send; - upd_loc_skip = 0; - auth_info_skip = 0; - talloc_free(sgsn->gsup_client); - sgsn->gsup_client = NULL; - - cleanup_test(); -} - -/* - * Test the GMM Rejects - */ -static void test_gmm_reject(void) -{ - struct gprs_ra_id raid = { 0, }; - struct sgsn_mm_ctx *ctx = NULL; - uint32_t foreign_tlli; - struct gprs_llc_lle *lle; - int idx; - - /* DTAP - Attach Request */ - /* Invalid MI length */ - static const unsigned char attach_req_inv_mi_len[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x09, 0xf4, - 0xfb, 0xc5, 0x46, 0x79, 0xff, 0xff, 0xff, 0xff, 0x11, 0x22, - 0x33, 0x40, 0x50, 0x60, 0x19, 0x18, 0xb3, 0x43, 0x2b, 0x25, - 0x96, 0x62, 0x00, 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, - 0x60, 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00 - }; - - /* DTAP - Attach Request */ - /* Invalid MI type (IMEI) */ - static const unsigned char attach_req_inv_mi_type[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x05, 0xf2, - 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x19, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, - 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, - 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00 - }; - - /* DTAP - Routing Area Update Request */ - static const unsigned char dtap_ra_upd_req[] = { - 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, - 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 - }; - - /* DTAP - Routing Area Update Request */ - /* Invalid type: GPRS_UPD_T_RA_LA_IMSI_ATT */ - static const unsigned char dtap_ra_upd_req_inv_type[] = { - 0x08, 0x08, 0x12, 0x11, 0x22, 0x33, 0x40, 0x50, - 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 - }; - - /* DTAP - Routing Area Update Request */ - /* Invalid cap length */ - static const unsigned char dtap_ra_upd_req_inv_cap_len[] = { - 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, - 0x60, 0x3d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 - }; - - struct test { - const char *title; - const unsigned char *msg; - unsigned msg_len; - unsigned num_resp; - - }; - static struct test tests[] = { - { - .title = "Attach Request (invalid MI length)", - .msg = attach_req_inv_mi_len, - .msg_len = sizeof(attach_req_inv_mi_len), - .num_resp = 1 /* Reject */ - - }, - { - .title = "Attach Request (invalid MI type)", - .msg = attach_req_inv_mi_type, - .msg_len = sizeof(attach_req_inv_mi_type), - .num_resp = 1 /* Reject */ - }, - { - .title = "Routing Area Update Request (valid)", - .msg = dtap_ra_upd_req, - .msg_len = sizeof(dtap_ra_upd_req), - .num_resp = 2 /* XID Reset + Reject */ - }, - { - .title = "Routing Area Update Request (invalid type)", - .msg = dtap_ra_upd_req_inv_type, - .msg_len = sizeof(dtap_ra_upd_req_inv_type), - .num_resp = 1 /* Reject */ - }, - { - .title = "Routing Area Update Request (invalid CAP length)", - .msg = dtap_ra_upd_req_inv_cap_len, - .msg_len = sizeof(dtap_ra_upd_req_inv_cap_len), - .num_resp = 1 /* Reject */ - }, - }; - - printf("Testing GMM reject\n"); - - /* reset the PRNG used by sgsn_alloc_ptmsi */ - srand(1); - - foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); - - OSMO_ASSERT(count(gprs_llme_list()) == 0); - - for (idx = 0; idx < ARRAY_SIZE(tests); idx++) { - const struct test *test = &tests[idx]; - printf(" - %s\n", test->title); - - /* Create a LLE/LLME */ - lle = gprs_lle_get_or_create(foreign_tlli, 3); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* Inject the Request message */ - send_0408_message(lle->llme, foreign_tlli, &raid, - test->msg, test->msg_len); - - /* We expect a Reject message */ - fprintf(stderr, "sgsn_tx_counter = %d (expected %d)\n", - sgsn_tx_counter, test->num_resp); - OSMO_ASSERT(sgsn_tx_counter == test->num_resp); - - /* verify that LLME/MM are removed */ - ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid); - OSMO_ASSERT(ctx == NULL); - OSMO_ASSERT(count(gprs_llme_list()) == 0); - } - - cleanup_test(); -} - -/* - * Test cancellation of attached MM contexts - */ -static void test_gmm_cancel(void) -{ - struct gprs_ra_id raid = { 0, }; - struct sgsn_mm_ctx *ctx = NULL; - struct sgsn_mm_ctx *ictx; - uint32_t ptmsi1; - uint32_t foreign_tlli; - uint32_t local_tlli = 0; - struct gprs_llc_lle *lle; - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - - /* DTAP - Attach Request */ - /* The P-TMSI is not known by the SGSN */ - static const unsigned char attach_req[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, 0x05, 0xf4, - 0xfb, 0xc5, 0x46, 0x79, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, - 0x19, 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, 0x60, - 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, 0x80, 0xba, 0xc8, - 0xc6, 0x62, 0x00, 0x60, 0x80, 0x00 - }; - - /* DTAP - Identity Response IMEI */ - static const unsigned char ident_resp_imei[] = { - 0x08, 0x16, 0x08, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, - 0x56 - }; - - /* DTAP - Identity Response IMSI */ - static const unsigned char ident_resp_imsi[] = { - 0x08, 0x16, 0x08, 0x19, 0x32, 0x54, 0x76, 0x98, 0x10, 0x32, - 0x54 - }; - - /* DTAP - Attach Complete */ - static const unsigned char attach_compl[] = { - 0x08, 0x03 - }; - - printf("Testing cancellation\n"); - - sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_OPEN; - - foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); - - /* Create a LLE/LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - lle = gprs_lle_get_or_create(foreign_tlli, 3); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* inject the attach request */ - send_0408_message(lle->llme, foreign_tlli, &raid, - attach_req, ARRAY_SIZE(attach_req)); - - ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid); - OSMO_ASSERT(ctx != NULL); - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - - /* we expect an identity request (IMEI) */ - OSMO_ASSERT(sgsn_tx_counter == 1); - - /* inject the identity response (IMEI) */ - send_0408_message(ctx->gb.llme, foreign_tlli, &raid, - ident_resp_imei, ARRAY_SIZE(ident_resp_imei)); - - /* we expect an identity request (IMSI) */ - OSMO_ASSERT(sgsn_tx_counter == 1); - - /* inject the identity response (IMSI) */ - send_0408_message(ctx->gb.llme, foreign_tlli, &raid, - ident_resp_imsi, ARRAY_SIZE(ident_resp_imsi)); - - /* check that the MM context has not been removed due to a failed - * authorization */ - OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid)); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - - /* we expect an attach accept/reject */ - OSMO_ASSERT(sgsn_tx_counter == 1); - ptmsi1 = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(ptmsi1 != GSM_RESERVED_TMSI); - - /* this has been randomly assigned by the SGSN */ - local_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); - - /* inject the attach complete */ - send_0408_message(ctx->gb.llme, foreign_tlli, &raid, - attach_compl, ARRAY_SIZE(attach_compl)); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - /* cancel */ - gsm0408_gprs_access_cancelled(ctx, 0); - - /* verify that things are gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid); - OSMO_ASSERT(!ictx); - - sgsn->cfg.auth_policy = saved_auth_policy; - - cleanup_test(); -} - -/* - * Test the dynamic allocation of P-TMSIs - */ -static void test_gmm_ptmsi_allocation(void) -{ - struct gprs_ra_id raid = {332, 112, 16464, 96}; - struct sgsn_mm_ctx *ctx = NULL; - struct sgsn_mm_ctx *ictx; - uint32_t foreign_tlli; - uint32_t ptmsi1; - uint32_t ptmsi2; - uint32_t received_ptmsi; - uint32_t old_ptmsi; - uint32_t local_tlli = 0; - struct gprs_llc_lle *lle; - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - - /* DTAP - Attach Request (IMSI 12131415161718) */ - static const unsigned char attach_req[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, - 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, 0x19, - 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, - 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, - 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, - 0x00, - }; - - /* DTAP - Identity Response IMEI */ - static const unsigned char ident_resp_imei[] = { - 0x08, 0x16, 0x08, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, - 0x56 - }; - - /* DTAP - Attach Complete */ - static const unsigned char attach_compl[] = { - 0x08, 0x03 - }; - - /* DTAP - Routing Area Update Request */ - static const unsigned char ra_upd_req[] = { - 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, - 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 - }; - - /* DTAP - Routing Area Update Complete */ - static const unsigned char ra_upd_complete[] = { - 0x08, 0x0a - }; - - /* DTAP - Detach Request (MO) */ - /* normal detach, power_off = 1 */ - static const unsigned char detach_req[] = { - 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb - }; - - sgsn->cfg.auth_policy = SGSN_AUTH_POLICY_OPEN; - - printf("Testing P-TMSI allocation\n"); - - printf(" - sgsn_alloc_ptmsi\n"); - - /* reset the PRNG used by sgsn_alloc_ptmsi */ - srand(1); - - ptmsi1 = sgsn_alloc_ptmsi(); - OSMO_ASSERT(ptmsi1 != GSM_RESERVED_TMSI); - - ptmsi2 = sgsn_alloc_ptmsi(); - OSMO_ASSERT(ptmsi2 != GSM_RESERVED_TMSI); - - OSMO_ASSERT(ptmsi1 != ptmsi2); - - ptmsi1 = ptmsi2 = GSM_RESERVED_TMSI; - - printf(" - Repeated Attach Request\n"); - - foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); - - /* Create a LLE/LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - lle = gprs_lle_get_or_create(foreign_tlli, 3); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* inject the attach request */ - send_0408_message(lle->llme, foreign_tlli, &raid, - attach_req, ARRAY_SIZE(attach_req)); - - ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid); - OSMO_ASSERT(ctx != NULL); - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi != GSM_RESERVED_TMSI); - ptmsi1 = ctx->p_tmsi; - - old_ptmsi = ctx->p_tmsi_old; - - /* we expect an identity request (IMEI) */ - OSMO_ASSERT(sgsn_tx_counter == 1); - - /* inject the identity response (IMEI) */ - send_0408_message(ctx->gb.llme, foreign_tlli, &raid, - ident_resp_imei, ARRAY_SIZE(ident_resp_imei)); - - /* check that the MM context has not been removed due to a failed - * authorization */ - OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(foreign_tlli, &raid)); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi == ptmsi1); - - /* we expect an attach accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - received_ptmsi = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(received_ptmsi == ptmsi1); - - /* we ignore this and send the attach again */ - send_0408_message(lle->llme, foreign_tlli, &raid, - attach_req, ARRAY_SIZE(attach_req)); - - /* the allocated P-TMSI should be the same */ - ctx = sgsn_mm_ctx_by_tlli(foreign_tlli, &raid); - OSMO_ASSERT(ctx != NULL); - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi_old == old_ptmsi); - OSMO_ASSERT(ctx->p_tmsi == ptmsi1); - - /* we expect an attach accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - received_ptmsi = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(received_ptmsi == ptmsi1); - - /* inject the attach complete */ - local_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); - send_0408_message(ctx->gb.llme, local_tlli, &raid, - attach_compl, ARRAY_SIZE(attach_compl)); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - OSMO_ASSERT(ctx->p_tmsi_old == 0); - OSMO_ASSERT(ctx->p_tmsi == ptmsi1); - - printf(" - Repeated RA Update Request\n"); - - /* inject the RA update request */ - send_0408_message(ctx->gb.llme, local_tlli, &raid, - ra_upd_req, ARRAY_SIZE(ra_upd_req)); - - /* we expect an RA update accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi_old == ptmsi1); - OSMO_ASSERT(ctx->p_tmsi != GSM_RESERVED_TMSI); - OSMO_ASSERT(ctx->p_tmsi != ptmsi1); - ptmsi2 = ctx->p_tmsi; - - /* repeat the RA update request */ - send_0408_message(ctx->gb.llme, local_tlli, &raid, - ra_upd_req, ARRAY_SIZE(ra_upd_req)); - - /* we expect an RA update accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - received_ptmsi = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(received_ptmsi == ptmsi2); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi_old == ptmsi1); - OSMO_ASSERT(ctx->p_tmsi == ptmsi2); - - /* inject the RA update complete */ - local_tlli = gprs_tmsi2tlli(ptmsi2, TLLI_LOCAL); - send_0408_message(ctx->gb.llme, local_tlli, &raid, - ra_upd_complete, ARRAY_SIZE(ra_upd_complete)); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - OSMO_ASSERT(ctx->p_tmsi_old == 0); - OSMO_ASSERT(ctx->p_tmsi == ptmsi2); - - /* inject the detach */ - send_0408_message(ctx->gb.llme, local_tlli, &raid, - detach_req, ARRAY_SIZE(detach_req)); - - /* verify that things are gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid); - OSMO_ASSERT(!ictx); - - sgsn->cfg.auth_policy = saved_auth_policy; - - cleanup_test(); -} - -/* - * Test changing of routing areas - */ -static void test_gmm_routing_areas(void) -{ - struct gprs_ra_id raid1 = {332, 112, 16464, 96}; - struct gprs_ra_id raid2 = {332, 112, 16464, 97}; - struct sgsn_mm_ctx *ctx = NULL; - struct sgsn_mm_ctx *ictx; - uint32_t ptmsi1; - uint32_t received_ptmsi; - uint32_t ms_tlli = 0; - struct gprs_llc_lle *lle; - const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; - - /* DTAP - Attach Request (IMSI 12131415161718) */ - static const unsigned char attach_req[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, - 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x11, 0x22, 0x33, 0x40, 0x50, 0x60, 0x19, - 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, - 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, - 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, - 0x00, - }; - - /* DTAP - Attach Request (IMSI 12131415161718) (RA 2) */ - static const unsigned char attach_req2[] = { - 0x08, 0x01, 0x02, 0xf5, 0xe0, 0x21, 0x08, 0x02, - 0x08, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x11, 0x22, 0x33, 0x40, 0x50, 0x61, 0x19, - 0x18, 0xb3, 0x43, 0x2b, 0x25, 0x96, 0x62, 0x00, - 0x60, 0x80, 0x9a, 0xc2, 0xc6, 0x62, 0x00, 0x60, - 0x80, 0xba, 0xc8, 0xc6, 0x62, 0x00, 0x60, 0x80, - 0x00, - }; - - /* DTAP - Identity Response IMEI */ - static const unsigned char ident_resp_imei[] = { - 0x08, 0x16, 0x08, 0x9a, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, - 0x56 - }; - - /* DTAP - Attach Complete */ - static const unsigned char attach_compl[] = { - 0x08, 0x03 - }; - - /* DTAP - Routing Area Update Request (coming from RA 1) */ - static const unsigned char ra_upd_req1[] = { - 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, - 0x60, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 - }; - - /* DTAP - Routing Area Update Request (coming from RA 2) */ - static const unsigned char ra_upd_req2[] = { - 0x08, 0x08, 0x10, 0x11, 0x22, 0x33, 0x40, 0x50, - 0x61, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 - }; - - /* DTAP - Routing Area Update Request (coming from RA other) */ - /* raid_other = {443, 223, 16464, 98}; */ - static const unsigned char ra_upd_req_other[] = { - 0x08, 0x08, 0x10, 0x22, 0x33, 0x44, 0x40, 0x50, - 0x62, 0x1d, 0x19, 0x13, 0x42, 0x33, 0x57, 0x2b, - 0xf7, 0xc8, 0x48, 0x02, 0x13, 0x48, 0x50, 0xc8, - 0x48, 0x02, 0x14, 0x48, 0x50, 0xc8, 0x48, 0x02, - 0x17, 0x49, 0x10, 0xc8, 0x48, 0x02, 0x00, 0x19, - 0x8b, 0xb2, 0x92, 0x17, 0x16, 0x27, 0x07, 0x04, - 0x31, 0x02, 0xe5, 0xe0, 0x32, 0x02, 0x20, 0x00 - }; - - /* DTAP - Routing Area Update Complete */ - static const unsigned char ra_upd_complete[] = { - 0x08, 0x0a - }; - - /* DTAP - Detach Request (MO) */ - /* normal detach, power_off = 1 */ - static const unsigned char detach_req[] = { - 0x08, 0x05, 0x09, 0x18, 0x05, 0xf4, 0xef, 0xe2, - 0xb7, 0x00, 0x19, 0x03, 0xb9, 0x97, 0xcb - }; - - sgsn->cfg.auth_policy = SGSN_AUTH_POLICY_OPEN; - - printf("Testing routing area changes\n"); - - /* reset the PRNG used by sgsn_alloc_ptmsi */ - srand(1); - - ptmsi1 = GSM_RESERVED_TMSI; - - printf(" - Attach Request (RA 1)\n"); - - ms_tlli = gprs_tmsi2tlli(0x00000023, TLLI_RANDOM); - - /* Create a LLE/LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - lle = gprs_lle_get_or_create(ms_tlli, 3); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* inject the attach request */ - send_0408_message(lle->llme, ms_tlli, &raid1, - attach_req, ARRAY_SIZE(attach_req)); - - ctx = sgsn_mm_ctx_by_tlli(ms_tlli, &raid1); - OSMO_ASSERT(ctx != NULL); - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi != GSM_RESERVED_TMSI); - - /* we expect an identity request (IMEI) */ - OSMO_ASSERT(sgsn_tx_counter == 1); - OSMO_ASSERT(last_dl_parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_ID_REQ); - OSMO_ASSERT(last_dl_parse_ctx.tlli == ms_tlli); - - /* inject the identity response (IMEI) */ - send_0408_message(ctx->gb.llme, ms_tlli, &raid1, - ident_resp_imei, ARRAY_SIZE(ident_resp_imei)); - - /* check that the MM context has not been removed due to a failed - * authorization */ - OSMO_ASSERT(ctx == sgsn_mm_ctx_by_tlli(ms_tlli, &raid1)); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - - /* we expect an attach accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - OSMO_ASSERT(last_dl_parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_ATTACH_ACK); - OSMO_ASSERT(last_dl_parse_ctx.tlli == ms_tlli); - - received_ptmsi = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(received_ptmsi == ctx->p_tmsi); - ptmsi1 = received_ptmsi; - - /* inject the attach complete */ - ms_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); - send_0408_message(ctx->gb.llme, ms_tlli, &raid1, - attach_compl, ARRAY_SIZE(attach_compl)); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - OSMO_ASSERT(ctx->p_tmsi_old == 0); - OSMO_ASSERT(ctx->p_tmsi == ptmsi1); - - printf(" - RA Update Request (RA 1 -> RA 1)\n"); - - /* inject the RA update request */ - send_0408_message(ctx->gb.llme, ms_tlli, &raid1, - ra_upd_req1, ARRAY_SIZE(ra_upd_req1)); - - /* we expect an RA update accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - OSMO_ASSERT(last_dl_parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_RA_UPD_ACK); - // OSMO_ASSERT(last_dl_parse_ctx.tlli == ms_tlli); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi_old == ptmsi1); - OSMO_ASSERT(ctx->p_tmsi != GSM_RESERVED_TMSI); - OSMO_ASSERT(ctx->p_tmsi != ptmsi1); - - received_ptmsi = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(received_ptmsi == ctx->p_tmsi); - ptmsi1 = received_ptmsi; - - /* inject the RA update complete */ - ms_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); - send_0408_message(ctx->gb.llme, ms_tlli, &raid1, - ra_upd_complete, ARRAY_SIZE(ra_upd_complete)); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - OSMO_ASSERT(ctx->p_tmsi_old == 0); - OSMO_ASSERT(ctx->p_tmsi == ptmsi1); - OSMO_ASSERT(ctx->gb.tlli == ms_tlli); - - printf(" - RA Update Request (RA 1 -> RA 2)\n"); - - /* inject the RA update request */ - ms_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_FOREIGN); - - /* It is coming from RA 1 => ra_upd_req1 */ - send_0408_message(ctx->gb.llme, ms_tlli, &raid2, - ra_upd_req1, ARRAY_SIZE(ra_upd_req1)); - - /* we expect an RA update accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - OSMO_ASSERT(last_dl_parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_RA_UPD_ACK); - - printf(" - RA Update Request (RA other -> RA 2)\n"); - - /* inject the RA update request */ - ms_tlli = gprs_tmsi2tlli(0x12345678, TLLI_FOREIGN); - - /* It is coming from RA 1 => ra_upd_req1 */ - send_0408_message(ctx->gb.llme, ms_tlli, &raid2, - ra_upd_req_other, ARRAY_SIZE(ra_upd_req_other)); - - /* we expect an RA update reject (and a LLC XID RESET) */ - OSMO_ASSERT(sgsn_tx_counter == 2); - OSMO_ASSERT(last_dl_parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_RA_UPD_REJ); - /* this has killed the LLE/LLME */ - - printf(" - Attach Request (RA 2)\n"); - - /* Create a LLE/LLME */ - OSMO_ASSERT(count(gprs_llme_list()) == 1); - lle = gprs_lle_get_or_create(ms_tlli, 3); - OSMO_ASSERT(count(gprs_llme_list()) == 1); - - /* inject the attach request */ - send_0408_message(lle->llme, ms_tlli, &raid2, - attach_req2, ARRAY_SIZE(attach_req2)); - - ctx = sgsn_mm_ctx_by_tlli(ms_tlli, &raid2); - OSMO_ASSERT(ctx != NULL); - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi != GSM_RESERVED_TMSI); - - /* we expect an attach accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - OSMO_ASSERT(last_dl_parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_ATTACH_ACK); - - received_ptmsi = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(received_ptmsi == ctx->p_tmsi); - ptmsi1 = received_ptmsi; - - /* inject the attach complete */ - ms_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); - ictx = sgsn_mm_ctx_by_tlli(ms_tlli, &raid2); - OSMO_ASSERT(ictx != NULL); - OSMO_ASSERT(ictx == ctx); - - send_0408_message(ctx->gb.llme, ms_tlli, &raid2, - attach_compl, ARRAY_SIZE(attach_compl)); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - OSMO_ASSERT(ctx->p_tmsi_old == 0); - OSMO_ASSERT(ctx->p_tmsi == ptmsi1); - - printf(" - RA Update Request (RA 2 -> RA 2)\n"); - - /* inject the RA update request */ - send_0408_message(ctx->gb.llme, ms_tlli, &raid2, - ra_upd_req2, ARRAY_SIZE(ra_upd_req2)); - - /* we expect an RA update accept */ - OSMO_ASSERT(sgsn_tx_counter == 1); - OSMO_ASSERT(last_dl_parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_RA_UPD_ACK); - - OSMO_ASSERT(ctx->gmm_state == GMM_COMMON_PROC_INIT); - OSMO_ASSERT(ctx->p_tmsi_old == ptmsi1); - OSMO_ASSERT(ctx->p_tmsi != GSM_RESERVED_TMSI); - OSMO_ASSERT(ctx->p_tmsi != ptmsi1); - - received_ptmsi = get_new_ptmsi(&last_dl_parse_ctx); - OSMO_ASSERT(received_ptmsi == ctx->p_tmsi); - ptmsi1 = received_ptmsi; - - /* inject the RA update complete */ - ms_tlli = gprs_tmsi2tlli(ptmsi1, TLLI_LOCAL); - send_0408_message(ctx->gb.llme, ms_tlli, &raid2, - ra_upd_complete, ARRAY_SIZE(ra_upd_complete)); - - /* we don't expect a response */ - OSMO_ASSERT(sgsn_tx_counter == 0); - - OSMO_ASSERT(ctx->gmm_state == GMM_REGISTERED_NORMAL); - OSMO_ASSERT(ctx->p_tmsi_old == 0); - OSMO_ASSERT(ctx->p_tmsi == ptmsi1); - OSMO_ASSERT(ctx->gb.tlli == ms_tlli); - - - /* inject the detach */ - send_0408_message(ctx->gb.llme, ms_tlli, &raid2, - detach_req, ARRAY_SIZE(detach_req)); - - /* verify that things are gone */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ictx = sgsn_mm_ctx_by_tlli(ms_tlli, &raid2); - OSMO_ASSERT(!ictx); - - sgsn->cfg.auth_policy = saved_auth_policy; - - cleanup_test(); -} - -static void test_apn_matching(void) -{ - struct apn_ctx *actx, *actxs[9]; - - printf("Testing APN matching\n"); - - actxs[0] = sgsn_apn_ctx_find_alloc("*.test", ""); - actxs[1] = sgsn_apn_ctx_find_alloc("*.def.test", ""); - actxs[2] = sgsn_apn_ctx_find_alloc("abc.def.test", ""); - actxs[3] = NULL; - - actxs[4] = sgsn_apn_ctx_find_alloc("abc.def.test", "456"); - actxs[5] = sgsn_apn_ctx_find_alloc("abc.def.test", "456123"); - actxs[6] = sgsn_apn_ctx_find_alloc("*.def.test", "456"); - actxs[7] = sgsn_apn_ctx_find_alloc("*.def.test", "456123"); - - actxs[8] = sgsn_apn_ctx_find_alloc("ghi.def.test", "456"); - - actx = sgsn_apn_ctx_match("abc.def.test", "12345678"); - OSMO_ASSERT(actx == actxs[2]); - actx = sgsn_apn_ctx_match("aBc.dEf.test", "12345678"); - OSMO_ASSERT(actx == actxs[2]); - actx = sgsn_apn_ctx_match("xyz.def.test", "12345678"); - OSMO_ASSERT(actx == actxs[1]); - actx = sgsn_apn_ctx_match("xyz.dEf.test", "12345678"); - OSMO_ASSERT(actx == actxs[1]); - actx = sgsn_apn_ctx_match("xyz.uvw.test", "12345678"); - OSMO_ASSERT(actx == actxs[0]); - actx = sgsn_apn_ctx_match("xyz.uvw.foo", "12345678"); - OSMO_ASSERT(actx == NULL); - - actxs[3] = sgsn_apn_ctx_find_alloc("*", ""); - actx = sgsn_apn_ctx_match("xyz.uvw.foo", "12345678"); - OSMO_ASSERT(actx == actxs[3]); - - actx = sgsn_apn_ctx_match("abc.def.test", "45699900"); - OSMO_ASSERT(actx == actxs[4]); - - actx = sgsn_apn_ctx_match("xyz.def.test", "45699900"); - OSMO_ASSERT(actx == actxs[6]); - - actx = sgsn_apn_ctx_match("abc.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[5]); - - actx = sgsn_apn_ctx_match("xyz.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[7]); - - actx = sgsn_apn_ctx_match("ghi.def.test", "45699900"); - OSMO_ASSERT(actx == actxs[8]); - - actx = sgsn_apn_ctx_match("ghi.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[7]); - - /* Free APN contexts and check how the matching changes */ - - sgsn_apn_ctx_free(actxs[7]); - actx = sgsn_apn_ctx_match("ghi.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[8]); - - sgsn_apn_ctx_free(actxs[8]); - actx = sgsn_apn_ctx_match("ghi.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[6]); - - sgsn_apn_ctx_free(actxs[6]); - actx = sgsn_apn_ctx_match("ghi.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[1]); - - sgsn_apn_ctx_free(actxs[5]); - actx = sgsn_apn_ctx_match("abc.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[4]); - - sgsn_apn_ctx_free(actxs[4]); - actx = sgsn_apn_ctx_match("abc.def.test", "45612300"); - OSMO_ASSERT(actx == actxs[2]); - - sgsn_apn_ctx_free(actxs[2]); - actx = sgsn_apn_ctx_match("abc.def.test", "12345678"); - OSMO_ASSERT(actx == actxs[1]); - - sgsn_apn_ctx_free(actxs[1]); - actx = sgsn_apn_ctx_match("abc.def.test", "12345678"); - OSMO_ASSERT(actx == actxs[0]); - - sgsn_apn_ctx_free(actxs[0]); - actx = sgsn_apn_ctx_match("abc.def.test", "12345678"); - OSMO_ASSERT(actx == actxs[3]); - - sgsn_apn_ctx_free(actxs[3]); - actx = sgsn_apn_ctx_match("abc.def.test", "12345678"); - OSMO_ASSERT(actx == NULL); - - cleanup_test(); -} - -struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc( - struct sgsn_subscriber_data *sdata); - -static void test_ggsn_selection(void) -{ - struct apn_ctx *actxs[4]; - struct sgsn_ggsn_ctx *ggc, *ggcs[3]; - struct gprs_subscr *s1; - const char *imsi1 = "1234567890"; - struct sgsn_mm_ctx *ctx; - struct gprs_ra_id raid = { 0, }; - uint32_t local_tlli = 0xffeeddcc; - enum gsm48_gsm_cause gsm_cause; - struct tlv_parsed tp; - uint8_t apn_enc[GSM_APN_LENGTH + 10]; - struct sgsn_subscriber_pdp_data *pdp_data; - char apn_str[GSM_APN_LENGTH]; - - printf("Testing GGSN selection\n"); - - gsup_client_send_cb = my_gsup_client_send_dummy; - - /* Check for emptiness */ - OSMO_ASSERT(gprs_subscr_get_by_imsi(imsi1) == NULL); - - /* Create a context */ - OSMO_ASSERT(count(gprs_llme_list()) == 0); - ctx = alloc_mm_ctx(local_tlli, &raid); - osmo_strlcpy(ctx->imsi, imsi1, sizeof(ctx->imsi)); - - /* Allocate and attach a subscriber */ - s1 = gprs_subscr_get_or_create_by_mmctx(ctx); - assert_subscr(s1, imsi1); - - tp.lv[GSM48_IE_GSM_APN].len = 0; - tp.lv[GSM48_IE_GSM_APN].val = apn_enc; - - /* TODO: Add PDP info entries to s1 */ - - ggcs[0] = sgsn_ggsn_ctx_find_alloc(0); - ggcs[1] = sgsn_ggsn_ctx_find_alloc(1); - ggcs[2] = sgsn_ggsn_ctx_find_alloc(2); - - actxs[0] = sgsn_apn_ctx_find_alloc("test.apn", "123456"); - actxs[0]->ggsn = ggcs[0]; - actxs[1] = sgsn_apn_ctx_find_alloc("*.apn", "123456"); - actxs[1]->ggsn = ggcs[1]; - actxs[2] = sgsn_apn_ctx_find_alloc("*", "456789"); - actxs[2]->ggsn = ggcs[2]; - - pdp_data = sgsn_subscriber_pdp_data_alloc(s1->sgsn_data); - pdp_data->context_id = 1; - pdp_data->pdp_type = 0x0121; - osmo_strlcpy(pdp_data->apn_str, "*", sizeof(pdp_data->apn_str)); - - /* Resolve GGSNs */ - - tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn"); - - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc != NULL); - OSMO_ASSERT(ggc->id == 0); - OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0); - - tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn"); - - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc != NULL); - OSMO_ASSERT(ggc->id == 1); - OSMO_ASSERT(strcmp(apn_str, "Other.Apn") == 0); - - tp.lv[GSM48_IE_GSM_APN].len = 0; - tp.lv[GSM48_IE_GSM_APN].val = NULL; - - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc != NULL); - OSMO_ASSERT(ggc->id == 0); - OSMO_ASSERT(strcmp(apn_str, "") == 0); - - actxs[3] = sgsn_apn_ctx_find_alloc("*", "123456"); - actxs[3]->ggsn = ggcs[2]; - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc != NULL); - OSMO_ASSERT(ggc->id == 2); - OSMO_ASSERT(strcmp(apn_str, "") == 0); - - sgsn_apn_ctx_free(actxs[3]); - tp.lv[GSM48_IE_GSM_APN].val = apn_enc; - - tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Foo.Bar"); - - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc == NULL); - OSMO_ASSERT(gsm_cause == GSM_CAUSE_MISSING_APN); - OSMO_ASSERT(strcmp(apn_str, "Foo.Bar") == 0); - - tp.lv[GSM48_IE_GSM_APN].len = sizeof(apn_enc); - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc == NULL); - OSMO_ASSERT(gsm_cause == GSM_CAUSE_INV_MAND_INFO); - - /* Add PDP data entry to subscriber */ - - osmo_strlcpy(pdp_data->apn_str, "Test.Apn", sizeof(pdp_data->apn_str)); - - tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Test.Apn"); - - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc != NULL); - OSMO_ASSERT(ggc->id == 0); - OSMO_ASSERT(strcmp(apn_str, "Test.Apn") == 0); - - tp.lv[GSM48_IE_GSM_APN].len = - gprs_str_to_apn(apn_enc, sizeof(apn_enc), "Other.Apn"); - - ggc = sgsn_mm_ctx_find_ggsn_ctx(ctx, &tp, &gsm_cause, apn_str); - OSMO_ASSERT(ggc == NULL); - OSMO_ASSERT(gsm_cause == GSM_CAUSE_REQ_SERV_OPT_NOTSUB); - OSMO_ASSERT(strcmp(apn_str, "") == 0); - - /* Cleanup */ - - gprs_subscr_put(s1); - sgsn_mm_ctx_cleanup_free(ctx); - - assert_no_subscrs(); - - sgsn_apn_ctx_free(actxs[0]); - sgsn_apn_ctx_free(actxs[1]); - sgsn_apn_ctx_free(actxs[2]); - - sgsn_ggsn_ctx_free(ggcs[0]); - sgsn_ggsn_ctx_free(ggcs[1]); - sgsn_ggsn_ctx_free(ggcs[2]); - - gsup_client_send_cb = __real_gsup_client_send; - - cleanup_test(); -} - -static struct log_info_cat gprs_categories[] = { - [DMM] = { - .name = "DMM", - .description = "Layer3 Mobility Management (MM)", - .color = "\033[1;33m", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, - [DPAG] = { - .name = "DPAG", - .description = "Paging Subsystem", - .color = "\033[1;38m", - .enabled = 1, .loglevel = LOGL_NOTICE, - }, - [DMEAS] = { - .name = "DMEAS", - .description = "Radio Measurement Processing", - .enabled = 0, .loglevel = LOGL_NOTICE, - }, - [DREF] = { - .name = "DREF", - .description = "Reference Counting", - .enabled = 0, .loglevel = LOGL_NOTICE, - }, - [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, - }, - [DLLC] = { - .name = "DLLC", - .description = "GPRS Logical Link Control Protocol (LLC)", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, - [DSNDCP] = { - .name = "DSNDCP", - .description = "GPRS Sub-Network Dependent Control Protocol (SNDCP)", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, -}; - -static struct log_info info = { - .cat = gprs_categories, - .num_cat = ARRAY_SIZE(gprs_categories), -}; - -int main(int argc, char **argv) -{ - void *osmo_sgsn_ctx; - void *msgb_ctx; - - osmo_init_logging(&info); - osmo_sgsn_ctx = talloc_named_const(NULL, 0, "osmo_sgsn"); - tall_bsc_ctx = talloc_named_const(osmo_sgsn_ctx, 0, "bsc"); - msgb_ctx = msgb_talloc_ctx_init(osmo_sgsn_ctx, 0); - - sgsn_rate_ctr_init(); - sgsn_auth_init(); - gprs_subscr_init(sgsn); - - test_llme(); - test_subscriber(); - test_auth_triplets(); - test_subscriber_gsup(); - test_gmm_detach(); - test_gmm_detach_power_off(); - test_gmm_detach_no_mmctx(); - test_gmm_detach_accept_unexpected(); - test_gmm_status_no_mmctx(); - test_gmm_attach_acl(); - test_gmm_attach_subscr(); - test_gmm_attach_subscr_fake_auth(); - test_gmm_attach_subscr_real_auth(); - test_gmm_attach_subscr_gsup_auth(0); - test_gmm_attach_subscr_gsup_auth(1); - test_gmm_attach_subscr_real_gsup_auth(0); - test_gmm_reject(); - test_gmm_cancel(); - test_gmm_ptmsi_allocation(); - test_gmm_routing_areas(); - test_apn_matching(); - test_ggsn_selection(); - printf("Done\n"); - - talloc_report_full(osmo_sgsn_ctx, stderr); - OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1); - OSMO_ASSERT(talloc_total_blocks(tall_bsc_ctx) == 2); - return 0; -} - - -/* stubs */ -struct osmo_prim_hdr; -int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) -{ - abort(); -} diff --git a/tests/sgsn/sgsn_test.ok b/tests/sgsn/sgsn_test.ok deleted file mode 100644 index f38d7309d..000000000 --- a/tests/sgsn/sgsn_test.ok +++ /dev/null @@ -1,45 +0,0 @@ -Testing LLME allocations -Testing core subscriber data API -llist_count(gprs_subscribers) == 0 -llist_count(gprs_subscribers) == 1 -llist_count(gprs_subscribers) == 1 -llist_count(gprs_subscribers) == 2 -llist_count(gprs_subscribers) == 3 -llist_count(gprs_subscribers) == 2 -llist_count(gprs_subscribers) == 1 -llist_count(gprs_subscribers) == 0 -Testing authentication triplet handling -Testing subscriber GSUP handling -Testing GMM detach -Testing GMM detach (power off) -Testing GMM detach (no MMCTX) -Testing GMM detach accept (unexpected) -Testing GMM Status (no MMCTX) -Auth policy 'closed': Testing GMM attach -Auth policy 'remote': Testing GMM attach -Auth policy 'remote', auth faked: Testing GMM attach -Auth policy 'remote', triplet based auth: Testing GMM attach -Auth policy 'remote', GSUP based auth: Testing GMM attach -Auth policy 'remote', GSUP based auth: Testing GMM attach with retry -Auth policy 'remote', real GSUP based auth: Testing GMM attach -Testing GMM reject - - Attach Request (invalid MI length) - - Attach Request (invalid MI type) - - Routing Area Update Request (valid) - - Routing Area Update Request (invalid type) - - Routing Area Update Request (invalid CAP length) -Testing cancellation -Testing P-TMSI allocation - - sgsn_alloc_ptmsi - - Repeated Attach Request - - Repeated RA Update Request -Testing routing area changes - - Attach Request (RA 1) - - RA Update Request (RA 1 -> RA 1) - - RA Update Request (RA 1 -> RA 2) - - RA Update Request (RA other -> RA 2) - - Attach Request (RA 2) - - RA Update Request (RA 2 -> RA 2) -Testing APN matching -Testing GGSN selection -Done diff --git a/tests/slhc/Makefile.am b/tests/slhc/Makefile.am deleted file mode 100644 index 32a3cc447..000000000 --- a/tests/slhc/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) - -EXTRA_DIST = slhc_test.ok - -noinst_PROGRAMS = slhc_test - -slhc_test_SOURCES = slhc_test.c - -slhc_test_LDADD = \ - $(top_builddir)/src/gprs/slhc.o \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) - - diff --git a/tests/slhc/slhc_test.c b/tests/slhc/slhc_test.c deleted file mode 100644 index d2e1cd9dc..000000000 --- a/tests/slhc/slhc_test.c +++ /dev/null @@ -1,272 +0,0 @@ -/* Test SLHC/RFC1144 TCP/IP Header compression/decompression */ - -/* (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 . - */ - -#include -#include - -#include -#include - -#include - -#include -#include -#include - -/* Number of compression slots (S0-1) */ -#define SLOTS 8 - -/* Maximum packet bytes to display */ -#define DISP_MAX_BYTES 100 - -/* Sample packets to test with */ -#define PACKETS_LEN 15 -char *packets[] = { - /* With TCP Option 10 (Timestamps) in place (forces UNCOMPRESSED_TCP) */ - "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", - "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", - "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", - "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", - "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", - "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20", - /* Regular TCP packets (COMPRESSED_TCP) */ - "4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27", - "4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", - "4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01", - "4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01", - "4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", - "4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20", - /* UDP packets (TYPE_IP */ - "450000396e0b40004011a0310a0901650a09170105da003500255489a60f01000001000000000000076f736d6f636f6d036f72670000010001", - "450000dc9eeb00004011aeae0a0917010a090165003505da00c83fbaa60f81800001000100030004076f736d6f636f6d036f72670000010001c00c00010001000079be0004904c2b4cc00c000200010000173d00130773756e6265616d08676e756d6f6e6b73c014c00c000200010000173d000603646e73c041c00c000200010000173d000a0767616e65736861c041c058000100010000173d0004d55f2e45c058001c00010000173d0010200107800045f0460000000000690001c06a0001000100006a710004d55f1b78c039000100010000173d000453ecb2cb", - "45000037652340004011a91b0a0901650a091701ef1b0035002376a2c3910100000100000000000006676f6f676c650264650000010001", - "0050b6162c10000db93a3ff908004500004726a6000038114083080808080a0901650035ef1b00338a8cc3918180000100010000000006676f6f676c650264650000010001c00c000100010000012b0004d83ad503", -}; - -/* Compress a packet using Van Jacobson RFC1144 header compression */ -static int compress(uint8_t *data_o, uint8_t *data_i, int len, - struct slcompress *comp) -{ - uint8_t *comp_ptr; /* Not used */ - int compr_len; - - /* Create a working copy of the incoming data */ - memcpy(data_o, data_i, len); - - /* Run compressor */ - compr_len = slhc_compress(comp, data_i, len, data_o, &comp_ptr, 0); - return compr_len; -} - -/* Expand a packet using Van Jacobson RFC1144 header compression */ -static int expand(uint8_t *data_o, uint8_t *data_i, int len, - struct slcompress *comp) -{ - int data_decompressed_len; - - /* Create a working copy of the incoming data */ - memcpy(data_o, data_i, len); - - /* Handle an uncompressed packet (learn header information */ - if ((data_i[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) { - data_o[0] &= 0x4F; - data_decompressed_len = slhc_remember(comp, data_o, len); - return data_decompressed_len; - } - - /* Uncompress compressed packets */ - else if (data_o[0] & SL_TYPE_COMPRESSED_TCP) { - data_decompressed_len = slhc_uncompress(comp, data_o, len); - return data_decompressed_len; - } - - /* Regular or unknown packets will not be touched */ - return len; -} - -/* Calculate IP Header 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; -} - -/* Check TCP/IP packet */ -static void check_packet(const void *ctx, uint8_t *packet, int len) -{ - /* Check IP header */ - OSMO_ASSERT(len > 20); - OSMO_ASSERT(calc_ip_csum(packet, 20) == 0); - - printf("packet[9]=%02x\n", packet[9]); - - /* Check TCP packet */ - if (packet[9] != 0x06) - return; - OSMO_ASSERT(len > 40); - OSMO_ASSERT(calc_tcpip_csum(ctx, packet, len) == 0); -} - -/* Compress / Decompress packets */ -static void test_slhc(const void *ctx) -{ - char packet_ascii[2048]; - int i; - - struct slcompress *comp; - uint8_t packet[1024]; - int packet_len; - uint8_t packet_compr[1024]; - int packet_compr_len; - uint8_t packet_decompr[1024]; - int packet_decompr_len; - - printf("Allocating compression state...\n"); - comp = slhc_init(ctx, SLOTS, SLOTS); - OSMO_ASSERT(comp); - - for (i = 0; i < PACKETS_LEN; i++) { - printf("Testing with packet No. %d\n", i); - - /* Read input file */ - memset(packet_ascii, 0, sizeof(packet_ascii)); - memset(packet, 0, sizeof(packet)); - memset(packet_compr, 0, sizeof(packet_compr)); - memset(packet_decompr, 0, sizeof(packet_decompr)); - - OSMO_ASSERT(strlen(packets[i]) < sizeof(packet_ascii)); - strcpy(packet_ascii, packets[i]); - - packet_len = - osmo_hexparse(packet_ascii, packet, sizeof(packet)); - check_packet(ctx, packet, packet_len); - - /* Run compression/decompression algorithm */ - printf("Compressing...\n"); - packet_compr_len = - compress(packet_compr, packet, packet_len, comp); - printf("Decompressing...\n"); - packet_decompr_len = - expand(packet_decompr, packet_compr, packet_compr_len, - comp); - OSMO_ASSERT(packet_decompr_len == packet_len); - check_packet(ctx, packet_decompr, packet_decompr_len); - - /* Display results */ - printf("Results:\n"); - if (packet_compr_len > DISP_MAX_BYTES) - packet_compr_len = DISP_MAX_BYTES; - if (packet_len > DISP_MAX_BYTES) - packet_len = DISP_MAX_BYTES; - if (packet_decompr_len > DISP_MAX_BYTES) - packet_decompr_len = DISP_MAX_BYTES; - printf("Original Packet: (%i bytes) %s\n", packet_len, - osmo_hexdump_nospc(packet, packet_len)); - printf("DecompressedPacket: (%i bytes) %s\n", - packet_decompr_len, osmo_hexdump_nospc(packet_decompr, - packet_decompr_len)); - printf("CompressedPacket: (%i bytes) %s\n", packet_compr_len, - osmo_hexdump_nospc(packet_compr, packet_compr_len)); - slhc_o_status(comp); - slhc_o_status(comp); - - printf("\n"); - } - - printf("Freeing compression state...\n"); - slhc_free(comp); - printf("\n"); -} - -static struct log_info_cat gprs_categories[] = { - [DSNDCP] = { - .name = "DSNDCP", - .description = - "GPRS Sub-Network Dependent Control Protocol (SNDCP)", - .enabled = 1,.loglevel = LOGL_DEBUG, - }, - [DSLHC] = { - .name = "DSLHC", - .description = - "Van Jacobson RFC1144 TCP/IP header compression (SLHC)", - .enabled = 1,.loglevel = LOGL_DEBUG, - } -}; - -static struct log_info info = { - .cat = gprs_categories, - .num_cat = ARRAY_SIZE(gprs_categories), -}; - -int main(int argc, char **argv) -{ - void *ctx; - - osmo_init_logging(&info); - - ctx = talloc_named_const(NULL, 0, "slhc_ctx"); - - test_slhc(ctx); - - printf("Done\n"); - - talloc_report_full(ctx, stderr); - OSMO_ASSERT(talloc_total_blocks(ctx) == 1); - return 0; -} - -/* stubs */ -struct osmo_prim_hdr; -int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) -{ - abort(); -} diff --git a/tests/slhc/slhc_test.ok b/tests/slhc/slhc_test.ok deleted file mode 100644 index 71f48a179..000000000 --- a/tests/slhc/slhc_test.ok +++ /dev/null @@ -1,154 +0,0 @@ -Allocating compression state... -Testing with packet No. 0 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (64 bytes) 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 -DecompressedPacket: (64 bytes) 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 -CompressedPacket: (64 bytes) 7510004046dd40004000a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 - -Testing with packet No. 1 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (91 bytes) 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 -DecompressedPacket: (91 bytes) 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 -CompressedPacket: (91 bytes) 7510005b46de40004000a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 - -Testing with packet No. 2 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (55 bytes) 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 -DecompressedPacket: (55 bytes) 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 -CompressedPacket: (55 bytes) 7510003746df40004000a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 - -Testing with packet No. 3 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (55 bytes) 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 -DecompressedPacket: (55 bytes) 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 -CompressedPacket: (55 bytes) 7510003746e040004000a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 - -Testing with packet No. 4 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (100 bytes) 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d -DecompressedPacket: (100 bytes) 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d -CompressedPacket: (100 bytes) 7510007446e140004000a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d - -Testing with packet No. 5 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (66 bytes) 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 -DecompressedPacket: (66 bytes) 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 -CompressedPacket: (66 bytes) 7510004246e240004000a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 - -Testing with packet No. 6 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 -DecompressedPacket: (52 bytes) 4510003446dd40004006a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 -CompressedPacket: (52 bytes) 7510003446dd40004000a9b3c0a8646ec0a864640017ad8b81980100f3ac984d501800e371410000fffd18fffd20fffd23fffd27 - -Testing with packet No. 7 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 -DecompressedPacket: (79 bytes) 4510004f46de40004006a997c0a8646ec0a864640017ad8b8198010cf3ac984d501800e3cda40000fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 -CompressedPacket: (43 bytes) df00cda4fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 - -Testing with packet No. 8 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 -DecompressedPacket: (43 bytes) 4510002b46df40004006a9bac0a8646ec0a864640017ad8b81980133f3ac989f501800e3a70a0000fffd01 -CompressedPacket: (9 bytes) dc00a70a5227fffd01 - -Testing with packet No. 9 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 -DecompressedPacket: (43 bytes) 4510002b46e040004006a9b9c0a8646ec0a864640017ad8b81980136f3ac98a2501800e3a7060000fffb01 -CompressedPacket: (7 bytes) db00a706fffb01 - -Testing with packet No. 10 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d -DecompressedPacket: (100 bytes) 4510006846e140004006a97bc0a8646ec0a864640017ad8b81980139f3ac98a5501800e3c2d000000d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d -CompressedPacket: (68 bytes) db00c2d00d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a - -Testing with packet No. 11 -packet[9]=06 -Compressing... -Decompressing... -packet[9]=06 -Results: -Original Packet: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 -DecompressedPacket: (54 bytes) 4510003646e240004006a9acc0a8646ec0a864640017ad8b81980179f3ac98a5501800e321fb0000706f6c6c7578206c6f67696e3a20 -CompressedPacket: (18 bytes) df0021fb706f6c6c7578206c6f67696e3a20 - -Testing with packet No. 12 -packet[9]=11 -Compressing... -Decompressing... -packet[9]=11 -Results: -Original Packet: (57 bytes) 450000396e0b40004011a0310a0901650a09170105da003500255489a60f01000001000000000000076f736d6f636f6d036f72670000010001 -DecompressedPacket: (57 bytes) 450000396e0b40004011a0310a0901650a09170105da003500255489a60f01000001000000000000076f736d6f636f6d036f72670000010001 -CompressedPacket: (57 bytes) 450000396e0b40004011a0310a0901650a09170105da003500255489a60f01000001000000000000076f736d6f636f6d036f72670000010001 - -Testing with packet No. 13 -packet[9]=11 -Compressing... -Decompressing... -packet[9]=11 -Results: -Original Packet: (100 bytes) 450000dc9eeb00004011aeae0a0917010a090165003505da00c83fbaa60f81800001000100030004076f736d6f636f6d036f72670000010001c00c00010001000079be0004904c2b4cc00c000200010000173d00130773756e6265616d08676e756d6f6e -DecompressedPacket: (100 bytes) 450000dc9eeb00004011aeae0a0917010a090165003505da00c83fbaa60f81800001000100030004076f736d6f636f6d036f72670000010001c00c00010001000079be0004904c2b4cc00c000200010000173d00130773756e6265616d08676e756d6f6e -CompressedPacket: (100 bytes) 450000dc9eeb00004011aeae0a0917010a090165003505da00c83fbaa60f81800001000100030004076f736d6f636f6d036f72670000010001c00c00010001000079be0004904c2b4cc00c000200010000173d00130773756e6265616d08676e756d6f6e - -Testing with packet No. 14 -packet[9]=11 -Compressing... -Decompressing... -packet[9]=11 -Results: -Original Packet: (55 bytes) 45000037652340004011a91b0a0901650a091701ef1b0035002376a2c3910100000100000000000006676f6f676c650264650000010001 -DecompressedPacket: (55 bytes) 45000037652340004011a91b0a0901650a091701ef1b0035002376a2c3910100000100000000000006676f6f676c650264650000010001 -CompressedPacket: (55 bytes) 45000037652340004011a91b0a0901650a091701ef1b0035002376a2c3910100000100000000000006676f6f676c650264650000010001 - -Freeing compression state... - -Done diff --git a/tests/sms_queue/Makefile.am b/tests/sms_queue/Makefile.am index 06c54bcec..1d3b9da6f 100644 --- a/tests/sms_queue/Makefile.am +++ b/tests/sms_queue/Makefile.am @@ -33,8 +33,6 @@ sms_queue_test_SOURCES = \ sms_queue_test_LDADD = \ $(top_builddir)/src/libmsc/libmsc.a \ $(top_builddir)/src/libvlr/libvlr.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libtrau/libtrau.a \ $(top_builddir)/src/libcommon/libcommon.a \ $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ $(LIBSMPP34_LIBS) \ diff --git a/tests/sndcp_xid/Makefile.am b/tests/sndcp_xid/Makefile.am deleted file mode 100644 index d09c41b28..000000000 --- a/tests/sndcp_xid/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) - -EXTRA_DIST = sndcp_xid_test.ok - -noinst_PROGRAMS = sndcp_xid_test - -sndcp_xid_test_SOURCES = sndcp_xid_test.c - -sndcp_xid_test_LDADD = \ - $(top_builddir)/src/gprs/gprs_sndcp_xid.o \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOGB_LIBS) \ - $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) \ - $(LIBGTP_LIBS) \ - -lrt -lm - - diff --git a/tests/sndcp_xid/sndcp_xid_test.c b/tests/sndcp_xid/sndcp_xid_test.c deleted file mode 100644 index 151dd2bb5..000000000 --- a/tests/sndcp_xid/sndcp_xid_test.c +++ /dev/null @@ -1,284 +0,0 @@ -/* Test SNDCP-XID Encoding/Decoding */ - -/* (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 . - */ - -#include -#include - -#include -#include - -#include - -#include -#include - -/* Test SNDCP-XID decoding with a real world sample */ -static void test_xid_decode_realworld(const void *ctx) -{ - struct llist_head *comp_fields; - int rc; - printf("Testing SNDCP XID-Decoder/Encoder (real world data)\n"); - - /* Example of a real world SNDCP-XID message */ - uint8_t xid[] = - { 0x00, 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, - 0x00, 0x0f, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, - 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, - 0x01, 0x05, 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, - 0x80, 0x00, 0x04, 0x12, 0x00, 0x40, 0x07 }; - uint8_t xid_r[512]; - - /* Parse and show contained comp fields */ - comp_fields = gprs_sndcp_parse_xid(NULL, ctx, xid, sizeof(xid), NULL); - OSMO_ASSERT(comp_fields); - printf("Decoded:\n"); - gprs_sndcp_dump_comp_fields(comp_fields, DSNDCP); - - /* Encode comp-fields again */ - rc = gprs_sndcp_compile_xid(xid_r,sizeof(xid_r), comp_fields, - DEFAULT_SNDCP_VERSION); - printf("Result length=%i\n",rc); - printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); - printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); - - OSMO_ASSERT(rc == 54); - OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); - - /* Free comp fields */ - talloc_free(comp_fields); - - printf("\n"); -} - -/* Encode and decode test with artificial test data */ -static void test_xid_encode_decode(const void *ctx) -{ - printf("Testing SNDCP XID-Encoder/Decoder\n"); - - LLIST_HEAD(comp_fields); - struct gprs_sndcp_pcomp_rfc1144_params rfc1144_params; - struct gprs_sndcp_comp_field rfc1144_comp_field; - struct gprs_sndcp_pcomp_rfc2507_params rfc2507_params; - struct gprs_sndcp_comp_field rfc2507_comp_field; - struct gprs_sndcp_pcomp_rohc_params rohc_params; - struct gprs_sndcp_comp_field rohc_comp_field; - struct gprs_sndcp_dcomp_v42bis_params v42bis_params; - struct gprs_sndcp_comp_field v42bis_comp_field; - struct gprs_sndcp_dcomp_v44_params v44_params; - struct gprs_sndcp_comp_field v44_comp_field; - struct llist_head *comp_fields_dec; - - uint8_t xid[512]; - unsigned int xid_len = sizeof(xid); - int rc; - - memset(&rfc1144_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); - memset(&rfc2507_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); - memset(&rohc_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); - memset(&v42bis_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); - memset(&v44_comp_field, 0, sizeof(struct gprs_sndcp_comp_field)); - - /* Setup which NSAPIs shall make use of rfc1144 */ - rfc1144_params.nsapi[0] = 5; - rfc1144_params.nsapi_len = 1; - - /* Setup rfc1144 operating parameters */ - rfc1144_params.s01 = 7; - - /* Setup rfc1144 compression field */ - rfc1144_comp_field.p = 1; - rfc1144_comp_field.entity = 0; - 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; - - /* Setup which NSAPIs shall make use of rfc1144 */ - rfc2507_params.nsapi[0] = 6; - rfc2507_params.nsapi_len = 1; - - /* Setup rfc2507 operating parameters */ - rfc2507_params.f_max_period = 256; - rfc2507_params.f_max_time = 5; - rfc2507_params.max_header = 168; - rfc2507_params.tcp_space = 15; - rfc2507_params.non_tcp_space = 15; - - /* Setup rfc2507 compression field */ - rfc2507_comp_field.p = 1; - rfc2507_comp_field.entity = 1; - rfc2507_comp_field.algo = RFC_2507; - rfc2507_comp_field.comp[RFC2507_PCOMP1] = 3; - rfc2507_comp_field.comp[RFC2507_PCOMP2] = 4; - rfc2507_comp_field.comp[RFC2507_PCOMP3] = 5; - rfc2507_comp_field.comp[RFC2507_PCOMP4] = 6; - rfc2507_comp_field.comp[RFC2507_PCOMP5] = 7; - rfc2507_comp_field.comp_len = RFC2507_PCOMP_NUM; - rfc2507_comp_field.rfc2507_params = &rfc2507_params; - - /* Setup which NSAPIs shall make use of ROHC */ - rohc_params.nsapi[0] = 5; - rohc_params.nsapi[1] = 6; - rohc_params.nsapi[2] = 7; - rohc_params.nsapi[3] = 8; - rohc_params.nsapi[4] = 9; - rohc_params.nsapi[5] = 10; - rohc_params.nsapi[6] = 11; - rohc_params.nsapi[7] = 12; - rohc_params.nsapi[8] = 13; - rohc_params.nsapi[9] = 14; - rohc_params.nsapi[10] = 15; - rohc_params.nsapi_len = 11; - - /* Setup ROHC operating parameters */ - rohc_params.max_cid = 15; /* default */ - rohc_params.max_header = 168; /* default */ - rohc_params.profile[0] = ROHC_UNCOMPRESSED; - rohc_params.profile[1] = ROHC_RTP; - rohc_params.profile[2] = ROHCV2_RTP; - rohc_params.profile[3] = ROHC_UDP; - rohc_params.profile[4] = ROHCv2_UDP; - rohc_params.profile[5] = ROHC_ESP; - rohc_params.profile[6] = ROHCV2_ESP; - rohc_params.profile[7] = ROHC_IP; - rohc_params.profile[8] = ROHCV2_IP; - rohc_params.profile[9] = ROHC_LLA; - rohc_params.profile[10] = ROHC_LLA_WITH_R_MODE; - rohc_params.profile[11] = ROHC_TCP; - rohc_params.profile[12] = ROHC_RTP_UDP_LITE; - rohc_params.profile[13] = ROHCV2_RTP_UDP_LITE; - rohc_params.profile[14] = ROHC_UDP_LITE; - rohc_params.profile[15] = ROHCV2_UDP_LITE; - rohc_params.profile_len = 16; - - /* Setup ROHC compression field */ - rohc_comp_field.p = 1; - rohc_comp_field.entity = 2; - rohc_comp_field.algo = ROHC; - rohc_comp_field.comp[ROHC_PCOMP1] = 8; - rohc_comp_field.comp[ROHC_PCOMP2] = 9; - rohc_comp_field.comp_len = ROHC_PCOMP_NUM; - rohc_comp_field.rohc_params = &rohc_params; - - /* Setup which NSAPIs shall make use of v42bis */ - v42bis_params.nsapi[0] = 5; - v42bis_params.nsapi_len = 1; - - /* Setup v42bis operating parameters */ - v42bis_params.p0 = 3; - v42bis_params.p1 = 2048; - v42bis_params.p2 = 20; - - /* Setup v42bis compression field */ - v42bis_comp_field.p = 1; - v42bis_comp_field.entity = 3; - v42bis_comp_field.algo = V42BIS; - v42bis_comp_field.comp[V42BIS_DCOMP1] = 10; - v42bis_comp_field.comp_len = V42BIS_DCOMP_NUM; - v42bis_comp_field.v42bis_params = &v42bis_params; - - /* Setup which NSAPIs shall make use of v44 */ - v44_params.nsapi[0] = 5; - v44_params.nsapi_len = 1; - - /* Setup v44 operating parameters */ - v44_params.c0 = 0x80; - v44_params.p0 = 3; - v44_params.p1t = 300; - v44_params.p1r = 300; - v44_params.p3t = 600; - v44_params.p3r = 600; - - /* Setup v44 compression field */ - v44_comp_field.p = 1; - v44_comp_field.entity = 3; - v44_comp_field.algo = V44; - v44_comp_field.comp[V44_DCOMP1] = 10; - v44_comp_field.comp[V44_DCOMP2] = 11; - v44_comp_field.comp_len = V44_DCOMP_NUM; - v44_comp_field.v44_params = &v44_params; - - /* Add compression field(s) to list */ - llist_add(&v44_comp_field.list, &comp_fields); - llist_add(&v42bis_comp_field.list, &comp_fields); - llist_add(&rfc1144_comp_field.list, &comp_fields); - llist_add(&rfc2507_comp_field.list, &comp_fields); - llist_add(&rohc_comp_field.list, &comp_fields); - printf("Test input data:\n"); - gprs_sndcp_dump_comp_fields(&comp_fields, DSNDCP); - - /* Encode SNDCP-XID fields */ - rc = gprs_sndcp_compile_xid(xid, xid_len, &comp_fields, - DEFAULT_SNDCP_VERSION); - OSMO_ASSERT(rc > 0); - - printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); - - /* Parse and show contained comp fields */ - comp_fields_dec = gprs_sndcp_parse_xid(NULL, ctx, xid, rc, NULL); - OSMO_ASSERT(comp_fields_dec); - - printf("Decoded:\n"); - gprs_sndcp_dump_comp_fields(comp_fields_dec, DSNDCP); - - /* Free comp fields */ - talloc_free(comp_fields_dec); -} - -static struct log_info_cat gprs_categories[] = { - [DSNDCP] = { - .name = "DSNDCP", - .description = - "GPRS Sub-Network Dependent Control Protocol (SNDCP)", - .enabled = 1,.loglevel = LOGL_DEBUG, - } -}; - -static struct log_info info = { - .cat = gprs_categories, - .num_cat = ARRAY_SIZE(gprs_categories), -}; - -int main(int argc, char **argv) -{ - void *xid_ctx; - - osmo_init_logging(&info); - - xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); - - test_xid_decode_realworld(xid_ctx); - test_xid_encode_decode(xid_ctx); - - printf("Done\n"); - - talloc_report_full(xid_ctx, stderr); - OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); - return 0; -} - -/* stubs */ -struct osmo_prim_hdr; -int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) -{ - abort(); -} diff --git a/tests/sndcp_xid/sndcp_xid_test.ok b/tests/sndcp_xid/sndcp_xid_test.ok deleted file mode 100644 index f3572827c..000000000 --- a/tests/sndcp_xid/sndcp_xid_test.ok +++ /dev/null @@ -1,11 +0,0 @@ -Testing SNDCP XID-Decoder/Encoder (real world data) -Decoded: -Result length=54 -Encoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 -Rencoded: 000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 - -Testing SNDCP XID-Encoder/Decoder -Test input data: -Encoded: 000100011a83010dab00208003012c012c02580258830007a000200308001402408000041200200781010c3456700040010005a80f000f82022789ffe0000f00a80000000101010002010200030103000401040005010500060007010700080108 (97 bytes) -Decoded: -Done diff --git a/tests/subscr/Makefile.am b/tests/subscr/Makefile.am deleted file mode 100644 index 5b770bcb2..000000000 --- a/tests/subscr/Makefile.am +++ /dev/null @@ -1,43 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBSMPP34_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - bsc_subscr_test.ok \ - bsc_subscr_test.err \ - $(NULL) - -noinst_PROGRAMS = \ - bsc_subscr_test \ - $(NULL) - -bsc_subscr_test_SOURCES = \ - bsc_subscr_test.c \ - $(NULL) - -bsc_subscr_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBSMPP34_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(NULL) diff --git a/tests/subscr/bsc_subscr_test.c b/tests/subscr/bsc_subscr_test.c deleted file mode 100644 index 60d687d58..000000000 --- a/tests/subscr/bsc_subscr_test.c +++ /dev/null @@ -1,130 +0,0 @@ -/* (C) 2008 by Jan Luebbe - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2014 by Alexander Chemeris - * 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 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 . - * - */ - -#include -#include - -#include -#include - -#include -#include -#include -#include - -struct llist_head *bsc_subscribers; - -#define VERBOSE_ASSERT(val, expect_op, fmt) \ - do { \ - printf(#val " == " fmt "\n", (val)); \ - OSMO_ASSERT((val) expect_op); \ - } while (0); - -static void assert_bsc_subscr(const struct bsc_subscr *bsub, const char *imsi) -{ - struct bsc_subscr *sfound; - OSMO_ASSERT(bsub); - OSMO_ASSERT(strcmp(bsub->imsi, imsi) == 0); - - sfound = bsc_subscr_find_by_imsi(bsc_subscribers, imsi); - OSMO_ASSERT(sfound == bsub); - - bsc_subscr_put(sfound); -} - -static void test_bsc_subscr(void) -{ - struct bsc_subscr *s1, *s2, *s3; - const char *imsi1 = "1234567890"; - const char *imsi2 = "9876543210"; - const char *imsi3 = "5656565656"; - - printf("Test BSC subscriber allocation and deletion\n"); - - /* Check for emptiness */ - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 0, "%d"); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi1) == NULL); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi2) == NULL); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi3) == NULL); - - /* Allocate entry 1 */ - s1 = bsc_subscr_find_or_create_by_imsi(bsc_subscribers, imsi1); - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d"); - assert_bsc_subscr(s1, imsi1); - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d"); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi2) == NULL); - - /* Allocate entry 2 */ - s2 = bsc_subscr_find_or_create_by_imsi(bsc_subscribers, imsi2); - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 2, "%d"); - - /* Allocate entry 3 */ - s3 = bsc_subscr_find_or_create_by_imsi(bsc_subscribers, imsi3); - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 3, "%d"); - - /* Check entries */ - assert_bsc_subscr(s1, imsi1); - assert_bsc_subscr(s2, imsi2); - assert_bsc_subscr(s3, imsi3); - - /* Free entry 1 */ - bsc_subscr_put(s1); - s1 = NULL; - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 2, "%d"); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi1) == NULL); - - assert_bsc_subscr(s2, imsi2); - assert_bsc_subscr(s3, imsi3); - - /* Free entry 2 */ - bsc_subscr_put(s2); - s2 = NULL; - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 1, "%d"); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi1) == NULL); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi2) == NULL); - assert_bsc_subscr(s3, imsi3); - - /* Free entry 3 */ - bsc_subscr_put(s3); - s3 = NULL; - VERBOSE_ASSERT(llist_count(bsc_subscribers), == 0, "%d"); - OSMO_ASSERT(bsc_subscr_find_by_imsi(bsc_subscribers, imsi3) == NULL); - - OSMO_ASSERT(llist_empty(bsc_subscribers)); -} - -int main() -{ - printf("Testing BSC subscriber core code.\n"); - osmo_init_logging(&log_info); - log_set_print_filename(osmo_stderr_target, 0); - log_set_print_timestamp(osmo_stderr_target, 0); - log_set_use_color(osmo_stderr_target, 0); - log_set_print_category(osmo_stderr_target, 1); - log_set_category_filter(osmo_stderr_target, DREF, 1, LOGL_DEBUG); - - bsc_subscribers = talloc_zero(NULL, struct llist_head); - INIT_LLIST_HEAD(bsc_subscribers); - - test_bsc_subscr(); - - printf("Done\n"); - return 0; -} diff --git a/tests/subscr/bsc_subscr_test.err b/tests/subscr/bsc_subscr_test.err deleted file mode 100644 index a66317a36..000000000 --- a/tests/subscr/bsc_subscr_test.err +++ /dev/null @@ -1,17 +0,0 @@ -DREF BSC subscr IMSI:1234567890 usage increases to: 2 -DREF BSC subscr IMSI:1234567890 usage decreases to: 1 -DREF BSC subscr IMSI:1234567890 usage increases to: 2 -DREF BSC subscr IMSI:1234567890 usage decreases to: 1 -DREF BSC subscr IMSI:9876543210 usage increases to: 2 -DREF BSC subscr IMSI:9876543210 usage decreases to: 1 -DREF BSC subscr IMSI:5656565656 usage increases to: 2 -DREF BSC subscr IMSI:5656565656 usage decreases to: 1 -DREF BSC subscr IMSI:1234567890 usage decreases to: 0 -DREF BSC subscr IMSI:9876543210 usage increases to: 2 -DREF BSC subscr IMSI:9876543210 usage decreases to: 1 -DREF BSC subscr IMSI:5656565656 usage increases to: 2 -DREF BSC subscr IMSI:5656565656 usage decreases to: 1 -DREF BSC subscr IMSI:9876543210 usage decreases to: 0 -DREF BSC subscr IMSI:5656565656 usage increases to: 2 -DREF BSC subscr IMSI:5656565656 usage decreases to: 1 -DREF BSC subscr IMSI:5656565656 usage decreases to: 0 diff --git a/tests/subscr/bsc_subscr_test.ok b/tests/subscr/bsc_subscr_test.ok deleted file mode 100644 index 0f6a8be01..000000000 --- a/tests/subscr/bsc_subscr_test.ok +++ /dev/null @@ -1,11 +0,0 @@ -Testing BSC subscriber core code. -Test BSC subscriber allocation and deletion -llist_count(bsc_subscribers) == 0 -llist_count(bsc_subscribers) == 1 -llist_count(bsc_subscribers) == 1 -llist_count(bsc_subscribers) == 2 -llist_count(bsc_subscribers) == 3 -llist_count(bsc_subscribers) == 2 -llist_count(bsc_subscribers) == 1 -llist_count(bsc_subscribers) == 0 -Done diff --git a/tests/testsuite.at b/tests/testsuite.at index 7a8d84bbe..e3e901769 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -1,41 +1,6 @@ AT_INIT AT_BANNER([Regression tests.]) -AT_SETUP([gsm0408]) -AT_KEYWORDS([gsm0408]) -cat $abs_srcdir/gsm0408/gsm0408_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/gsm0408/gsm0408_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([bsc_subscr]) -AT_KEYWORDS([bsc_subscr]) -cat $abs_srcdir/subscr/bsc_subscr_test.ok > expout -cat $abs_srcdir/subscr/bsc_subscr_test.err > experr -AT_CHECK([$abs_top_builddir/tests/subscr/bsc_subscr_test], [], [expout], [experr]) -AT_CLEANUP - -AT_SETUP([channel]) -AT_KEYWORDS([channel]) -cat $abs_srcdir/channel/channel_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/channel/channel_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([gprs]) -AT_KEYWORDS([gprs]) -cat $abs_srcdir/gprs/gprs_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/gprs/gprs_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([bsc-nat]) -AT_KEYWORDS([bsc-nat]) -AT_CHECK([test "$enable_nat_test" != no || exit 77]) -cp $abs_srcdir/bsc-nat/prefixes.csv . -cp $abs_srcdir/bsc-nat/barr.cfg . -cp $abs_srcdir/bsc-nat/barr_dup.cfg . -cat $abs_srcdir/bsc-nat/bsc_nat_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/bsc-nat/bsc_nat_test], [], [expout], [ignore]) -AT_CLEANUP - AT_SETUP([smpp]) AT_KEYWORDS([smpp]) AT_CHECK([test "$enable_smpp_test" != no || exit 77]) @@ -44,95 +9,6 @@ cat $abs_srcdir/smpp/smpp_test.err > experr AT_CHECK([$abs_top_builddir/tests/smpp/smpp_test], [], [expout], [experr]) AT_CLEANUP -AT_SETUP([bsc-nat-trie]) -AT_KEYWORDS([bsc-nat-trie]) -AT_CHECK([test "$enable_nat_test" != no || exit 77]) -cp $abs_srcdir/bsc-nat-trie/prefixes.csv . -cat $abs_srcdir/bsc-nat-trie/bsc_nat_trie_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/bsc-nat-trie/bsc_nat_trie_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([abis]) -AT_KEYWORDS([abis]) -cat $abs_srcdir/abis/abis_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/abis/abis_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([bsc]) -AT_KEYWORDS([bsc]) -AT_CHECK([test "$enable_bsc_test" != no || exit 77]) -cat $abs_srcdir/bsc/bsc_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/bsc/bsc_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([gbproxy]) -AT_KEYWORDS([gbproxy]) -cat $abs_srcdir/gbproxy/gbproxy_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/gbproxy/gbproxy_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([trau]) -AT_KEYWORDS([trau]) -cat $abs_srcdir/trau/trau_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/trau/trau_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([sgsn]) -AT_KEYWORDS([sgsn]) -AT_CHECK([test "$enable_sgsn_test" != no || exit 77]) -cat $abs_srcdir/sgsn/sgsn_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/sgsn/sgsn_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([oap]) -AT_KEYWORDS([oap]) -AT_CHECK([test "$enable_oap_test" != no || exit 77]) -cat $abs_srcdir/oap/oap_client_test.ok > expout -cat $abs_srcdir/oap/oap_client_test.err > experr -AT_CHECK([$abs_top_builddir/tests/oap/oap_client_test], [], [expout], [experr]) -AT_CLEANUP - -AT_SETUP([gtphub]) -AT_KEYWORDS([gtphub]) -AT_CHECK([test "$enable_gtphub_test" != no || exit 77]) -cat $abs_srcdir/gtphub/gtphub_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/gtphub/gtphub_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([xid]) -AT_KEYWORDS([xid]) -AT_CHECK([test "$enable_sgsn_test" != no || exit 77]) -cat $abs_srcdir/xid/xid_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/xid/xid_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([sndcp_xid]) -AT_KEYWORDS([sndcp_xid]) -AT_CHECK([test "$enable_sgsn_test" != no || exit 77]) -cat $abs_srcdir/sndcp_xid/sndcp_xid_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/sndcp_xid/sndcp_xid_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([slhc]) -AT_KEYWORDS([slhc]) -AT_CHECK([test "$enable_sgsn_test" != no || exit 77]) -cat $abs_srcdir/slhc/slhc_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/slhc/slhc_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([v42bis]) -AT_KEYWORDS([v42bis]) -AT_CHECK([test "$enable_sgsn_test" != no || exit 77]) -cat $abs_srcdir/v42bis/v42bis_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/v42bis/v42bis_test], [], [expout], [ignore]) -AT_CLEANUP - -AT_SETUP([nanobts_omlattr]) -AT_KEYWORDS([nanobts_omlattr]) -cat $abs_srcdir/nanobts_omlattr/nanobts_omlattr_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/nanobts_omlattr/nanobts_omlattr_test], [], [expout], [ignore]) -AT_CLEANUP - AT_SETUP([sms_queue_test]) AT_KEYWORDS([sms_queue_test]) cat $abs_srcdir/sms_queue/sms_queue_test.ok > expout diff --git a/tests/trau/Makefile.am b/tests/trau/Makefile.am deleted file mode 100644 index 1d014ba3c..000000000 --- a/tests/trau/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBSMPP34_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - trau_test.ok \ - $(NULL) - -noinst_PROGRAMS = \ - trau_test \ - $(NULL) - -trau_test_SOURCES = \ - trau_test.c \ - $(NULL) - -trau_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ - $(top_builddir)/src/libtrau/libtrau.a \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBSMPP34_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBRARY_DL) \ - -ldbi \ - $(NULL) - diff --git a/tests/trau/trau_test.c b/tests/trau/trau_test.c deleted file mode 100644 index c74e6dbb3..000000000 --- a/tests/trau/trau_test.c +++ /dev/null @@ -1,84 +0,0 @@ -/* (C) 2013 by Andreas Eversberg - * 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 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 . - * - */ - -#include -#include -#include - -#include -#include -#include - -void test_trau_fr_efr(unsigned char *data) -{ - struct decoded_trau_frame tf; - struct msgb *msg; - struct gsm_data_frame *frame; - - printf("Testing TRAU FR transcoding.\n"); - data[0] = 0xd0; - trau_encode_fr(&tf, data); - tf.c_bits[11] = 0; /* clear BFI */ - msg = trau_decode_fr(1, &tf); - OSMO_ASSERT(msg != NULL); - frame = (struct gsm_data_frame *)msg->data; - OSMO_ASSERT(frame->msg_type == GSM_TCHF_FRAME); - OSMO_ASSERT(!memcmp(frame->data, data, 33)); - msgb_free(msg); - - printf("Testing TRAU EFR transcoding.\n"); - data[0] = 0xc0; - trau_encode_efr(&tf, data); - OSMO_ASSERT(tf.d_bits[0] == 1); /* spare bit must be 1 */ - tf.c_bits[11] = 0; /* clear BFI */ - msg = trau_decode_efr(1, &tf); - OSMO_ASSERT(msg != NULL); - frame = (struct gsm_data_frame *)msg->data; - OSMO_ASSERT(frame->msg_type == GSM_TCHF_FRAME_EFR); - OSMO_ASSERT(!memcmp(frame->data, data, 31)); - - printf("Testing TRAU EFR decoding with CRC error.\n"); - tf.d_bits[0] = 0; /* spare bit must be included */ - msg = trau_decode_efr(1, &tf); - OSMO_ASSERT(msg != NULL); - frame = (struct gsm_data_frame *)msg->data; - OSMO_ASSERT(frame->msg_type == GSM_BAD_FRAME); - msgb_free(msg); -} - -int main() -{ - unsigned char data[33]; - int i; - - msgb_talloc_ctx_init(NULL, 0); - - memset(data, 0x00, sizeof(data)); - test_trau_fr_efr(data); - memset(data, 0xff, sizeof(data)); - test_trau_fr_efr(data); - srandom(42); - for (i = 0; i < sizeof(data); i++) - data[i] = random(); - test_trau_fr_efr(data); - printf("Done\n"); - return 0; -} - -/* stubs */ -void vty_out() {} diff --git a/tests/trau/trau_test.ok b/tests/trau/trau_test.ok deleted file mode 100644 index ef7123073..000000000 --- a/tests/trau/trau_test.ok +++ /dev/null @@ -1,10 +0,0 @@ -Testing TRAU FR transcoding. -Testing TRAU EFR transcoding. -Testing TRAU EFR decoding with CRC error. -Testing TRAU FR transcoding. -Testing TRAU EFR transcoding. -Testing TRAU EFR decoding with CRC error. -Testing TRAU FR transcoding. -Testing TRAU EFR transcoding. -Testing TRAU EFR decoding with CRC error. -Done diff --git a/tests/v42bis/Makefile.am b/tests/v42bis/Makefile.am deleted file mode 100644 index a031e33bd..000000000 --- a/tests/v42bis/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBCARES_CFLAGS) - -EXTRA_DIST = v42bis_test.ok - -noinst_PROGRAMS = v42bis_test - -v42bis_test_SOURCES = v42bis_test.c - -v42bis_test_LDADD = \ - $(top_builddir)/src/gprs/v42bis.o \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) - - diff --git a/tests/v42bis/v42bis_test.c b/tests/v42bis/v42bis_test.c deleted file mode 100644 index 7e907858d..000000000 --- a/tests/v42bis/v42bis_test.c +++ /dev/null @@ -1,435 +0,0 @@ -/* Test v42bis Compression/Decompression */ - -/* (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 . - */ - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -/* V.42bis compression parameters */ -#define P0 3 /* Direction */ -#define P1 512 /* Max number of codewords */ -#define P2 20 /* Max string length */ - -/* V.42bis compression buffer size - * (Does not affect the compression/decompression result) */ -#define MAX_BLOCK_SIZE 1024 - -/* Compressed sample packets, sniffed from real communication */ -#define COMPR_PACKETS_LEN 33 -char *compr_packets[] = { - /* K800i */ - "4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", - "4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100", - "4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", - "4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100", - "450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", - "450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", - "450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", - "450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", - "4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100", - "450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", - "450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00", - "4500010239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d69786564330057b36eedfa954dd8b165cfa6ddb3e60e9c372ef6049eab95ab57b062fd02164cf8cdd53b68f640256b16ed9cb38547b490d1e22791a043efc030b2c6a91d344547e0b99306c68eabad5fd3c871958d1d39b077e0e00183c6eddcbf67e4b89103061e337660d4b86a650d9b3477c4346162e56a11366a7080164d14c6133271d4e021a3068d5134717eee818119c69c3a72d2b079837e4489bf77e6f4902103738cdc71f8a0a9d3d58ec11866e4c091818548fcf9329cec9831834d951a33783e2ef173891c3bab69cc88c1a3674f1d347a6cdcf8134bea3a30889c8fb3da4a583e48162a37a891231b19208b8ca882c63e99d432a038fd6d8339471d238ac8d793534614d549e40b956123868d1153e4d3b77f97c99129cc63cc1861242c7df275beb2092bc3c89323467ef7fc693a4e1c3466c0c631ea04cdd09d5cf3a0e96e66e81d1848e2403cc366bcd13368d2bcf98ae6aa9a3e4c7ffe0c00", - "450001025b000a00004006ac35c0a800020a0901ab40011f90c293b0a8af5e58be5018400072a60000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c33005cbd82154b368e59b46ad9ee597307ce1b177b066fedfa35ec583665010b266cf8cdd63b68f6543d9b76ed1cb58747b490d16268d1a34961185933d50e1aa523f0dc490363c7d6d7b169e4d8cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b3538461b457a07c6133238f190518366299a3843f7c0d80c634e1d3969d8bc513fa244e03b737ac890b139c6ee387cd0d4096b07610c3372e0c8c042647e7d194e76cc98c1a64a8d1940259718ba448e9dd63466c4e01134a80e1a3d38721c8a65751d1844d2c7696d65261f240d9923dcd8918d0c9045465441839fcc6a1950a606b7e1bca38e1145e8ebd929230aeb24f485cab011c3c68829f4ede3d7cbe4c814e731668c3032d3be1a3c75c6b2296be4c91123c1830e451d270e1a3364e32c758206694fb079d07c3f9a1406923812cfb0c1b9f40c9a346fc6a2d9aaa64fd4a175d33064b894bfff812b5bc2a421b3e60c8e32860e0d00", - "4500010267001200004006ac21c0a800020a0901ab40011f90c293b0a8af5e58be80184000ee770000050aaf5e6437af5e8c230000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fc8de41b3c72b5cb974e7cc853ca2858c164c9d42950ac3c81aae76d04c1d81e74e1a183bc8e2d64d2307593676e4ecde8183070c1ac2892b9f91e3460e1878ccd8815183ac95356cd2dc11d3848915b245d8a8c1c1fa69d43b309e90098a878c1a3454d1c461ba0706691873eac849c3e6cdfc112514df99d343860cd23188c7e183a68e5a3b126398910347061622fcfdcb70b263c60c36556acc48bab904d32572ecd8a63123060fa54a75d0e861d224532cb4ebc020223f8e6d2b3cf920b1585d62c9936c64a82c32a20a9a826468cb80c255b98deb27758c28d25f4f5119516a27e9df54868d1836464ce9ffbf20612647a65c8f316384119effd5e0a9c3968d5b234f8e1851ae94a9ec3871d098691b87aa1334518fa6cd83063d54a93090c4d978864d50aa67d0a479c3160d59357db432fd9ba66245aa0a193aac7953278d9e3f679894c1946900", - "4500010236003000004006cf03c0a80002550d93d740020050c30e84a9441d06ac80184000c2f400000101080a00052df410fc31bd474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005cbd82154b968d59b46ad9baddb3e60e9c372ef618c6fb35ecd8b26707173e9cf80dd73b68f6544dbbb6ed1cb68a47b490d16268d1a34961185933d50e1aa523f0dc49036307d7d8b369e4e0cac68e1cda3b70f080416377efe13372dcc801038f193b306a70b5b2864d9a3b629a30b1c2b5081b35384a1b457a07c6133271d4e021a306cd52347186ee81d119c69c3a72d2b079d37e4409c277e6f49021a3738cde71f8a0a923d60ec31866e4c0918185887dfc329cec9831834d951a3380522e3174891c3baff5e8d113a38f1c336e285a1c8aa5751d1844d8c7796dc52c1f24109d33f408928d8c9145465441b39f4c6b1950a60eb7011da48e1145eeebc929238aeb24f77dcab011c3c68829f7f3efbfcbe4c814e831668c3062367ffa3a64d9989561e4c91123c363d0186a3a4e1c3466cac659ea040dd29d61f3a0097f34290c24712a9e61837ee9193469de9045c3554d9fa843870600", - "4500010260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fcede41b3072c5dbb78e7dcad3ca2858c164ea14aa50ac3c81aaf76d0541d81e74e1a183bcef2f64d23c7593676e4fcde8183070c1ac6913b9f91e3460e187884c2a871d6ca1a3669ee8869c2c4cad9226cd4e0801d75ea1d184f7caac143460d1aab68e238dd0303358c3975e4a461f3c6fe88128fefcce9214306ea18c8e3f04153a7edd0b841e5c0918185c87f83329cec9831834d951a33967e2ee174891c3bbaf5e8d113a38f1c336e3ac2718a05771d1844eac7d16d252e1f241985563489928d8c954546544193900c6e1950bc3ab7a11da58e11450aea292a234aee240595cab011c3c68829050f2624cce4c814ed31668c3012f7a0fc3a6fd9c49561e4c91123ce63d0702a3b4e1c3466e0c6b1ea04cdd4a36cf3a0592f952a0c2471ccc839c3268e1aab67d0a479f316cd59357db83af59b062346ab0d1f46b47933e7ce9e329c3a0d00", - "4500010264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf517b07cd1e9f77f3ee9da317f38816325a48a56a152b0c236bc4da419375049e3b6960ec50fb3b388d1c6ad9d891237c070e1e3068245f1e7d468e1b3960e0316307460db556d6b04973474c132656d4f254836376d5ab7760008da3060f193568b4a28923750f8cd530e6d4919386cd9bfc234a48be33a7870c19ab632c8fc3074d1db87630c63023078e0c2c440c2294e164c78c196caad498f1547409a94be4d8e9ad478f9e187de498710352a4542cbbebc020823f4e6f2b74f920e1c81da34a966c64bc2c32a20a1a866476cb802236ba0def2c758c2872500f521951782739d854868d1836464c39a89061612647a6788f31638411ba0aebd791cb86ae0c234f8e18891e838654da71e2a03133378e562768ae2a7d9b078d7bab5861208913f20c1bfa5acfa049f3462e1ab56afa80950a38cdc68d5a214aa4a873e74fa144474a951a00", - "4500010264005800004006ceadc0a80002550d93d740050050c31389acaf7b26538018400075c900000101080a000537d010fc354a474554202f382d4269742f41636f726e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf497b07cd1e9f76f1ea9d93f7f28816325a48a56af50e0c236bc2da418375049e3b6960ec48eb1b388d1c69d9d891137c070e1e306820570e7d468e1b3960e0316307468db456d6b04973474c132656d2f2548343b699aa57613c2113470d1e326ad064451347ea1e18aa61cca923270d9b37f94794887c674e0f193254c7501e870f9a3a6fed608c11148e0c2c440c2294e164c78c196caad498f1347409a94be4d8e1ad478f9e187de4987103520e1ca95874d78141047f1cde56e6f241c2713bc6942bd9c87059644415340cc9e89601252c741bdd57ea1851e4a09ea432a2ec4e72d0a90c1b316c8c9872502143c34c8e4ce91e63c608237315d6af1397cd5c19469e1c31023d060da9b4e3c44163466e9cac4ed0585dea360f9af6efefc0401227e81936f4b39e4193e64d5c3469d5f4f92a15709a8d1bb342944831a7ce9e42898a942a3500", - "4500010266007600004006ce8dc0a80002550d93d740060050c31431ada11fa06780184000f08e00000101080a00053b3c10fc35ef474554202f382d4269742f416d73747261642e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf597b07cd9e9e78f5f2d5a379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b77aac141db2ad63b309e9089a3060f193568b6a28933750f0cc830e6d4919386cd9bfd234a50be33a7870c199063308fc3074d9db87636c63023078e0c2c44103294e164c78c196caad49801957489a94be404ddaa478f9e187de4987133b2e4542cbcebc020a23f8e6f2b75f920f9d87d63cb976c64c82c32a20a9a876478cb803256ba8def2f758c28a2500f5319517a27512855868d1836464c51d8f061622647a67c8f31638491ba0defd799cba6ae0c234f8e18911e83c6d4db71e2a0314337ce562768b03a859b07cdfbab5961208943f20c1bfb5bcfa049f3662e9ab56afa849d3a388d478f5b2756bcf813e850a3484d4e9d1a00", - "4500010264007700004006ce8ec0a80002550d93d740040050c3135ddb2189e0108018400060d600000101080a00053b4010fc35e7474554202f382d4269742f41746172692e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300932bbf497b07cd1e9f76f1ea9d93d7f28816325a48a56a152b0c236b84da419375049e3b6960ec48dbfb378d1c69d9d891037c070e1e30681c4ffe7c468e1b3960e0316307468db456d6b04973474c132656d2f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9b37f84794807c674e0f193252c7481e870f9aa1da2fc63023078e0c2c440a1e94e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d968e7224a956c64b42c32a20a9a856472cb8022f4b90dee2a758c286250cf511951742731c854868d1836464c31887061612647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae26759b070d7bab58612089f3f10c9bf95acfa049f3262e9ab46afa8095fa378d468d5a1f469c8833e7ce9f41434a951a00", - "4500010264007c00004006ce89c0a80002550d93d740070050c314f3aefa37ceb18018400009f900000101080a00053e3410fc369e474554202f382d4269742f4170706c652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf517b07cd1e9f76f1ea9d93f7f28816325a48a56a152b0c236bc4da419375049e3b6960ec50dbfb378d1c6ad9d891037c070e1e30681c4ffe7c468e1b3960e0316307460db556d6b04973474c132656d4f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9ba15a4b44be33a7870c19a963248fc3074d9db7762cc63023078e0c2c400da691e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d1a8dd224a956c64b42c32a20a9aa16472cb8022f6b90dee2a758c2862504f521951742731e854868d1836464c29a910cd602647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae2e7dc3260f1af656b1c24012e7e31936f3b59e4193e64d5c346ad5f4012bd56f9a8c19b53a84281167ce9d3f8b86942a3500", - "4500010265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009631bf597b07cd1e9f8df5f2d59379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b79aac141db2ad63b309e9089a3068f50345bd1c499ba07c6631873eac849c3e68dfe112526df99d343868cc73198c7e183a64e5c3b1963989103470616220715ca70b263c60c36556acc804abac4d42572ecf8d6a3474f8c3e72ccb80939722a16de75601051c3dfb715a27c9074ec9e71654b363260161951054d4332bc6540192bddc6f7963a461441a847a98c28bd93208ce3d3460c1b23a6205cd89030932353bec79831c208d185f7ebcc6553d7c8932346a4c7a03175769c3868ccd08db3d5091aac4ce1e641f3fe6a561848e2883cc3c6fed63368d2bc998b66ad9a3e61a7fe4dc391e3d688132beeec0974a8519253a70600", - "4500010269008000004006ce80c0a80002550d93d740060050c3143301dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f6600952f67defcc66dd03d3df7f6fd3bc72fe7112d64b4b08a552b571846d6983dda75049e3b6960ec701b7c388d1c6e8dca21be03070f183496db694e63468e1b3960e0316307460db756d6b04973474c132656dcee5483c376d6ad77603c2113470d1e326ad0784513c7ea1e18ae6110959386cd1bfe234a58be33a7870c19ae63548fc347285d3b1b63989103470616220ad3c870b263c60c36556acc986aba84d52572ecfcd6a3474f8c3e72ccb81149d22a96a3756010d91fe7b715bc7c90d4f9b891a54b36326216195105cd4332476540312bdd0678973a4614a923478f531951d0dc49d299aa0c1b316c8c98d2b9e143c64c8e4c011f63c60823781be2af63970d5e19469e1c31223d060dabbce3c44163e66e1caf4ed06c853a370f1af85ab9c2401267e41936f7bd9e4193e68d5d346ed5f4216bd5701aa142bd4eac78d1e7cfa1489596b46a3500", - "4500010268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f3300952f67defcc6ed1d347b7ceeedfb778e5fce235ac8686115ab56ae308cac316b074dd71178eea481b1c3edf0e23472b86563478ef11d3878c0a0d1fc79f519396ee48081c78c1d1835dc5a59c326cd1d314d985871cb530d8edb59b7de81f1844c1c3578c8a841e3154d1cab7b60bc8631a78e9c346cdef81f51c2f29d393d64c8781de3791c3e68ead0b5d3318699a032b01061e85086931d3366b0a95263c654d325ac2e916327b81e3d7a62f49163c64dc9a056b1fcae038348ff38c1ade0e5832424f88e2e61b29131b3c8882a682292f92d038ad9ea36c4c3d431a248433d4c6544019ea46154193662d81831a5e1c38889991c99223ec68c1146f03ed45fc72e1bbc328c3c3962a47a0c1a5671c78983c6ccdd385e9da0d9ea746e1e34f2b5728581248ec9336cf27b3d8326cd1bbb68dcaae943d62ae13420417aad78312350a1448d228523c3aad500", - "4500010263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330096dfa4bd83668f4fbb78f5cec97b79440b192da24ead7a1586913561eda0c13a02cf9d343076a4f50d9c468eb46cecc809be03070f1834902b873e23c78d1c30f098b103a3465a2b6bd8a4b923a609132b6979aac1219baad53b309e9089a3060f193568b2a28913750f0cd530e6d4919386cd9bfc234a44be33a7870c19aa63288fc3074d9db77630c63023078e0c2c440c2294e164c78c196caad498e1347489a84be4d8e1ad478f9e187de49871035264542cbaebc020823f0e6f2b73f920e1b81da34a966c64bc2c32a20a1a866474cb801216ba8dee2c758c287250cf511951762739c854868d1836464c39a89021612647a6748f31638491b90aebd789cb66ae0c234f8e18811e8346d4d971e2a03123374e562768ac26759b074dfbaa5761208913f20c1bfa59cfa049f3262e9ab46afa7c8dfa37cdc68d59214aa4a873e7cfa04347468d1a00", - "4500010262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa0bd83668fcfba77f3cec16b79440b192da04aa56a1586913560eda0b93a02cf9d343076a0edfd9b460eb46cecc801be03070f18348e277f3e23c78d1c30f098b103a3065a2b6bd8a4b923a609132b6879aac1117b6ad53b309e9089a3060f193568b0a28903750f8cd430e6d4919386cd1bfc234a40be33a7870c19a963248fc3074d1db7762ec63023078e0c2c440a1e94e164c78c196caad498d1147409a84be4d8d9ad478f9e187de49871f33124542cb9ebc020723fce6e2b72f920d9a8fd62ca956c64b82c32a20a9a856472cb8002f6b90dee2b758c2862508f511951742731b854868d1836464c318870e1602647a6708f31638411b908e9d781cb46ae0c234f8e18791e830654d971e2a03113370e562768aa226d9b070d7baa5661208903f20c9bf958cfa049f3062e1ab46afa7885ea378d468d581f469c9853674fa0424542851a00", - "4500010265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf512b744fcfbb79f7ced17b79440b192da452b58a1586913562eda0c93a02cf9d343076a8edfd9b460eb56cecc801be03070f18348e277f3e23c78d1c30f098b103a3865a2b6bd8a4b923a609132b6a77aac111bbead53b309e9089a3060f193568b4a28923750f8cd430e6d4919386cd1bfc234a44be33a7870c19a963248fc3074d1db87630c63023078e0c2c440a1e94e164c78c196caad498f1347409a94be4d8d9ad478f9e187de498710352a4542cb9ebc020723fce6e2b74f920e1a81da34a966c64bc2c32a20a1a866472cb8022f6b90dee2c758c2862504f521951742731e854868d1836464c31889021612647a6708f31638411ba08e9d791bbd8c89323469ec7a02195769c3868cc7ca5abd5099aab4bdfe641c3de2a561848e2843cc366bed63368d2bc018a46ad9a3e60a5fe4db371a356881229eae4f97368d19152a50600", - "4500010263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa4bd83668f4fc578f5eab13ca2858c1651a756bd0ac3c89ab076d0601d81e74e1a183bd2fa064e23475a3676e404df8183070c1ac895439f91e3460e1878ccd8815123ad95356cd2dc11d3848995b43cd5e0904dd5ea1d184fc8c45183878c1a3459d1c489ba0706631873eac849c3e64dfe112520df99d343860cc63194c7e18326e8768c31ccc88123030b1183086538d93163069b2a356638155d22ea12397678ebd1a327461f3966dc7c0c19158bee3a3088e08fc3db8a5c3e4838dac19872251b192e8b8ca882862119dd32a084856ea3fb4a1d238a1cd483544694dd490e36956123868d11530e2a642898c99129dd63cc186144aec2fa75e0b2912bc3c8932346a0c7a01135769c3868ccc48d93d5091aab4adde641d3beea551848e2803cc3867ed63368d2bc818b26ad9a3e5fa3f64db3716356881229e6d4d91328519151a30600", - "4500010269009e00004006ce62c0a80002550d93d740060050c3143845a11fab60801840003c1c00000101080a000547d810fc38b7474554202f382d4269742f526164696f536861636b2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f330096316be6fcc6ed1d347b7a46f60b584fe7112d64b4b08a552b5718468ad6b183a6eb083c77d2c0d8e17678711a39dcb2b123c7f80e1c3c60d068febcfa8c1c3772c0c063c60e8c1a6e89b24973474c132656dcee5483e376d6ad77603c2113470d1e326ad0784513c7ea1e189361cca923270d9b37fd4794b87c674e0f193226c7781e870f9a3a74ed748c61460e1c195888307428c3c98e1933d854a93163eae9125697c8b1135c8f1e3d31fac831e3a6e449ab587ed78141847f9ce056f0f24112127cc79731d9c8a0596444153411c9fc9601c56c751be263ea1851a4a19ea732a2004fd2b0aa0c1b316c8c98d2f061c4c54c8e4c111f63c60823781fe6af6357685e234f8e18a91e838655dd71e2a03173378e572768b6469d9b074d7cad5c61208963f20c1bfc5ecfa049f3c62e1ab76afa90b55a380d48905e2b5ecc1874e8d1a44b515ab51a00", - "4500010266009f00004006ce64c0a80002550d93d740050050c313903caf7b2f9580183d5ce4ef00000101080a0005481810fc3934474554202f382d4269742f5068696c6970732e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf597b07cd1e9f8cf5f2d58379440b192da85ac5aa1586913563eda0d93a02cf9d343076acfd1d9c468eb56cecc811be03070f1834922f8f3e23c78d1c30f098b103a3c65a2b41d3dc11d3848995b53cd5e0987d35eb1d184fc8c45183878c1a345cd1c4a1ba0786631873eac8492334ff881292efcce9214386e318cbe3f0415307b19d8b31ccc88123030b1183086538d93163069b2a3566441d5d82ea1239767aebd1a327461f3966dc7c0c4915cbee3a3088e08fd3db0a5d3e483672bf9872251b192e8b8ca882e60d1a32bb6540191bdd86f7953a461439a847a98c28bc931c7c2ac3460c1b23a61c5428f830932353bcc79831c2085d85f5ebc8654357869127478c448f4183eaed3871d098991b87ab133459990ecd83a63d56ad3090c40179860d7dae67d0a4792317cd5a357d8852059c46a346ae0f234ecca9b32750a322a9520d00", - "450001049b00ae00004006cc20c0a80002550d93d740050050c31396ceaf7b396e801840009ad400000101080a0005611010fc3d6b474554202f382d4269742f6d72776f6e672e67696620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf617b07cd9e9f8ef7f6d5a379440b192da85ac5aa1586913564eda0d93a02cf9d343076b00d3e9c460eb66cecc821be03070f183496379f3e23c78d1c30f098b103a3065b2b6b92de11d3848915b63dd5e0a87d35eb1d184fc814c543460d1aae68e250dd0303328c3975e4a461f346ff881294efcce9214306e418cde3f0415347ae1d8c31ccc88123030b1183086538d93163069b2a3566442d5d82ea1239767eebd1a327461f3966dc801449154bef3a3088e48ff3db0a513e48387ac7a892251b192f8b8ca882862199de32a0909d6e033c4b1d238a1cd4a3544614df490e3e956123868d11530e2a644898c99129e063cc186184a8423578ead06563d7c8932346a6c7a04175769c3868ccd48dc3d5099aac4ce3e641f31eab561848e2843cc3a628d73368d2bca18b86ad9a3e62a9fe4db3712357881229eadce933e8d09154a92a417265848c1d307afec489074e198678e6108d31a7e8882557ae4c9111357903abdf7f7b052b96ec4f3868d51e7e1b77ae74198ef7f63d1a76ce52bf50cf4c9d7355b7ddb290634cae7cb9b4dec05f135b76c178c41d347b7e16eeabc732db16325a74cf7a07869135647bff0e3e7c075bdad3732c6f4e7c070e1ed37dcb993e23c78d1c30f07807cfd6ca1a3669ee8869c2c40adb9e6a70a8d60ae30999a278c8e4e78a260ed53d3020c33088900d43ae25204aa46818239f8d6cbc631c3a120b11ff6964a864c9e6e58ca8a54b505d220727579d3b7d06bd48158b52a6f99f72b542940f923a13ed600c39838d8c974546fc6548a63761b2d36d8067a96344913a72f428951105cd9d248a9fcab011c3c688298ad30c444398c99129e063cc18313bce683578eae8b66be4c91123d363246f003b0e1a33d2b93a41939569dc3c68d6df8181248e193967d814e57a064d9a3774d1b055d387cd1caa7fd36cdcc835618f853a63d07473510655aa0100", - - /* SGSN with IAXMODEM V.42bis */ - "45000101a0f3d84000400679210a0901abc0a800021f90400538e210f07a827bb1501900ed7be90000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205765642c203301312041756720323031362030393a32383a353220474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a66003f481c9162e40a97294800002068746d6c20506600588a3c6162644409183200002f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d66006f8234f87187cd1d006c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c990068bcff2823e70c9fff6b6a943f9f7e7dfbf7f1e7d7bf9f5fb1c2ef6beafcc7d3fd3b7ced646aa34f03a404fa3373a4c64113630efdec27534e7509538d7e32ff657044a8f1bb0c82067f72f71e00", - "45000101a0e9a54000400683540a0901abc0a800021f904004437442f17a4ab3b1501900ed04900000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205765642c203301312041756720323031362030393a32373a353520474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a66003f481c9162e40a97294800002068746d6c20506600588a3c6162644409183200002f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c990068beff2823e70c9f816b6a9847af9ebd7bf8f2e9dbc7af5ff142f06bea0cc4e31d7cfced646aa74f03a444fa3373a4c64113634e7ded28554e7d1953cd7e320365744cb811bc8c82078376ff1e00", -}; - -/* Uncompressed sample packets, sniffed from real communication */ -#define UNCOMPR_PACKETS_LEN 11 -char *uncompr_packets[] = { - "45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a", - "4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27", - "4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0", - "4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01", - "4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01", - "4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a", - "4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20", - "450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a", - "450000e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a", - "450000e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a", - "450000e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a", -}; - -/* Calculate IP Header 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; -} - -/* A simple function to show the ascii content of a packet */ -void show_packet(uint8_t *packet, int len) -{ - int i; - char c; - for (i = 0; i < len; i++) { - c = packet[i]; - if (c >= 0x20 && c <= 0x7E) - printf("%c", c); - else - printf("."); - } - printf("\n"); -} - -/* A struct to capture the output data of compressor and decompressor */ -struct v42bis_output_buffer { - uint8_t *buf; - uint8_t *buf_pointer; - int len; -}; - -/* A simple testpattern generator */ -static void gen_test_pattern(uint8_t *data, int len) -{ - int i; - for (i = 0; i < len; i++) - data[i] = i & 0xF0; -} - -/* 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 tx_v42bis_data_handler(void *user_data, const uint8_t *buf, int len) -{ - /* stub, never used */ - OSMO_ASSERT(false); - return; -} - -/* Handler to capture the output data from the compressor */ -void rx_v42bis_frame_handler(void *user_data, const uint8_t *pkt, int len) -{ - /* stub, never used */ - OSMO_ASSERT(false); - 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; -} - -/* Test V.42bis compression and decompression */ -static void v42bis(const void *ctx, int mode, uint8_t *testvec, int len) -{ - v42bis_state_t *tx_state; - v42bis_state_t *rx_state; - uint8_t *uncompressed_original; - uint8_t *compressed; - uint8_t *uncompressed; - - uncompressed_original = talloc_zero_size(ctx, len); - uncompressed = talloc_zero_size(ctx, len); - - /* Note: We allocate double the size for the compressed buffer, - * because in some cases the compression may increase the amount. - * of data. */ - compressed = talloc_zero_size(ctx, len * 2); - - int rc; - int rc_sum = 0; - struct v42bis_output_buffer compressed_data; - struct v42bis_output_buffer uncompressed_data; - - /* Initalize */ - tx_state = - v42bis_init(ctx, NULL, P0, P1, P2, - &tx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, - &tx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); - OSMO_ASSERT(tx_state); - rx_state = - v42bis_init(ctx, NULL, P0, P1, P2, - &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, - &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); - OSMO_ASSERT(rx_state); - v42bis_compression_control(tx_state, mode); - - /* Setup input data */ - memcpy(uncompressed_original, testvec, len); - - /* Run compressor */ - compressed_data.buf = compressed; - compressed_data.buf_pointer = compressed; - compressed_data.len = 0; - tx_state->compress.user_data = (&compressed_data); - rc = v42bis_compress(tx_state, uncompressed_original, len); - printf("v42bis_compress() rc=%d\n", rc); - OSMO_ASSERT(rc == 0); - rc = v42bis_compress_flush(tx_state); - printf("v42bis_compress_flush() rc=%d\n", rc); - OSMO_ASSERT(rc == 0); - - /* Decompress again */ - uncompressed_data.buf = uncompressed; - uncompressed_data.buf_pointer = uncompressed; - uncompressed_data.len = 0; - rx_state->decompress.user_data = (&uncompressed_data); - rc = v42bis_decompress(rx_state, compressed_data.buf, - compressed_data.len); - printf("v42bis_decompress() rc=%d\n", rc); - rc = v42bis_decompress_flush(rx_state); - rc_sum += rc; - printf("v42bis_decompress_flush() rc=%d\n", rc); - rc_sum += rc; - - /* Check results */ - printf("Mode: %i\n", mode); - - printf("uncompressed_original= %s ASCII:", - osmo_hexdump_nospc(uncompressed_original, len)); - show_packet(uncompressed_original, len); - printf("uncompressed= %s ASCII:", - osmo_hexdump_nospc(uncompressed_data.buf, - uncompressed_data.len)); - show_packet(uncompressed_data.buf, uncompressed_data.len); - printf("compressed= %s ASCII:", - osmo_hexdump_nospc(compressed_data.buf, compressed_data.len)); - show_packet(compressed_data.buf, compressed_data.len); - - rc = memcmp(uncompressed, uncompressed_original, len); - printf("memcmp() rc=%d\n", rc); - rc_sum += rc; - OSMO_ASSERT(rc_sum == 0); - - /* Free buffers and exit */ - v42bis_free(tx_state); - v42bis_free(rx_state); - talloc_free(uncompressed_original); - talloc_free(compressed); - talloc_free(uncompressed); - printf("\n"); -} - -/* Test V.42bis compression and decompression with generated data*/ -static void test_v42bis(const void *ctx) -{ - printf("Testing compression/decompression with generated data:\n"); - uint8_t testvec[1024]; - int len = sizeof(testvec); - gen_test_pattern(testvec, len); - v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); - v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); - v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); -} - -/* Test V.42bis compression and decompression with some TCP/IP packets */ -static void test_v42bis_tcpip(const void *ctx, int packet_id) -{ - uint8_t *testvec; - int len; - printf - ("Testing compression/decompression with realistic TCP/IP packets:\n"); - printf("Packet No.: %i\n", packet_id); - len = strlen(uncompr_packets[packet_id]); - testvec = talloc_zero_size(ctx, len); - len = osmo_hexparse(uncompr_packets[packet_id], testvec, len); - OSMO_ASSERT(len > 0); - v42bis(ctx, V42BIS_COMPRESSION_MODE_DYNAMIC, testvec, len); - v42bis(ctx, V42BIS_COMPRESSION_MODE_ALWAYS, testvec, len); - v42bis(ctx, V42BIS_COMPRESSION_MODE_NEVER, testvec, len); - talloc_free(testvec); -} - -/* Test V.42bis decompression with real, sniffed packets */ -static void test_v42bis_tcpip_decompress(const void *ctx, int packet_id) -{ - uint8_t *compressed; - int compressed_len; - uint8_t *uncompressed; - v42bis_state_t *rx_state; - int rc; - int rc_sum = 0; - int len; - struct v42bis_output_buffer uncompressed_data; - - printf - ("Testing decompression with sniffed compressed TCP/IP packets:\n"); - printf("Packet No.: %i\n", packet_id); - len = strlen(compr_packets[packet_id]); - - uncompressed = talloc_zero_size(ctx, len); - compressed = talloc_zero_size(ctx, len); - - /* Initalize */ - rx_state = - v42bis_init(ctx, NULL, P0, P1, P2, - &rx_v42bis_frame_handler, NULL, MAX_BLOCK_SIZE, - &rx_v42bis_data_handler, NULL, MAX_BLOCK_SIZE); - OSMO_ASSERT(rx_state); - - /* Setup input data */ - compressed_len = - osmo_hexparse(compr_packets[packet_id], compressed, len); - - /* Decompress */ - uncompressed_data.buf = uncompressed; - uncompressed_data.buf_pointer = uncompressed; - uncompressed_data.len = 0; - rx_state->decompress.user_data = (&uncompressed_data); - rc = v42bis_decompress_flush(rx_state); - printf("v42bis_decompress_flush() rc=%d\n", rc); - rc_sum += rc; - rc = v42bis_decompress(rx_state, compressed, compressed_len); - printf("v42bis_decompress() rc=%d\n", rc); - rc_sum += rc; - rc = v42bis_decompress_flush(rx_state); - printf("v42bis_decompress_flush() rc=%d\n", rc); - rc_sum += rc; - - /* Check results */ - printf("compressed= %s ASCII:", - osmo_hexdump_nospc(compressed, compressed_len)); - show_packet(compressed, compressed_len); - printf("uncompressed= %s ASCII:", - osmo_hexdump_nospc(uncompressed_data.buf, - uncompressed_data.len)); - show_packet(uncompressed_data.buf, uncompressed_data.len); - - OSMO_ASSERT(calc_ip_csum(uncompressed_data.buf, 20) == 0); - OSMO_ASSERT(calc_tcpip_csum(ctx, uncompressed_data.buf, - uncompressed_data.len) == 0); - - /* Free buffers and exit */ - v42bis_free(rx_state); - talloc_free(uncompressed); - talloc_free(compressed); - printf("\n"); -} - -static struct log_info_cat gprs_categories[] = { - [DV42BIS] = { - .name = "DV42BIS", - .description = "V.42bis data compression (SNDCP)", - .enabled = 1,.loglevel = LOGL_DEBUG, - } -}; - -static struct log_info info = { - .cat = gprs_categories, - .num_cat = ARRAY_SIZE(gprs_categories), -}; - -int main(int argc, char **argv) -{ - void *v42bis_ctx; - int i; - - osmo_init_logging(&info); - - v42bis_ctx = talloc_named_const(NULL, 0, "v42bis_ctx"); - - test_v42bis(v42bis_ctx); - - for (i = 0; i < UNCOMPR_PACKETS_LEN; i++) - test_v42bis_tcpip(v42bis_ctx, i); - - for (i = 0; i < COMPR_PACKETS_LEN; i++) - test_v42bis_tcpip_decompress(v42bis_ctx, i); - - printf("Done\n"); - talloc_report_full(v42bis_ctx, stderr); - OSMO_ASSERT(talloc_total_blocks(v42bis_ctx) == 1); - return 0; -} - -/* stubs */ -struct osmo_prim_hdr; -int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) -{ - abort(); -} diff --git a/tests/v42bis/v42bis_test.ok b/tests/v42bis/v42bis_test.ok deleted file mode 100644 index 070767473..000000000 --- a/tests/v42bis/v42bis_test.ok +++ /dev/null @@ -1,648 +0,0 @@ -Testing compression/decompression with generated data: -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ -uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ -compressed= 000100000000000000003300040b4e9870f020428409478c58b89021c38633663c7c081162c42143264ea448b1e29429172f62c49871cc988d1b3972ec3867cec78f2041861c3468e44892244b4e9a74f2244a9429478d5ab99225cb96b366bd7c091366cc61c366cea449b3e6b469376fe2c49973dcb89d3b79f2ec396fdecf9f4081062d587028c184098d226cd83029c388119942ac58f129c58c19a562ecd8b12ac79021b1822c59722bc99429bda26cd9322ccb9831c9c2ac59f32ccd9c39d5e2ecd9b32dcfa041e102254ad4e0d1a348952a5ddab4a953a850a34e9d4ad5aad5ab59b36ae5cab5ebd7af60c58a1d5bb6ac59b468d3ae5dcbd6addbb771e3ca9d3b7740ddba07efde5d9837efc3bd7b27f6ed7bf1efdf8d81037f1c3c7864e1c2270f1f5e9938f1cbc58b67366e7cf3f1e39d9123ff0c00 ASCII:..........3...N.p. B..G.X..!..3f<|..b.!C&N.H...)./b..q....9r.8g... A..4h.H.$KN.t.$J.)G.Z..%...f.|..f.a.f..I...i7o...s...;y..9o...@..-Xp(...."l.0)....B.X.)....b...*..!..,Yr+..)..l.2,..1...Y.,..9.....-..A..%J....H.*]...S.P.N.J....Y.j......`...[..Y.h..].....q...;w@.....].7...{'..{..........wb.......8....G..|.......\.xf..7.?..9... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ -uncompressed= 00000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ -compressed= 0001000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f000000000000000000000000000000000101010101010101010101010101010102020202020202020202020202020202030303030303030303030303030303030404040404040404040404040404040405050505050505050505050505050505060606060606060606060606060606060707070707070707070707070707070708080808080808080808080808080808090909090909090909090909090909090a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0 ASCII:................................. 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................................................ 0000000000000000@@@@@@@@@@@@@@@@PPPPPPPPPPPPPPPP````````````````pppppppppppppppp................................................................................................................................ -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 0 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6....@..,....U...@..P. ....Zp..@..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... -uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6....@..,....U...@..P. ....Zp..@..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... -compressed= 4500010236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c6963330062d990358b562ddb3d6beec079e3620f61bb5dbf861d5b36f0e0c287df68bd8366cfd4b369d7ce518b78440b192d820e2d7a1486913551eda0413a02cf9d343076687d1d9b460ead6cecc891bd03070f183472ef0e3e23c78d1c30f098b103a386562b6bd8a4b923a609132b5a8bb05183633451a377603c2113470d1e326ad024451327e81e189b61cca923270d9b37eb4794107c674e0f193236c7d81d870f9a3a60ed288c61460e1c195888d0b72fc3c98e1933d854a931c3a7e4124197c8b1d35a8f1e3d31fac831e34622c5a05856d78141447d9cd656c8f241e290b9c28e1fd9c8105964441534f9c9ac9601256a701bce3fea1851a4be1e9c32a2b04e52bfa70c1b316c8c9852ff7efebb4c8e4c711e63c6082364ef9faf23960d5919469e1c31123c068da0a5e3c44163666c9ca44ed018d5f9350f9aef458fc2401267e21936e6939e4193e68d58345ad5f4791a346800 ASCII:E...6....@..,....U...@..P. ....Zp..@..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, applic3.b..5.V-.=k..y.b.a.]...[6.....h..f...i..Q.xD..-..-z...5Q..A:...40vh}..F..l........4r..>#...0......V+k...#...+Z..Q.c4Q.w`r...H1(..u`.Q.....|.8d...G62D..Q.M~2.e@......:F......(....).F..#.......#S...1.......eCV..'G...A#h.8q....'..4Fu~...{..0...x....g..y#..V5}..... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6....@..,....U...@..P. ....Zp..@..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... -uncompressed= 45000236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6....@..,....U...@..P. ....Zp..@..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... -compressed= 4500010236000700004006cf2cc0a80002550d93d7400000501e200da7c0c95a70801840002e3700000101080a000174140853d489474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d3133012d323030372042726f777365722f4e657446726f6e742f332e332050726f6601696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E...6....@..,....U...@..P. ....Zp..@..7........t..S..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13.-2007 Browser/NetFront/3.3 Prof.ile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 1 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E..@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E..@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E...@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E..@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E..@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -compressed= 45000013060c49026e48c104ac540d5b75268ec33367066880e588d0260203ecbdda0465d08601e65a641830800081050d062450122e013561610402dc5073444d1335550400 ASCII:E.....I.nH...T.[u&..3g.h....&......e....Zd.0......$P...5aa...PsDM.5U.. -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E..@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -uncompressed= 4510004046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E..@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -compressed= 451000014046dd40004006a9a7c0a8646ec0a864640017ad8b81980100f3ac984d801800e32a1600000101080a000647de06d1bf5efffd18fffd20fffd23fffd27 ASCII:E...@F.@.@.....dn..dd...........M....*.........G....^..... ..#..' -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 2 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -compressed= 45000013067849126ec880210958391ab6ea4c9c8767ce0cd000cb11a14d041ed87bb509caa00d03cc25c233600001020b1a0c48a0445c026ac2c808f467402040113949080c58c2260281fd461010386fa809a348fba9583a74c3d200 ASCII:E....xI.n..!.X9...L..g.......M...{.......%.3`......H.D\.j....g@ @.9I..X.&...F..8o...H..X:t... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -uncompressed= 4510005b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E..[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -compressed= 451000015b46de40004006a98bc0a8646ec0a864640017ad8b8198010cf3ac984d801800e3867500000101080a000647df06d1bf61fffb03fffd1ffffd21fffe22fffb05fffa2001fff0fffa2301fff0fffa2701fff0fffa1801fff0 ASCII:E...[F.@.@.....dn..dd...........M.....u........G....a........!.."..... .....#.....'......... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 3 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F.@.@.....dn..dd.......3........_.........G....c... -uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F.@.@.....dn..dd.......3........_.........G....c... -compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F.@.@.....dn..dd.......3........._.........G....c... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F.@.@.....dn..dd.......3........_.........G....c... -uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F.@.@.....dn..dd.......3........_.........G....c... -compressed= 4500001306e848226ec880210958c51ab6ea4c9c8767ce0cd000cb11a14d046cd87bb549d4a00d03cc89d136600001020b1a0c48a0845c026ac2cc0804482000 ASCII:E.....H"n..!.X....L..g.......M.l.{.I.......6`......H..\.j....H . -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F.@.@.....dn..dd.......3........_.........G....c... -uncompressed= 4510003746df40004006a9aec0a8646ec0a864640017ad8b81980133f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E..7F.@.@.....dn..dd.......3........_.........G....c... -compressed= 451000013746df40004006a9aec0a8646ec0a864640017ad8b8198013301f3ac989f801800e35fd700000101080a000647e106d1bf63fffd01 ASCII:E...7F.@.@.....dn..dd.......3........._.........G....c... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 4 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F.@.@.....dn..dd.......6........_.........G....d... -uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F.@.@.....dn..dd.......6........_.........G....d... -compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F.@.@.....dn..dd.......6........_.........G....d... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F.@.@.....dn..dd.......6........_.........G....d... -uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F.@.@.....dn..dd.......6........_.........G....d... -compressed= 4500001306e848326ec880210958c11ab6ea4c9c8767ce0cd000cb11a14d0472d87bb5a9d4a00d03cc89a936600001020b1a0c48a0845c026ac2ce08f4472000 ASCII:E.....H2n..!.X....L..g.......M.r.{.........6`......H..\.j....G . -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F.@.@.....dn..dd.......6........_.........G....d... -uncompressed= 4510003746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E..7F.@.@.....dn..dd.......6........_.........G....d... -compressed= 451000013746e040004006a9adc0a8646ec0a864640017ad8b81980136f3ac98a2801800e35fd200000101080a000647e106d1bf64fffb01 ASCII:E...7F.@.@.....dn..dd.......6........_.........G....d... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 5 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF.@.@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... -uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF.@.@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... -compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d3300386d6a41f3e68d193970d08cb82367c41c3940f1ecb1b97327549e0d6c0600 ASCII:E...tF.@.@..o..dn..dd.......9........{.........G....d..----------------3.8mjA....9p...#g..9@....s'T..l.. -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF.@.@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... -uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF.@.@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... -compressed= 4500001306dc49426ec880210958c919b6ea4c9c8767ce0cd000cb11a14d0478d87bb509d5a00d03ccf9f134600001020b1a0c48a0a45c026ac2ce40680003064e9c3973eac469530b9a376fccc8818366c41d3923e6c8018a678fcd9d3ba1f26c603300 ASCII:E.....IBn..!.X....L..g.......M.x.{.........4`......H..\.j..@h...N.9s..iS..7o....f..9#....g...;..l`3. -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF.@.@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... -uncompressed= 4510007446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E..tF.@.@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... -compressed= 451000017446e140004006a96fc0a8646ec0a864640017ad8b81980139f3ac98a5801800e37b9b00000101080a000647e206d1bf640d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a57656c6c636f6d6520746f20706f6c6c75780d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0d0a0d0a ASCII:E...tF.@.@..o..dn..dd.......9........{.........G....d..------------------..Wellcome to pollux..------------------.... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 6 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF.@.@.....dn..dd.......y..................G....opollux login: -uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF.@.@.....dn..dd.......y..................G....opollux login: -compressed= 451000014246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E...BF.@.@.....dn..dd.......y..................G....opollux login: -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF.@.@.....dn..dd.......y..................G....opollux login: -uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF.@.@.....dn..dd.......y..................G....opollux login: -compressed= 45000013061449526ec8802109588d1ab6ea4c9c8767ce0cd000cb11a14d04f8d87bb509d5a00d03cc759b35600001020b1a0c48a0e45d026ac2e4cc91f3e60d9e3d23dec851c3264e8f110100 ASCII:E.....IRn..!.X....L..g.......M...{.......u.5`......H..].j........=#..Q.&N.... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF.@.@.....dn..dd.......y..................G....opollux login: -uncompressed= 4510004246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E..BF.@.@.....dn..dd.......y..................G....opollux login: -compressed= 451000014246e240004006a9a0c0a8646ec0a864640017ad8b81980179f3ac98a5801800e3dab000000101080a000647ec06d1bf6f706f6c6c7578206c6f67696e3a20 ASCII:E...BF.@.@.....dn..dd.......y..................G....opollux login: -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 7 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E.....@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... -uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E.....@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... -compressed= 45000101a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c203301302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a206600356ad4c899f3078923528c5ce13205c908c58c9d6229f2848991112560c890a1050033432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c990068bcff2823e70c9fff6b6a943f9f7e7dfbf7f1e7d7bf9f3fb1c2ef6beafcc7d3fd3b7ced6468a34f03a404fa3373a4c64113630efdec27534e7509538d7e32ff657044a8f1bb0c82067f72f71e00 ASCII:E......@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 3.0 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: f.5j......#R.\.2......b).....%`.....3C//DTD HTML 3.2 Final//EN">.Directory listing f.or /</titl..h..(#....kj.?.~}.......?...k.....;|.dh.O....3s..A.c...'SNu.S.~2.epD.......r... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E.....@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222....<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>.<title>Directory listing for /..

Directory listing for /

.
..
... -uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E.....@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... -compressed= 45000003088cba4561c880210976ad6bc08080ab61ab061410316948016cbbc6e0ea556b48ac291c06c04b0462c0802557ae4c914123c68c113566c894e20442032b68eae4e1d96384153670e6bc41b3b2a58c1931728c98c2e7ce1a397164d488a18369ce2364eea0017a050f9a17236cc8248247cdcc19349acee0d1e3868d1e33748c5002e54a4e2353bbc6b903e30e9f395e4774dd7347c69a3b70def81861660d993a76d0dc0182e54a12183bf4f245e317c693cf6aa202ad51a346ce9c3f481c9162e40a972948462866ec144b91274c8c8c280143860c2d368c003f72e5c88895509e908d516344123671c8bc018e244a89203f6abf09d2e0c71d36778c0639c2a60e1a3377e4d4e133e20d1b3be1e3a44dc37e848c1f32c28f47e3fd47193967f8fc5f53a3fcf9f4ebdbbf8f3fbffefdfc89157e5f53e73f9eeedfe16b27431b7d1a2025d09f9923350e9a1873e8673f9972aa4b986af493f92f8323428ddf651034f893bbf700 ASCII:E......Ea..!.v.k....a....1iH.l....UkH.)...K.b..%W.L.A#...5f....B.+h....c..6p..A.....1r......9qd....i.#d...z....#l.$.G...4........3t.P..JN#S.......9^Gt.sG..;p...af..:v.....J..;..E.....j...Q.F..?H..b...)HF(f..K.'L..(.C..-6..?r....P...QcD.6q....$J. ?j......6w..9....3w...3...;...M.~...2..G..G.9g.._S........?......~_S.?....k'C.}. %...#5...s.g?.r.K.j.../.#B..e.4..... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E.....@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... -uncompressed= 450001a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c2033302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E.....@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 30 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing for /..

Directory listing for /

.
..
... -compressed= 45000101a0b41140004006b8e80a0901abc0a800021f904002d5b860b5bab240ae501900ed861d0000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205475652c203301302041756720323031362030393a34333a303720474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E......@.@.............@...`...@.P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Tue, 3.0 Aug 2016 09:43:07 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222.....Directory listing f.or /..

Directory listing for /

.
..
... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 8 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 450000e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a ASCII:E.....@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8ec0".... -uncompressed= 450000e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a ASCII:E.....@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8ec0".... -compressed= 45000100e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e312033013034204e6f74204d6f646966016965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d3432373638613865633865990066669478fa3400 ASCII:E......@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 3.04 Not Modif.ied..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8e..ff.x.4. -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 450000e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a ASCII:E.....@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8ec0".... -uncompressed= 450000e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a ASCII:E.....@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8ec0".... -compressed= 450000030694d3e461c8001d090abcc102c192b661ab061418306588121282b894606600cfa7411b06fc91728b2001020b1a50b0128dc78017f9d62db972658a0c1a31688cb031e3c6882872ee8c8022e70c9b346cd09c81d0e008993b687a8cb88207cd0b9f334610c1a366448d1934728c20dbc3468e1e37b82a8172e5a9153475f2ccad4a640e19336bd03c3522274e1c3466eeb0015cd5091a3473601079c3a6eed3c48b1b3fae5bb5301c3472f0dc0152432b1c327b80d0983163c6532457c8a8a95ae286991d6468dce001e3460e34b76be8c8217bc760e066669478fa3400 ASCII:E.......a...........a....0e......`f...A....r. ....P........-.re...1h..1...(r..."...4l.......;hz.......3F...fD..4r. ..F..7.*.r...4u...Jd..3k.<5"'N.4f...\...4s`.y.......?.[.0.4r...RC+.2{...1c.S$W...Z....dh....F.4.k..!{.`.ff.x.4. -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 450000e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a ASCII:E.....@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8ec0".... -uncompressed= 450000e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a ASCII:E.....@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8ec0".... -compressed= 45000100e2971b40003706026c550d93d7c0a8000200504047217f5922c903759c8018007c4fb400000101080a1153ce39002cf6e8485454502f312e312033013034204e6f74204d6f646966016965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613134392d3436652d34323736386138656338656330220d0a0d0a ASCII:E......@.7..lU........P@G!.Y"..u....|O........S.9.,..HTTP/1.1 3.04 Not Modif.ied..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a149-46e-42768a8ec8ec0".... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 9 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 450000e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E...$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -uncompressed= 450000e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E...$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -compressed= 45000100e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e312033013034204e6f74204d6f646966016965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E....$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 3.04 Not Modif.ied..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 450000e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E...$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -uncompressed= 450000e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E...$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -compressed= 4500000306943b416fc8001d09ee64c202c192b661ab0614183065c8124b8adccd63766087a8411b06fc79a7852001020b1a50b0228dc08017fbfe2db972658a0c1a31688cb031e3c6882872ee8c8022e70c9b346cd09c81d0e008993b687a8cb88207cd0b9f334610c1a366448d1934728c20dbc3468e1e37b82a8172e5a9153475f2ccad4a640e19336bd03c3522274e1c3466eeb0015cd5091a3473601079c3a6eed3c48b1b3fae5bb5301c3472f0dc0152432b1c327b80d0983163c6532457c8a8a95ae286991d646cec980143760e18376ae8c8b14307991a357cd72ef1f46900 ASCII:E.....;Ao.....d.....a....0e..K...cv`..A...y.. ....P."......-.re...1h..1...(r..."...4l.......;hz.......3F...fD..4r. ..F..7.*.r...4u...Jd..3k.<5"'N.4f...\...4s`.y.......?.[.0.4r...RC+.2{...1c.S$W...Z....dl...Cv..7j...C...5|....i. -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 450000e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E...$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -uncompressed= 450000e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E...$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -compressed= 45000100e224f1400037067496550d93d7c0a80002005040489387ebf0c904389f8018007cec5700000101080a1153cf01002cf8fc485454502f312e312033013034204e6f74204d6f646966016965640d0a446174653a205475652c2033302041756720323031362031363a33363a343020474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338613338302d3861362d34323736383761323236383830220d0a0d0a ASCII:E....$.@.7.t.U........P@H......8....|.W.......S...,..HTTP/1.1 3.04 Not Modif.ied..Date: Tue, 30 Aug 2016 16:36:40 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8a380-8a6-427687a226880".... -memcmp() rc=0 - -Testing compression/decompression with realistic TCP/IP packets: -Packet No.: 10 -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 0 -uncompressed_original= 450000e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -uncompressed= 450000e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -compressed= 45000100e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e312033013034204e6f74204d6f646966016965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E.....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 3.04 Not Modif.ied..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 1 -uncompressed_original= 450000e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -uncompressed= 450000e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -compressed= 450000030694cb4566c8001d09cca1c002c192b661ab061418306508137fb9f8fc628620c4a9411b06fc71d78e2001020b1a50b022eddb8017006f2db972658a0c1a31688cb031e3c6882872ee8c8022e70c9b346cd09c81d0e008993b687a8cb88207cd0b9f334610c1a366448d1934728c20dbc3468e1e377a2a8172e5a9153475f2ccad4a640e19336bd03c3522274e1c3466eeb0015cd5091a3473601079c3a6eed3c48b1b3fae5bb5301c3472f0dc0152432b1c327b80d0983163c6532457c8a8a95ae286991d34d29e81416347ed1b387688453383478e1d40679478fa3400 ASCII:E......Ef...........a....0e......b. ..A...q.. ....P.".....o-.re...1h..1...(r..."...4l.......;hz.......3F...fD..4r. ..F..7z*.r...4u...Jd..3k.<5"'N.4f...\...4s`.y.......?.[.0.4r...RC+.2{...1c.S$W...Z....4...AcG..8v.E3.G..@g.x.4. -memcmp() rc=0 - -v42bis_compress() rc=0 -v42bis_compress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -Mode: 2 -uncompressed_original= 450000e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -uncompressed= 450000e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e3120333034204e6f74204d6f6469666965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 304 Not Modified..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -compressed= 45000100e2b66140003706e325550d93d7c0a8000200504049fbb679bcc9051ea48018007cebea00000101080a1153cfdc002cfdb4485454502f312e312033013034204e6f74204d6f646966016965640d0a446174653a205475652c2033302041756720323031362031363a33363a343120474d540d0a5365727665723a204170616368650d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4b6565702d416c6976653a2074696d656f75743d322c206d61783d313030300d0a455461673a2022346338313336642d3138642d34353832306530393638303430220d0a0d0a ASCII:E.....a@.7..%U........P@I..y........|.........S...,..HTTP/1.1 3.04 Not Modif.ied..Date: Tue, 30 Aug 2016 16:36:41 GMT..Server: Apache..Connection: Keep-Alive..Keep-Alive: timeout=2, max=1000..ETag: "4c8136d-18d-45820e0968040".... -memcmp() rc=0 - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 0 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h....@.......U...@..PF,{...u:..@............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... -uncompressed= 45000268000700004006cefac0a80002550d93d740000050462c7ba7e4d1753a80184000aad500000101080a0001a670084dafb4474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h....@.......U...@..PF,{...u:..@............p.M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 1 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992becf8918d0c9145465441939fcc6a1950a206b7e1fca38e1145eaebc129230aeb24f57bcab011c3c68829f5efe7bfcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0085a3a4e1c3466c6c649ea048d519d5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622e7fa7dac30ac602f9af40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h....@.......U...@..PF,{...u:..@.~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.{......).........1f.0B...:b...a...#.c..Z:N.4f..I...Q._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.`/.....#jT&.G...9F.......5x.P..J.... -uncompressed= 45000268000900004006cef8c0a80002550d93d740000050462c7ba7e4d1753a801840007e7f00000101080a0001d1cc084db0ae474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h....@.......U...@..PF,{...u:..@.~............M..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 2 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h....@.......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... -uncompressed= 45000268000b00004006cef6c0a80002550d93d740000050462c7ba7e4d1753b80193fff131c00000101080a00022884084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h....@.......U...@..PF,{...u;..?...........(..M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 3 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005ab97a052b960d59b368d5b2ddb3e60e9c372ef610b6dbf56bd8b165030f2e7cf88dd63b68f64c3d9b76ed1cb58847b490d122e8d0a24761185913d50e1aa423f0dc49036387d6d7b169e4d0cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a68b5b2864d9a3b629a30b1a2b5081b35384613357a07c6133271d4e021a3064d52347182ee81b119c69c3a72d2b079b37e4409c177e6f4902163738cdd71f8a0a903d68ec21866e4c0918185087dfb329cec9831834d951a337c4a2e1174891c3badf5e8d113a38f1c336e24520c8a65751d1844d4c7696d852c1f240e992be4e8918d8c9045465441939fcc6a1950a206b7e1dca38e1145eaebb929230aeb24f579cab011c3c68829f5efe7afcbe4c814e731668c3042f6fef93a62d9909561e4c91123c163d0084a3a4e1c3466c6c649ea048dd19c5ff3a0f95ef4280c2471269e61633ee9193469de8845a3554d9fa74199c48622c7fa7dac30ac5c2f9af40a1ef0236a502682478dff913946d0a8d1c3c68d1e35788c5002e54ad0a00100 ASCII:E...h....@.......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.Z.z.+..Y.h.......7......k..e...|...;h.L=.v....G..."...Ga.Y.....#..I.c....i.......;p..A#...3r......;0jh...M.;b.0.....58F.5z...2q..!..MR4q.......:r..y.~D..w...!cs..q........f......}.2...1.M..3|J..t..;........3n$R..eu..D..im.,.$..+......EFTA...j.P........E...)#..$.y......).........1f.0B...:b...a...#.c..J:N.4f..I....._...^.(.$q&.ac>..4i..E.UM..A..."..}.0.\/.....#jP&.G...9F.......5x.P..J.... -uncompressed= 45000268000c00004006cef5c0a80002550d93d740000050462c7ba7e4d1753b80193fff65ab00000101080a0002d5f4084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h....@.......U...@..PF,{...u;..?.e............M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 4 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-....@..^........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e@9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... -uncompressed= 4500022d000f00004006ac5ec0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-....@..^........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 5 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-....@..]........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e@9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... -uncompressed= 4500022d001000004006ac5dc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-....@..]........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 6 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-....@..\........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e@9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... -uncompressed= 4500022d001100004006ac5cc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-....@..\........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 7 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-....@..[........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e@9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... -uncompressed= 4500022d001200004006ac5bc0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-....@..[........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 8 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d6978656433005bbb7e0d3b964dd9b369d7b6ddb3e60e9c372ef614beeb15ac58b2660513368cf8cdd63b68f65045ab96ed9cb58947b490d1422851a34861185923d50e9aa423f0dc490363c756d8b269e4d8cac68e9cd93b70f0804143376fe13372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b353848173d7a07c6133271d4e021a3068d52347184ee81c119c69c3a72d2b079c37e4489c177e6f4902183730cde71f8a0a913d6cec21866e4c091818548fdfb329cec9831834d951a337e4e2e2174891c3baef5e8d113a38f1c336e2656148a85751d1844d6c7716da52c1f240f9b2fecf8918d0c9145465441a39f0c6b1950a40ab7f1fca38e1145ecebc129234aeb24f67bcab011c3c68829f6f1ebb7cbe4c894e731668c3052163ffa3a63d9949561e4c91123c263d0105a3a4e1c3466c8c651ea04cd519d60f3a0016f14290c2471289e61735ee9193469de8c45b3554d1fa84299c88622e73afeac30ac6037aaf40a9ef0236a54268247cd7f923946d0a8d1c3c68d1e35788c5002e58a50a10100 ASCII:E...h....@.......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.[.~.;.M..i.......7.......X.f..6....;h.PE......G...B(Q.Ha.Y#....#..I.c.V..i.......;p..AC7o.3r......;0jl...M.;b.0.....58H.=z...2q..!...R4q.......:r..y.~D..w...!.s..q........f.....H..2...1.M..3~N.!t..;........3n&V...u..D..qm.,.$../......EFTA...k.P........E...)#J.$.{......).........1f.0R.?.:c...a...#.c..Z:N.4f..Q...Q.`...o.).$q(.as^..4i..E.UM..B...".:..0.`7.....#jT&.G...9F.......5x.P...P... -uncompressed= 45000268001300004006ceeec0a80002550d93d740000050462c7ba7e4d1753b80193fff7b4a00000101080a0003c054084dc558474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a49662d4d6f6469666965642d53696e63653a205475652c2032332041756720323031362031323a33343a323920474d540d0a0d0a ASCII:E..h....@.......U...@..PF,{...u;..?.{J.........T.M.XGET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..If-Modified-Since: Tue, 23 Aug 2016 12:34:29 GMT.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 9 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-....@..Y........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e@9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... -uncompressed= 4500022d001400004006ac59c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-....@..Y........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 10 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e33005cbd8215bb67cd1d386f5cecd1cb766ad5ab59b7decdbbb7ef1ba877d0ec49daf56bd83960fd8e6821a3c5cd9c3b7bc230b2e6a81d343e47e0b99306c60ea8a54fd3c801958d1d39a877e0e00183c6ebd8b767e4b89103061e337660d4806a650d9b3477c4346162056a11366a7064d6c9f30e8c2764e2a8c143460d9a9f68e2dcdc0323328c3975e4a461f326fc881278efcce9214346e418b1e3f04153c7aa9dfd31ccc88123030b11f5ec6538d93163069b2a3566d0445ce2e612397646d398118347cd9a3a68f49848f12696d0756010011f67b415ad7c90fc17be5f224536322e16195105cd7b32a16540397adb06718a3a461459afe7a58c28a293acb729c3460c1b23a6ac6ffffe2d93235388c79831c288d6f6ddeb6065a355869127478cdcae79b3739c3868cc648df3d3091a9e31abe641537d674f1848e2203cc386fbcf3368d2bcc18a06aa9a3e456fde0c00 ASCII:E...-....@..X........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application3.\....g..8o\...vj..Y........w..I..k.9`..h!....;{.0....4>G........O......9.w........g......3v`..je..4w.4ab.j.6jpd.....'d...CF...h....#2.9u..a.&...x...!CF.....AS....1...#.....e8.1c..*5f.D\...9vF....G..:h..H.&..u`...g...|...._"E62...Q..{2.e@9z..q.:F.Y....(....).F..#..o..-.#S...1......`e.U..'G...y.s.8h.d......1..AS}gO.H. <....3h.......>Eo... -uncompressed= 4500022d001500004006ac58c0a800020a0901ab40011f4046a2f5a8e0a618025018400093480000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383030300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..-....@..X........@..@F.......P.@..H..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8000..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 11 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d69786564330057b36eedfa954dd8b165cfa6ddb3e60e9c372ef6049eab95ab57b062fd02164cf8cdd53b68f640256b16ed9cb38547b490d1e22791a043efc030b2c6a91d344547e0b99306c68eabad5fd3c871958d1d39b077e0e00183c6eddcbf67e4b89103061e337660d4b86a650d9b3477c4346162e56a11366a7080164d14c6133271d4e021a3068d5134717eee818119c69c3a72d2b079837e4489bf77e6f4902103738cdc71f8a0a9d3d58ec11866e4c091818548fcf9329cec9831834d951a33783e2ef173891c3bab69cc88c1a3674f1d347a6cdcf8134bea3a30889c8fb3da4a583e48162a37a891231b19208b8ca882c63e99d432a038fd6d8339471d238ac8d793534614d549e40b956123868d1153e4d3b77f97c99129cc63cc1861242c7df275beb2092bc3c89323467ef7fc693a4e1c3466c0c631ea04cdd09d5cf3a0e96e66e81d1848e2403cc366bcd13368d2bcf98ae6aa9a3e4c7ffe0c00 ASCII:E...9....@..\........@.......A.H...@.......A.H.A.JD..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed3.W.n...M..e.......7.......W.b...L...;h.@%k.....G....'..C..0....4EG........_..q...9.w........g......3v`..je..4w.4ab.j.6jp..M...2q..!...Q4q~......:r..y.~D..w...!.s..q........f.....H..2...1.M..3x>..s..;.i....gO.4zl...K.:0.....JX>H.*7..#.. .....>..2.8.m.9G.#....SF..I...a#...S.......).c..a$,}.u...+...#F~..i:N.4f..1.....\...nf...H.@<.f..3h.......>L.... -uncompressed= 45000239000500004006ac5cc0a800020a0901ab40001f90c286afa741a348cb801840007fcb0000050a41a348dc41a34a440000474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a2031302e392e312e3137313a383038300d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..9....@..\........@.......A.H...@.......A.H.A.JD..GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: 10.9.1.171:8080..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 12 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001025b000a00004006ac35c0a800020a0901ab40011f90c293b0a8af5e58be5018400072a60000474554202f72656470686f6e652e706e6720485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c33005cbd82154b368e59b46ad9ee597307ce1b177b066fedfa35ec583665010b266cf8cdd63b68f6543d9b76ed1cb58747b490d16268d1a34961185933d50e1aa523f0dc490363c7d6d7b169e4d8cac68e1cd93b70f0804123f7eee03372dcc801038f193b306a6cb5b2864d9a3b629a30b1b2b5081b3538461b457a07c6133238f190518366299a3843f7c0d80c634e1d3969d8bc513fa244e03b737ac890b139c6ee387cd0d4096b07610c3372e0c8c042647e7d194e76cc98c1a64a8d1940259718ba448e9dd63466c4e01134a80e1a3d38721c8a65751d1844d2c7696d65261f240d9923dcd8918d0c9045465441839fcc6a1950a606b7e1bca38e1145e8ebd929230aeb24f485cab011c3c68829f4ede3d7cbe4c814e731668c3032d3be1a3c75c6b2296be4c91123c1830e451d270e1a3364e32c758206694fb079d07c3f9a1406923812cfb0c1b9f40c9a346fc6a2d9aaa64fd4a175d33064b894bfff812b5bc2a421b3e60c8e32860e0d00 ASCII:E...[....@..5........@........^X.P.@.r...GET /redphone.png HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed,3.\...K6.Y.j..Ys....{.o..5.X6e..&l...;h.T=.v....G...bh..Ia.Y3....#..I.c....i.......;p..A#...3r......;0jl...M.;b.0.....58F.Ez...28..Q.f).8C....cN.9i..Q?.D.;sz...9..8|...k.a.3r...Bd~}.Nv....J..@%...D...4f...4...=8r..eu..D..ime&.$..#......EFTA...j.P........E...)#..$........).........1f.02.......;h.TM......G...bh..Ia.Y3....#..I.c....i.......;p..Acw..3r......;0jp...M.;b.0.....58J.Ez...2q..!...R4q.......:r..y.~D..w...!.s..q...#....f......}.2...1.M..3.R.1t..;........3n(Z...u..D..ym.,.$..3......EFTA..Lk.P........E...)#..$.}......).........1f.0b6..:d...a...#.c..j:N.4f..Y.....a....4).$q*.a.~..4i..E.UM..C... -uncompressed= 45000236003000004006cf03c0a80002550d93d740020050c30e84a9441d06ac80184000c2f400000101080a00052df410fc31bd474554202f20485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a0d0a ASCII:E..6.0..@.......U...@..P....D.....@...........-...1.GET / HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 15 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d33006fcede41b3072c5dbb78e7dcad3ca2858c164ea14aa50ac3c81aaf76d0541d81e74e1a183bcef2f64d23c7593676e4fcde8183070c1ac6913b9f91e3460e187884c2a871d6ca1a3669ee8869c2c4cad9226cd4e0801d75ea1d184f7caac143460d1aab68e238dd0303358c3975e4a461f3c6fe88128fefcce9214306ea18c8e3f04153a7edd0b841e5c0918185c87f83329cec9831834d951a33967e2ee174891c3bbaf5e8d113a38f1c336e3ac2718a05771d1844eac7d16d252e1f241985563489928d8c954546544193900c6e1950bc3ab7a11da58e11450aea292a234aee240595cab011c3c68829050f2624cce4c814ed31668c3012f7a0fc3a6fd9c49561e4c91123ce63d0702a3b4e1c3466e0c6b1ea04cdd4a36cf3a0592f952a0c2471ccc839c3268e1aab67d0a479f316cd59357db83af59b062346ab0d1f46b47933e7ce9e329c3a0d00 ASCII:E...`.E..@.......U...@..P..O....)..@.W.........5...4.GET /nirvana.css HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xm3.o..A..,].x...<....N.J......v.T...N..;...M#.Y6v..........;...F..x...q...6i..i...."l....u...O|..CF...h.8...5.9u..a.........!C......AS....A........2...1.M..3.~..t..;........3n:.q..w..D...m%..$..V4.....EFTA...n.P.:......E..)*#J.$........)..&$.....1f.0....:o...a...#.c.p*;N.4f........l..Y/.*.$q..9.&...g..y...Y5}.:...#F...F.y3...2.:.. -uncompressed= 45000260004500004006cec4c0a80002550d93d740030050c3134faac89c8b2980184000578d00000101080a000535c010fc34c8474554202f6e697276616e612e63737320485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..`.E..@.......U...@..P..O....)..@.W.........5...4.GET /nirvana.css HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 16 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300952fbf517b07cd1e9f77f3ee9da317f38816325a48a56a152b0c236bc4da419375049e3b6960ec50fb3b388d1c6ad9d891237c070e1e3068245f1e7d468e1b3960e0316307460db556d6b04973474c132656d4f254836376d5ab7760008da3060f193568b4a28923750f8cd530e6d4919386cd9bfc234a48be33a7870c19ab632c8fc3074d1db87630c63023078e0c2c440c2294e164c78c196caad498f1547409a94be4d8e9ad478f9e187de498710352a4542cbbebc020823f4e6f2b74f920e1c81da34a966c64bc2c32a20a1a866476cb802236ba0def2c758c2872500f521951782739d854868d1836464c39a89061612647a6788f31638411ba0aebd791cb86ae0c234f8e18891e838654da71e2a03133378e562768ae2a7d9b078d7bab5861208913f20c1bfa5acfa049f3462e1ab56afa80950a38cdc68d5a214aa4a873e74fa144474a951a00 ASCII:E...d.F..@.......U...@..P..[.!..a..@..-........5...4.GET /8-Bit/Label.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3../.Q{....w........2ZH.j.+.#k..A.u..;i`.P.;8..j...#|...0h$_.}F..9`.1c.F..V..IsGL.&V..T.cv..w`......5h...#u...0........#JH.3.....c,...M..v0.0#...,D."..d...l....Tt..K....G...}..q.R.T,... .?No+t. ....J.ld.,2....dv.."6...,u.(rP.R.Qx'9.T...6FL9..aa&G.x.1c...........#O......T.q..137.V'h.*}...{.Xa ......Z..I.F...j....8...Z!J..s.O.DGJ... -uncompressed= 45000264004600004006cebfc0a80002550d93d740040050c3135bab2189da61801840008f2d00000101080a000535c410fc34dc474554202f382d4269742f4c6162656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..d.F..@.......U...@..P..[.!..a..@..-........5...4.GET /8-Bit/Label.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 17 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010264005800004006ceadc0a80002550d93d740050050c31389acaf7b26538018400075c900000101080a000537d010fc354a474554202f382d4269742f41636f726e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf497b07cd1e9f76f1ea9d93f7f28816325a48a56af50e0c236bc2da418375049e3b6960ec48eb1b388d1c69d9d891137c070e1e306820570e7d468e1b3960e0316307468db456d6b04973474c132656d2f2548343b699aa57613c2113470d1e326ad064451347ea1e18aa61cca923270d9b37f94794887c674e0f193254c7501e870f9a3a6fed608c11148e0c2c440c2294e164c78c196caad498f1347409a94be4d8e1ad478f9e187de4987103520e1ca95874d78141047f1cde56e6f241c2713bc6942bd9c87059644415340cc9e89601252c741bdd57ea1851e4a09ea432a2ec4e72d0a90c1b316c8c9872502143c34c8e4ce91e63c608237315d6af1397cd5c19469e1c31023d060da9b4e3c44163466e9cac4ed0585dea360f9af6efefc0401227e81936f4b39e4193e64d5c3469d5f4f92a15709a8d1bb342944831a7ce9e42898a942a3500 ASCII:E...d.X..@.......U...@..P.....{&S..@.u.........7...5JGET /8-Bit/Acorn.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.I{....v........2ZH.j...#k..A.u..;i`.H..8..i....|...0h W.}F..9`.1c.F..V..IsGL.&V..T.C...Wa#...0......Z+k...#...+kw..A.*.;0.......5h...3u...0........#JP.3.....c0...M..v6.0#...,D.2..d...l.....t..K....G...}..q3..T,... .?.o+u. ..}c..ld.,2....dx..2V.../u.(.P.S.Qz'Q(U...6FLQ..ab&G.|.1c...........#O........q..1C7.V'h.:......Ya .C....[..I.f...j...:8.G.['V....P.HMN... -uncompressed= 45000266007600004006ce8dc0a80002550d93d740060050c31431ada11fa06780184000f08e00000101080a00053b3c10fc35ef474554202f382d4269742f416d73747261642e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..f.v..@.......U...@..P..1....g..@...........;<..5.GET /8-Bit/Amstrad.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 19 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010264007700004006ce8ec0a80002550d93d740040050c3135ddb2189e0108018400060d600000101080a00053b4010fc35e7474554202f382d4269742f41746172692e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300932bbf497b07cd1e9f76f1ea9d93d7f28816325a48a56a152b0c236b84da419375049e3b6960ec48dbfb378d1c69d9d891037c070e1e30681c4ffe7c468e1b3960e0316307468db456d6b04973474c132656d2f254832376d5ab77603c2113470d1e326ad068451347ea1e18a961cca923270d9b37f84794807c674e0f193252c7481e870f9aa1da2fc63023078e0c2c440a1e94e164c78c196caad498f1147409a94be4d8d9ad478f9e187de49871e311a4542cb9ebc020723fce6e2b73f920d968e7224a956c64b42c32a20a9a856472cb8022f4b90dee2a758c286250cf511951742731c854868d1836464c31887061612647a6708f31638491b908e9d789cb66ae0c234f8e18791e8386d4d971e2a03123378e562768ae26759b070d7bab58612089f3f10c9bf95acfa049f3262e9ab46afa8095fa378d468d5a1f469c8833e7ce9f41434a951a00 ASCII:E...d.w..@.......U...@..P..].!.....@.`.........;@..5.GET /8-Bit/Atari.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..+.I{....v........2ZH.j.+.#k..A.u..;i`.H..7..i....|...0h.O.|F..9`.1c.F..V..IsGL.&V..T.#v..w`4..6.GET /8-Bit/Apple.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.Q{....v........2ZH.j.+.#k..A.u..;i`.P..7..j....|...0h.O.|F..9`.1c.F..V..IsGL.&V..T.#v..w`4..6.GET /8-Bit/Apple.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 21 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009631bf597b07cd1e9f8df5f2d59379440b192da656bd9a1586913563eda0d13a02cf9d343076ac052e9c468eb56cecc819be03070f18349433973e23c78d1c30f098b103a3c65a2b6bd8a4b923a609132b6b79aac141db2ad63b309e9089a3068f50345bd1c499ba07c6631873eac849c3e68dfe112526df99d343868cc73198c7e183a64e5c3b1963989103470616220715ca70b263c60c36556acc804abac4d42572ecf8d6a3474f8c3e72ccb80939722a16de75601051c3dfb715a27c9074ec9e71654b363260161951054d4332bc6540192bddc6f7963a461441a847a98c28bd93208ce3d3460c1b23a6205cd89030932353bec79831c208d185f7ebcc6553d7c8932346a4c7a03175769c3868ccd08db3d5091aac4ce1e641f3fe6a561848e2883cc3c6fed63368d2bc998b66ad9a3e61a7fe4dc391e3d688132beeec0974a8519253a70600 ASCII:E...e.}..@.......U...@..P.....{)g..<...........>4..6.GET /8-Bit/Dragon.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..1.Y{.........yD..-.V.....5c...:...40v....F..l........4.3.>#...0......Z+k...#...+ky..A.*.;0......P4[......c.s..I.....%&...C...1.....N\;.c...G.."...p.c..6Uj..J...%r....GO.>r...9r*..u`.Q.....|.t..qeK62`..Q.MC2.e@.+....:F.A.G..(.. ...F..#. \..0.#S...1.......eS...#F...1uv.8h........L..A..jV.H..<....3h....f..>a..M......+...t.Q.S... -uncompressed= 45000265007d00004006ce87c0a80002550d93d740050050c3138bdcaf7b296780183cec0de600000101080a00053e3410fc368e474554202f382d4269742f447261676f6e2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..e.}..@.......U...@..P.....{)g..<...........>4..6.GET /8-Bit/Dragon.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 22 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010269008000004006ce80c0a80002550d93d740060050c3143301dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f6600952f67defcc66dd03d3df7f6fd3bc72fe7112d64b4b08a552b571846d6983dda75049e3b6960ec701b7c388d1c6e8dca21be03070f183496db694e63468e1b3960e0316307460db756d6b04973474c132656dcee5483c376d6ad77603c2113470d1e326ad0784513c7ea1e18ae6110959386cd1bfe234a58be33a7870c19ae63548fc347285d3b1b63989103470616220ad3c870b263c60c36556acc986aba84d52572ecfcd6a3474f8c3e72ccb81149d22a96a3756010d91fe7b715bc7c90d4f9b891a54b36326216195105cd4332476540312bdd0678973a4614a923478f531951d0dc49d299aa0c1b316c8c98d2b9e143c64c8e4c011f63c60823781be2af63970d5e19469e1c31223d060dabbce3c44163e66e1caf4ed06c853a370f1af85ab9c2401267e41936f7bd9e4193e68d5d346ed5f4216bd5701aa142bd4eac78d1e7cfa1489596b46a3500 ASCII:E...i....@.......U...@..P..3........<.+]........A,..7aGET /8-Bit/Enterprise.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/f../g...m.==...;./..-d...U+W.F..=.u..;i`.p.|8..n..!.....4..iNcF..9`.1c.F..V..IsGL.&V..T..v..w`r...I.*..u`.......|......K62b..Q..C2Ge@1+..x.:F..#G.S.Q..I.....1l.....C.L.L..c..#x...c..^.F..1"=......Ac.n..N.l.:7...Z..@.g..6...A...]4n..!k.p..B.N.x....H...j5. -uncompressed= 45000269008000004006ce80c0a80002550d93d740060050c31433dfa11fa3de80183c892b5d00000101080a0005412c10fc3761474554202f382d4269742f456e74657270726973652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..i....@.......U...@..P..3.......<.+]........A,..7aGET /8-Bit/Enterprise.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 23 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f3300952f67defcc6ed1d347b7ceeedfb778e5fce235ac8686115ab56ae308cac316b074dd71178eea481b1c3edf0e23472b86563478ef11d3878c0a0d1fc79f519396ee48081c78c1d1835dc5a59c326cd1d314d985871cb530d8edb59b7de81f1844c1c3578c8a841e3154d1cab7b60bc8631a78e9c346cdef81f51c2f29d393d64c8781de3791c3e68ead0b5d3318699a032b01061e85086931d3366b0a95263c654d325ac2e916327b81e3d7a62f49163c64dc9a056b1fcae038348ff38c1ade0e5832424f88e2e61b29131b3c8882a682292f92d038ad9ea36c4c3d431a248433d4c6544019ea46154193662d81831a5e1c38889991c99223ec68c1146f03ed45fc72e1bbc328c3c3962a47a0c1a5671c78983c6ccdd385e9da0d9ea746e1e34f2b5728581248ec9336cf27b3d8326cd1bbb68dcaae943d62ae13420417aad78312350a1448d228523c3aad500 ASCII:E...h....@.......U...@..P..`.!.....=..k........A...7.GET /8-Bit/Commodore.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/3../g.....4{|...w._.#Z.ha..V.0..1k.M..x........4r.ecG...8x....y..9n.......5.ZY.&..1M.Xq.S...Y.....L.5x..A..M..{`..1...4l...Q...9=d.x..y.>h....1...2..a.P...3f..Rc.T.%...c'..=zb..c.M..V.....H.8.....$$...a..1...*h"..-....6...1.HC=LeD...aT.6b..1........">...F.>._....2.<9b.z..Vq......8^....tn.4..r..$..3l.{=.&...h...C.*.4 Az.x1#P.D.".#.... -uncompressed= 45000268008100004006ce80c0a80002550d93d740040050c313600b2189e30280183d0e896b00000101080a000541d810fc379d474554202f382d4269742f436f6d6d6f646f72652e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..h....@.......U...@..P..`.!.....=..k........A...7.GET /8-Bit/Commodore.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 24 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330096dfa4bd83668f4fbb78f5cec97b79440b192da24ead7a1586913561eda0c13a02cf9d343076a4f50d9c468eb46cecc809be03070f1834902b873e23c78d1c30f098b103a3465a2b6bd8a4b923a609132b6979aac1219baad53b309e9089a3060f193568b2a28913750f0cd530e6d4919386cd9bfc234a44be33a7870c19aa63288fc3074d9db77630c63023078e0c2c440c2294e164c78c196caad498e1347489a84be4d8e1ad478f9e187de49871035264542cbaebc020823f0e6f2b73f920e1b81da34a966c64bc2c32a20a1a866474cb801216ba8dee2c758c287250cf511951762739c854868d1836464c39a89021612647a6748f31638491b90aebd789cb66ae0c234f8e18811e8346d4d971e2a03123374e562768ac26759b074dfbaa5761208913f20c1bfa59cfa049f3262e9ab46afa7c8dfa37cdc68d59214aa4a873e7cfa04347468d1a00 ASCII:E...c....@.......U...@..P.....{,...9b./........B...8"GET /8-Bit/EACA.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f.O.x...{yD..-.N.z...5a...:...40v....F..l........4.+.>#...0.....FZ+k...#...+iy..!...;0.......5h....u...0........#JD.3.....c(...M..v0.0#...,D."..d...l....4t..K....G...}..q.RdT,... .?.o+s. ....J.ld.,2....dt.......,u.(rP.Q.Qv'9.T...6FL9..!a&G.t.1c........f..#O.....F..q..1#7NV'h.&u..M..Wa ......Y..I.&...j.|..7...Y!J..s...CGF... -uncompressed= 45000263008200004006ce84c0a80002550d93d740050050c3138e0daf7b2cf180183962cb2f00000101080a000542b410fc3822474554202f382d4269742f454143412e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..c....@.......U...@..P.....{,...9b./........B...8"GET /8-Bit/EACA.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 25 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa0bd83668fcfba77f3cec16b79440b192da04aa56a1586913560eda0b93a02cf9d343076a0edfd9b460eb46cecc801be03070f18348e277f3e23c78d1c30f098b103a3065a2b6bd8a4b923a609132b6879aac1117b6ad53b309e9089a3060f193568b0a28903750f8cd430e6d4919386cd1bfc234a40be33a7870c19a963248fc3074d1db7762ec63023078e0c2c440a1e94e164c78c196caad498d1147409a84be4d8d9ad478f9e187de49871f33124542cb9ebc020723fce6e2b72f920d9a8fd62ca956c64b82c32a20a9a856472cb8002f6b90dee2b758c2862508f511951742731b854868d1836464c318870e1602647a6708f31638411b908e9d781cb46ae0c234f8e18791e830654d971e2a03113370e562768aa226d9b070d7baa5661208903f20c9bf958cfa049f3062e1ab46afa7885ea378d468d581f469c9853674fa0424542851a00 ASCII:E...b....@.......U...@..P.....7....<..a........B...7.GET /8-Bit/MSX.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f...w...kyD..-.J.j...5`...:...40v....F..l........4.'.>#...0......Z+k...#...+hy...{j.;0.......5h....u...0........#J@.3.....c$...M..v..0#...,D....d...l.....t..K....G...}..q.1$T,... r?.n+r. ...b..ld.,2....dr.......+u.(bP.Q.Qt'1.T...6FL1.p.`&G.p.1c........F..#O..y...T.q..1.7.V'h."m...{.Va ......X..I.....j.x..7.F.X.F..SgO.BEB... -uncompressed= 45000262008500004006ce82c0a80002550d93d740070050c314f5defa37d29b80183c168b6100000101080a000542c810fc37e5474554202f382d4269742f4d53582e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..b....@.......U...@..P.....7....<..a........B...7.GET /8-Bit/MSX.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 26 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d3300942dbf512b744fcfbb79f7ced17b79440b192da452b58a1586913562eda0c93a02cf9d343076a8edfd9b460eb56cecc801be03070f18348e277f3e23c78d1c30f098b103a3865a2b6bd8a4b923a609132b6a77aac111bbead53b309e9089a3060f193568b4a28923750f8cd430e6d4919386cd1bfc234a44be33a7870c19a963248fc3074d1db87630c63023078e0c2c440a1e94e164c78c196caad498f1347409a94be4d8d9ad478f9e187de498710352a4542cb9ebc020723fce6e2b74f920e1a81da34a966c64bc2c32a20a1a866472cb8022f6b90dee2c758c2862504f521951742731e854868d1836464c31889021612647a6708f31638411ba08e9d791bbd8c89323469ec7a02195769c3868cc7ca5abd5099aab4bdfe641c3de2a561848e2843cc366bed63368d2bc018a46ad9a3e60a5fe4db371a356881229eae4f97368d19152a50600 ASCII:E...e....@..p....U...@..P..6.......6..<........E...8.GET /8-Bit/Mattel.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..-.Q+tO..y...{yD..-.R.....5b...:...40v....F..l........4.'.>#...0......Z+k...#...+jw......;0.......5h...#u...0........#JD.3.....c$...M..v0.0#...,D....d...l....4t..K....G...}..q.R.T,... r?.n+t. ....J.ld.,2....dr.."....,u.(bPOR.Qt'1.T...6FL1..!a&G.p.1c...........#F...!.v.8h.|......K..A..*V.H..<.f..3h....F..>`..M.q.V..)...sh..R... -uncompressed= 45000265009400004006ce70c0a80002550d93d740060050c3143614a11fa986801836e1f43c00000101080a000545b010fc38b7474554202f382d4269742f4d617474656c2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..e....@..p....U...@..P..6.......6..<........E...8.GET /8-Bit/Mattel.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 27 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b330095dfa4bd83668f4fc578f5eab13ca2858c1651a756bd0ac3c89ab076d0601d81e74e1a183bd2fa064e23475a3676e404df8183070c1ac895439f91e3460e1878ccd8815123ad95356cd2dc11d3848995b43cd5e0904dd5ea1d184fc8c45183878c1a3459d1c489ba0706631873eac849c3e64dfe112520df99d343860cc63194c7e18326e8768c31ccc88123030b1183086538d93163069b2a356638155d22ea12397678ebd1a327461f3966dc7c0c19158bee3a3088e08fc3db8a5c3e4838dac19872251b192e8b8ca882862119dd32a084856ea3fb4a1d238a1cd483544694dd490e36956123868d11530e2a642898c99129dd63cc186144aec2fa75e0b2912bc3c8932346a0c7a01135769c3868ccc48d93d5091aab4adde641d3beea551848e2803cc3867ed63368d2bc818b26ad9a3e5fa3f64db3716356881229e6d4d91328519151a30600 ASCII:E...c....@..m....U...@..P..b?!..k..9.s.........FL..8.GET /8-Bit/Oric.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+3......f.O.x...<....Q.V......v.`...N..;...N#GZ6v..........C...F..x...Q#..5l........<...M....O..Q....4Y......c.s..I..M..% ...C...1....&.v.1...#.....e8.1c..*5f8.]"..9vx...'F.9f.|.....:0......\>H8...r%........!..2...n..J.#....TF..I.6.a#...S.*d(...).c..aD...u...+...#F....5v.8h........J..A...U.H..<..~.3h....&..>_..M.qcV..)....(Q.Q... -uncompressed= 45000263009900004006ce6dc0a80002550d93d740040050c313623f2189e66b801839a5739a00000101080a0005464c10fc38f3474554202f382d4269742f4f7269632e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..c....@..m....U...@..P..b?!..k..9.s.........FL..8.GET /8-Bit/Oric.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 28 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 4500010269009e00004006ce62c0a80002550d93d740060050c3143845a11fab60801840003c1c00000101080a000547d810fc38b7474554202f382d4269742f526164696f536861636b2e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f330096316be6fcc6ed1d347b7a46f60b584fe7112d64b4b08a552b5718468ad6b183a6eb083c77d2c0d8e17678711a39dcb2b123c7f80e1c3c60d068febcfa8c1c3772c0c063c60e8c1a6e89b24973474c132656dcee5483e376d6ad77603c2113470d1e326ad0784513c7ea1e189361cca923270d9b37fd4794b87c674e0f193226c7781e870f9a3a74ed748c61460e1c195888307428c3c98e1933d854a93163eae9125697c8b1135c8f1e3d31fac831e3a6e449ab587ed78141847f9ce056f0f24112127cc79731d9c8a0596444153411c9fc9601c56c751be263ea1851a4a19ea732a2004fd2b0aa0c1b316c8c98d2f061c4c54c8e4c111f63c60823781fe6af6357685e234f8e18a91e838655dd71e2a03173378e572768b6469d9b074d7cad5c61208963f20c1bfc5ecfa049f3c62e1ab76afa90b55a380d48905e2b5ecc1874e8d1a44b515ab51a00 ASCII:E...i....@..b....U...@..P..8E...`..@.<.........G...8.GET /8-Bit/RadioShack.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/3..1k.....4{zF..XO..-d...U+W.F.......#...0......Z+A........<...}5...O..Q....4\......c.s..I#4.......!C......AS....1...#.....e8.1c..*5fD.]...9vz...'F.9f.|.I...:0......]>H6r..r%..........2.e@......:F.9.G..(...|*.F..#..T(.0.#S...1..]....eCW..'G.D.A...8q.......4Y.....=V.0...y..}.g..y#..Z5}.R..F.F..#N...'P.".R.. -uncompressed= 45000266009f00004006ce64c0a80002550d93d740050050c313903caf7b2f9580183d5ce4ef00000101080a0005481810fc3934474554202f382d4269742f5068696c6970732e47494620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d6c2b786d6c2c20746578742f766e642e7761702e776d6c2c202a2f2a0d0a4163636570742d436861727365743a207574662d382c207574662d31362c2069736f2d383835392d312c2069736f2d31303634362d7563732d322c2053686966745f4a49532c20426967350d0a4163636570742d4c616e67756167653a20656e0d0a782d7761702d70726f66696c653a2022687474703a2f2f7761702e736f6e796572696373736f6e2e636f6d2f554170726f662f4b38303069523230312e786d6c220d0a486f73743a207777772e7a6f636b2e636f6d0d0a557365722d4167656e743a20536f6e794572696373736f6e4b383030692f5232422052656c656173652f4d61722d31332d323030372042726f777365722f4e657446726f6e742f332e332050726f66696c652f4d4944502d322e3020436f6e66696775726174696f6e2f434c44432d312e310d0a436f6e6e656374696f6e3a204b6565702d416c6976650d0a4163636570742d456e636f64696e673a206465666c6174652c20677a69700d0a526566657265723a20687474703a2f2f7777772e7a6f636b2e636f6d2f0d0a0d0a ASCII:E..f....@..d....U...@..P...<.{/...=\..........H...94GET /8-Bit/Philips.GIF HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/vnd.wap.wml, */*..Accept-Charset: utf-8, utf-16, iso-8859-1, iso-10646-ucs-2, Shift_JIS, Big5..Accept-Language: en..x-wap-profile: "http://wap.sonyericsson.com/UAprof/K800iR201.xml"..Host: www.zock.com..User-Agent: SonyEricssonK800i/R2B Release/Mar-13-2007 Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1..Connection: Keep-Alive..Accept-Encoding: deflate, gzip..Referer: http://www.zock.com/.... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 30 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 450001049b00ae00004006cc20c0a80002550d93d740050050c31396ceaf7b396e801840009ad400000101080a0005611010fc3d6b474554202f382d4269742f6d72776f6e672e67696620485454502f312e310d0a4163636570743a206d756c7469706172742f6d697865642c206170706c69636174696f6e2f766e642e7761702e6d756c7469706172742e6d697865642c206170706c69636174696f6e2f766e642e7761702e7868746d6c2b786d6c2c206170706c69636174696f6e2f7868746d33009733bf617b07cd9e9f8ef7f6d5a379440b192da85ac5aa1586913564eda0d93a02cf9d343076b00d3e9c460eb66cecc821be03070f183496379f3e23c78d1c30f098b103a3065b2b6b92de11d3848915b63dd5e0a87d35eb1d184fc814c543460d1aae68e250dd0303328c3975e4a461f346ff881294efcce9214306e418cde3f0415347ae1d8c31ccc88123030b1183086538d93163069b2a3566442d5d82ea1239767eebd1a327461f3966dc801449154bef3a3088e48ff3db0a513e48387ac7a892251b192f8b8ca882862199de32a0909d6e033c4b1d238a1cd4a3544614df490e3e956123868d11530e2a644898c99129e063cc186184a8423578ead06563d7c8932346a6c7a04175769c3868ccd48dc3d5099aac4ce3e641f31eab561848e2843cc3a628d73368d2bca18b86ad9a3e62a9fe4db3712357881229eadce933e8d09154a92a417265848c1d307afec489074e198678e6108d31a7e8882557ae4c9111357903abdf7f7b052b96ec4f3868d51e7e1b77ae74198ef7f63d1a76ce52bf50cf4c9d7355b7ddb290634cae7cb9b4dec05f135b76c178c41d347b7e16eeabc732db16325a74cf7a07869135647bff0e3e7c075bdad3732c6f4e7c070e1ed37dcb993e23c78d1c30f07807cfd6ca1a3669ee8869c2c40adb9e6a70a8d60ae30999a278c8e4e78a260ed53d3020c33088900d43ae25204aa46818239f8d6cbc631c3a120b11ff6964a864c9e6e58ca8a54b505d220727579d3b7d06bd48158b52a6f99f72b542940f923a13ed600c39838d8c974546fc6548a63761b2d36d8067a96344913a72f428951105cd9d248a9fcab011c3c688298ad30c444398c99129e063cc18313bce683578eae8b66be4c91123d363246f003b0e1a33d2b93a41939569dc3c68d6df8181248e193967d814e57a064d9a3774d1b055d387cd1caa7fd36cdcc835618f853a63d07473510655aa0100 ASCII:E........@.. ....U...@..P.....{9n..@...........a...=kGET /8-Bit/mrwong.gif HTTP/1.1..Accept: multipart/mixed, application/vnd.wap.multipart.mixed, application/vnd.wap.xhtml+xml, application/xhtm3..3.a{.........yD..-.Z.....5d...:...40v..>.F..l..!.....4.7.>#...0......[+k........=...}5...O...CF...h.P...2.9u..a.F.......!C......ASG...1...#.....e8.1c..*5fD-]...9v~...'F.9f...I.K.:0......Q>H8z...%../.....!..2...n..a#...S.*dH...).c..a..B5x..ec...#F...Auv.8h........L..A...V.H..<..(.3h.......>b..M.q#W..)...3...T.*Are...0z....N..x...1...%W.L..5y....{.+..O8h..~.w.t....=.v.R.P.L.sU....cL.|...._.[v.x..4{~....2..2Zt.z...5d{..>|.[..s,oN|....}..>#...0.x.....6i..i.....jp.......x....&..=0 .0...C.% J.h.#..l.c.:....id.d......KP]".'W.;}..H..R...r.B...:..`.9....EF.eH.7a..m.g.cD.:r.(.....$........)...DC...).c..1;.h5x...k...#.c$o.;..3..:A..i.Directory listing f.or /.Directory listing for /..

Directory listing for /

.
..
... - -Testing decompression with sniffed compressed TCP/IP packets: -Packet No.: 32 -v42bis_decompress_flush() rc=0 -v42bis_decompress() rc=0 -v42bis_decompress_flush() rc=0 -compressed= 45000101a0e9a54000400683540a0901abc0a800021f904004437442f17a4ab3b1501900ed04900000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205765642c203301312041756720323031362030393a32373a353520474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a66003f481c9162e40a97294800002068746d6c20506600588a3c6162644409183200002f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e672066016f72202f3c2f7469746c990068beff2823e70c9f816b6a9847af9ebd7bf8f2e9dbc7af5ff142f06bea0cc4e31d7cfced646aa74f03a444fa3373a4c64113634e7ded28554e7d1953cd7e320365744cb811bc8c82078376ff1e00 ASCII:E......@.@..T..........@.CtB.zJ..P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Wed, 3.1 Aug 2016 09:27:55 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222....f.?H..b...)H.. html Pf.X..Directory listing f.or /</titl..h..(#....kj.G...{......_.B.k.....|..dj.O..D.3s..A.cN}.(UN}.S.~2.etL.......v... -uncompressed= 450001a0e9a54000400683540a0901abc0a800021f904004437442f17a4ab3b1501900ed04900000485454502f312e3020323030204f4b0d0a5365727665723a2053696d706c65485454502f302e3620507974686f6e2f322e372e360d0a446174653a205765642c2033312041756720323031362030393a32373a353520474d540d0a436f6e74656e742d747970653a20746578742f68746d6c3b20636861727365743d5554462d380d0a436f6e74656e742d4c656e6774683a203232320d0a0d0a3c21444f43545950452068746d6c205055424c494320222d2f2f5733432f2f4454442048544d4c20332e322046696e616c2f2f454e223e3c68746d6c3e0a3c7469746c653e4469726563746f7279206c697374696e6720666f72202f3c2f7469746c653e0a3c626f64793e0a3c68323e4469726563746f7279206c697374696e6720666f72202f3c2f68323e0a3c68723e0a3c756c3e0a3c6c693e3c6120687265663d2272656470686f6e652e706e67223e72656470686f6e652e706e673c2f613e0a3c2f756c3e0a3c68723e0a3c2f626f64793e0a3c2f68746d6c3e0a ASCII:E.....@.@..T..........@.CtB.zJ..P.......HTTP/1.0 200 OK..Server: SimpleHTTP/0.6 Python/2.7.6..Date: Wed, 31 Aug 2016 09:27:55 GMT..Content-type: text/html; charset=UTF-8..Content-Length: 222....<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>.<title>Directory listing for /..

Directory listing for /

.
..
... - -Done diff --git a/tests/vty_test_runner.py b/tests/vty_test_runner.py index c4a3c8fbc..8989f246f 100644 --- a/tests/vty_test_runner.py +++ b/tests/vty_test_runner.py @@ -71,43 +71,6 @@ class TestVTYBase(unittest.TestCase): self.vty = None osmoutil.end_proc(self.proc) - -class TestVTYGenericBSC(TestVTYBase): - - def _testConfigNetworkTree(self, include_bsc_items=True): - self.vty.enable() - self.assertTrue(self.vty.verify("configure terminal",[''])) - self.assertEquals(self.vty.node(), 'config') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify("network",[''])) - self.assertEquals(self.vty.node(), 'config-net') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify("bts 0",[''])) - self.assertEquals(self.vty.node(), 'config-net-bts') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify("trx 0",[''])) - self.assertEquals(self.vty.node(), 'config-net-bts-trx') - self.checkForEndAndExit() - self.vty.command("write terminal") - self.assertTrue(self.vty.verify("exit",[''])) - self.assertEquals(self.vty.node(), 'config-net-bts') - self.assertTrue(self.vty.verify("exit",[''])) - self.assertTrue(self.vty.verify("bts 1",[''])) - self.assertEquals(self.vty.node(), 'config-net-bts') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify("trx 1",[''])) - self.assertEquals(self.vty.node(), 'config-net-bts-trx') - self.checkForEndAndExit() - self.vty.command("write terminal") - self.assertTrue(self.vty.verify("exit",[''])) - self.assertEquals(self.vty.node(), 'config-net-bts') - self.assertTrue(self.vty.verify("exit",[''])) - self.assertEquals(self.vty.node(), 'config-net') - self.assertTrue(self.vty.verify("exit",[''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify("exit",[''])) - self.assertTrue(self.vty.node() is None) - class TestVTYMSC(TestVTYBase): def vty_command(self): @@ -284,699 +247,6 @@ class TestVTYMSC(TestVTYBase): self.assertEquals(res.find('meas-feed scenario abcdefghijklmnopqrstuvwxyz012345'), -1) self.assert_(res.find('meas-feed scenario abcdefghijklmnopqrstuvwxyz01234') > 0) - -class TestVTYBSC(TestVTYGenericBSC): - - def vty_command(self): - return ["./src/osmo-bsc/osmo-bsc", "-c", - "doc/examples/osmo-bsc/osmo-bsc.cfg"] - - def vty_app(self): - return (4242, "./src/osmo-bsc/osmo-bsc", "OsmoBSC", "bsc") - - def testConfigNetworkTree(self): - self._testConfigNetworkTree() - - def testVtyTree(self): - self.vty.enable() - self.assertTrue(self.vty.verify("configure terminal", [''])) - self.assertEquals(self.vty.node(), 'config') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify("msc 0", [''])) - self.assertEquals(self.vty.node(), 'config-msc') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify("exit", [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify("bsc", [''])) - self.assertEquals(self.vty.node(), 'config-bsc') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify("exit", [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify("exit", [''])) - self.assertTrue(self.vty.node() is None) - - # Check searching for outer node's commands - self.vty.command("configure terminal") - self.vty.command('msc 0') - self.vty.command("bsc") - self.assertEquals(self.vty.node(), 'config-bsc') - self.vty.command("msc 0") - self.assertEquals(self.vty.node(), 'config-msc') - - def testUssdNotificationsMsc(self): - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("msc") - - # Test invalid input - self.vty.verify("bsc-msc-lost-text", ['% Command incomplete.']) - self.vty.verify("bsc-welcome-text", ['% Command incomplete.']) - self.vty.verify("bsc-grace-text", ['% Command incomplete.']) - - # Enable USSD notifications - self.vty.verify("bsc-msc-lost-text MSC disconnected", ['']) - self.vty.verify("bsc-welcome-text Hello MS", ['']) - self.vty.verify("bsc-grace-text In grace period", ['']) - - # Verify settings - res = self.vty.command("write terminal") - self.assert_(res.find('bsc-msc-lost-text MSC disconnected') > 0) - self.assertEquals(res.find('no bsc-msc-lost-text'), -1) - self.assert_(res.find('bsc-welcome-text Hello MS') > 0) - self.assertEquals(res.find('no bsc-welcome-text'), -1) - self.assert_(res.find('bsc-grace-text In grace period') > 0) - self.assertEquals(res.find('no bsc-grace-text'), -1) - - # Now disable it.. - self.vty.verify("no bsc-msc-lost-text", ['']) - self.vty.verify("no bsc-welcome-text", ['']) - self.vty.verify("no bsc-grace-text", ['']) - - # Verify settings - res = self.vty.command("write terminal") - self.assertEquals(res.find('bsc-msc-lost-text MSC disconnected'), -1) - self.assert_(res.find('no bsc-msc-lost-text') > 0) - self.assertEquals(res.find('bsc-welcome-text Hello MS'), -1) - self.assert_(res.find('no bsc-welcome-text') > 0) - self.assertEquals(res.find('bsc-grace-text In grace period'), -1) - self.assert_(res.find('no bsc-grace-text') > 0) - - def testUssdNotificationsBsc(self): - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("bsc") - - # Test invalid input - self.vty.verify("missing-msc-text", ['% Command incomplete.']) - - # Enable USSD notifications - self.vty.verify("missing-msc-text No MSC found", ['']) - - # Verify settings - res = self.vty.command("write terminal") - self.assert_(res.find('missing-msc-text No MSC found') > 0) - self.assertEquals(res.find('no missing-msc-text'), -1) - - # Now disable it.. - self.vty.verify("no missing-msc-text", ['']) - - # Verify settings - res = self.vty.command("write terminal") - self.assertEquals(res.find('missing-msc-text No MSC found'), -1) - self.assert_(res.find('no missing-msc-text') > 0) - - def testNetworkTimezone(self): - self.vty.enable() - self.vty.verify("configure terminal", ['']) - self.vty.verify("network", ['']) - - # Test invalid input - self.vty.verify("timezone", ['% Command incomplete.']) - self.vty.verify("timezone 20 0", ['% Unknown command.']) - self.vty.verify("timezone 0 11", ['% Unknown command.']) - self.vty.verify("timezone 0 0 99", ['% Unknown command.']) - - # Set time zone without DST - self.vty.verify("timezone 2 30", ['']) - - # Verify settings - res = self.vty.command("write terminal") - self.assert_(res.find('timezone 2 30') > 0) - self.assertEquals(res.find('timezone 2 30 '), -1) - - # Set time zone with DST - self.vty.verify("timezone 2 30 1", ['']) - - # Verify settings - res = self.vty.command("write terminal") - self.assert_(res.find('timezone 2 30 1') > 0) - - # Now disable it.. - self.vty.verify("no timezone", ['']) - - # Verify settings - res = self.vty.command("write terminal") - self.assertEquals(res.find(' timezone'), -1) - - def testShowNetwork(self): - res = self.vty.command("show network") - self.assert_(res.startswith('BSC is on Country Code') >= 0) - - def testPingPongConfiguration(self): - self.vty.enable() - self.vty.verify("configure terminal", ['']) - self.vty.verify("network", ['']) - self.vty.verify("msc 0", ['']) - - self.vty.verify("timeout-ping 12", ['']) - self.vty.verify("timeout-pong 14", ['']) - res = self.vty.command("show running-config") - self.assert_(res.find(" timeout-ping 12") > 0) - self.assert_(res.find(" timeout-pong 14") > 0) - self.assert_(res.find(" no timeout-ping advanced") > 0) - - self.vty.verify("timeout-ping advanced", ['']) - res = self.vty.command("show running-config") - self.assert_(res.find(" timeout-ping 12") > 0) - self.assert_(res.find(" timeout-pong 14") > 0) - self.assert_(res.find(" timeout-ping advanced") > 0) - - self.vty.verify("no timeout-ping advanced", ['']) - res = self.vty.command("show running-config") - self.assert_(res.find(" timeout-ping 12") > 0) - self.assert_(res.find(" timeout-pong 14") > 0) - self.assert_(res.find(" no timeout-ping advanced") > 0) - - self.vty.verify("no timeout-ping", ['']) - res = self.vty.command("show running-config") - self.assertEquals(res.find(" timeout-ping 12"), -1) - self.assertEquals(res.find(" timeout-pong 14"), -1) - self.assertEquals(res.find(" no timeout-ping advanced"), -1) - self.assert_(res.find(" no timeout-ping") > 0) - - self.vty.verify("timeout-ping advanced", ['%ping handling is disabled. Enable it first.']) - - # And back to enabling it - self.vty.verify("timeout-ping 12", ['']) - self.vty.verify("timeout-pong 14", ['']) - res = self.vty.command("show running-config") - self.assert_(res.find(" timeout-ping 12") > 0) - self.assert_(res.find(" timeout-pong 14") > 0) - self.assert_(res.find(" timeout-ping advanced") > 0) - - def testMscDataCoreLACCI(self): - self.vty.enable() - res = self.vty.command("show running-config") - self.assertEquals(res.find("core-location-area-code"), -1) - self.assertEquals(res.find("core-cell-identity"), -1) - - self.vty.command("configure terminal") - self.vty.command("msc 0") - self.vty.command("core-location-area-code 666") - self.vty.command("core-cell-identity 333") - - res = self.vty.command("show running-config") - self.assert_(res.find("core-location-area-code 666") > 0) - self.assert_(res.find("core-cell-identity 333") > 0) - -class TestVTYNAT(TestVTYGenericBSC): - - def vty_command(self): - return ["./src/osmo-bsc_nat/osmo-bsc_nat", "-l", "127.0.0.1", "-c", - "doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg"] - - def vty_app(self): - return (4244, "src/osmo-bsc_nat/osmo-bsc_nat", "OsmoBSCNAT", "nat") - - def testBSCreload(self): - # Use different port for the mock msc to avoid clashing with - # the osmo-bsc_nat itself - ip = "127.0.0.1" - port = 5522 - self.vty.enable() - bscs1 = self.vty.command("show bscs-config") - nat_bsc_reload(self) - bscs2 = self.vty.command("show bscs-config") - # check that multiple calls to bscs-config-file give the same result - self.assertEquals(bscs1, bscs2) - - # add new bsc - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("bsc 5") - self.vty.command("token key") - self.vty.command("location_area_code 666") - self.vty.command("end") - - # update bsc token - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("bsc 1") - self.vty.command("token xyu") - self.vty.command("end") - - nat_msc_ip(self, ip, port) - msc_socket, msc = nat_msc_test(self, ip, port, verbose=True) - try: - b0 = nat_bsc_sock_test(0, "lol", verbose=True, proc=self.proc) - b1 = nat_bsc_sock_test(1, "xyu", verbose=True, proc=self.proc) - b2 = nat_bsc_sock_test(5, "key", verbose=True, proc=self.proc) - - self.assertEquals("3 BSCs configured", self.vty.command("show nat num-bscs-configured")) - self.assertTrue(3 == nat_bsc_num_con(self)) - self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection")) - - nat_bsc_reload(self) - bscs2 = self.vty.command("show bscs-config") - # check that the reset to initial config succeeded - self.assertEquals(bscs1, bscs2) - - self.assertEquals("2 BSCs configured", self.vty.command("show nat num-bscs-configured")) - self.assertTrue(1 == nat_bsc_num_con(self)) - rem = self.vty.command("show bsc connections").split(' ') - # remaining connection is for BSC0 - self.assertEquals('0', rem[2]) - # remaining connection is authorized - self.assertEquals('1', rem[4]) - self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection")) - finally: - msc.close() - msc_socket.close() - - def testVtyTree(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('mgcp', [''])) - self.assertEquals(self.vty.node(), 'config-mgcp') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('nat', [''])) - self.assertEquals(self.vty.node(), 'config-nat') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('bsc 0', [''])) - self.assertEquals(self.vty.node(), 'config-nat-bsc') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config-nat') - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('exit', [''])) - self.assertTrue(self.vty.node() is None) - - # Check searching for outer node's commands - self.vty.command('configure terminal') - self.vty.command('mgcp') - self.vty.command('nat') - self.assertEquals(self.vty.node(), 'config-nat') - self.vty.command('mgcp') - self.assertEquals(self.vty.node(), 'config-mgcp') - self.vty.command('nat') - self.assertEquals(self.vty.node(), 'config-nat') - self.vty.command('bsc 0') - self.vty.command('mgcp') - self.assertEquals(self.vty.node(), 'config-mgcp') - - def testRewriteNoRewrite(self): - self.vty.enable() - res = self.vty.command("configure terminal") - res = self.vty.command("nat") - res = self.vty.command("number-rewrite rewrite.cfg") - res = self.vty.command("no number-rewrite") - - def testEnsureNoEnsureModeSet(self): - self.vty.enable() - res = self.vty.command("configure terminal") - res = self.vty.command("nat") - - # Ensure the default - res = self.vty.command("show running-config") - self.assert_(res.find('\n sdp-ensure-amr-mode-set') > 0) - - self.vty.command("sdp-ensure-amr-mode-set") - res = self.vty.command("show running-config") - self.assert_(res.find('\n sdp-ensure-amr-mode-set') > 0) - - self.vty.command("no sdp-ensure-amr-mode-set") - res = self.vty.command("show running-config") - self.assert_(res.find('\n no sdp-ensure-amr-mode-set') > 0) - - def testRewritePostNoRewrite(self): - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.verify("number-rewrite-post rewrite.cfg", ['']) - self.vty.verify("no number-rewrite-post", ['']) - - - def testPrefixTreeLoading(self): - cfg = os.path.join(confpath, "tests/bsc-nat-trie/prefixes.csv") - - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - res = self.vty.command("prefix-tree %s" % cfg) - self.assertEqual(res, "% prefix-tree loaded 17 rules.") - self.vty.command("end") - - res = self.vty.command("show prefix-tree") - self.assertEqual(res, '1,1\r\n12,2\r\n123,3\r\n1234,4\r\n12345,5\r\n123456,6\r\n1234567,7\r\n12345678,8\r\n123456789,9\r\n1234567890,10\r\n13,11\r\n14,12\r\n15,13\r\n16,14\r\n82,16\r\n823455,15\r\n+49123,17') - - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("no prefix-tree") - self.vty.command("end") - - res = self.vty.command("show prefix-tree") - self.assertEqual(res, "% there is now prefix tree loaded.") - - def testUssdSideChannelProvider(self): - self.vty.command("end") - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("ussd-token key") - self.vty.command("end") - - res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is not connected and not authorized.']) - self.assertTrue(res) - - ussdSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ussdSocket.connect(('127.0.0.1', 5001)) - ussdSocket.settimeout(2.0) - print "Connected to %s:%d" % ussdSocket.getpeername() - - print "Expecting ID_GET request" - data = ussdSocket.recv(4) - self.assertEqual(data, "\x00\x01\xfe\x04") - - print "Going to send ID_RESP response" - res = ussdSocket.send(IPA().id_resp(IPA().tag_name('key'))) - self.assertEqual(res, 10) - - # initiating PING/PONG cycle to know, that the ID_RESP message has been processed - - print "Going to send PING request" - res = ussdSocket.send(IPA().ping()) - self.assertEqual(res, 4) - - print "Expecting PONG response" - data = ussdSocket.recv(4) - self.assertEqual(data, "\x00\x01\xfe\x01") - - res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is connected and authorized.']) - self.assertTrue(res) - - print "Going to shut down connection" - ussdSocket.shutdown(socket.SHUT_WR) - - print "Expecting EOF" - data = ussdSocket.recv(4) - self.assertEqual(data, "") - - ussdSocket.close() - - res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is not connected and not authorized.']) - self.assertTrue(res) - - def testAccessList(self): - """ - Verify that the imsi-deny can have a reject cause or no reject cause - """ - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - - # Old default - self.vty.command("access-list test-default imsi-deny ^123[0-9]*$") - res = self.vty.command("show running-config").split("\r\n") - asserted = False - for line in res: - if line.startswith(" access-list test-default"): - self.assertEqual(line, " access-list test-default imsi-deny ^123[0-9]*$ 11 11") - asserted = True - self.assert_(asserted) - - # Check the optional CM Service Reject Cause - self.vty.command("access-list test-cm-deny imsi-deny ^123[0-9]*$ 42").split("\r\n") - res = self.vty.command("show running-config").split("\r\n") - asserted = False - for line in res: - if line.startswith(" access-list test-cm"): - self.assertEqual(line, " access-list test-cm-deny imsi-deny ^123[0-9]*$ 42 11") - asserted = True - self.assert_(asserted) - - # Check the optional LU Reject Cause - self.vty.command("access-list test-lu-deny imsi-deny ^123[0-9]*$ 23 42").split("\r\n") - res = self.vty.command("show running-config").split("\r\n") - asserted = False - for line in res: - if line.startswith(" access-list test-lu"): - self.assertEqual(line, " access-list test-lu-deny imsi-deny ^123[0-9]*$ 23 42") - asserted = True - self.assert_(asserted) - -class TestVTYGbproxy(TestVTYGenericBSC): - - def vty_command(self): - return ["./src/gprs/osmo-gbproxy", "-c", - "doc/examples/osmo-gbproxy/osmo-gbproxy.cfg"] - - def vty_app(self): - return (4246, "./src/gprs/osmo-gbproxy", "OsmoGbProxy", "bsc") - - def testVtyTree(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('ns', [''])) - self.assertEquals(self.vty.node(), 'config-ns') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('gbproxy', [''])) - self.assertEquals(self.vty.node(), 'config-gbproxy') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - - def testVtyShow(self): - res = self.vty.command("show ns") - self.assert_(res.find('Encapsulation NS-UDP-IP') >= 0) - - res = self.vty.command("show gbproxy stats") - self.assert_(res.find('GBProxy Global Statistics') >= 0) - - def testVtyDeletePeer(self): - self.vty.enable() - self.assertTrue(self.vty.verify('delete-gbproxy-peer 9999 bvci 7777', ['BVC not found'])) - res = self.vty.command("delete-gbproxy-peer 9999 all dry-run") - self.assert_(res.find('Not Deleted 0 BVC') >= 0) - self.assert_(res.find('Not Deleted 0 NS-VC') >= 0) - res = self.vty.command("delete-gbproxy-peer 9999 only-bvc dry-run") - self.assert_(res.find('Not Deleted 0 BVC') >= 0) - self.assert_(res.find('Not Deleted 0 NS-VC') < 0) - res = self.vty.command("delete-gbproxy-peer 9999 only-nsvc dry-run") - self.assert_(res.find('Not Deleted 0 BVC') < 0) - self.assert_(res.find('Not Deleted 0 NS-VC') >= 0) - res = self.vty.command("delete-gbproxy-peer 9999 all") - self.assert_(res.find('Deleted 0 BVC') >= 0) - self.assert_(res.find('Deleted 0 NS-VC') >= 0) - -class TestVTYSGSN(TestVTYGenericBSC): - - def vty_command(self): - return ["./src/gprs/osmo-sgsn", "-c", - "doc/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg"] - - def vty_app(self): - return (4245, "./src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn") - - def testVtyTree(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('ns', [''])) - self.assertEquals(self.vty.node(), 'config-ns') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('sgsn', [''])) - self.assertEquals(self.vty.node(), 'config-sgsn') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - - def testVtyShow(self): - res = self.vty.command("show ns") - self.assert_(res.find('Encapsulation NS-UDP-IP') >= 0) - self.assertTrue(self.vty.verify('show bssgp', [''])) - self.assertTrue(self.vty.verify('show bssgp stats', [''])) - # TODO: uncomment when the command does not segfault anymore - # self.assertTrue(self.vty.verify('show bssgp nsei 123', [''])) - # self.assertTrue(self.vty.verify('show bssgp nsei 123 stats', [''])) - - self.assertTrue(self.vty.verify('show sgsn', [''])) - self.assertTrue(self.vty.verify('show mm-context all', [''])) - self.assertTrue(self.vty.verify('show mm-context imsi 000001234567', ['No MM context for IMSI 000001234567'])) - self.assertTrue(self.vty.verify('show pdp-context all', [''])) - - res = self.vty.command("show sndcp") - self.assert_(res.find('State of SNDCP Entities') >= 0) - - res = self.vty.command("show llc") - self.assert_(res.find('State of LLC Entities') >= 0) - - def testVtyAuth(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('sgsn', [''])) - self.assertEquals(self.vty.node(), 'config-sgsn') - self.assertTrue(self.vty.verify('auth-policy accept-all', [''])) - res = self.vty.command("show running-config") - self.assert_(res.find('auth-policy accept-all') > 0) - self.assertTrue(self.vty.verify('auth-policy acl-only', [''])) - res = self.vty.command("show running-config") - self.assert_(res.find('auth-policy acl-only') > 0) - self.assertTrue(self.vty.verify('auth-policy closed', [''])) - res = self.vty.command("show running-config") - self.assert_(res.find('auth-policy closed') > 0) - self.assertTrue(self.vty.verify('gsup remote-ip 127.0.0.4', [''])) - self.assertTrue(self.vty.verify('gsup remote-port 2222', [''])) - self.assertTrue(self.vty.verify('auth-policy remote', [''])) - res = self.vty.command("show running-config") - self.assert_(res.find('auth-policy remote') > 0) - - def testVtySubscriber(self): - self.vty.enable() - res = self.vty.command('show subscriber cache') - self.assert_(res.find('1234567890') < 0) - self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 create', [''])) - res = self.vty.command('show subscriber cache') - self.assert_(res.find('1234567890') >= 0) - self.assert_(res.find('Authorized: 0') >= 0) - self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 update-location-result ok', [''])) - res = self.vty.command('show subscriber cache') - self.assert_(res.find('1234567890') >= 0) - self.assert_(res.find('Authorized: 1') >= 0) - self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 cancel update-procedure', [''])) - res = self.vty.command('show subscriber cache') - self.assert_(res.find('1234567890') >= 0) - self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 destroy', [''])) - res = self.vty.command('show subscriber cache') - self.assert_(res.find('1234567890') < 0) - - def testVtyGgsn(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('sgsn', [''])) - self.assertEquals(self.vty.node(), 'config-sgsn') - self.assertTrue(self.vty.verify('ggsn 0 remote-ip 127.99.99.99', [''])) - self.assertTrue(self.vty.verify('ggsn 0 gtp-version 1', [''])) - self.assertTrue(self.vty.verify('apn * ggsn 0', [''])) - self.assertTrue(self.vty.verify('apn apn1.test ggsn 0', [''])) - self.assertTrue(self.vty.verify('apn apn1.test ggsn 1', ['% a GGSN with id 1 has not been defined'])) - self.assertTrue(self.vty.verify('apn apn1.test imsi-prefix 123456 ggsn 0', [''])) - self.assertTrue(self.vty.verify('apn apn2.test imsi-prefix 123456 ggsn 0', [''])) - res = self.vty.command("show running-config") - self.assert_(res.find('ggsn 0 remote-ip 127.99.99.99') >= 0) - self.assert_(res.find('ggsn 0 gtp-version 1') >= 0) - self.assert_(res.find('apn * ggsn 0') >= 0) - self.assert_(res.find('apn apn1.test ggsn 0') >= 0) - self.assert_(res.find('apn apn1.test imsi-prefix 123456 ggsn 0') >= 0) - self.assert_(res.find('apn apn2.test imsi-prefix 123456 ggsn 0') >= 0) - - def testVtyEasyAPN(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('sgsn', [''])) - self.assertEquals(self.vty.node(), 'config-sgsn') - - res = self.vty.command("show running-config") - self.assertEquals(res.find("apn internet"), -1) - - self.assertTrue(self.vty.verify("access-point-name internet.apn", [''])) - res = self.vty.command("show running-config") - self.assert_(res.find("apn internet.apn ggsn 0") >= 0) - - self.assertTrue(self.vty.verify("no access-point-name internet.apn", [''])) - res = self.vty.command("show running-config") - self.assertEquals(res.find("apn internet"), -1) - - def testVtyCDR(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('sgsn', [''])) - self.assertEquals(self.vty.node(), 'config-sgsn') - - res = self.vty.command("show running-config") - self.assert_(res.find("no cdr filename") > 0) - - self.vty.command("cdr filename bla.cdr") - res = self.vty.command("show running-config") - self.assertEquals(res.find("no cdr filename"), -1) - self.assert_(res.find(" cdr filename bla.cdr") > 0) - - self.vty.command("no cdr filename") - res = self.vty.command("show running-config") - self.assert_(res.find("no cdr filename") > 0) - self.assertEquals(res.find(" cdr filename bla.cdr"), -1) - - res = self.vty.command("show running-config") - self.assert_(res.find(" cdr interval 600") > 0) - - self.vty.command("cdr interval 900") - res = self.vty.command("show running-config") - self.assert_(res.find(" cdr interval 900") > 0) - self.assertEquals(res.find(" cdr interval 600"), -1) - -def add_nat_test(suite, workdir): - if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc_nat/osmo-bsc_nat")): - print("Skipping the NAT test") - return - test = unittest.TestLoader().loadTestsFromTestCase(TestVTYNAT) - suite.addTest(test) - -def nat_bsc_reload(x): - x.vty.command("configure terminal") - x.vty.command("nat") - x.vty.command("bscs-config-file bscs.cfg") - x.vty.command("end") - -def nat_msc_ip(x, ip, port): - x.vty.command("configure terminal") - x.vty.command("nat") - x.vty.command("msc ip " + ip) - x.vty.command("msc port " + str(port)) - x.vty.command("end") - -def data2str(d): - return d.encode('hex').lower() - -def nat_msc_test(x, ip, port, verbose = False): - msc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - msc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - msc.settimeout(5) - msc.bind((ip, port)) - msc.listen(5) - if (verbose): - print "MSC is ready at " + ip - conn = None - while True: - vty_response = x.vty.command("show msc connection") - print "'show msc connection' says: %r" % vty_response - if vty_response == "MSC is connected: 1": - # success - break; - if vty_response != "MSC is connected: 0": - raise Exception("Unexpected response to 'show msc connection'" - " vty command: %r" % vty_response) - - timeout_retries = 6 - while timeout_retries > 0: - try: - conn, addr = msc.accept() - print "MSC got connection from ", addr - break - except socket.timeout: - print "socket timed out." - timeout_retries -= 1 - continue - - if not conn: - raise Exception("VTY reports MSC is connected, but I haven't" - " connected yet: %r %r" % (ip, port)) - return msc, conn - def ipa_handle_small(x, verbose = False): s = data2str(x.recv(4)) if len(s) != 4*2: @@ -1020,50 +290,6 @@ def ipa_handle_resp(x, tk, verbose = False, proc=None): if (verbose): print "\tBSC <- NAT: ", s -def nat_bsc_num_con(x): - return len(x.vty.command("show bsc connections").split('\n')) - -def nat_bsc_sock_test(nr, tk, verbose = False, proc=None): - bsc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - bsc.bind(('127.0.0.1', 0)) - bsc.connect(('127.0.0.1', 5000)) - if (verbose): - print "BSC%d " %nr - print "\tconnected to %s:%d" % bsc.getpeername() - if proc: - print "\tproc.poll() = %r" % proc.poll() - print "\tproc.pid = %r" % proc.pid - ipa_handle_small(bsc, verbose) - ipa_handle_resp(bsc, tk, verbose, proc=proc) - if proc: - print "\tproc.poll() = %r" % proc.poll() - bsc.recv(27) # MGCP msg - if proc: - print "\tproc.poll() = %r" % proc.poll() - ipa_handle_small(bsc, verbose) - return bsc - -def add_bsc_test(suite, workdir): - if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc/osmo-bsc")): - print("Skipping the BSC test") - return - test = unittest.TestLoader().loadTestsFromTestCase(TestVTYBSC) - suite.addTest(test) - -def add_gbproxy_test(suite, workdir): - if not os.path.isfile(os.path.join(workdir, "src/gprs/osmo-gbproxy")): - print("Skipping the Gb-Proxy test") - return - test = unittest.TestLoader().loadTestsFromTestCase(TestVTYGbproxy) - suite.addTest(test) - -def add_sgsn_test(suite, workdir): - if not os.path.isfile(os.path.join(workdir, "src/gprs/osmo-sgsn")): - print("Skipping the SGSN test") - return - test = unittest.TestLoader().loadTestsFromTestCase(TestVTYSGSN) - suite.addTest(test) - if __name__ == '__main__': import argparse import sys @@ -1095,10 +321,6 @@ if __name__ == '__main__': print "Running tests for specific VTY commands" suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TestVTYMSC)) - add_bsc_test(suite, workdir) - add_nat_test(suite, workdir) - add_gbproxy_test(suite, workdir) - add_sgsn_test(suite, workdir) if args.test_name: osmoutil.pick_tests(suite, *args.test_name) diff --git a/tests/xid/Makefile.am b/tests/xid/Makefile.am deleted file mode 100644 index aaf17edf2..000000000 --- a/tests/xid/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBCARES_CFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - xid_test.ok \ - $(NULL) - -noinst_PROGRAMS = \ - xid_test \ - $(NULL) - -xid_test_SOURCES = \ - xid_test.c \ - $(NULL) - -xid_test_LDADD = \ - $(top_builddir)/src/gprs/gprs_llc_xid.o \ - $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOGB_LIBS) \ - $(LIBCARES_LIBS) \ - $(LIBCRYPTO_LIBS) \ - $(LIBGTP_LIBS) \ - -lrt \ - -lm \ - $(NULL) - diff --git a/tests/xid/xid_test.c b/tests/xid/xid_test.c deleted file mode 100644 index b77a4ae85..000000000 --- a/tests/xid/xid_test.c +++ /dev/null @@ -1,164 +0,0 @@ -/* Test LLC-XID Encoding/Decoding */ - -/* (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 . - */ - -#include -#include - -#include -#include - -#include - -#include -#include - -/* Test XID encoding */ -static void test_xid_encode(const void *ctx) -{ - struct gprs_llc_xid_field xid_field_1; - struct gprs_llc_xid_field xid_field_2; - struct gprs_llc_xid_field xid_field_3; - struct gprs_llc_xid_field xid_field_4; - LLIST_HEAD(xid_fields); - uint8_t xid[255]; - uint8_t xid_expected[] = - { 0x10, 0x8c, 0x14, 0x43, 0x43, 0x43, 0x43, 0x43, 0x0b, 0x42, 0x42, - 0x42, 0x05, 0x41 }; - int rc; - - printf("Testing LLC XID-Encoder\n"); - - /* Setup some simple XID data */ - xid_field_1.type = 1; - xid_field_2.type = 2; - xid_field_3.type = 3; - xid_field_4.type = 4; - - xid_field_1.data = (uint8_t *) "A"; - xid_field_2.data = (uint8_t *) "BBB"; - xid_field_3.data = (uint8_t *) "CCCCC"; - xid_field_4.data = NULL; - - xid_field_1.data_len = 1; - xid_field_2.data_len = 3; - xid_field_3.data_len = 5; - xid_field_4.data_len = 0; - - llist_add(&xid_field_4.list, &xid_fields); - llist_add(&xid_field_3.list, &xid_fields); - llist_add(&xid_field_2.list, &xid_fields); - llist_add(&xid_field_1.list, &xid_fields); - - printf("Data to encode:\n"); - gprs_llc_dump_xid_fields(&xid_fields, DSNDCP); - - /* Encode data */ - rc = gprs_llc_compile_xid(xid, sizeof(xid), &xid_fields); - OSMO_ASSERT(rc == 14); - printf("Encoded: %s (%i bytes)\n", osmo_hexdump_nospc(xid, rc), rc); - printf("Expected: %s (%i bytes)\n", - osmo_hexdump_nospc(xid_expected, sizeof(xid_expected)), - (int)sizeof(xid_expected)); - - OSMO_ASSERT(memcmp(xid_expected, xid, sizeof(xid_expected)) == 0); - - printf("\n"); -} - -/* Test XID decoding */ -static void test_xid_decode(const void *ctx) -{ - struct llist_head *xid_fields; - int rc; - - printf("Testing LLC XID-Decoder/Encoder\n"); - - /* Example of a real world LLC-XID message */ - uint8_t xid[] = - { 0x01, 0x00, 0x16, 0x05, 0xf0, 0x1a, 0x05, 0xf0, 0xac, 0xd8, 0x00, - 0x01, 0x00, 0x02, 0x31, 0x82, 0x02, 0x27, 0x89, 0xff, 0xe0, 0x00, 0x0f, - 0x00, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x01, 0x02, - 0x00, 0x03, 0x01, 0x03, 0x00, 0x04, 0x01, 0x04, 0x00, 0x05, 0x01, 0x05, - 0x00, 0x06, 0x00, 0x07, 0x01, 0x07, 0x00, 0x08, 0x01, 0x08, 0x80, 0x00, - 0x04, 0x12, 0x00, 0x40, 0x07 }; - - uint8_t xid_r[512]; - - /* Decode and display XID fields */ - xid_fields = gprs_llc_parse_xid(ctx, xid, sizeof(xid)); - OSMO_ASSERT(xid_fields); - - printf("Decoded:\n"); - gprs_llc_dump_xid_fields(xid_fields, DSNDCP); - - - /* Encode xid-fields again */ - rc = gprs_llc_compile_xid(xid_r, sizeof(xid_r), xid_fields); - printf("Result length=%i\n",rc); - printf("Encoded: %s\n", osmo_hexdump_nospc(xid, sizeof(xid))); - printf("Rencoded: %s\n", osmo_hexdump_nospc(xid_r, rc)); - - OSMO_ASSERT(rc == 64); - OSMO_ASSERT(memcmp(xid, xid_r, sizeof(xid)) == 0); - - /* Free xid fields */ - talloc_free(xid_fields); - - printf("\n"); -} - -static struct log_info_cat gprs_categories[] = { - [DSNDCP] = { - .name = "DSNDCP", - .description = - "GPRS Sub-Network Dependent Control Protocol (SNDCP)", - .enabled = 1,.loglevel = LOGL_DEBUG, - } -}; - -static struct log_info info = { - .cat = gprs_categories, - .num_cat = ARRAY_SIZE(gprs_categories), -}; - -int main(int argc, char **argv) -{ - void *xid_ctx; - - osmo_init_logging(&info); - - xid_ctx = talloc_named_const(NULL, 0, "xid_ctx"); - - test_xid_decode(xid_ctx); - test_xid_encode(xid_ctx); - printf("Done\n"); - - talloc_report_full(xid_ctx, stderr); - OSMO_ASSERT(talloc_total_blocks(xid_ctx) == 1); - return 0; -} - -/* stubs */ -struct osmo_prim_hdr; -int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx) -{ - abort(); -} diff --git a/tests/xid/xid_test.ok b/tests/xid/xid_test.ok deleted file mode 100644 index 4cf825ca5..000000000 --- a/tests/xid/xid_test.ok +++ /dev/null @@ -1,12 +0,0 @@ -Testing LLC XID-Decoder/Encoder -Decoded: -Result length=64 -Encoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 -Rencoded: 01001605f01a05f0acd8000100023182022789ffe0000f00a8000000010101000201020003010300040104000501050006000701070008010880000412004007 - -Testing LLC XID-Encoder -Data to encode: -Encoded: 108c1443434343430b4242420541 (14 bytes) -Expected: 108c1443434343430b4242420541 (14 bytes) - -Done diff --git a/tools/hlrstat.pl b/tools/hlrstat.pl deleted file mode 100755 index 668fc9a4a..000000000 --- a/tools/hlrstat.pl +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/perl - -use strict; -use DBI; -my $dbh = DBI->connect("dbi:SQLite:dbname=hlr.sqlite3","",""); - - -my %mcc_names; -my %mcc_mnc_names; - -sub get_mcc_mnc_name($) -{ - my $mcc_mnc = shift; - my $ret = $mcc_mnc; - - if ($mcc_mnc_names{$mcc_mnc} ne '') { - $ret = $mcc_mnc_names{$mcc_mnc}; - } - - return $ret; -} - -sub read_networks($) -{ - my $filename = shift; - my $cur_name; - - open(INFILE, $filename); - while (my $l = ) { - chomp($l); - if ($l =~ /^#/) { - next; - } - if ($l =~ /^\t/) { - my ($mcc, $mnc, $brand, $r) = split(' ', $l, 4); - #printf("%s|%s|%s\n", $mcc, $mnc, $brand); - $mcc_mnc_names{"$mcc-$mnc"} = $brand; - $mcc_names{$mcc} = $cur_name; - } elsif ($l =~ /^(\w\w)\t(.*)/) { - #printf("%s|%s\n", $1, $2); - $cur_name = $2; - } - } - close(INFILE); -} - -read_networks("networks.tab"); - -my %oper_count; -my %country_count; - -#my $sth = $dbh->prepare("SELECT imsi FROM subscriber where authorized=1"); -my $sth = $dbh->prepare("SELECT imsi FROM subscriber"); - -$sth->execute(); - -while (my $href = $sth->fetchrow_hashref) { - my ($mcc, $mnc) = $$href{imsi} =~ /(\d{3})(\d{2}).*/; - #printf("%s %s-%s \n", $$href{imsi}, $mcc, $mnc); - $oper_count{"$mcc-$mnc"}++; - $country_count{$mcc}++; -} - - -foreach my $c (sort{$country_count{$b} <=> $country_count{$a}} keys %country_count) { - printf("%s: %d\n", $mcc_names{$c}, $country_count{$c}); - - foreach my $k (sort{$oper_count{$b} <=> $oper_count{$a}} keys %oper_count) { - if ($k =~ /^$c-/) { - printf("\t%s: %d\n", get_mcc_mnc_name($k), $oper_count{$k}); - } - } -}