mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-sgsn.git
synced 2025-11-05 06:33:14 +00:00
Compare commits
160 Commits
osmith/fix
...
1.7.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80adb30e93 | ||
|
|
ebd39830cb | ||
|
|
b05c1d0ce4 | ||
|
|
999a776b70 | ||
|
|
11ccc4305d | ||
|
|
901ed14c89 | ||
|
|
4be5ab3707 | ||
|
|
c999c223ae | ||
|
|
2ce050ba46 | ||
|
|
43e5f8a2c6 | ||
|
|
caf73b803c | ||
|
|
0018d3e0ec | ||
|
|
f955d078ed | ||
|
|
93ccc3cf5d | ||
|
|
10e0fcaae2 | ||
|
|
592eb140f0 | ||
|
|
c7b6aabac1 | ||
|
|
873c8a55e7 | ||
|
|
e0876bda26 | ||
|
|
21afdf9a32 | ||
|
|
c09cb29d78 | ||
|
|
6ad4040f55 | ||
|
|
45bf92feb4 | ||
|
|
d367b8bc78 | ||
|
|
5037b6817f | ||
|
|
d245c0e542 | ||
|
|
4380f94cf2 | ||
|
|
0d170d61aa | ||
|
|
fb5ccb468a | ||
|
|
b96d5a6ead | ||
|
|
6ff8d21fed | ||
|
|
5b1122f717 | ||
|
|
914484d561 | ||
|
|
b6343a72d8 | ||
|
|
ef0c2a4b85 | ||
|
|
02b24c5a44 | ||
|
|
cd7c7a74b7 | ||
|
|
ddb3fbb0f2 | ||
|
|
e245677cdd | ||
|
|
1c33e4af05 | ||
|
|
3844da98f8 | ||
|
|
dee0bcc8e9 | ||
|
|
51730f7a8c | ||
|
|
f23e2db752 | ||
|
|
8a33528854 | ||
|
|
00c1f91ed7 | ||
|
|
8d382c5337 | ||
|
|
ef3c9af0f9 | ||
|
|
5a21f07dff | ||
|
|
ea0b5d0df6 | ||
|
|
3054213e87 | ||
|
|
3326ba7d4c | ||
|
|
b6b2f14197 | ||
|
|
959f77e34b | ||
|
|
9e917647ae | ||
|
|
784c59f87e | ||
|
|
1aa0ae9db1 | ||
|
|
cab8588242 | ||
|
|
4b4c997dc5 | ||
|
|
c4c1db9e78 | ||
|
|
61ff273365 | ||
|
|
bf69833b6d | ||
|
|
7cb76a4321 | ||
|
|
c91f53ca0a | ||
|
|
5687ae65fa | ||
|
|
7c86a1efce | ||
|
|
453a51d1a1 | ||
|
|
a54ed46bac | ||
|
|
052d855449 | ||
|
|
11ad5713f2 | ||
|
|
d651edcce0 | ||
|
|
56f5e74d7d | ||
|
|
4bf53ef19a | ||
|
|
91bb720449 | ||
|
|
993d3f4d9a | ||
|
|
78db244b42 | ||
|
|
0e1b791c81 | ||
|
|
8cd74407ab | ||
|
|
6c4c6f08ae | ||
|
|
fb7f8c5f07 | ||
|
|
9a2fc908df | ||
|
|
e794c1f00b | ||
|
|
bd356a6d84 | ||
|
|
e8c8ec9683 | ||
|
|
55253716d2 | ||
|
|
1239cf457e | ||
|
|
ac44d6b2a2 | ||
|
|
c8d98ac8f9 | ||
|
|
6626bbc215 | ||
|
|
103a7ec033 | ||
|
|
6e8ed2784e | ||
|
|
7418797027 | ||
|
|
d97ff681c3 | ||
|
|
83142beca2 | ||
|
|
8c3d7fd263 | ||
|
|
9e583c8d89 | ||
|
|
5937dfd39f | ||
|
|
cafa3881ad | ||
|
|
447ad441e6 | ||
|
|
f7a1aed0e6 | ||
|
|
eb4233e505 | ||
|
|
2636e89ff0 | ||
|
|
bcd7709452 | ||
|
|
7ffc6603e2 | ||
|
|
826eaa327b | ||
|
|
952fbf20c9 | ||
|
|
8553f5532a | ||
|
|
3375fa4d64 | ||
|
|
e1ba4239b4 | ||
|
|
638cddd8f1 | ||
|
|
58937ce333 | ||
|
|
02f2c34f8a | ||
|
|
62fa6198ae | ||
|
|
c42331f359 | ||
|
|
15c9da226b | ||
|
|
8bca8de5cb | ||
|
|
82182d09c7 | ||
|
|
08395b3369 | ||
|
|
25998ddcc5 | ||
|
|
60581ae7c9 | ||
|
|
c70e8388c7 | ||
|
|
5ce54ba1e6 | ||
|
|
ff5b59a821 | ||
|
|
be2330fde4 | ||
|
|
8d2d7db818 | ||
|
|
92ef0c8675 | ||
|
|
68d9c5a468 | ||
|
|
ef6205ba00 | ||
|
|
86336af2a3 | ||
|
|
6d92f148aa | ||
|
|
27a0bf70e7 | ||
|
|
d3c3ddeb51 | ||
|
|
e6c5b4a970 | ||
|
|
aae7daff81 | ||
|
|
b32936d823 | ||
|
|
d5dc143001 | ||
|
|
65a5a0a27b | ||
|
|
9d16b14345 | ||
|
|
dd930a25ad | ||
|
|
b3e10aa8eb | ||
|
|
36ecddb705 | ||
|
|
90dedcb2e7 | ||
|
|
cfd307b4e8 | ||
|
|
b26a5a82db | ||
|
|
7369d449f1 | ||
|
|
5e1a486a72 | ||
|
|
627e285fd0 | ||
|
|
5e0b829884 | ||
|
|
bd6d677179 | ||
|
|
482bb07301 | ||
|
|
b63e19d7d2 | ||
|
|
c6548bbaab | ||
|
|
b2ebc59f30 | ||
|
|
9d550cb369 | ||
|
|
e6b2883f10 | ||
|
|
6528e8c1cb | ||
|
|
6e4cd085b5 | ||
|
|
91a8bbd5db | ||
|
|
d999e54aa2 | ||
|
|
394aa533e9 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -14,6 +14,7 @@ bscconfig.h.in
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.gcda
|
*.gcda
|
||||||
*.gcno
|
*.gcno
|
||||||
|
*~
|
||||||
|
|
||||||
#configure
|
#configure
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
@@ -40,7 +41,6 @@ ltmain.sh
|
|||||||
|
|
||||||
# apps and app data
|
# apps and app data
|
||||||
src/sgsn/osmo-sgsn
|
src/sgsn/osmo-sgsn
|
||||||
src/gbproxy/osmo-gbproxy
|
|
||||||
src/gtphub/osmo-gtphub
|
src/gtphub/osmo-gtphub
|
||||||
src/libcommon/gsup_test_client
|
src/libcommon/gsup_test_client
|
||||||
|
|
||||||
@@ -69,3 +69,5 @@ doc/manuals/generated/
|
|||||||
doc/manuals/osmomsc-usermanual.xml
|
doc/manuals/osmomsc-usermanual.xml
|
||||||
doc/manuals/common
|
doc/manuals/common
|
||||||
doc/manuals/build
|
doc/manuals/build
|
||||||
|
|
||||||
|
contrib/osmo-sgsn.spec
|
||||||
|
|||||||
10
Makefile.am
10
Makefile.am
@@ -9,15 +9,21 @@ AM_CPPFLAGS = \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
doc \
|
|
||||||
include \
|
include \
|
||||||
src \
|
src \
|
||||||
contrib \
|
contrib \
|
||||||
tests \
|
tests \
|
||||||
|
doc \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
BUILT_SOURCES = $(top_srcdir)/.version
|
BUILT_SOURCES = $(top_srcdir)/.version
|
||||||
EXTRA_DIST = git-version-gen osmoappdesc.py .version
|
EXTRA_DIST = \
|
||||||
|
.version \
|
||||||
|
contrib/osmo-sgsn.spec.in \
|
||||||
|
debian \
|
||||||
|
git-version-gen \
|
||||||
|
osmoappdesc.py \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||||
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||||
|
|||||||
@@ -1,4 +1 @@
|
|||||||
#component what description / commit summary line
|
#component what description / commit summary line
|
||||||
osmo-sgsn libgtp We dropped libgtp gtp_retranstimeout timer code which became a
|
|
||||||
no-op in osmo-ggsn.git c94837c6a401bf0f80791b619a9b4cfbe9160afd,
|
|
||||||
which means next osmo-sgsn release will require libgtp > 1.4.0.
|
|
||||||
|
|||||||
46
configure.ac
46
configure.ac
@@ -22,6 +22,11 @@ AC_PROG_CC
|
|||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
LT_INIT
|
LT_INIT
|
||||||
|
|
||||||
|
dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang
|
||||||
|
AS_CASE(["$LD"],[*clang*],
|
||||||
|
[AS_CASE(["${host_os}"],
|
||||||
|
[*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])])
|
||||||
|
|
||||||
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
|
dnl check for pkg-config (explained in detail in libosmocore/configure.ac)
|
||||||
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
|
AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no)
|
||||||
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
|
||||||
@@ -34,34 +39,40 @@ m4_ifdef([AX_CHECK_COMPILE_FLAG], [], [
|
|||||||
AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
|
AC_MSG_ERROR([Please install autoconf-archive; re-run 'autoreconf -fi' for it to take effect.])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl use a defined standard across all builds and don't depend on compiler default
|
||||||
|
CFLAGS="$CFLAGS -std=gnu11"
|
||||||
|
|
||||||
dnl checks for libraries
|
dnl checks for libraries
|
||||||
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
|
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
|
||||||
AC_SUBST(LIBRARY_DL)
|
AC_SUBST(LIBRARY_DL)
|
||||||
|
|
||||||
|
AC_SEARCH_LIBS([dlsym], [dl dld], [LIBRARY_DLSYM="$LIBS";LIBS=""])
|
||||||
|
AC_SUBST(LIBRARY_DLSYM)
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.2.0)
|
|
||||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.2.0)
|
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.2.0)
|
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.5.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.2.0)
|
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.5.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.2.0)
|
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.5.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.6.0)
|
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 1.5.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.4.0)
|
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.1.0)
|
||||||
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.0.0)
|
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 1.1.0)
|
||||||
|
PKG_CHECK_MODULES(LIBOSMOGSUPCLIENT, libosmo-gsup-client >= 1.3.0)
|
||||||
|
|
||||||
# Enable/disable 3G aka IuPS + IuCS support?
|
# Enable/disable 3G aka IuPS + IuCS support?
|
||||||
AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS and IuCS interfaces])],
|
AC_ARG_ENABLE([iu], [AS_HELP_STRING([--enable-iu], [Build 3G support, aka IuPS and IuCS interfaces])],
|
||||||
[osmo_ac_iu="$enableval"],[osmo_ac_iu="no"])
|
[osmo_ac_iu="$enableval"],[osmo_ac_iu="no"])
|
||||||
if test "x$osmo_ac_iu" = "xyes" ; then
|
if test "x$osmo_ac_iu" = "xyes" ; then
|
||||||
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.0.0)
|
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 1.4.0)
|
||||||
PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30)
|
PKG_CHECK_MODULES(LIBASN1C, libasn1c >= 0.9.30)
|
||||||
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.4.0)
|
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap >= 0.7.0)
|
||||||
AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support])
|
AC_DEFINE(BUILD_IU, 1, [Define if we want to build IuPS and IuCS interfaces support])
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
|
AM_CONDITIONAL(BUILD_IU, test "x$osmo_ac_iu" = "xyes")
|
||||||
AC_SUBST(osmo_ac_iu)
|
AC_SUBST(osmo_ac_iu)
|
||||||
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.4.0)
|
PKG_CHECK_MODULES(LIBGTP, libgtp >= 1.7.0)
|
||||||
PKG_CHECK_MODULES(LIBCARES, libcares)
|
PKG_CHECK_MODULES(LIBCARES, libcares)
|
||||||
|
|
||||||
dnl checks for header files
|
dnl checks for header files
|
||||||
@@ -110,8 +121,8 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])],
|
|||||||
CFLAGS="$saved_CFLAGS"
|
CFLAGS="$saved_CFLAGS"
|
||||||
AC_SUBST(SYMBOL_VISIBILITY)
|
AC_SUBST(SYMBOL_VISIBILITY)
|
||||||
|
|
||||||
CPPFLAGS="$CPPFLAGS -Wall"
|
CPPFLAGS="$CPPFLAGS -Wall -Wno-trigraphs"
|
||||||
CFLAGS="$CFLAGS -Wall"
|
CFLAGS="$CFLAGS -Wall -Wno-trigraphs"
|
||||||
|
|
||||||
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
|
AX_CHECK_COMPILE_FLAG([-Werror=implicit], [CFLAGS="$CFLAGS -Werror=implicit"])
|
||||||
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
|
AX_CHECK_COMPILE_FLAG([-Werror=maybe-uninitialized], [CFLAGS="$CFLAGS -Werror=maybe-uninitialized"])
|
||||||
@@ -164,9 +175,9 @@ AC_ARG_ENABLE([external_tests],
|
|||||||
[Include the VTY/CTRL tests in make check [default=no]]),
|
[Include the VTY/CTRL tests in make check [default=no]]),
|
||||||
[enable_ext_tests="$enableval"],[enable_ext_tests="no"])
|
[enable_ext_tests="$enableval"],[enable_ext_tests="no"])
|
||||||
if test "x$enable_ext_tests" = "xyes" ; then
|
if test "x$enable_ext_tests" = "xyes" ; then
|
||||||
AC_CHECK_PROG(PYTHON2_AVAIL,python2,yes)
|
AC_CHECK_PROG(PYTHON3_AVAIL,python3,yes)
|
||||||
if test "x$PYTHON2_AVAIL" != "xyes" ; then
|
if test "x$PYTHON3_AVAIL" != "xyes" ; then
|
||||||
AC_MSG_ERROR([Please install python2 to run the VTY/CTRL tests.])
|
AC_MSG_ERROR([Please install python3 to run the VTY/CTRL tests.])
|
||||||
fi
|
fi
|
||||||
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
|
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
|
||||||
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
|
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
|
||||||
@@ -248,12 +259,10 @@ AC_OUTPUT(
|
|||||||
src/Makefile
|
src/Makefile
|
||||||
src/gprs/Makefile
|
src/gprs/Makefile
|
||||||
src/sgsn/Makefile
|
src/sgsn/Makefile
|
||||||
src/gbproxy/Makefile
|
|
||||||
src/gtphub/Makefile
|
src/gtphub/Makefile
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
tests/atlocal
|
tests/atlocal
|
||||||
tests/gprs/Makefile
|
tests/gprs/Makefile
|
||||||
tests/gbproxy/Makefile
|
|
||||||
tests/sgsn/Makefile
|
tests/sgsn/Makefile
|
||||||
tests/gtphub/Makefile
|
tests/gtphub/Makefile
|
||||||
tests/xid/Makefile
|
tests/xid/Makefile
|
||||||
@@ -265,4 +274,5 @@ AC_OUTPUT(
|
|||||||
doc/manuals/Makefile
|
doc/manuals/Makefile
|
||||||
contrib/Makefile
|
contrib/Makefile
|
||||||
contrib/systemd/Makefile
|
contrib/systemd/Makefile
|
||||||
|
contrib/osmo-sgsn.spec
|
||||||
Makefile)
|
Makefile)
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
"""
|
|
||||||
demonstrate a unblock bug on the GB Proxy..
|
|
||||||
"""
|
|
||||||
|
|
||||||
bts_ns_reset = "\x02\x00\x81\x01\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
|
|
||||||
ns_reset_ack = "\x03\x01\x82\x1f\xe7\x04\x82\x1f\xe7"
|
|
||||||
|
|
||||||
bts_ns_unblock = "\x06"
|
|
||||||
ns_unblock_ack = "\x07"
|
|
||||||
|
|
||||||
bts_bvc_reset_0 = "\x00\x00\x00\x00\x22\x04\x82\x00\x00\x07\x81\x03\x3b\x81\x02"
|
|
||||||
ns_bvc_reset_0_ack = "\x00\x00\x00\x00\x23\x04\x82\x00\x00"
|
|
||||||
|
|
||||||
bts_bvc_reset_8167 = "\x00\x00\x00\x00\x22\x04\x82\x1f\xe7\x07\x81\x08\x08\x88\x72\xf4\x80\x10\x1c\x00\x9c\x40"
|
|
||||||
|
|
||||||
|
|
||||||
import socket
|
|
||||||
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
socket.bind(("0.0.0.0", 0))
|
|
||||||
socket.setblocking(1)
|
|
||||||
|
|
||||||
|
|
||||||
import sys
|
|
||||||
port = int(sys.argv[1])
|
|
||||||
print "Sending data to port: %d" % port
|
|
||||||
|
|
||||||
def send_and_receive(packet):
|
|
||||||
socket.sendto(packet, ("127.0.0.1", port))
|
|
||||||
|
|
||||||
try:
|
|
||||||
data, addr = socket.recvfrom(4096)
|
|
||||||
except socket.error, e:
|
|
||||||
print "ERROR", e
|
|
||||||
import sys
|
|
||||||
sys.exit(0)
|
|
||||||
return data
|
|
||||||
|
|
||||||
#send stuff once
|
|
||||||
|
|
||||||
to_send = [
|
|
||||||
(bts_ns_reset, ns_reset_ack, "reset ack"),
|
|
||||||
(bts_ns_unblock, ns_unblock_ack, "unblock ack"),
|
|
||||||
(bts_bvc_reset_0, ns_bvc_reset_0_ack, "BVCI=0 reset ack"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
for (out, inp, type) in to_send:
|
|
||||||
res = send_and_receive(out)
|
|
||||||
if res != inp:
|
|
||||||
print "Failed to get the %s" % type
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|
||||||
import time
|
|
||||||
time.sleep(3)
|
|
||||||
res = send_and_receive(bts_bvc_reset_8167)
|
|
||||||
print "Sent all messages... check wireshark for the last response"
|
|
||||||
@@ -50,7 +50,6 @@ fi
|
|||||||
# Additional configure options and depends
|
# Additional configure options and depends
|
||||||
CONFIG=""
|
CONFIG=""
|
||||||
if [ "$WITH_MANUALS" = "1" ]; then
|
if [ "$WITH_MANUALS" = "1" ]; then
|
||||||
osmo-build-dep.sh osmo-gsm-manuals
|
|
||||||
CONFIG="--enable-manuals"
|
CONFIG="--enable-manuals"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -70,12 +69,12 @@ LD_LIBRARY_PATH="$inst/lib" $MAKE check \
|
|||||||
|| cat-testlogs.sh
|
|| cat-testlogs.sh
|
||||||
LD_LIBRARY_PATH="$inst/lib" \
|
LD_LIBRARY_PATH="$inst/lib" \
|
||||||
DISTCHECK_CONFIGURE_FLAGS="$enable_werror $IU --enable-external-tests $CONFIG" \
|
DISTCHECK_CONFIGURE_FLAGS="$enable_werror $IU --enable-external-tests $CONFIG" \
|
||||||
$MAKE distcheck \
|
$MAKE $PARALLEL_MAKE distcheck \
|
||||||
|| cat-testlogs.sh
|
|| cat-testlogs.sh
|
||||||
|
|
||||||
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then
|
||||||
make -C "$base/doc/manuals" publish
|
make -C "$base/doc/manuals" publish
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$MAKE maintainer-clean
|
$MAKE $PARALLEL_MAKE maintainer-clean
|
||||||
osmo-clean-workspace.sh
|
osmo-clean-workspace.sh
|
||||||
|
|||||||
118
contrib/osmo-sgsn.spec.in
Normal file
118
contrib/osmo-sgsn.spec.in
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#
|
||||||
|
# spec file for package osmo-sgsn
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de>
|
||||||
|
#
|
||||||
|
# All modifications and additions to the file contributed by third parties
|
||||||
|
# remain the property of their copyright owners, unless otherwise agreed
|
||||||
|
# upon. The license for this file, and modifications and additions to the
|
||||||
|
# file, is the same license as for the pristine package itself (unless the
|
||||||
|
# license for the pristine package is not an Open Source License, in which
|
||||||
|
# case the license is the MIT License). An "Open Source License" is a
|
||||||
|
# license that conforms to the Open Source Definition (Version 1.9)
|
||||||
|
# published by the Open Source Initiative.
|
||||||
|
|
||||||
|
## Disable LTO for now since it breaks compilation of the tests
|
||||||
|
## https://osmocom.org/issues/4116
|
||||||
|
%define _lto_cflags %{nil}
|
||||||
|
|
||||||
|
%define with_iu 1
|
||||||
|
Name: osmo-sgsn
|
||||||
|
Version: @VERSION@
|
||||||
|
Release: 0
|
||||||
|
Summary: Osmocom's SGSN for 2G and 3G packet-switched mobile networks
|
||||||
|
License: AGPL-3.0-or-later AND GPL-2.0-or-later
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
URL: https://osmocom.org/projects/osmosgsn
|
||||||
|
Source: %{name}-%{version}.tar.xz
|
||||||
|
BuildRequires: autoconf
|
||||||
|
BuildRequires: automake
|
||||||
|
BuildRequires: libtool
|
||||||
|
BuildRequires: pkgconfig
|
||||||
|
%if 0%{?suse_version}
|
||||||
|
BuildRequires: systemd-rpm-macros
|
||||||
|
%endif
|
||||||
|
BuildRequires: pkgconfig(libcares)
|
||||||
|
BuildRequires: pkgconfig(libcrypto) >= 0.9.5
|
||||||
|
BuildRequires: pkgconfig(libgtp) >= 1.7.0
|
||||||
|
BuildRequires: pkgconfig(libosmo-gsup-client) >= 1.3.0
|
||||||
|
BuildRequires: pkgconfig(libosmo-netif) >= 1.1.0
|
||||||
|
BuildRequires: pkgconfig(libosmoabis) >= 1.1.0
|
||||||
|
BuildRequires: pkgconfig(libosmocore) >= 1.5.0
|
||||||
|
BuildRequires: pkgconfig(libosmoctrl) >= 1.5.0
|
||||||
|
BuildRequires: pkgconfig(libosmogb) >= 1.5.0
|
||||||
|
BuildRequires: pkgconfig(libosmogsm) >= 1.5.0
|
||||||
|
BuildRequires: pkgconfig(libosmovty) >= 1.5.0
|
||||||
|
%{?systemd_requires}
|
||||||
|
%if %{with_iu}
|
||||||
|
BuildRequires: pkgconfig(libasn1c)
|
||||||
|
BuildRequires: pkgconfig(libosmo-ranap) >= 0.7.0
|
||||||
|
BuildRequires: pkgconfig(libosmo-sigtran) >= 1.4.0
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%description
|
||||||
|
OsmoSGSN is Osmocom's Serving GPRS Support Node for 2G and 3G
|
||||||
|
packet-switched mobile networks.
|
||||||
|
|
||||||
|
%package -n osmo-gtphub
|
||||||
|
Summary: Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs
|
||||||
|
Group: Productivity/Telephony/Servers
|
||||||
|
|
||||||
|
%description -n osmo-gtphub
|
||||||
|
Osmocom GTP Hub: Proxy for GTP traffic between multiple SGSNs and GGSNs.
|
||||||
|
|
||||||
|
%prep
|
||||||
|
%setup -q
|
||||||
|
|
||||||
|
%build
|
||||||
|
echo "%{version}" >.tarball-version
|
||||||
|
autoreconf -fi
|
||||||
|
%configure \
|
||||||
|
%if %{with_iu}
|
||||||
|
--enable-iu \
|
||||||
|
%endif
|
||||||
|
--docdir=%{_docdir}/%{name} \
|
||||||
|
--with-systemdsystemunitdir=%{_unitdir}
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
|
%install
|
||||||
|
%make_install
|
||||||
|
|
||||||
|
%if 0%{?suse_version}
|
||||||
|
%preun %service_del_preun %{name}.service
|
||||||
|
%postun %service_del_postun %{name}.service
|
||||||
|
%pre %service_add_pre %{name}.service
|
||||||
|
%post %service_add_post %{name}.service
|
||||||
|
%preun -n osmo-gtphub %service_del_preun osmo-gtphub.service
|
||||||
|
%postun -n osmo-gtphub %service_del_postun osmo-gtphub.service
|
||||||
|
%pre -n osmo-gtphub %service_add_pre osmo-gtphub.service
|
||||||
|
%post -n osmo-gtphub %service_add_post osmo-gtphub.service
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%check
|
||||||
|
make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
||||||
|
|
||||||
|
%files
|
||||||
|
%doc AUTHORS README
|
||||||
|
%dir %{_docdir}/%{name}/examples
|
||||||
|
%dir %{_docdir}/%{name}/examples/osmo-sgsn
|
||||||
|
%exclude %{_docdir}/%{name}/examples/osmo-gtphub
|
||||||
|
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn-accept-all.cfg
|
||||||
|
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn.cfg
|
||||||
|
%{_docdir}/%{name}/examples/osmo-sgsn/osmo-sgsn_custom-sccp.cfg
|
||||||
|
%{_bindir}/osmo-sgsn
|
||||||
|
%dir %{_sysconfdir}/osmocom
|
||||||
|
%config(noreplace) %{_sysconfdir}/osmocom/osmo-sgsn.cfg
|
||||||
|
%{_unitdir}/%{name}.service
|
||||||
|
|
||||||
|
%files -n osmo-gtphub
|
||||||
|
%dir %{_docdir}/%{name}/examples
|
||||||
|
%dir %{_docdir}/%{name}/examples/osmo-gtphub
|
||||||
|
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
|
||||||
|
%{_docdir}/%{name}/examples/osmo-gtphub/osmo-gtphub.cfg
|
||||||
|
%{_bindir}/osmo-gtphub
|
||||||
|
%dir %{_sysconfdir}/osmocom
|
||||||
|
%config(noreplace) %{_sysconfdir}/osmocom/osmo-gtphub.cfg
|
||||||
|
%{_unitdir}/osmo-gtphub.service
|
||||||
|
|
||||||
|
%changelog
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
osmo-gbproxy.service \
|
|
||||||
osmo-gtphub.service \
|
osmo-gtphub.service \
|
||||||
osmo-sgsn.service
|
osmo-sgsn.service
|
||||||
|
|
||||||
if HAVE_SYSTEMD
|
if HAVE_SYSTEMD
|
||||||
SYSTEMD_SERVICES = \
|
SYSTEMD_SERVICES = \
|
||||||
osmo-gbproxy.service \
|
|
||||||
osmo-gtphub.service \
|
osmo-gtphub.service \
|
||||||
osmo-sgsn.service
|
osmo-sgsn.service
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Osmocom Gb proxy
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
ExecStart=/usr/bin/osmo-gbproxy -c /etc/osmocom/osmo-gbproxy.cfg
|
|
||||||
Restart=always
|
|
||||||
RestartSec=2
|
|
||||||
RestartPreventExitStatus=1
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
288
debian/changelog
vendored
288
debian/changelog
vendored
@@ -1,3 +1,291 @@
|
|||||||
|
osmo-sgsn (1.7.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
[ Daniel Willmann ]
|
||||||
|
* gprs_gmm: Check for RAT change and ensure this only happens for RAU/ATT
|
||||||
|
* gbproxy-usermanual: Explain BSSGP/BVC handling
|
||||||
|
* gbproxy: Whitespace fixes
|
||||||
|
* gbproxy: Add todo for BVC RESET logic
|
||||||
|
* gbproxy: Get the peer if paging by BVCI on SIG_BVC
|
||||||
|
* Let libosmocore handle VTY parent node tracking
|
||||||
|
* osmo-gbproxy: Free msgb in ns2 prim callback
|
||||||
|
* configure.ac: Require python3 for ext_tests
|
||||||
|
* osmo-gbproxy: Implement nsvc-state ctrl command
|
||||||
|
* gbproxy: Remove test testing NSVCI change
|
||||||
|
* gbproxy: Add NSE peer that can have multiple gbproxy_peers
|
||||||
|
* gbproxy: Ensure BVC0 is reset before handling PtP BVCs
|
||||||
|
* gbproxy: Only send paging to each matching NSE once
|
||||||
|
* gbproxy: Separate function to move gbproxy_peer to different nse
|
||||||
|
* gbproxy: Add logging macros for NSE and BVC
|
||||||
|
* gbproxy: Use LOG macros for NSE/BVC
|
||||||
|
* gbproxy: Change generic LOG messages so BVCI/NSEI fmt is consistent
|
||||||
|
* gbproxy: Add todos encountered while going through the code
|
||||||
|
* gbproxy: Add BVC log filters
|
||||||
|
* gbproxy: Add newline to log message
|
||||||
|
* gbproxy: Allow gbproxy_nse_free(NULL)
|
||||||
|
* gbproxy: Delete gbproxy_nse in delete-gbproxy-peer VTY command
|
||||||
|
* mm_state_gb_fsm: Handle implicit detach from mm_standby
|
||||||
|
* gbproxy: Fix bvci check in gbprox_rx_ptp_from_*
|
||||||
|
* osmo-gbproxy: Initialize all hash_maps
|
||||||
|
* gbproxy: Fix confusing log message in gbprox_relay2nse
|
||||||
|
* gbproxy: Add SGSN NRI configuration
|
||||||
|
* gbproxy: Add SGSN pooling support
|
||||||
|
* gbproxy: Add comments to sgsn functions
|
||||||
|
* gbproxy: Add config option to name an SGSN
|
||||||
|
* gbproxy: Add VTY command to override the node selection function
|
||||||
|
* Fix gbproxy_sgsn_by_tlli wraparound
|
||||||
|
* gbproxy: Implement TLLI cache and use it for SUSPEND/RESUME
|
||||||
|
* gbproxy: Increase TLLI cache timeout to 10s
|
||||||
|
* gbproxy: Implement IMSI cache
|
||||||
|
* gbproxy: Use IMSI cache to handle PAGING_PS_REJECT
|
||||||
|
* gbproxy: Use C-style comments
|
||||||
|
* gbproxy: Move helper function to a more logical place
|
||||||
|
* gbproxy: Remove unused variable assignment
|
||||||
|
* gbproxy: Fix VTY cmd name
|
||||||
|
* gbproxy: Define and use help string for gbproxy
|
||||||
|
* gbproxy: Add VTY commands to query the TLLI/IMSI cache
|
||||||
|
* gbproxy: Use IMSI cache for PTP paging and implement DUMMY_PAGING_PS
|
||||||
|
* gbproxy: Print the correct message type for dummy paging/paging reject
|
||||||
|
* gbproxy: Improve log messages in gbproxy_select_sgsn
|
||||||
|
* gbproxy: Fix radio status routing by TMSI
|
||||||
|
* manual/gbproxy: Update overview chapter
|
||||||
|
* Rename OsmoGbPROXY -> *Proxy
|
||||||
|
* manuals/gbproxy: Update configuration chapter
|
||||||
|
* manuals/gbproxy: Add osmo-bsc MSC pooling chapter from Neels as a base
|
||||||
|
* manuals/gbproxy: MSC -> SGSN for pooling chapter
|
||||||
|
* manuals/gbproxy: Move pooling to separate chapter
|
||||||
|
|
||||||
|
[ Alexander Couzens ]
|
||||||
|
* gprs_gmm_fsm.c: Implement RAT change between 2g and 3g
|
||||||
|
* gtphub: rename sgsn's oww osmo_sockaddr into sgsn_sockaddr
|
||||||
|
* gprs_llc: _bssgp_tx_dl_ud: ensure the LLME is valid before using it
|
||||||
|
* gmm: on invalid RA id reject the MS with an implicit detach
|
||||||
|
* gtphub_test: fix compilation error on gcc 10.2.0
|
||||||
|
* gtphub: fix compilation with gcc 10.2.0
|
||||||
|
* Port gbproxy to NS2
|
||||||
|
* sgsn: check for NULL of gprs_subscr_get_or_create()
|
||||||
|
* sgsn: Use the new NS2 api
|
||||||
|
* gbproxy: use ns2 vty2
|
||||||
|
* configure.ac: define a c standard instead of using the compilers default
|
||||||
|
* follow libosmocore/gprs_ns2 API changes of GPRS enums
|
||||||
|
* gbproxy: follow gprs_ns2 API vty changes
|
||||||
|
* sgsn: migrate to the new gprs_ns2_vty configuration
|
||||||
|
* follow libosmocore/gprs_ns2 API changes (gprs_ns2_dynamic_create_nse)
|
||||||
|
|
||||||
|
[ Neels Hofmeyr ]
|
||||||
|
* manual: explain IuPS, add SCCP/M3UA section from common chapters
|
||||||
|
* fix nullpointer: in gsm48_rx_gmm_ra_upd_req()
|
||||||
|
* gsup: send RAT type on LU
|
||||||
|
* gbproxy_test.c: fix mobile identity test data
|
||||||
|
* use new osmo_mobile_identity API everywhere
|
||||||
|
|
||||||
|
[ Eric ]
|
||||||
|
* tests: dlopen does not imply availability of dlsym..
|
||||||
|
* configure.ac: fix libtool issue with clang and sanitizer
|
||||||
|
|
||||||
|
[ Harald Welte ]
|
||||||
|
* gtphub_test: Fix compilation with gcc-10
|
||||||
|
* Fix memory leak when SNDCP de-fragmentation is used
|
||||||
|
* Treat RAU as implicit RESUME if GMM is suspended
|
||||||
|
* *.spec.in: Use %config(noreplace) to retain current config file
|
||||||
|
* Send a BVC-RESET to all persistent Gb interfaces at start-up
|
||||||
|
* Use osmo_fd_setup() whenever applicable
|
||||||
|
* Use osmo_fd_*_{disable,enable}
|
||||||
|
* gbproxy: Properly implement paging to LAC/RAC
|
||||||
|
* gbproxy: Implement paging to entire BSS area
|
||||||
|
* gprs_gb_parse: Add function to determine TLLI from encoded BSSGP
|
||||||
|
* gbproxy: Pass TLLI as LSP towards NS to facilitate load sharing
|
||||||
|
* gb_proxy_peer: Add some FIXMEs regarding invalid assumptions
|
||||||
|
* gb_proxy: More precise + readable log messages
|
||||||
|
* gb_proxy: Broadcast SGSN-INVOKE-TRACE and OVERLOAD
|
||||||
|
* gbproxy: Move BSS-side BVC-RESET processing to its own function
|
||||||
|
* gb_proxy: Slightly restructure processing of BSS-originated BVC-RESET
|
||||||
|
* gbproxy: Cosmetics: use longer lines
|
||||||
|
* gbproxy: Send BVC-STATUS if BSS sends us BVC-RESET without mandatory IEs
|
||||||
|
* gb_proxy: Use TLVP_PRES_LEN instead of TLVP_PRESENT
|
||||||
|
* gb_proxy: Rename gbproxy_peer to gbproxy_bvc
|
||||||
|
* gbproxy: Rename gbproxy_cfg.nses to gbproxy_cfg.bss_nses
|
||||||
|
* gbproxy: convert bss_nses from llist_head to hashtable
|
||||||
|
* gbproxy: convert nse->bvcs from llist_head to hashtable
|
||||||
|
* gbproxy: Remove patching, TLLI-tracking and SGSN2 support
|
||||||
|
* gb_proxy: cosmetic: Use function rather than open-coding is_sgsn
|
||||||
|
* gbproxy: Delete gbproxy_test
|
||||||
|
* gb_proxy: Introduce more validation / constraint checks
|
||||||
|
* gbproxy: use gbprox_relay2peer() whenever possible
|
||||||
|
* gb_proxy: Use osmo_tlv_prot_parse() to validate mandatory IEs
|
||||||
|
* gbproxy: Log FSM timeouts
|
||||||
|
* migrate to DLBSSGP as log sub-system for BSSGP
|
||||||
|
* gbproxy major rewrite for SGSN pool support
|
||||||
|
* gbproxy: Use "(nsei << 16) | bvci" as rate_ctr_group index
|
||||||
|
* gbproxy: Introduce new DOBJ log category; log object allocation/release
|
||||||
|
* gbproxy: Don't create an extra msgb copy for SGSN DL SIG
|
||||||
|
* gbproxy: Implement handling of BVC Flow Control
|
||||||
|
* gbproxy: Copy RA-ID from BSS side BVC to CELL and SGSN-side BVC
|
||||||
|
* gbproxy: (Re)allocate SGSN-side PTP BVC even if CELL already exists
|
||||||
|
* gbproxy: Fix segfault when receiving PAGING for unknown destination
|
||||||
|
* gbproxy: Add FSM related VTY commands
|
||||||
|
* gbproxy: Implement scaling of BVC flow control in SGSN pool
|
||||||
|
* gbproxy: Improve VTY state introspection
|
||||||
|
* gbproxy: rename vty command "show gbproxy ..." to "show gbproxy bvc ..."
|
||||||
|
* gbproxy: Add "show gbproxy cell ..." VTY command
|
||||||
|
* gbproxy: Fix build on Deiban 8
|
||||||
|
* gb_proxy: Don't use orphan log subsystem DPCU
|
||||||
|
* gbproxy: Avoid depending on any of the SGSN code
|
||||||
|
* main: add --vty-ref-mode, use vty_dump_xml_ref_mode()
|
||||||
|
* manuals: generate vty reference xml at build time
|
||||||
|
|
||||||
|
[ Pau Espin Pedrol ]
|
||||||
|
* Use OSMO_FD_* instead of deprecated BSC_FD_*
|
||||||
|
* sgsn_libgtp: Improve ps-paging logging
|
||||||
|
* gprs_gmm_fsm.c: Add missing license header
|
||||||
|
* sgsn_libgtp: Avoid ps-paging MS on GMM Suspended state
|
||||||
|
* configure.ac: Fix trailing whitespace
|
||||||
|
* doc: Update VTY reference xml file
|
||||||
|
* Support setting rt-prio and cpu-affinity mask through VTY
|
||||||
|
* Change default SCTP conn NULL->127.0.0.1 to localhost->localhost
|
||||||
|
* contrib/jenkins: Enable parallel make in make distcheck
|
||||||
|
* Log error if pdp ctx is freed while holding an active timer
|
||||||
|
* Fix crash rx DeactPdpReq while waiting for DeactPdpAck after gtp side is freed
|
||||||
|
* sgsn_delete_pdp_ctx: Add documentation and assert assumptions
|
||||||
|
* process_ms_ctx_status: refactor to avoid code duplication
|
||||||
|
* process_ms_ctx_status: Fix crash deleting PDP Ctx if GTP side was already released
|
||||||
|
* gbproxy: generate coredump and exit upon SIGABRT received
|
||||||
|
* gtphub: generate coredump and exit upon SIGABRT received
|
||||||
|
* sgsn: generate coredump and exit upon SIGABRT received
|
||||||
|
* gmm: fix build without define PTMSI_ALLOC
|
||||||
|
* gmm: Introduce comment to ease addition of Network feature support IE later
|
||||||
|
* .gitignore: Ignore new autofoo tmp files
|
||||||
|
* sndcp: Fix struct bit fields on big endian
|
||||||
|
* Fix nsei+bvci not updated on rx UL SNDCP data
|
||||||
|
|
||||||
|
[ Oliver Smith ]
|
||||||
|
* contrib: import RPM spec
|
||||||
|
* contrib: integrate RPM spec
|
||||||
|
* Makefile.am: EXTRA_DIST: debian, contrib/*.spec.in
|
||||||
|
* contrib/jenkins: don't build osmo-gsm-manuals
|
||||||
|
* gbproxy: remove (moved to own repository)
|
||||||
|
|
||||||
|
[ Vadim Yanitskiy ]
|
||||||
|
* debian/control: change maintainer to the Osmocom team / mailing list
|
||||||
|
* gb_proxy_peer: sgsn can never be NULL in gbproxy_sgsn_by_nri()
|
||||||
|
* gb_proxy_peer: fix NULL pointer dereference in gbproxy_sgsn_alloc()
|
||||||
|
|
||||||
|
[ Keith ]
|
||||||
|
* Fix Radio Priority in MM Attach and PDP Context Activation
|
||||||
|
* VTY: Add gtp state-dir command
|
||||||
|
|
||||||
|
[ Philipp Maier ]
|
||||||
|
* gprs_sndcp: fix use after free
|
||||||
|
* sgsn_rim: Add routing for (GERAN) BSSGP RIM messages
|
||||||
|
|
||||||
|
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 23 Feb 2021 20:29:33 +0100
|
||||||
|
|
||||||
|
osmo-sgsn (1.6.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
[ Pau Espin Pedrol ]
|
||||||
|
* gprs_gmm: Introduce macros to access msgb's associated IU UE ctx
|
||||||
|
* gprs_llc.h: Improve documentation of some structs
|
||||||
|
* gprs_gmm.c: Improve doc on nullable parameters
|
||||||
|
* gprs_gmm.c: Drop unneeded brackets
|
||||||
|
* Introduce define TLLI_UNASSIGNED
|
||||||
|
* gprs_sgsn.c: Warn upon llme free unexpected scenarios
|
||||||
|
* gprs_gmm: Clarify comment during TLLI assignment
|
||||||
|
* gprs_sgsn.c: Remove recently introduced assert
|
||||||
|
* gprs_gmm: Introduce assert to guard against unexpected condition
|
||||||
|
* gprs_gmm.c: Use correct function to set MM_IDLE state during cleanup
|
||||||
|
* gprs_sgsn.h: Flag MM_CTX_T_GERAN_Iu as not supported
|
||||||
|
* gprs_gmm.c: Flag mmctx_set_(p)mm_state() functions static
|
||||||
|
* sgsn: use sccp_simple_client API to setup ss7 id 0 instead of 1
|
||||||
|
* gprs_gmm.c: Fix typo in log message
|
||||||
|
* gprs_gmm.c: Call mmctx_set_(p)mm_state only on related ran_type
|
||||||
|
* Introduce and use log macros when no mm ctx available
|
||||||
|
* gprs_gmm: Avoid spaces in fsm events and enum strings
|
||||||
|
* tests: Verify that timers can be set over VTY
|
||||||
|
* Replace own timer infra with libosmocore osmo_tdef
|
||||||
|
* tests: Introduce vty-transcript-test tests
|
||||||
|
* gprs_gmm.c: Use osmo_rai_name() in log line
|
||||||
|
* examples: Add osmo-sgsn_custom-sccp.cfg
|
||||||
|
* vty: Introduce cs7-instance-iu
|
||||||
|
* gprs_gmm.c: Print value_string of reject cause
|
||||||
|
* gprs_gmm.c: Add spec document to function documentation
|
||||||
|
* gtp: make echo_interval unsigned
|
||||||
|
* gtp: cb_delete_context(): Clarify why pdp->lib is set to NULL
|
||||||
|
* Introduce log helper LOGGGSN and log category DGTP
|
||||||
|
* sgsn: gtp: Drop related pdp contexts on echo timeout against GGSN
|
||||||
|
* Move lots of Iu/ranap specific code into its own file
|
||||||
|
* Move llc->MM/SM Gb specific glue code to its own file
|
||||||
|
* Split enum gprs_pmm_state into Iu and Gb counterparts
|
||||||
|
* Merge common allocation steps for Gb and Iu ctx
|
||||||
|
* gprs_gmm.c: Replace inet_ntoa with inet_ntop
|
||||||
|
* sgsn_cdr.c: Fix ip addr string buffer size
|
||||||
|
* sgsn_vty: Fix mmctx rate_ctr output indentation
|
||||||
|
* sgsn_vty: Print correct Iu mmctx id in 'show mm-context'
|
||||||
|
* Introduce FSM mm_state_gb_fsm
|
||||||
|
* Introduce FSM mm_state_iu_fsm
|
||||||
|
* vty: Print MM state and RAN type in show mm-context
|
||||||
|
* src/gprs/Makefile.am: Move build of shared .c files to an internal lib
|
||||||
|
* Move out gbproxy to its own subdir
|
||||||
|
* Move out gtphub to its own subdir
|
||||||
|
* Move out sgsn to its own subdir
|
||||||
|
* gmm: Move code handling GMM Attach Complete to its own function
|
||||||
|
* gmm: Move code handling GMM Routing Area Update Complete to its own function
|
||||||
|
* gmm: Move code handling GMM PTMSI Realloc Complete to its own function
|
||||||
|
* enum gprs_gmm_state: Fix spec reference
|
||||||
|
* Implement GMM State using osmocom FSM
|
||||||
|
* Split out GPRS SM layer into its own file
|
||||||
|
* sgsn: Reject PdpActReq if no GTP pdp ctx exists
|
||||||
|
* Introduce TODO-RELEASE file
|
||||||
|
* sgsn_libgtp.c: Drop use of deprecated libgtp APIs gtp_retrans*()
|
||||||
|
* gmm: Fix assertion hit during RA UPD REQ before completting gmm attach
|
||||||
|
* Improve logging in gprs_llc.c code
|
||||||
|
* gprs_llc.c: Use enum instead of hardcoded value
|
||||||
|
* gprs_gmm.c: Send XID reset with received TLLI
|
||||||
|
|
||||||
|
[ Alexander Couzens ]
|
||||||
|
* gprs/gprs_gmm: implement T3314. Timeout to reset MM state READY->STANDBY
|
||||||
|
* gprs_gmm: only update gb/iu cell information when Iu/Gb present
|
||||||
|
* gprs_gmm: clarify comment of Iu follow-on request
|
||||||
|
* gprs_gmm: gsm48_rx_gmm_att_req(): refactor duplicated code
|
||||||
|
* sgsn_pdp_ctx_terminate: check llme before accessing
|
||||||
|
* gprs_ranap: send CommonId after receiving Security Mode Complete
|
||||||
|
* mm_gb_fsm: unassign the llme when entering MM_IDLE
|
||||||
|
* gprs_ranap: refactor REQUIRE_MM define
|
||||||
|
* sgsn: when receiving data PDU notify the Gb GMM fsm
|
||||||
|
* Avoid compiling unneeded files when building without Iu
|
||||||
|
* gprs_ranap: release Iu UE Context when exiting PMM Connected
|
||||||
|
* Iu: implement a user inactivity timer
|
||||||
|
* gprs_ranap: on Iu release, stop the attach fsm if running
|
||||||
|
* gprs_mm_state_gb_fsm: ensure T3350 is not running when entering IDLE
|
||||||
|
* gprs_ranap: add missing rc = 0
|
||||||
|
* gprs_sgsn: always allocate Gb/Iu mm fsm
|
||||||
|
* sgsn: MM Gb Fsm: fix event handling for implicit detach
|
||||||
|
* ranap: add non-spec X1001
|
||||||
|
* gprs_gmm: release Iu connection on RAU failures
|
||||||
|
* sgsn_mm_ctx_alloc(): check for unallocated fsms
|
||||||
|
* sgsn_libgtp: refactor ps paging into gprs_gb
|
||||||
|
* sgsn: Gb: implementing PS Paging when MS is MM_STANDBY
|
||||||
|
|
||||||
|
[ Vadim Yanitskiy ]
|
||||||
|
* gprs_mm_state_iu_fsm.c: fix: assign timer_cb to mm_state_iu_fsm
|
||||||
|
|
||||||
|
[ Max ]
|
||||||
|
* Use libosmocore constant for IMSI length in ACL entry
|
||||||
|
|
||||||
|
[ Harald Welte ]
|
||||||
|
* LLC: Don't use hard-coded N201-U / N201-I values in XID
|
||||||
|
* Initial OsmoGbPROXY user manual
|
||||||
|
* check for osmo_fsm_register() error return values
|
||||||
|
* check for osmo_ss7_init() error return value
|
||||||
|
* manual: Fix copy+paste error
|
||||||
|
* exit(2) on unsupported positional arguments on command line
|
||||||
|
|
||||||
|
[ Oliver Smith ]
|
||||||
|
* gitignore: fix paths to binaries
|
||||||
|
* doc: add OsmoGbProxy VTY reference
|
||||||
|
* regen_doc.sh: support gbproxy, run without docker
|
||||||
|
* osmoappdesc.py, tests: switch to python 3
|
||||||
|
|
||||||
|
-- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 03 Jan 2020 19:17:56 +0100
|
||||||
|
|
||||||
osmo-sgsn (1.5.0) unstable; urgency=medium
|
osmo-sgsn (1.5.0) unstable; urgency=medium
|
||||||
|
|
||||||
[ Max ]
|
[ Max ]
|
||||||
|
|||||||
36
debian/control
vendored
36
debian/control
vendored
@@ -1,7 +1,7 @@
|
|||||||
Source: osmo-sgsn
|
Source: osmo-sgsn
|
||||||
Section: net
|
Section: net
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: Alexander Couzens <lynxis@fe80.eu>
|
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||||
Build-Depends: debhelper (>=9),
|
Build-Depends: debhelper (>=9),
|
||||||
dh-autoreconf,
|
dh-autoreconf,
|
||||||
dh-systemd (>= 1.5),
|
dh-systemd (>= 1.5),
|
||||||
@@ -12,16 +12,16 @@ Build-Depends: debhelper (>=9),
|
|||||||
pkg-config,
|
pkg-config,
|
||||||
libtalloc-dev,
|
libtalloc-dev,
|
||||||
libc-ares-dev,
|
libc-ares-dev,
|
||||||
libgtp-dev (>= 1.4.0),
|
libgtp-dev (>= 1.7.0),
|
||||||
libosmocore-dev (>= 1.2.0),
|
libosmocore-dev (>= 1.5.0),
|
||||||
libosmo-abis-dev (>= 0.6.0),
|
libosmo-abis-dev (>= 1.1.0),
|
||||||
libosmo-netif-dev (>= 0.4.0),
|
libosmo-netif-dev (>= 1.1.0),
|
||||||
libosmo-gsup-client-dev (>= 1.0.0),
|
libosmo-gsup-client-dev (>= 1.3.0),
|
||||||
libasn1c-dev (>= 0.9.30),
|
libasn1c-dev (>= 0.9.30),
|
||||||
libosmo-ranap-dev (>= 0.4.0),
|
libosmo-ranap-dev (>= 0.7.0),
|
||||||
libosmo-sigtran-dev (>= 1.0.0),
|
libosmo-sigtran-dev (>= 1.4.0),
|
||||||
libosmo-sccp-dev (>= 1.0.0),
|
libosmo-sccp-dev (>= 1.4.0),
|
||||||
osmo-gsm-manuals-dev
|
osmo-gsm-manuals-dev (>= 1.1.0)
|
||||||
Standards-Version: 3.9.8
|
Standards-Version: 3.9.8
|
||||||
Vcs-Git: git://git.osmocom.org/osmo-sgsn.git
|
Vcs-Git: git://git.osmocom.org/osmo-sgsn.git
|
||||||
Vcs-Browser: https://git.osmocom.org/osmo-sgsn
|
Vcs-Browser: https://git.osmocom.org/osmo-sgsn
|
||||||
@@ -53,22 +53,6 @@ Priority: extra
|
|||||||
Depends: osmo-gtphub (= ${binary:Version}), ${misc:Depends}
|
Depends: osmo-gtphub (= ${binary:Version}), ${misc:Depends}
|
||||||
Description: Debug symbols for Osmocom GTP Hub
|
Description: Debug symbols for Osmocom GTP Hub
|
||||||
|
|
||||||
Package: osmo-gbproxy
|
|
||||||
Architecture: any
|
|
||||||
Depends: ${shlibs:Depends},
|
|
||||||
${misc:Depends}
|
|
||||||
Recommends: osmo-sgsn
|
|
||||||
Description: Osmocom GPRS Gb Interface Proxy
|
|
||||||
The purpose of the Gb proxy is to aggregate the Gb links of multiple
|
|
||||||
BSS's and present them in one Gb link to the SGSN.
|
|
||||||
|
|
||||||
Package: osmo-gbproxy-dbg
|
|
||||||
Architecture: any
|
|
||||||
Section: debug
|
|
||||||
Priority: extra
|
|
||||||
Depends: osmo-gbproxy (= ${binary:Version}), ${misc:Depends}
|
|
||||||
Description: Debug symbols for Osmocom GPRS Gb Interface Proxy
|
|
||||||
|
|
||||||
Package: osmo-sgsn-doc
|
Package: osmo-sgsn-doc
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Section: doc
|
Section: doc
|
||||||
|
|||||||
12
debian/copyright
vendored
12
debian/copyright
vendored
@@ -19,13 +19,10 @@ Files: .gitignore
|
|||||||
contrib/ipa.py
|
contrib/ipa.py
|
||||||
contrib/jenkins.sh
|
contrib/jenkins.sh
|
||||||
contrib/soap.py
|
contrib/soap.py
|
||||||
contrib/systemd/osmo-gbproxy.service
|
|
||||||
contrib/systemd/osmo-sgsn.service
|
contrib/systemd/osmo-sgsn.service
|
||||||
contrib/twisted_ipa.py
|
contrib/twisted_ipa.py
|
||||||
doc/Makefile.am
|
doc/Makefile.am
|
||||||
doc/examples/Makefile.am
|
doc/examples/Makefile.am
|
||||||
doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg
|
|
||||||
doc/examples/osmo-gbproxy/osmo-gbproxy.cfg
|
|
||||||
doc/examples/osmo-gtphub/gtphub-example.txt
|
doc/examples/osmo-gtphub/gtphub-example.txt
|
||||||
doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
|
doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg
|
||||||
doc/examples/osmo-gtphub/osmo-gtphub.cfg
|
doc/examples/osmo-gtphub/osmo-gtphub.cfg
|
||||||
@@ -51,8 +48,6 @@ Files: .gitignore
|
|||||||
src/gprs/osmo_sgsn.cfg
|
src/gprs/osmo_sgsn.cfg
|
||||||
tests/Makefile.am
|
tests/Makefile.am
|
||||||
tests/atlocal.in
|
tests/atlocal.in
|
||||||
tests/gbproxy/Makefile.am
|
|
||||||
tests/gbproxy/gbproxy_test.ok
|
|
||||||
tests/gprs/Makefile.am
|
tests/gprs/Makefile.am
|
||||||
tests/gprs/gprs_test.c
|
tests/gprs/gprs_test.c
|
||||||
tests/gprs/gprs_test.ok
|
tests/gprs/gprs_test.ok
|
||||||
@@ -86,12 +81,6 @@ Files: include/osmocom/sgsn/a_reset.h
|
|||||||
src/gprs/gprs_gb_parse.c
|
src/gprs/gprs_gb_parse.c
|
||||||
src/gprs/gprs_utils.c
|
src/gprs/gprs_utils.c
|
||||||
src/gprs/sgsn_ares.c
|
src/gprs/sgsn_ares.c
|
||||||
src/gbproxy/gb_proxy.c
|
|
||||||
src/gbproxy/gb_proxy_main.c
|
|
||||||
src/gbproxy/gb_proxy_patch.c
|
|
||||||
src/gbproxy/gb_proxy_peer.c
|
|
||||||
src/gbproxy/gb_proxy_tlli.c
|
|
||||||
src/gbproxy/gb_proxy_vty.c
|
|
||||||
src/gtphub/gtphub.c
|
src/gtphub/gtphub.c
|
||||||
src/gtphub/gtphub_main.c
|
src/gtphub/gtphub_main.c
|
||||||
src/gtphub/gtphub_vty.c
|
src/gtphub/gtphub_vty.c
|
||||||
@@ -142,7 +131,6 @@ License: AGPL-3.0+
|
|||||||
|
|
||||||
Files: src/gtphub/gtphub_ares.c
|
Files: src/gtphub/gtphub_ares.c
|
||||||
src/gtphub/gtphub_sock.c
|
src/gtphub/gtphub_sock.c
|
||||||
tests/gbproxy/gbproxy_test.c
|
|
||||||
Copyright: 2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
|
Copyright: 2013 Jacob Erlbeck <jerlbeck@sysmocom.de>
|
||||||
2013 sysmocom s.f.m.c. GmbH
|
2013 sysmocom s.f.m.c. GmbH
|
||||||
2014 Holger Hans Peter Freyther
|
2014 Holger Hans Peter Freyther
|
||||||
|
|||||||
151
debian/osmo-gbproxy.init
vendored
151
debian/osmo-gbproxy.init
vendored
@@ -1,151 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: osmo-gbproxy
|
|
||||||
# Required-Start: $network $local_fs
|
|
||||||
# Required-Stop:
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: Osmocom GBproxy
|
|
||||||
# Description: A tool to proxy the GPRS Gb interface.
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
# Author: Harald Welte <laforge@gnumonks.org>
|
|
||||||
|
|
||||||
# PATH should only include /usr/* if it runs after the mountnfs.sh script
|
|
||||||
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
|
||||||
NAME=osmo-gbproxy # Introduce the short server's name here
|
|
||||||
DESC="Osmocom GBProxy" # Introduce a short description here
|
|
||||||
DAEMON=/usr/bin/osmo-gbproxy # Introduce the server's location here
|
|
||||||
SCRIPTNAME=/etc/init.d/osmocom-gbproxy
|
|
||||||
CONFIG_FILE=/etc/osmocom/osmocom-gbproxy.cfg
|
|
||||||
|
|
||||||
# Exit if the package is not installed
|
|
||||||
[ -x $DAEMON ] || exit 0
|
|
||||||
|
|
||||||
# Read configuration variable file if it is present
|
|
||||||
[ -r /etc/default/osmocom-gbproxy ] && . /etc/default/osmocom-gbproxy
|
|
||||||
|
|
||||||
# Load the VERBOSE setting and other rcS variables
|
|
||||||
. /lib/init/vars.sh
|
|
||||||
|
|
||||||
# Define LSB log_* functions.
|
|
||||||
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
|
|
||||||
. /lib/lsb/init-functions
|
|
||||||
|
|
||||||
DAEMON_ARGS="-D -c $CONFIG_FILE"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Function that starts the daemon/service
|
|
||||||
#
|
|
||||||
do_start()
|
|
||||||
{
|
|
||||||
# Return
|
|
||||||
# 0 if daemon has been started
|
|
||||||
# 1 if daemon was already running
|
|
||||||
# 2 if daemon could not be started
|
|
||||||
start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
|
|
||||||
|| return 1
|
|
||||||
start-stop-daemon --start --quiet --exec $DAEMON -- \
|
|
||||||
$DAEMON_ARGS \
|
|
||||||
|| return 2
|
|
||||||
# Add code here, if necessary, that waits for the process to be ready
|
|
||||||
# to handle requests from services started subsequently which depend
|
|
||||||
# on this one. As a last resort, sleep for some time.
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Function that stops the daemon/service
|
|
||||||
#
|
|
||||||
do_stop()
|
|
||||||
{
|
|
||||||
# Return
|
|
||||||
# 0 if daemon has been stopped
|
|
||||||
# 1 if daemon was already stopped
|
|
||||||
# 2 if daemon could not be stopped
|
|
||||||
# other if a failure occurred
|
|
||||||
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
|
|
||||||
RETVAL="$?"
|
|
||||||
[ "$RETVAL" = 2 ] && return 2
|
|
||||||
# Wait for children to finish too if this is a daemon that forks
|
|
||||||
# and if the daemon is only ever run from this initscript.
|
|
||||||
# If the above conditions are not satisfied then add some other code
|
|
||||||
# that waits for the process to drop all resources that could be
|
|
||||||
# needed by services started subsequently. A last resort is to
|
|
||||||
# sleep for some time.
|
|
||||||
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
|
||||||
[ "$?" = 2 ] && return 2
|
|
||||||
return "$RETVAL"
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Function that sends a SIGHUP to the daemon/service
|
|
||||||
#
|
|
||||||
do_reload() {
|
|
||||||
#
|
|
||||||
# If the daemon can reload its configuration without
|
|
||||||
# restarting (for example, when it is sent a SIGHUP),
|
|
||||||
# then implement that here.
|
|
||||||
#
|
|
||||||
start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
|
|
||||||
do_start
|
|
||||||
case "$?" in
|
|
||||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
|
||||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
|
||||||
do_stop
|
|
||||||
case "$?" in
|
|
||||||
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
|
||||||
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
|
||||||
;;
|
|
||||||
#reload|force-reload)
|
|
||||||
#
|
|
||||||
# If do_reload() is not implemented then leave this commented out
|
|
||||||
# and leave 'force-reload' as an alias for 'restart'.
|
|
||||||
#
|
|
||||||
#log_daemon_msg "Reloading $DESC" "$NAME"
|
|
||||||
#do_reload
|
|
||||||
#log_end_msg $?
|
|
||||||
#;;
|
|
||||||
restart|force-reload)
|
|
||||||
#
|
|
||||||
# If the "reload" option is implemented then remove the
|
|
||||||
# 'force-reload' alias
|
|
||||||
#
|
|
||||||
log_daemon_msg "Restarting $DESC" "$NAME"
|
|
||||||
do_stop
|
|
||||||
case "$?" in
|
|
||||||
0|1)
|
|
||||||
do_start
|
|
||||||
case "$?" in
|
|
||||||
0) log_end_msg 0 ;;
|
|
||||||
1) log_end_msg 1 ;; # Old process is still running
|
|
||||||
*) log_end_msg 1 ;; # Failed to start
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# Failed to stop
|
|
||||||
log_end_msg 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
|
|
||||||
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
|
|
||||||
exit 3
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
:
|
|
||||||
5
debian/osmo-gbproxy.install
vendored
5
debian/osmo-gbproxy.install
vendored
@@ -1,5 +0,0 @@
|
|||||||
etc/osmocom/osmo-gbproxy.cfg
|
|
||||||
lib/systemd/system/osmo-gbproxy.service
|
|
||||||
usr/bin/osmo-gbproxy
|
|
||||||
usr/share/doc/osmo-sgsn/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg usr/share/doc/osmo-gbproxy/examples
|
|
||||||
usr/share/doc/osmo-sgsn/examples/osmo-gbproxy/osmo-gbproxy.cfg usr/share/doc/osmo-gbproxy/examples
|
|
||||||
1
debian/rules
vendored
1
debian/rules
vendored
@@ -58,7 +58,6 @@ override_dh_auto_configure:
|
|||||||
override_dh_strip:
|
override_dh_strip:
|
||||||
dh_strip -posmo-sgsn --dbg-package=osmo-sgsn-dbg
|
dh_strip -posmo-sgsn --dbg-package=osmo-sgsn-dbg
|
||||||
dh_strip -posmo-gtphub --dbg-package=osmo-gtphub-dbg
|
dh_strip -posmo-gtphub --dbg-package=osmo-gtphub-dbg
|
||||||
dh_strip -posmo-gbproxy --dbg-package=osmo-gbproxy-dbg
|
|
||||||
|
|
||||||
# Print test results in case of a failure
|
# Print test results in case of a failure
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
OSMOCONF_FILES = \
|
OSMOCONF_FILES = \
|
||||||
osmo-gtphub/osmo-gtphub.cfg \
|
osmo-gtphub/osmo-gtphub.cfg \
|
||||||
osmo-sgsn/osmo-sgsn.cfg \
|
osmo-sgsn/osmo-sgsn.cfg \
|
||||||
osmo-gbproxy/osmo-gbproxy.cfg
|
$(NULL)
|
||||||
|
|
||||||
osmoconfdir = $(sysconfdir)/osmocom
|
osmoconfdir = $(sysconfdir)/osmocom
|
||||||
osmoconf_DATA = $(OSMOCONF_FILES)
|
osmoconf_DATA = $(OSMOCONF_FILES)
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -1,26 +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-ip 127.0.0.100
|
|
||||||
encapsulation udp local-port 23000
|
|
||||||
@@ -21,9 +21,9 @@ ns
|
|||||||
timer tns-test 30
|
timer tns-test 30
|
||||||
timer tns-alive 3
|
timer tns-alive 3
|
||||||
timer tns-alive-retries 10
|
timer tns-alive-retries 10
|
||||||
encapsulation udp local-ip 127.0.0.1
|
bind udp local
|
||||||
encapsulation udp local-port 23000
|
listen 127.0.0.1 23000
|
||||||
encapsulation framerelay-gre enabled 0
|
accept-ipaccess
|
||||||
!
|
!
|
||||||
bssgp
|
bssgp
|
||||||
!
|
!
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ ns
|
|||||||
timer tns-test 30
|
timer tns-test 30
|
||||||
timer tns-alive 3
|
timer tns-alive 3
|
||||||
timer tns-alive-retries 10
|
timer tns-alive-retries 10
|
||||||
encapsulation udp local-ip 127.0.0.1
|
bind udp local
|
||||||
encapsulation udp local-port 23000
|
listen 127.0.0.1 23000
|
||||||
encapsulation framerelay-gre enabled 0
|
accept-ipaccess
|
||||||
!
|
!
|
||||||
bssgp
|
bssgp
|
||||||
!
|
!
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ ns
|
|||||||
timer tns-test 30
|
timer tns-test 30
|
||||||
timer tns-alive 3
|
timer tns-alive 3
|
||||||
timer tns-alive-retries 10
|
timer tns-alive-retries 10
|
||||||
encapsulation udp local-ip 127.0.0.1
|
bind udp local
|
||||||
encapsulation udp local-port 23000
|
listen 127.0.0.1 23000
|
||||||
encapsulation framerelay-gre enabled 0
|
accept-ipaccess
|
||||||
!
|
!
|
||||||
bssgp
|
bssgp
|
||||||
!
|
!
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
EXTRA_DIST = osmosgsn-usermanual.adoc \
|
EXTRA_DIST = osmosgsn-usermanual.adoc \
|
||||||
osmosgsn-usermanual-docinfo.xml \
|
osmosgsn-usermanual-docinfo.xml \
|
||||||
osmosgsn-vty-reference.xml \
|
osmosgsn-vty-reference.xml \
|
||||||
osmogbproxy-usermanual.adoc \
|
|
||||||
osmogbproxy-usermanual-docinfo.xml \
|
|
||||||
regen_doc.sh \
|
regen_doc.sh \
|
||||||
chapters \
|
chapters \
|
||||||
vty \
|
vty \
|
||||||
osmogbproxy-vty-reference.xml \
|
|
||||||
vty-osmogbproxy \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
if BUILD_MANUALS
|
if BUILD_MANUALS
|
||||||
ASCIIDOC = osmosgsn-usermanual.adoc osmogbproxy-usermanual.adoc
|
ASCIIDOC = osmosgsn-usermanual.adoc
|
||||||
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
|
ASCIIDOC_DEPS = $(srcdir)/chapters/*.adoc
|
||||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.asciidoc.inc
|
||||||
|
|
||||||
VTY_REFERENCE = osmosgsn-vty-reference.xml osmogbproxy-vty-reference.xml
|
VTY_REFERENCE = osmosgsn-vty-reference.xml
|
||||||
|
|
||||||
|
BUILT_REFERENCE_XML = $(builddir)/vty/sgsn_vty_reference.xml
|
||||||
|
$(builddir)/vty/sgsn_vty_reference.xml: $(top_builddir)/src/sgsn/osmo-sgsn
|
||||||
|
mkdir -p $(builddir)/vty
|
||||||
|
$(top_builddir)/src/sgsn/osmo-sgsn --vty-ref-xml > $@
|
||||||
|
|
||||||
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
include $(OSMO_GSM_MANUALS_DIR)/build/Makefile.vty-reference.inc
|
||||||
|
|
||||||
OSMO_REPOSITORY = osmo-sgsn
|
OSMO_REPOSITORY = osmo-sgsn
|
||||||
|
|||||||
@@ -356,3 +356,23 @@ sgsn
|
|||||||
sgsn
|
sgsn
|
||||||
encryption GEA0
|
encryption GEA0
|
||||||
----
|
----
|
||||||
|
|
||||||
|
=== Configure SCCP/M3UA to accept _IuPS_ links
|
||||||
|
|
||||||
|
OsmoSGSN acts as client to contact an STP instance and establish an SCCP/M3UA
|
||||||
|
link.
|
||||||
|
|
||||||
|
An example configuration of OsmoSGSN's SCCP link:
|
||||||
|
|
||||||
|
----
|
||||||
|
cs7 instance 0
|
||||||
|
point-code 0.23.4
|
||||||
|
asp asp-clnt-OsmoSGSN 2905 0 m3ua
|
||||||
|
remote-ip 127.0.0.1
|
||||||
|
sctp-role client
|
||||||
|
as as-clnt-OsmoSGSN m3ua
|
||||||
|
asp asp-clnt-OsmoSGSN
|
||||||
|
routing-key 0 0.23.4
|
||||||
|
----
|
||||||
|
|
||||||
|
This configuration is explained in detail in <<cs7_config>>.
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
== Configuring OsmoGbPROXY
|
|
||||||
|
|
||||||
TBD. Unfortunately this chapter of the manual still needs to be written.
|
|
||||||
Osmocom has very limited funding and support resources; Feel free to help
|
|
||||||
us completing this documentation by contributing with code, documentation
|
|
||||||
or by supporting the developers financially.
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[[control]]
|
|
||||||
== Control interface
|
|
||||||
|
|
||||||
The actual protocol is described in <<common-control-if>>, the variables
|
|
||||||
common to all programs using it are described in <<ctrl_common_vars>>. Here we
|
|
||||||
describe variables specific to OsmoGbPROXY.
|
|
||||||
|
|
||||||
.Variables available over control interface
|
|
||||||
[options="header",width="100%",cols="20%,5%,5%,50%,20%"]
|
|
||||||
|===
|
|
||||||
|Name|Access|Trap|Value|Comment
|
|
||||||
|nsvc-state|RO|No|"<nsei>,<nsvci>,<local-alive>,<local-blocked>,<remote-role>,<remote-alive>,<remote-blocked>"|See <<nsvc_state>> for details.
|
|
||||||
|gbproxy-state|RO|No|"<nsei>,<bvci>,<mcc>,<mnc>,<lac>,<rac>,<blocked>"|See <<gbproxy_state>> for details.
|
|
||||||
|number-of-peers|RO|No|"<num-of-bss>"|Count of concurrent BSS(BTS) peers.
|
|
||||||
|===
|
|
||||||
|
|
||||||
[[nsvc_state]]
|
|
||||||
=== nsvc-state
|
|
||||||
|
|
||||||
Return the list of active NS-VCs (NS Virtual Circuits), including information
|
|
||||||
on the key parameters, such as NSEI, NSVCI and the local + remote ALIVE
|
|
||||||
and BLOCKED state.
|
|
||||||
|
|
||||||
[[gbproxy_state]]
|
|
||||||
=== gbproxy-state
|
|
||||||
|
|
||||||
Return the list of active Peers, including information on the key
|
|
||||||
parameters, such as NSEI, BVCI, and the MCC-MNC-LAC-RAC of the attached
|
|
||||||
BSS, as well as the overall state (BLOCKED or UNBLOCKED).
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
[[chapter_overview]]
|
|
||||||
== Overview
|
|
||||||
|
|
||||||
=== About OsmoGbPROXY
|
|
||||||
|
|
||||||
OsmoGbPROXY is the Osmocom proxy for the 3GPP Gb interface. The Gb
|
|
||||||
interface is defined by 3GPP as the protocol between the BSS and the
|
|
||||||
SGSN inside the 2G/2.5G/2.75G packet switched network domain.
|
|
||||||
|
|
||||||
As Osmocom implements a BTS-colocated PCU, there are potentially many
|
|
||||||
Gb interface connections between all those many PCUs in the network
|
|
||||||
and the SGSN. This can be cumbersome to configure/maintain at the
|
|
||||||
SGSN sine.
|
|
||||||
|
|
||||||
OsmoGbPROXY aggregates many PCU-facing Gb connections into one Gb
|
|
||||||
connection to the SGSN. This is achieved by
|
|
||||||
|
|
||||||
* maintaining sepaate NS-VCs on the PCU side and on the SGSN side
|
|
||||||
* more or less transparently routing BSSGP peer-to-peer Virtual Circuits
|
|
||||||
(BVCs) through the proxy
|
|
||||||
* having some special handling for the signaling BVC (BVCI=0) which is
|
|
||||||
shared among all the PCUs connected to the proxy
|
|
||||||
|
|
||||||
=== Data Model
|
|
||||||
|
|
||||||
==== gbproxy_config
|
|
||||||
|
|
||||||
This contains the parsed configuration of the OsmoGbPROXY.
|
|
||||||
|
|
||||||
==== gproxy_peer
|
|
||||||
|
|
||||||
A "peer" is any remote NS-entity that the proxy interacts with. A peer
|
|
||||||
includes information about:
|
|
||||||
|
|
||||||
* the [unique] NSEI of the peer
|
|
||||||
* the [unique] BVCI of the peer
|
|
||||||
* the Routeing Area (RA) of the peer
|
|
||||||
|
|
||||||
==== gbproxy_tlli_state
|
|
||||||
|
|
||||||
One of the (unique) TLLI of any of the subscribers/UEs attached to any of
|
|
||||||
the BTSs/PCUs served by the proxy.
|
|
||||||
|
|
||||||
==== gbproxy_link_info
|
|
||||||
|
|
||||||
One of the [unique] subscribers/connections that are served through this
|
|
||||||
proxy. The information includes
|
|
||||||
|
|
||||||
* the TLLI on BSS side
|
|
||||||
* the TLLI on SGSN side (may be different due to P-TMSI rewriting)
|
|
||||||
* the NSEI of the SGSN for this link
|
|
||||||
* a timestamp when we last conversed with this subscriber
|
|
||||||
* state related to IMSI acquisition
|
|
||||||
** a temporary queue of stored messages (until IMSI acquisition succeeds)
|
|
||||||
** N(U) rewriting state (inserting IDENTTIY REQ changes LLC sequence numbers)
|
|
||||||
|
|
||||||
==== gbproxy_match
|
|
||||||
|
|
||||||
A single matching rule against which IMSIs are matched. The matching rule
|
|
||||||
is expressed as regular expression. There can be one such matching rule for
|
|
||||||
each
|
|
||||||
|
|
||||||
* routing between two different SGSNs, see below
|
|
||||||
* patching of messages (e.g. APN, PLMN)
|
|
||||||
|
|
||||||
|
|
||||||
=== Advanced Features
|
|
||||||
|
|
||||||
==== PLMN patching
|
|
||||||
|
|
||||||
This feature permits to modify the PLMN inside any BSSGP messages
|
|
||||||
containing the Routing Area ID (RAID).
|
|
||||||
|
|
||||||
The configured core-mcc and core-mnc will be used towards the SGSN,
|
|
||||||
irrespective of which MCC/MNC the PCU is using/reporting on Gb.
|
|
||||||
|
|
||||||
==== APN patching
|
|
||||||
|
|
||||||
This will transparently re-write the APN name inside SM ACTIVATE PDP
|
|
||||||
REQUEST messages on the way from the MS to the SGSN. The patching is
|
|
||||||
performed based on matching on the IMSI of the subscriber.
|
|
||||||
|
|
||||||
The configured core-apn will be used towards the SGSN, irrespective
|
|
||||||
of which APN the MS is requesting in its Layer3 signaling.
|
|
||||||
|
|
||||||
APN patching can only be performed if no GPRS encryption is enabled in
|
|
||||||
the network!
|
|
||||||
|
|
||||||
APN patching is useful in case a valid APN cannot reliably be
|
|
||||||
provisioned via other means, such as via the SIM Card, OTA-DM or via
|
|
||||||
CAMEL rewriting in the SGSN.
|
|
||||||
|
|
||||||
==== P-TMSI patching
|
|
||||||
|
|
||||||
This feature transparently rewrite the P-TMSI between MS and SGSN. This
|
|
||||||
is required when using the Secondary SGSN support, as both SGSNs could
|
|
||||||
allocate overlapping TMSIs and we must make sure they're unique across
|
|
||||||
both SGSNs.
|
|
||||||
|
|
||||||
P-TMSI patching is required by (and hence automatically enablede if
|
|
||||||
secondary SGSN support is enabled.
|
|
||||||
|
|
||||||
P-TMSI patching can only be performed if no GPRS encryption is enabled in
|
|
||||||
the network!
|
|
||||||
|
|
||||||
==== IMSI Acquisition
|
|
||||||
|
|
||||||
This is a special feature where the proxy will by itself inject GMM IDENTITY
|
|
||||||
REQUEST messages for the IMSI into the downlink BSSGP traffic in order
|
|
||||||
to establish the IMSI of subscribers for which it is not otherwise known
|
|
||||||
|
|
||||||
IMSI acquisition is automatically enabled if secondary SGSN support is
|
|
||||||
enabled.
|
|
||||||
|
|
||||||
==== Secondary SGSN Support
|
|
||||||
|
|
||||||
This allows the proxy to connect not only to one SGSN, but to two
|
|
||||||
different SGSNs. IMSI matching rules are applied to determine which of
|
|
||||||
the SGSNs is to be used for traffic of this subscriber.
|
|
||||||
|
|
||||||
One possible use case of this feature is to have a "local break-out" for
|
|
||||||
subscribers who are native to this network (and hence save
|
|
||||||
latencies/overhead of back-hauling all related traffic via the
|
|
||||||
SGSN+GGSN) while at the same time maintaining the classic behavior for
|
|
||||||
inbound roaming subscribers, where the roaming agreements mandate that
|
|
||||||
data traffic is brought back to the GGSN in the HPLMN via the SGSN of
|
|
||||||
the VPLMN.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
== Running OsmoGbPROXY
|
|
||||||
|
|
||||||
The OsmoGbPROXY executable (`osmo-gbproxy`) offers the following command-line
|
|
||||||
options:
|
|
||||||
|
|
||||||
|
|
||||||
=== SYNOPSIS
|
|
||||||
|
|
||||||
*osmo-gbproxy* [-h|-V] [-d 'DBGMASK'] [-D] [-c 'CONFIGFILE'] [-s] [-e 'LOGLEVEL'] [-T]
|
|
||||||
|
|
||||||
|
|
||||||
=== OPTIONS
|
|
||||||
|
|
||||||
*-h, --help*::
|
|
||||||
Print a short help message about the supported options
|
|
||||||
*-V, --version*::
|
|
||||||
Print the compile-time version number of the program
|
|
||||||
*-d, --debug 'DBGMASK','DBGLEVELS'*::
|
|
||||||
Set the log subsystems and levels for logging to stderr. This
|
|
||||||
has mostly been superseded by VTY-based logging configuration,
|
|
||||||
see <<logging>> for further information.
|
|
||||||
*-D, --daemonize*::
|
|
||||||
Fork the process as a daemon into background.
|
|
||||||
*-c, --config-file 'CONFIGFILE'*::
|
|
||||||
Specify the file and path name of the configuration file to be
|
|
||||||
used. If none is specified, use `osmo_sgsn.cfg` in the current
|
|
||||||
working directory.
|
|
||||||
*-s, --disable-color*::
|
|
||||||
Disable colors for logging to stderr. This has mostly been
|
|
||||||
deprecated by VTY based logging configuration, see <<logging>>
|
|
||||||
for more information.
|
|
||||||
*-e, --log-level 'LOGLEVEL'*::
|
|
||||||
Set the global log level for logging to stderr. This has mostly
|
|
||||||
been deprecated by VTY based logging configuration, see
|
|
||||||
<<logging>> for more information.
|
|
||||||
*-T, --timestamp*::
|
|
||||||
Enable prefixing each log line on stderr with a timestamp. This
|
|
||||||
has mostly been deprecated by VTY based logging configuration, see
|
|
||||||
<<logging>> for more information.
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<revhistory>
|
|
||||||
<revision>
|
|
||||||
<revnumber>1</revnumber>
|
|
||||||
<date>March 21, 2019</date>
|
|
||||||
<authorinitials>HW</authorinitials>
|
|
||||||
<revremark>
|
|
||||||
Initial version.
|
|
||||||
</revremark>
|
|
||||||
</revision>
|
|
||||||
</revhistory>
|
|
||||||
|
|
||||||
<authorgroup>
|
|
||||||
<author>
|
|
||||||
<firstname>Harald</firstname>
|
|
||||||
<surname>Welte</surname>
|
|
||||||
<email>hwelte@sysmocom.de</email>
|
|
||||||
<authorinitials>HW</authorinitials>
|
|
||||||
<affiliation>
|
|
||||||
<shortaffil>sysmocom</shortaffil>
|
|
||||||
<orgname>sysmocom - s.f.m.c. GmbH</orgname>
|
|
||||||
<jobtitle>Managing Director</jobtitle>
|
|
||||||
</affiliation>
|
|
||||||
</author>
|
|
||||||
</authorgroup>
|
|
||||||
|
|
||||||
<copyright>
|
|
||||||
<year>2013-2019</year>
|
|
||||||
<holder>sysmocom - s.f.m.c. GmbH</holder>
|
|
||||||
</copyright>
|
|
||||||
|
|
||||||
<legalnotice>
|
|
||||||
<para>
|
|
||||||
Permission is granted to copy, distribute and/or modify this
|
|
||||||
document under the terms of the GNU Free Documentation License,
|
|
||||||
Version 1.3 or any later version published by the Free Software
|
|
||||||
Foundation; with no Invariant Sections, no Front-Cover Texts,
|
|
||||||
and no Back-Cover Texts. A copy of the license is included in
|
|
||||||
the section entitled "GNU Free Documentation License".
|
|
||||||
</para>
|
|
||||||
<para>
|
|
||||||
The Asciidoc source code of this manual can be found at
|
|
||||||
<ulink url="https://git.osmocom.org/osmo-sgsn/doc/">
|
|
||||||
https://git.osmocom.org/osmo-sgsn/doc/
|
|
||||||
</ulink>
|
|
||||||
</para>
|
|
||||||
</legalnotice>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
:gfdl-enabled:
|
|
||||||
|
|
||||||
OsmoGbPROXY User Manual
|
|
||||||
=======================
|
|
||||||
Harald Welte <hwelte@sysmocom.de>
|
|
||||||
|
|
||||||
|
|
||||||
include::./common/chapters/preface.adoc[]
|
|
||||||
|
|
||||||
include::{srcdir}/chapters/gbproxy-overview.adoc[]
|
|
||||||
|
|
||||||
include::{srcdir}/chapters/gbproxy-running.adoc[]
|
|
||||||
|
|
||||||
include::{srcdir}/chapters/gbproxy-control.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/vty.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/logging.adoc[]
|
|
||||||
|
|
||||||
include::{srcdir}/chapters/gbproxy-configuration.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/gb.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/control_if.adoc[]
|
|
||||||
|
|
||||||
//include::{srcdir}/chapters/counters.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/port_numbers.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/bibliography.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/glossary.adoc[]
|
|
||||||
|
|
||||||
include::./common/chapters/gfdl.adoc[]
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
ex:ts=2:sw=42sts=2:et
|
|
||||||
-*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
|
||||||
-->
|
|
||||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML 5.0//EN"
|
|
||||||
"http://docbook.org/xml/5.0/dtd/docbook.dtd" [
|
|
||||||
<!ENTITY chapter-vty SYSTEM "./common/chapters/vty.xml" >
|
|
||||||
<!ENTITY sections-vty SYSTEM "generated/docbook_osmogbproxy-vty-reference.xml" >
|
|
||||||
]>
|
|
||||||
|
|
||||||
<book>
|
|
||||||
<info>
|
|
||||||
<revhistory>
|
|
||||||
<revision>
|
|
||||||
<revnumber>v1</revnumber>
|
|
||||||
<date>2nd December 2019</date>
|
|
||||||
<authorinitials>hw</authorinitials>
|
|
||||||
<revremark>Initial</revremark>
|
|
||||||
</revision>
|
|
||||||
</revhistory>
|
|
||||||
|
|
||||||
<title>OsmoGbProxy VTY Reference</title>
|
|
||||||
|
|
||||||
<copyright>
|
|
||||||
<year>2019</year>
|
|
||||||
</copyright>
|
|
||||||
|
|
||||||
<legalnotice>
|
|
||||||
<para>This work is copyright by <orgname>sysmocom - s.f.m.c. GmbH</orgname>. All rights reserved.
|
|
||||||
</para>
|
|
||||||
</legalnotice>
|
|
||||||
</info>
|
|
||||||
|
|
||||||
<!-- Main chapters-->
|
|
||||||
&chapter-vty;
|
|
||||||
</book>
|
|
||||||
|
|
||||||
@@ -19,6 +19,8 @@ include::./common/chapters/logging.adoc[]
|
|||||||
|
|
||||||
include::{srcdir}/chapters/configuration.adoc[]
|
include::{srcdir}/chapters/configuration.adoc[]
|
||||||
|
|
||||||
|
include::./common/chapters/cs7-config.adoc[]
|
||||||
|
|
||||||
include::./common/chapters/gb.adoc[]
|
include::./common/chapters/gb.adoc[]
|
||||||
|
|
||||||
include::./common/chapters/control_if.adoc[]
|
include::./common/chapters/control_if.adoc[]
|
||||||
|
|||||||
@@ -61,12 +61,6 @@ interact_vty \
|
|||||||
4245 \
|
4245 \
|
||||||
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
|
osmo-sgsn -c "../examples/osmo-sgsn/osmo-sgsn.cfg"
|
||||||
|
|
||||||
interact_vty \
|
|
||||||
"update_vty_reference" \
|
|
||||||
"vty-osmogbproxy/gbproxy_vty_reference.xml" \
|
|
||||||
4246 \
|
|
||||||
osmo-gbproxy -c "../examples/osmo-gbproxy/osmo-gbproxy.cfg"
|
|
||||||
|
|
||||||
interact_vty \
|
interact_vty \
|
||||||
"update_counters" \
|
"update_counters" \
|
||||||
"chapters/counters_generated.adoc" \
|
"chapters/counters_generated.adoc" \
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>
|
|
||||||
<node id='config-gbproxy'>
|
|
||||||
<description>Configure the Gb proxy</description>
|
|
||||||
</node>
|
|
||||||
</vtydoc>
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ noinst_HEADERS = \
|
|||||||
common.h \
|
common.h \
|
||||||
crc24.h \
|
crc24.h \
|
||||||
debug.h \
|
debug.h \
|
||||||
gb_proxy.h \
|
|
||||||
gprs_gb.h \
|
gprs_gb.h \
|
||||||
gprs_gb_parse.h \
|
gprs_gb_parse.h \
|
||||||
gprs_gmm.h \
|
gprs_gmm.h \
|
||||||
@@ -24,6 +23,7 @@ noinst_HEADERS = \
|
|||||||
gprs_utils.h \
|
gprs_utils.h \
|
||||||
gtphub.h \
|
gtphub.h \
|
||||||
sgsn.h \
|
sgsn.h \
|
||||||
|
sgsn_rim.h \
|
||||||
signal.h \
|
signal.h \
|
||||||
slhc.h \
|
slhc.h \
|
||||||
v42bis.h \
|
v42bis.h \
|
||||||
|
|||||||
@@ -8,38 +8,26 @@
|
|||||||
|
|
||||||
/* Debug Areas of the code */
|
/* Debug Areas of the code */
|
||||||
enum {
|
enum {
|
||||||
DRLL,
|
|
||||||
DCC,
|
|
||||||
DMM,
|
DMM,
|
||||||
DRR,
|
|
||||||
DRSL,
|
|
||||||
DNM,
|
|
||||||
DMNCC,
|
|
||||||
DPAG,
|
DPAG,
|
||||||
DMEAS,
|
DMEAS,
|
||||||
DSCCP,
|
|
||||||
DMSC,
|
|
||||||
DHO,
|
|
||||||
DDB,
|
|
||||||
DREF,
|
DREF,
|
||||||
DGPRS,
|
DGPRS,
|
||||||
DNS,
|
DNS,
|
||||||
DBSSGP,
|
|
||||||
DLLC,
|
DLLC,
|
||||||
DSNDCP,
|
DSNDCP,
|
||||||
DSLHC,
|
DSLHC,
|
||||||
DNAT,
|
|
||||||
DCTRL,
|
DCTRL,
|
||||||
DFILTER,
|
DFILTER,
|
||||||
DGTPHUB,
|
DGTPHUB,
|
||||||
DRANAP,
|
DRANAP,
|
||||||
DSUA,
|
DSUA,
|
||||||
DV42BIS,
|
DV42BIS,
|
||||||
DPCU,
|
|
||||||
DVLR,
|
|
||||||
DIUCS,
|
DIUCS,
|
||||||
DSIGTRAN,
|
DSIGTRAN,
|
||||||
DGTP,
|
DGTP,
|
||||||
|
DOBJ,
|
||||||
|
DRIM,
|
||||||
Debug_LastEntry,
|
Debug_LastEntry,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
#ifndef _GB_PROXY_H
|
|
||||||
#define _GB_PROXY_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <osmocom/core/msgb.h>
|
|
||||||
#include <osmocom/gsm/gsm23003.h>
|
|
||||||
|
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
|
||||||
#include <osmocom/vty/command.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#define GBPROXY_INIT_VU_GEN_TX 256
|
|
||||||
|
|
||||||
struct rate_ctr_group;
|
|
||||||
struct gprs_gb_parse_context;
|
|
||||||
struct tlv_parsed;
|
|
||||||
|
|
||||||
enum gbproxy_global_ctr {
|
|
||||||
GBPROX_GLOB_CTR_INV_BVCI,
|
|
||||||
GBPROX_GLOB_CTR_INV_LAI,
|
|
||||||
GBPROX_GLOB_CTR_INV_RAI,
|
|
||||||
GBPROX_GLOB_CTR_INV_NSEI,
|
|
||||||
GBPROX_GLOB_CTR_PROTO_ERR_BSS,
|
|
||||||
GBPROX_GLOB_CTR_PROTO_ERR_SGSN,
|
|
||||||
GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS,
|
|
||||||
GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN,
|
|
||||||
GBPROX_GLOB_CTR_RESTART_RESET_SGSN,
|
|
||||||
GBPROX_GLOB_CTR_TX_ERR_SGSN,
|
|
||||||
GBPROX_GLOB_CTR_OTHER_ERR,
|
|
||||||
GBPROX_GLOB_CTR_PATCH_PEER_ERR,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum gbproxy_peer_ctr {
|
|
||||||
GBPROX_PEER_CTR_BLOCKED,
|
|
||||||
GBPROX_PEER_CTR_UNBLOCKED,
|
|
||||||
GBPROX_PEER_CTR_DROPPED,
|
|
||||||
GBPROX_PEER_CTR_INV_NSEI,
|
|
||||||
GBPROX_PEER_CTR_TX_ERR,
|
|
||||||
GBPROX_PEER_CTR_RAID_PATCHED_BSS,
|
|
||||||
GBPROX_PEER_CTR_RAID_PATCHED_SGSN,
|
|
||||||
GBPROX_PEER_CTR_APN_PATCHED,
|
|
||||||
GBPROX_PEER_CTR_TLLI_PATCHED_BSS,
|
|
||||||
GBPROX_PEER_CTR_TLLI_PATCHED_SGSN,
|
|
||||||
GBPROX_PEER_CTR_PTMSI_PATCHED_BSS,
|
|
||||||
GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN,
|
|
||||||
GBPROX_PEER_CTR_PATCH_CRYPT_ERR,
|
|
||||||
GBPROX_PEER_CTR_PATCH_ERR,
|
|
||||||
GBPROX_PEER_CTR_ATTACH_REQS,
|
|
||||||
GBPROX_PEER_CTR_ATTACH_REJS,
|
|
||||||
GBPROX_PEER_CTR_ATTACH_ACKS,
|
|
||||||
GBPROX_PEER_CTR_ATTACH_COMPLS,
|
|
||||||
GBPROX_PEER_CTR_RA_UPD_REQS,
|
|
||||||
GBPROX_PEER_CTR_RA_UPD_REJS,
|
|
||||||
GBPROX_PEER_CTR_RA_UPD_ACKS,
|
|
||||||
GBPROX_PEER_CTR_RA_UPD_COMPLS,
|
|
||||||
GBPROX_PEER_CTR_GMM_STATUS_BSS,
|
|
||||||
GBPROX_PEER_CTR_GMM_STATUS_SGSN,
|
|
||||||
GBPROX_PEER_CTR_DETACH_REQS,
|
|
||||||
GBPROX_PEER_CTR_DETACH_ACKS,
|
|
||||||
GBPROX_PEER_CTR_PDP_ACT_REQS,
|
|
||||||
GBPROX_PEER_CTR_PDP_ACT_REJS,
|
|
||||||
GBPROX_PEER_CTR_PDP_ACT_ACKS,
|
|
||||||
GBPROX_PEER_CTR_PDP_DEACT_REQS,
|
|
||||||
GBPROX_PEER_CTR_PDP_DEACT_ACKS,
|
|
||||||
GBPROX_PEER_CTR_TLLI_UNKNOWN,
|
|
||||||
GBPROX_PEER_CTR_TLLI_CACHE_SIZE,
|
|
||||||
GBPROX_PEER_CTR_LAST,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum gbproxy_keep_mode {
|
|
||||||
GBPROX_KEEP_NEVER, /* don't ever keep TLLI/IMSI state of de-registered subscribers */
|
|
||||||
GBPROX_KEEP_REATTACH, /* keep if re-attach has been requested by SGSN */
|
|
||||||
GBPROX_KEEP_IDENTIFIED, /* keep if we had resolved an IMSI */
|
|
||||||
GBPROX_KEEP_ALWAYS, /* always keep */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum gbproxy_match_id {
|
|
||||||
GBPROX_MATCH_PATCHING, /* match rule on whether or not we should patch */
|
|
||||||
GBPROX_MATCH_ROUTING, /* match rule on whether or not we should route (2-SGSN) */
|
|
||||||
GBPROX_MATCH_LAST
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gbproxy_match {
|
|
||||||
bool enable; /* is this match enabled? */
|
|
||||||
char *re_str; /* regular expression (for IMSI) in string format */
|
|
||||||
regex_t re_comp; /* compiled regular expression (for IMSI) */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* global gb-proxy configuration */
|
|
||||||
struct gbproxy_config {
|
|
||||||
/* parsed from config file */
|
|
||||||
uint16_t nsip_sgsn_nsei;
|
|
||||||
|
|
||||||
/* NS instance of libosmogb */
|
|
||||||
struct gprs_ns_inst *nsi;
|
|
||||||
|
|
||||||
/* Linked list of all Gb peers (except SGSN) */
|
|
||||||
struct llist_head bts_peers;
|
|
||||||
|
|
||||||
/* Counter */
|
|
||||||
struct rate_ctr_group *ctrg;
|
|
||||||
|
|
||||||
/* MCC/MNC to be patched into RA-ID on the way from BSS to SGSN? */
|
|
||||||
struct osmo_plmn_id core_plmn;
|
|
||||||
|
|
||||||
/* APN to be patched into PDP CTX ACT REQ on the way from BSS to SGSN */
|
|
||||||
uint8_t* core_apn;
|
|
||||||
size_t core_apn_size;
|
|
||||||
|
|
||||||
/* Frequency (sec) at which timer to clean stale links is fired (0 disabled) */
|
|
||||||
unsigned int clean_stale_timer_freq;
|
|
||||||
/* If !0, Max age to consider a struct gbproxy_link_info as stale */
|
|
||||||
int tlli_max_age;
|
|
||||||
/* If !0, Max len of gbproxy_peer->list (list of struct gbproxy_link_info) */
|
|
||||||
int tlli_max_len;
|
|
||||||
/* If !0, Max len of gbproxy_link_info->stored_msgs (list of msgb) */
|
|
||||||
uint32_t stored_msgs_max_len;
|
|
||||||
|
|
||||||
/* Should the P-TMSI be patched on the fly (required for 2-SGSN config) */
|
|
||||||
bool patch_ptmsi;
|
|
||||||
/* Should the IMSI be acquired by the proxy (required for 2-SGSN config) */
|
|
||||||
bool acquire_imsi;
|
|
||||||
/* Should we route subscribers to two different SGSNs? */
|
|
||||||
bool route_to_sgsn2;
|
|
||||||
/* NSEI of the second SGSN */
|
|
||||||
uint16_t nsip_sgsn2_nsei;
|
|
||||||
/* should we keep a cache of per-subscriber state even after de-registration? */
|
|
||||||
enum gbproxy_keep_mode keep_link_infos;
|
|
||||||
|
|
||||||
/* IMSI checking/matching for 2-SGSN routing and patching */
|
|
||||||
struct gbproxy_match matches[GBPROX_MATCH_LAST];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gbproxy_patch_state {
|
|
||||||
struct osmo_plmn_id local_plmn;
|
|
||||||
|
|
||||||
/* List of TLLIs for which patching is enabled */
|
|
||||||
struct llist_head logical_links;
|
|
||||||
int logical_link_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* one peer at NS level that we interact with (BSS/PCU) */
|
|
||||||
struct gbproxy_peer {
|
|
||||||
/* linked to gbproxy_config.bts_peers */
|
|
||||||
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;
|
|
||||||
bool blocked;
|
|
||||||
|
|
||||||
/* Routeing Area that this peer is part of (raw 04.08 encoding) */
|
|
||||||
uint8_t ra[6];
|
|
||||||
|
|
||||||
/* Counter */
|
|
||||||
struct rate_ctr_group *ctrg;
|
|
||||||
|
|
||||||
/* State related to on-the-fly patching of certain messages */
|
|
||||||
struct gbproxy_patch_state patch_state;
|
|
||||||
|
|
||||||
/* Fired periodically to clean up stale links from list */
|
|
||||||
struct osmo_timer_list clean_stale_timer;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gbproxy_tlli_state {
|
|
||||||
/* currently active TLLI */
|
|
||||||
uint32_t current;
|
|
||||||
/* newly-assigned TLLI (e.g. during P-TMSI allocation procedure) */
|
|
||||||
uint32_t assigned;
|
|
||||||
/* has the BSS side validated (confirmed) the new TLLI? */
|
|
||||||
bool bss_validated;
|
|
||||||
/* has the SGSN side validated (confirmed) the new TLLI? */
|
|
||||||
bool net_validated;
|
|
||||||
/* NOTE: once both are validated, we set current = assigned and assigned = 0 */
|
|
||||||
|
|
||||||
/* The P-TMSI for this subscriber */
|
|
||||||
uint32_t ptmsi;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* One TLLI (= UE, = Subscriber) served via this proxy */
|
|
||||||
struct gbproxy_link_info {
|
|
||||||
/* link to gbproxy_peer.patch_state.logical_links */
|
|
||||||
struct llist_head list;
|
|
||||||
|
|
||||||
/* TLLI on the BSS/PCU side */
|
|
||||||
struct gbproxy_tlli_state tlli;
|
|
||||||
/* TLLI on the SGSN side (can be different in case of P-TMSI patching) */
|
|
||||||
struct gbproxy_tlli_state sgsn_tlli;
|
|
||||||
/* NSEI of the SGSN serving this link */
|
|
||||||
uint32_t sgsn_nsei;
|
|
||||||
|
|
||||||
/* timestamp when we last had any contact with this UE */
|
|
||||||
time_t timestamp;
|
|
||||||
|
|
||||||
/* IMSI of the subscriber (if/once known) */
|
|
||||||
uint8_t *imsi;
|
|
||||||
size_t imsi_len;
|
|
||||||
|
|
||||||
/* is the IMSI acquisition still pending? */
|
|
||||||
bool imsi_acq_pending;
|
|
||||||
|
|
||||||
/* queue of stored UL messages (until IMSI acquisition completes and we can
|
|
||||||
* determine which of the SGSNs we should route this to */
|
|
||||||
struct llist_head stored_msgs;
|
|
||||||
uint32_t stored_msgs_len;
|
|
||||||
|
|
||||||
/* generated N(U) we use (required due to IMSI acquisition */
|
|
||||||
unsigned vu_gen_tx_bss;
|
|
||||||
|
|
||||||
/* is this subscriber deregistered (TLLI invalidated)? */
|
|
||||||
bool is_deregistered;
|
|
||||||
|
|
||||||
/* does this link match either the (2-SGSN) routing or the patching rule? */
|
|
||||||
bool 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_ctrl.c */
|
|
||||||
int gb_ctrl_cmds_install(void);
|
|
||||||
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
@@ -8,7 +8,13 @@
|
|||||||
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
|
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
|
||||||
bool drop_cipherable);
|
bool drop_cipherable);
|
||||||
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
|
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
|
||||||
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx);
|
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg);
|
||||||
|
|
||||||
/* page a MS in its routing area */
|
/* page a MS in its routing area */
|
||||||
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx);
|
int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx);
|
||||||
|
|
||||||
|
/* called by the bssgp layer to send NS PDUs */
|
||||||
|
int gprs_gb_send_cb(void *ctx, struct msgb *msg);
|
||||||
|
|
||||||
|
/* called by the ns layer */
|
||||||
|
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
|
|||||||
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
|
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
|
||||||
struct gprs_gb_parse_context *parse_ctx);
|
struct gprs_gb_parse_context *parse_ctx);
|
||||||
|
|
||||||
|
int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli);
|
||||||
|
|
||||||
const char *gprs_gb_message_name(const 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);
|
const char *default_msg_name);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <osmocom/core/fsm.h>
|
#include <osmocom/core/fsm.h>
|
||||||
|
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||||
|
|
||||||
|
|
||||||
/* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */
|
/* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */
|
||||||
enum gmm_fsm_states {
|
enum gmm_fsm_states {
|
||||||
@@ -23,6 +25,12 @@ enum gmm_fsm_events {
|
|||||||
E_GMM_SUSPEND,
|
E_GMM_SUSPEND,
|
||||||
E_GMM_RESUME,
|
E_GMM_RESUME,
|
||||||
E_GMM_CLEANUP,
|
E_GMM_CLEANUP,
|
||||||
|
E_GMM_RAT_CHANGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gmm_rat_change_data {
|
||||||
|
enum sgsn_ran_type new_ran_type;
|
||||||
|
struct gprs_llc_llme *llme;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool gmm_fsm_is_registered(struct osmo_fsm_inst *fi)
|
static inline bool gmm_fsm_is_registered(struct osmo_fsm_inst *fi)
|
||||||
|
|||||||
@@ -35,14 +35,14 @@
|
|||||||
|
|
||||||
/* TODO move to osmocom/core/socket.c ? */
|
/* TODO move to osmocom/core/socket.c ? */
|
||||||
#include <netdb.h> /* for IPPROTO_* etc */
|
#include <netdb.h> /* for IPPROTO_* etc */
|
||||||
struct osmo_sockaddr {
|
struct sgsn_sockaddr {
|
||||||
struct sockaddr_storage a;
|
struct sockaddr_storage a;
|
||||||
socklen_t l;
|
socklen_t l;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO move to osmocom/core/socket.c ? */
|
/* TODO move to osmocom/core/socket.c ? */
|
||||||
/*! \brief Initialize a sockaddr
|
/*! \brief Initialize a sockaddr
|
||||||
* \param[out] addr Valid osmo_sockaddr pointer to write result to
|
* \param[out] addr Valid sgsn_sockaddr pointer to write result to
|
||||||
* \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
|
* \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC
|
||||||
* \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
|
* \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
|
||||||
* \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
|
* \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
|
||||||
@@ -53,16 +53,16 @@ struct osmo_sockaddr {
|
|||||||
* Copy the first result from a getaddrinfo() call with the given parameters to
|
* Copy the first result from a getaddrinfo() call with the given parameters to
|
||||||
* *addr and *addr_len. On error, do not change *addr and return nonzero.
|
* *addr and *addr_len. On error, do not change *addr and return nonzero.
|
||||||
*/
|
*/
|
||||||
int osmo_sockaddr_init(struct osmo_sockaddr *addr,
|
int sgsn_sockaddr_init(struct sgsn_sockaddr *addr,
|
||||||
uint16_t family, uint16_t type, uint8_t proto,
|
uint16_t family, uint16_t type, uint8_t proto,
|
||||||
const char *host, uint16_t port);
|
const char *host, uint16_t port);
|
||||||
|
|
||||||
/* Conveniently pass AF_UNSPEC, SOCK_DGRAM and IPPROTO_UDP to
|
/* Conveniently pass AF_UNSPEC, SOCK_DGRAM and IPPROTO_UDP to
|
||||||
* osmo_sockaddr_init(). */
|
* sgsn_sockaddr_init(). */
|
||||||
static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr,
|
static inline int sgsn_sockaddr_init_udp(struct sgsn_sockaddr *addr,
|
||||||
const char *host, uint16_t port)
|
const char *host, uint16_t port)
|
||||||
{
|
{
|
||||||
return osmo_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
|
return sgsn_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
host, port);
|
host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,25 +71,25 @@ static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr,
|
|||||||
* \param[in] addr_str_len Size of buffer addr_str points at.
|
* \param[in] addr_str_len Size of buffer addr_str points at.
|
||||||
* \param[out] port_str Valid pointer to a buffer of length port_str_len.
|
* \param[out] port_str Valid pointer to a buffer of length port_str_len.
|
||||||
* \param[in] port_str_len Size of buffer port_str points at.
|
* \param[in] port_str_len Size of buffer port_str points at.
|
||||||
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
|
* \param[in] addr Binary representation as returned by sgsn_sockaddr_init().
|
||||||
* \param[in] flags flags as passed to getnameinfo().
|
* \param[in] flags flags as passed to getnameinfo().
|
||||||
* \returns 0 on success, an error code on error.
|
* \returns 0 on success, an error code on error.
|
||||||
*
|
*
|
||||||
* Return the IPv4 or IPv6 address string and the port (a.k.a. service) string
|
* Return the IPv4 or IPv6 address string and the port (a.k.a. service) string
|
||||||
* representations of the given struct osmo_sockaddr in two caller provided
|
* representations of the given struct sgsn_sockaddr in two caller provided
|
||||||
* char buffers. Flags of (NI_NUMERICHOST | NI_NUMERICSERV) return numeric
|
* char buffers. Flags of (NI_NUMERICHOST | NI_NUMERICSERV) return numeric
|
||||||
* address and port. Either one of addr_str or port_str may be NULL, in which
|
* address and port. Either one of addr_str or port_str may be NULL, in which
|
||||||
* case nothing is returned there.
|
* case nothing is returned there.
|
||||||
*
|
*
|
||||||
* See also osmo_sockaddr_to_str() (less flexible, but much more convenient). */
|
* See also sgsn_sockaddr_to_str() (less flexible, but much more convenient). */
|
||||||
int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
|
int sgsn_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
|
||||||
char *port_str, size_t port_str_len,
|
char *port_str, size_t port_str_len,
|
||||||
const struct osmo_sockaddr *addr,
|
const struct sgsn_sockaddr *addr,
|
||||||
int flags);
|
int flags);
|
||||||
|
|
||||||
|
|
||||||
/*! \brief concatenate the parts returned by osmo_sockaddr_to_strs().
|
/*! \brief concatenate the parts returned by sgsn_sockaddr_to_strs().
|
||||||
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
|
* \param[in] addr Binary representation as returned by sgsn_sockaddr_init().
|
||||||
* \param[in] buf A buffer to use for string operations.
|
* \param[in] buf A buffer to use for string operations.
|
||||||
* \param[in] buf_len Length of the buffer.
|
* \param[in] buf_len Length of the buffer.
|
||||||
* \returns Address string (in buffer).
|
* \returns Address string (in buffer).
|
||||||
@@ -98,33 +98,33 @@ int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
|
|||||||
* the form "<ip-addr> port <port>". The returned string is valid until the
|
* the form "<ip-addr> port <port>". The returned string is valid until the
|
||||||
* next invocation of this function.
|
* next invocation of this function.
|
||||||
*/
|
*/
|
||||||
const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
|
const char *sgsn_sockaddr_to_strb(const struct sgsn_sockaddr *addr,
|
||||||
char *buf, size_t buf_len);
|
char *buf, size_t buf_len);
|
||||||
|
|
||||||
/*! \brief conveniently return osmo_sockaddr_to_strb() in a static buffer.
|
/*! \brief conveniently return sgsn_sockaddr_to_strb() in a static buffer.
|
||||||
* \param[in] addr Binary representation as returned by osmo_sockaddr_init().
|
* \param[in] addr Binary representation as returned by sgsn_sockaddr_init().
|
||||||
* \returns Address string in static buffer.
|
* \returns Address string in static buffer.
|
||||||
*
|
*
|
||||||
* See osmo_sockaddr_to_strb().
|
* See sgsn_sockaddr_to_strb().
|
||||||
*
|
*
|
||||||
* Note: only one osmo_sockaddr_to_str() call will work per print/log
|
* Note: only one sgsn_sockaddr_to_str() call will work per print/log
|
||||||
* statement. For two or more, use osmo_sockaddr_to_strb() with a separate
|
* statement. For two or more, use sgsn_sockaddr_to_strb() with a separate
|
||||||
* buffer each.
|
* buffer each.
|
||||||
*/
|
*/
|
||||||
const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr);
|
const char *sgsn_sockaddr_to_str(const struct sgsn_sockaddr *addr);
|
||||||
|
|
||||||
/*! \brief compare two osmo_sockaddr.
|
/*! \brief compare two sgsn_sockaddr.
|
||||||
* \param[in] a The first address to compare.
|
* \param[in] a The first address to compare.
|
||||||
* \param[in] b The other address to compare.
|
* \param[in] b The other address to compare.
|
||||||
* \returns 0 if equal, otherwise -1 or 1.
|
* \returns 0 if equal, otherwise -1 or 1.
|
||||||
*/
|
*/
|
||||||
int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
|
int sgsn_sockaddr_cmp(const struct sgsn_sockaddr *a,
|
||||||
const struct osmo_sockaddr *b);
|
const struct sgsn_sockaddr *b);
|
||||||
|
|
||||||
/*! \brief Overwrite *dst with *src.
|
/*! \brief Overwrite *dst with *src.
|
||||||
* Like memcpy(), but copy only the valid bytes. */
|
* Like memcpy(), but copy only the valid bytes. */
|
||||||
void osmo_sockaddr_copy(struct osmo_sockaddr *dst,
|
void sgsn_sockaddr_copy(struct sgsn_sockaddr *dst,
|
||||||
const struct osmo_sockaddr *src);
|
const struct sgsn_sockaddr *src);
|
||||||
|
|
||||||
|
|
||||||
/* general */
|
/* general */
|
||||||
@@ -179,7 +179,7 @@ int gsn_addr_same(const struct gsn_addr *a, const struct gsn_addr *b);
|
|||||||
/* Decode sa to gsna. Return 0 on success. If port is non-NULL, the port number
|
/* Decode sa to gsna. Return 0 on success. If port is non-NULL, the port number
|
||||||
* from sa is also returned. */
|
* from sa is also returned. */
|
||||||
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
|
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
|
||||||
const struct osmo_sockaddr *sa);
|
const struct sgsn_sockaddr *sa);
|
||||||
|
|
||||||
/* expiry */
|
/* expiry */
|
||||||
|
|
||||||
@@ -389,7 +389,7 @@ struct gtphub_peer_port {
|
|||||||
struct gtphub_peer_addr *peer_addr;
|
struct gtphub_peer_addr *peer_addr;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
unsigned int ref_count; /* references from other peers' seq_maps */
|
unsigned int ref_count; /* references from other peers' seq_maps */
|
||||||
struct osmo_sockaddr sa; /* a "cache" for (peer_addr->addr, port) */
|
struct sgsn_sockaddr sa; /* a "cache" for (peer_addr->addr, port) */
|
||||||
int last_restart_count; /* 0..255 = valid, all else means unknown */
|
int last_restart_count; /* 0..255 = valid, all else means unknown */
|
||||||
|
|
||||||
struct rate_ctr_group *counters_io;
|
struct rate_ctr_group *counters_io;
|
||||||
@@ -496,13 +496,13 @@ int gtphub_tunnel_complete(struct gtphub_tunnel *tun);
|
|||||||
int gtphub_handle_buf(struct gtphub *hub,
|
int gtphub_handle_buf(struct gtphub *hub,
|
||||||
unsigned int side_idx,
|
unsigned int side_idx,
|
||||||
unsigned int port_idx,
|
unsigned int port_idx,
|
||||||
const struct osmo_sockaddr *from_addr,
|
const struct sgsn_sockaddr *from_addr,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t received,
|
size_t received,
|
||||||
time_t now,
|
time_t now,
|
||||||
uint8_t **reply_buf,
|
uint8_t **reply_buf,
|
||||||
struct osmo_fd **to_ofd,
|
struct osmo_fd **to_ofd,
|
||||||
struct osmo_sockaddr *to_addr);
|
struct sgsn_sockaddr *to_addr);
|
||||||
|
|
||||||
struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
|
struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
|
||||||
struct gtphub_bind *bind,
|
struct gtphub_bind *bind,
|
||||||
@@ -510,7 +510,7 @@ struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
|
|||||||
uint16_t port);
|
uint16_t port);
|
||||||
|
|
||||||
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
|
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
|
||||||
const struct osmo_sockaddr *addr);
|
const struct sgsn_sockaddr *addr);
|
||||||
|
|
||||||
void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
|
void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
|
||||||
struct gsn_addr *resolved_addr,
|
struct gsn_addr *resolved_addr,
|
||||||
@@ -519,5 +519,5 @@ void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str,
|
|||||||
const char *gtphub_port_str(struct gtphub_peer_port *port);
|
const char *gtphub_port_str(struct gtphub_peer_port *port);
|
||||||
|
|
||||||
int gtphub_write(const struct osmo_fd *to,
|
int gtphub_write(const struct osmo_fd *to,
|
||||||
const struct osmo_sockaddr *to_addr,
|
const struct sgsn_sockaddr *to_addr,
|
||||||
const uint8_t *buf, size_t buf_len);
|
const uint8_t *buf, size_t buf_len);
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
|
#include <osmocom/core/select.h>
|
||||||
#include <osmocom/crypt/gprs_cipher.h>
|
#include <osmocom/crypt/gprs_cipher.h>
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
#include <osmocom/gprs/gprs_ns2.h>
|
||||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||||
#include <osmocom/gsm/oap_client.h>
|
#include <osmocom/gsm/oap_client.h>
|
||||||
#include <osmocom/gsupclient/gsup_client.h>
|
#include <osmocom/gsupclient/gsup_client.h>
|
||||||
@@ -69,7 +70,7 @@ struct sgsn_config {
|
|||||||
struct sockaddr_in gtp_listenaddr;
|
struct sockaddr_in gtp_listenaddr;
|
||||||
|
|
||||||
/* misc */
|
/* misc */
|
||||||
struct gprs_ns_inst *nsi;
|
struct gprs_ns2_inst *nsi;
|
||||||
|
|
||||||
enum sgsn_auth_policy auth_policy;
|
enum sgsn_auth_policy auth_policy;
|
||||||
enum gprs_ciph_algo cipher;
|
enum gprs_ciph_algo cipher;
|
||||||
@@ -157,7 +158,7 @@ char *sgsn_gtp_ntoa(struct ul16_t *ul);
|
|||||||
/* sgsn.c */
|
/* sgsn.c */
|
||||||
|
|
||||||
/* Main input function for Gb proxy */
|
/* Main input function for Gb proxy */
|
||||||
int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
|
int sgsn_rcvmsg(struct msgb *msg, struct gprs_ns2_vc *nsvc, uint16_t ns_bvci);
|
||||||
|
|
||||||
/* sgsn_libgtp.c */
|
/* sgsn_libgtp.c */
|
||||||
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
||||||
|
|||||||
3
include/osmocom/sgsn/sgsn_rim.h
Normal file
3
include/osmocom/sgsn/sgsn_rim.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg);
|
||||||
@@ -16,19 +16,16 @@
|
|||||||
|
|
||||||
|
|
||||||
app_configs = {
|
app_configs = {
|
||||||
"gbproxy": ["doc/examples/osmo-gbproxy/osmo-gbproxy.cfg",
|
|
||||||
"doc/examples/osmo-gbproxy/osmo-gbproxy-legacy.cfg"],
|
|
||||||
"sgsn": ["doc/examples/osmo-sgsn/osmo-sgsn.cfg"],
|
"sgsn": ["doc/examples/osmo-sgsn/osmo-sgsn.cfg"],
|
||||||
"gtphub": ["doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg"]
|
"gtphub": ["doc/examples/osmo-gtphub/osmo-gtphub-1iface.cfg"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
apps = [(4246, "src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy"),
|
apps = [(4245, "src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn"),
|
||||||
(4245, "src/sgsn/osmo-sgsn", "OsmoSGSN", "sgsn"),
|
|
||||||
(4253, "src/gtphub/osmo-gtphub", "OsmoGTPhub", "gtphub")
|
(4253, "src/gtphub/osmo-gtphub", "OsmoGTPhub", "gtphub")
|
||||||
]
|
]
|
||||||
|
|
||||||
vty_command = ["./src/sgsn/osmo-sgsn", "-c",
|
vty_command = ["./src/sgsn/osmo-sgsn", "-c",
|
||||||
"doc/examples/osmo-sgsn/osmo-sgsn.cfg"]
|
"doc/examples/osmo-sgsn/osmo-sgsn.cfg"]
|
||||||
|
|
||||||
vty_app = apps[1]
|
vty_app = apps[0]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
gprs \
|
gprs \
|
||||||
sgsn \
|
sgsn \
|
||||||
gbproxy \
|
|
||||||
gtphub \
|
gtphub \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|||||||
@@ -1,46 +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) \
|
|
||||||
$(LIBOSMOGSUPCLIENT_CFLAGS) \
|
|
||||||
$(COVERAGE_CFLAGS) \
|
|
||||||
$(LIBGTP_CFLAGS) \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
bin_PROGRAMS = \
|
|
||||||
osmo-gbproxy \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
osmo_gbproxy_SOURCES = \
|
|
||||||
gb_proxy.c \
|
|
||||||
gb_proxy_main.c \
|
|
||||||
gb_proxy_vty.c \
|
|
||||||
gb_proxy_ctrl.c \
|
|
||||||
gb_proxy_patch.c \
|
|
||||||
gb_proxy_tlli.c \
|
|
||||||
gb_proxy_peer.c \
|
|
||||||
$(NULL)
|
|
||||||
osmo_gbproxy_LDADD = \
|
|
||||||
$(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 \
|
|
||||||
$(LIBOSMOCORE_LIBS) \
|
|
||||||
$(LIBOSMOGSM_LIBS) \
|
|
||||||
$(LIBOSMOVTY_LIBS) \
|
|
||||||
$(LIBOSMOCTRL_LIBS) \
|
|
||||||
$(LIBOSMOGB_LIBS) \
|
|
||||||
$(LIBGTP_LIBS) \
|
|
||||||
-lrt \
|
|
||||||
$(NULL)
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,98 +0,0 @@
|
|||||||
/* Control Interface Implementation for the Gb-proxy */
|
|
||||||
/*
|
|
||||||
* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* Author: Daniel Willmann
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <osmocom/core/talloc.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include <osmocom/gprs/gprs_bssgp.h>
|
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
|
||||||
|
|
||||||
#include <osmocom/ctrl/control_if.h>
|
|
||||||
#include <osmocom/ctrl/control_cmd.h>
|
|
||||||
#include <osmocom/sgsn/gb_proxy.h>
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
|
||||||
|
|
||||||
extern vector ctrl_node_vec;
|
|
||||||
|
|
||||||
static int get_nsvc_state(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct gbproxy_config *cfg = data;
|
|
||||||
struct gprs_ns_inst *nsi = cfg->nsi;
|
|
||||||
struct gprs_nsvc *nsvc;
|
|
||||||
|
|
||||||
cmd->reply = talloc_strdup(cmd, "");
|
|
||||||
|
|
||||||
llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) {
|
|
||||||
if (nsvc == nsi->unknown_nsvc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
cmd->reply = gprs_nsvc_state_append(cmd->reply, nsvc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTRL_CMD_DEFINE_RO(nsvc_state, "nsvc-state");
|
|
||||||
|
|
||||||
static int get_gbproxy_state(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct gbproxy_config *cfg = data;
|
|
||||||
struct gbproxy_peer *peer;
|
|
||||||
|
|
||||||
cmd->reply = talloc_strdup(cmd, "");
|
|
||||||
|
|
||||||
llist_for_each_entry(peer, &cfg->bts_peers, list) {
|
|
||||||
struct gprs_ra_id raid;
|
|
||||||
gsm48_parse_ra(&raid, peer->ra);
|
|
||||||
|
|
||||||
cmd->reply = talloc_asprintf_append(cmd->reply, "%u,%u,%u,%u,%u,%u,%s\n",
|
|
||||||
peer->nsei, peer->bvci,
|
|
||||||
raid.mcc, raid.mnc,
|
|
||||||
raid.lac, raid.rac,
|
|
||||||
peer->blocked ? "BLOCKED" : "UNBLOCKED");
|
|
||||||
}
|
|
||||||
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTRL_CMD_DEFINE_RO(gbproxy_state, "gbproxy-state");
|
|
||||||
|
|
||||||
static int get_num_peers(struct ctrl_cmd *cmd, void *data)
|
|
||||||
{
|
|
||||||
struct gbproxy_config *cfg = data;
|
|
||||||
|
|
||||||
cmd->reply = talloc_strdup(cmd, "");
|
|
||||||
cmd->reply = talloc_asprintf_append(cmd->reply, "%u", llist_count(&cfg->bts_peers));
|
|
||||||
|
|
||||||
return CTRL_CMD_REPLY;
|
|
||||||
}
|
|
||||||
CTRL_CMD_DEFINE_RO(num_peers, "number-of-peers");
|
|
||||||
|
|
||||||
int gb_ctrl_cmds_install(void)
|
|
||||||
{
|
|
||||||
int rc = 0;
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_nsvc_state);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_gbproxy_state);
|
|
||||||
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_num_peers);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
@@ -1,398 +0,0 @@
|
|||||||
/* NS-over-IP proxy */
|
|
||||||
|
|
||||||
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
|
||||||
* (C) 2010 by On-Waves
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/application.h>
|
|
||||||
#include <osmocom/core/talloc.h>
|
|
||||||
#include <osmocom/core/select.h>
|
|
||||||
#include <osmocom/core/rate_ctr.h>
|
|
||||||
#include <osmocom/core/stats.h>
|
|
||||||
|
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
|
||||||
#include <osmocom/gprs/gprs_bssgp.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/signal.h>
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
|
||||||
#include <osmocom/sgsn/vty.h>
|
|
||||||
#include <osmocom/sgsn/gb_proxy.h>
|
|
||||||
|
|
||||||
#include <osmocom/ctrl/control_vty.h>
|
|
||||||
#include <osmocom/ctrl/control_if.h>
|
|
||||||
#include <osmocom/ctrl/ports.h>
|
|
||||||
|
|
||||||
#include <osmocom/vty/command.h>
|
|
||||||
#include <osmocom/vty/telnet_interface.h>
|
|
||||||
#include <osmocom/vty/logging.h>
|
|
||||||
#include <osmocom/vty/stats.h>
|
|
||||||
#include <osmocom/vty/ports.h>
|
|
||||||
#include <osmocom/vty/misc.h>
|
|
||||||
|
|
||||||
#include "../../bscconfig.h"
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
void *tall_sgsn_ctx;
|
|
||||||
|
|
||||||
const char *openbsc_copyright =
|
|
||||||
"Copyright (C) 2010 Harald Welte and On-Waves\r\n"
|
|
||||||
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
|
||||||
"This is free software: you are free to change and redistribute it.\r\n"
|
|
||||||
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
|
||||||
|
|
||||||
#define CONFIG_FILE_DEFAULT "osmo-gbproxy.cfg"
|
|
||||||
#define CONFIG_FILE_LEGACY "osmo_gbproxy.cfg"
|
|
||||||
|
|
||||||
static char *config_file = NULL;
|
|
||||||
struct gbproxy_config *gbcfg;
|
|
||||||
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_sgsn_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 [%s]\n", CONFIG_FILE_DEFAULT);
|
|
||||||
printf(" -s --disable-color\n");
|
|
||||||
printf(" -T --timestamp Prefix every log line with a timestamp\n");
|
|
||||||
printf(" -V --version. Print the version.\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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc > optind) {
|
|
||||||
fprintf(stderr, "Unsupported positional arguments on command line\n");
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int gbproxy_vty_is_config_node(struct vty *vty, int node)
|
|
||||||
{
|
|
||||||
switch (node) {
|
|
||||||
/* add items that are not config */
|
|
||||||
case CONFIG_NODE:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int gbproxy_vty_go_parent(struct vty *vty)
|
|
||||||
{
|
|
||||||
switch (vty->node) {
|
|
||||||
case GBPROXY_NODE:
|
|
||||||
default:
|
|
||||||
if (gbproxy_vty_is_config_node(vty, vty->node))
|
|
||||||
vty->node = CONFIG_NODE;
|
|
||||||
else
|
|
||||||
vty->node = ENABLE_NODE;
|
|
||||||
|
|
||||||
vty->index = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return vty->node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct vty_app_info vty_info = {
|
|
||||||
.name = "OsmoGbProxy",
|
|
||||||
.version = PACKAGE_VERSION,
|
|
||||||
.go_parent_cb = gbproxy_vty_go_parent,
|
|
||||||
.is_config_node = gbproxy_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),
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool file_exists(const char *path)
|
|
||||||
{
|
|
||||||
struct stat sb;
|
|
||||||
return stat(path, &sb) ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
struct ctrl_handle *ctrl;
|
|
||||||
|
|
||||||
tall_sgsn_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
|
|
||||||
msgb_talloc_ctx_init(tall_sgsn_ctx, 0);
|
|
||||||
vty_info.tall_ctx = tall_sgsn_ctx;
|
|
||||||
|
|
||||||
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_logging2(tall_sgsn_ctx, &gprs_log_info);
|
|
||||||
|
|
||||||
vty_info.copyright = openbsc_copyright;
|
|
||||||
vty_init(&vty_info);
|
|
||||||
logging_vty_add_cmds();
|
|
||||||
osmo_talloc_vty_add_cmds();
|
|
||||||
osmo_stats_vty_add_cmds();
|
|
||||||
gbproxy_vty_init();
|
|
||||||
|
|
||||||
handle_options(argc, argv);
|
|
||||||
|
|
||||||
/* Backwards compatibility: for years, the default config file name was
|
|
||||||
* osmo_gbproxy.cfg. All other Osmocom programs use osmo-*.cfg with a
|
|
||||||
* dash. To be able to use the new config file name without breaking
|
|
||||||
* previous setups that might rely on the legacy default config file
|
|
||||||
* name, we need to look for the old config file if no -c option was
|
|
||||||
* passed AND no file exists with the new default file name. */
|
|
||||||
if (!config_file) {
|
|
||||||
/* No -c option was passed */
|
|
||||||
if (file_exists(CONFIG_FILE_LEGACY)
|
|
||||||
&& !file_exists(CONFIG_FILE_DEFAULT))
|
|
||||||
config_file = CONFIG_FILE_LEGACY;
|
|
||||||
else
|
|
||||||
config_file = CONFIG_FILE_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
rate_ctr_init(tall_sgsn_ctx);
|
|
||||||
osmo_stats_init(tall_sgsn_ctx);
|
|
||||||
|
|
||||||
bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb, tall_sgsn_ctx);
|
|
||||||
if (!bssgp_nsi) {
|
|
||||||
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
gbcfg = talloc_zero(tall_sgsn_ctx, struct gbproxy_config);
|
|
||||||
if (!gbcfg) {
|
|
||||||
LOGP(DGPRS, LOGL_FATAL, "Unable to allocate config\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 '%s'\n", config_file);
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start telnet after reading config for vty_get_bind_addr() */
|
|
||||||
rc = telnet_init_dynif(tall_sgsn_ctx, NULL,
|
|
||||||
vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY);
|
|
||||||
if (rc < 0)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
/* Start control interface after getting config for
|
|
||||||
* ctrl_vty_get_bind_addr() */
|
|
||||||
ctrl = ctrl_interface_setup_dynip(gbcfg, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_GBPROXY, NULL);
|
|
||||||
if (!ctrl) {
|
|
||||||
LOGP(DGPRS, LOGL_FATAL, "Failed to create CTRL interface.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gb_ctrl_cmds_install() != 0) {
|
|
||||||
LOGP(DGPRS, LOGL_FATAL, "Failed to install CTRL commands.\n");
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@@ -1,465 +0,0 @@
|
|||||||
/* Gb-proxy message patching */
|
|
||||||
|
|
||||||
/* (C) 2014 by On-Waves
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/gb_proxy.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/gprs_utils.h>
|
|
||||||
#include <osmocom/sgsn/gprs_gb_parse.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
|
||||||
|
|
||||||
#include <osmocom/gprs/protocol/gsm_08_18.h>
|
|
||||||
#include <osmocom/core/rate_ctr.h>
|
|
||||||
#include <osmocom/gsm/apn.h>
|
|
||||||
|
|
||||||
extern void *tall_sgsn_ctx;
|
|
||||||
|
|
||||||
/* patch RA identifier in place */
|
|
||||||
static void gbproxy_patch_raid(struct gsm48_ra_id *raid_enc, struct gbproxy_peer *peer,
|
|
||||||
int to_bss, const char *log_text)
|
|
||||||
{
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
struct osmo_plmn_id old_plmn;
|
|
||||||
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_plmn.mcc || !state->local_plmn.mnc)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gsm48_parse_ra(&raid, (uint8_t *)raid_enc);
|
|
||||||
|
|
||||||
old_plmn = (struct osmo_plmn_id){
|
|
||||||
.mcc = raid.mcc,
|
|
||||||
.mnc = raid.mnc,
|
|
||||||
.mnc_3_digits = raid.mnc_3_digits,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!to_bss) {
|
|
||||||
/* BSS -> SGSN */
|
|
||||||
if (state->local_plmn.mcc)
|
|
||||||
raid.mcc = peer->cfg->core_plmn.mcc;
|
|
||||||
|
|
||||||
if (state->local_plmn.mnc) {
|
|
||||||
raid.mnc = peer->cfg->core_plmn.mnc;
|
|
||||||
raid.mnc_3_digits = peer->cfg->core_plmn.mnc_3_digits;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* SGSN -> BSS */
|
|
||||||
if (state->local_plmn.mcc)
|
|
||||||
raid.mcc = state->local_plmn.mcc;
|
|
||||||
|
|
||||||
if (state->local_plmn.mnc) {
|
|
||||||
raid.mnc = state->local_plmn.mnc;
|
|
||||||
raid.mnc_3_digits = state->local_plmn.mnc_3_digits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGP(DGPRS, LOGL_DEBUG,
|
|
||||||
"Patching %s to %s: "
|
|
||||||
"%s-%d-%d -> %s\n",
|
|
||||||
log_text,
|
|
||||||
to_bss ? "BSS" : "SGSN",
|
|
||||||
osmo_plmn_name(&old_plmn), raid.lac, raid.rac,
|
|
||||||
osmo_rai_name(&raid));
|
|
||||||
|
|
||||||
gsm48_encode_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;
|
|
||||||
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;
|
|
||||||
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((struct gsm48_ra_id *)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((struct gsm48_ra_id *)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_plmn.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((struct gsm48_ra_id *)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 = false;
|
|
||||||
}
|
|
||||||
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 = true;
|
|
||||||
match->re_str = talloc_strdup(tall_sgsn_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;
|
|
||||||
}
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
/* Gb proxy peer handling */
|
|
||||||
|
|
||||||
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
|
||||||
* (C) 2010-2013 by On-Waves
|
|
||||||
* (C) 2013 by Holger Hans Peter Freyther
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/gb_proxy.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
|
||||||
|
|
||||||
#include <osmocom/gprs/protocol/gsm_08_18.h>
|
|
||||||
#include <osmocom/core/rate_ctr.h>
|
|
||||||
#include <osmocom/core/stats.h>
|
|
||||||
#include <osmocom/core/talloc.h>
|
|
||||||
#include <osmocom/gsm/tlv.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
extern void *tall_sgsn_ctx;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clean_stale_timer_cb(void *data)
|
|
||||||
{
|
|
||||||
time_t now;
|
|
||||||
struct timespec ts = {0,};
|
|
||||||
struct gbproxy_peer *peer = (struct gbproxy_peer *) data;
|
|
||||||
|
|
||||||
osmo_clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
||||||
now = ts.tv_sec;
|
|
||||||
gbproxy_remove_stale_link_infos(peer, now);
|
|
||||||
if (peer->cfg->clean_stale_timer_freq != 0)
|
|
||||||
osmo_timer_schedule(&peer->clean_stale_timer,
|
|
||||||
peer->cfg->clean_stale_timer_freq, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
|
|
||||||
{
|
|
||||||
struct gbproxy_peer *peer;
|
|
||||||
|
|
||||||
peer = talloc_zero(tall_sgsn_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);
|
|
||||||
|
|
||||||
osmo_timer_setup(&peer->clean_stale_timer, clean_stale_timer_cb, peer);
|
|
||||||
if (peer->cfg->clean_stale_timer_freq != 0)
|
|
||||||
osmo_timer_schedule(&peer->clean_stale_timer,
|
|
||||||
peer->cfg->clean_stale_timer_freq, 0);
|
|
||||||
|
|
||||||
return peer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_peer_free(struct gbproxy_peer *peer)
|
|
||||||
{
|
|
||||||
llist_del(&peer->list);
|
|
||||||
osmo_timer_del(&peer->clean_stale_timer);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,723 +0,0 @@
|
|||||||
/* Gb-proxy TLLI state handling */
|
|
||||||
|
|
||||||
/* (C) 2014 by On-Waves
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <osmocom/gsm/gsm48.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/gb_proxy.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/gprs_utils.h>
|
|
||||||
#include <osmocom/sgsn/gprs_gb_parse.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
|
||||||
|
|
||||||
#include <osmocom/gsm/gsm_utils.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/rate_ctr.h>
|
|
||||||
#include <osmocom/core/talloc.h>
|
|
||||||
|
|
||||||
struct gbproxy_link_info *gbproxy_link_info_by_tlli(struct gbproxy_peer *peer,
|
|
||||||
uint32_t tlli)
|
|
||||||
{
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
if (!tlli)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
llist_for_each_entry(link_info, &state->logical_links, list)
|
|
||||||
if (link_info->tlli.current == tlli ||
|
|
||||||
link_info->tlli.assigned == tlli)
|
|
||||||
return link_info;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
|
|
||||||
struct gbproxy_peer *peer,
|
|
||||||
uint32_t ptmsi)
|
|
||||||
{
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
if (ptmsi == GSM_RESERVED_TMSI)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
llist_for_each_entry(link_info, &state->logical_links, list)
|
|
||||||
if (link_info->tlli.ptmsi == ptmsi)
|
|
||||||
return link_info;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
|
|
||||||
struct gbproxy_peer *peer,
|
|
||||||
uint32_t tlli)
|
|
||||||
{
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
if (!tlli)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Don't care about the NSEI */
|
|
||||||
llist_for_each_entry(link_info, &state->logical_links, list)
|
|
||||||
if (link_info->sgsn_tlli.current == tlli ||
|
|
||||||
link_info->sgsn_tlli.assigned == tlli)
|
|
||||||
return link_info;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
|
|
||||||
struct gbproxy_peer *peer,
|
|
||||||
uint32_t tlli, uint32_t sgsn_nsei)
|
|
||||||
{
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
if (!tlli)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
llist_for_each_entry(link_info, &state->logical_links, list)
|
|
||||||
if ((link_info->sgsn_tlli.current == tlli ||
|
|
||||||
link_info->sgsn_tlli.assigned == tlli) &&
|
|
||||||
link_info->sgsn_nsei == sgsn_nsei)
|
|
||||||
return link_info;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct gbproxy_link_info *gbproxy_link_info_by_imsi(
|
|
||||||
struct gbproxy_peer *peer,
|
|
||||||
const uint8_t *imsi,
|
|
||||||
size_t imsi_len)
|
|
||||||
{
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
if (!gprs_is_mi_imsi(imsi, imsi_len))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
llist_for_each_entry(link_info, &state->logical_links, list) {
|
|
||||||
if (link_info->imsi_len != imsi_len)
|
|
||||||
continue;
|
|
||||||
if (memcmp(link_info->imsi, imsi, imsi_len) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return link_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info)
|
|
||||||
{
|
|
||||||
struct msgb *msg, *nxt;
|
|
||||||
|
|
||||||
llist_for_each_entry_safe(msg, nxt, &link_info->stored_msgs, list) {
|
|
||||||
llist_del(&msg->list);
|
|
||||||
msgb_free(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_delete_link_info(struct gbproxy_peer *peer,
|
|
||||||
struct gbproxy_link_info *link_info)
|
|
||||||
{
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
gbproxy_link_info_discard_messages(link_info);
|
|
||||||
|
|
||||||
llist_del(&link_info->list);
|
|
||||||
talloc_free(link_info);
|
|
||||||
state->logical_link_count -= 1;
|
|
||||||
|
|
||||||
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
|
|
||||||
state->logical_link_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_delete_link_infos(struct gbproxy_peer *peer)
|
|
||||||
{
|
|
||||||
struct gbproxy_link_info *link_info, *nxt;
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list)
|
|
||||||
gbproxy_delete_link_info(peer, link_info);
|
|
||||||
|
|
||||||
OSMO_ASSERT(state->logical_link_count == 0);
|
|
||||||
OSMO_ASSERT(llist_empty(&state->logical_links));
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
|
|
||||||
struct gbproxy_link_info *link_info)
|
|
||||||
{
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
link_info->timestamp = now;
|
|
||||||
llist_add(&link_info->list, &state->logical_links);
|
|
||||||
state->logical_link_count += 1;
|
|
||||||
|
|
||||||
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
|
|
||||||
state->logical_link_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
|
|
||||||
{
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
int exceeded_max_len = 0;
|
|
||||||
int deleted_count = 0;
|
|
||||||
int check_for_age;
|
|
||||||
|
|
||||||
if (peer->cfg->tlli_max_len > 0)
|
|
||||||
exceeded_max_len =
|
|
||||||
state->logical_link_count - peer->cfg->tlli_max_len;
|
|
||||||
|
|
||||||
check_for_age = peer->cfg->tlli_max_age > 0;
|
|
||||||
|
|
||||||
for (; exceeded_max_len > 0; exceeded_max_len--) {
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
OSMO_ASSERT(!llist_empty(&state->logical_links));
|
|
||||||
link_info = llist_entry(state->logical_links.prev,
|
|
||||||
struct gbproxy_link_info,
|
|
||||||
list);
|
|
||||||
LOGP(DGPRS, LOGL_INFO,
|
|
||||||
"Removing TLLI %08x from list "
|
|
||||||
"(stale, length %d, max_len exceeded)\n",
|
|
||||||
link_info->tlli.current, state->logical_link_count);
|
|
||||||
|
|
||||||
gbproxy_delete_link_info(peer, link_info);
|
|
||||||
deleted_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (check_for_age && !llist_empty(&state->logical_links)) {
|
|
||||||
time_t age;
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
link_info = llist_entry(state->logical_links.prev,
|
|
||||||
struct gbproxy_link_info,
|
|
||||||
list);
|
|
||||||
age = now - link_info->timestamp;
|
|
||||||
/* age < 0 only happens after system time jumps, discard entry */
|
|
||||||
if (age <= peer->cfg->tlli_max_age && age >= 0) {
|
|
||||||
check_for_age = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGP(DGPRS, LOGL_INFO,
|
|
||||||
"Removing TLLI %08x from list "
|
|
||||||
"(stale, age %d, max_age exceeded)\n",
|
|
||||||
link_info->tlli.current, (int)age);
|
|
||||||
|
|
||||||
gbproxy_delete_link_info(peer, link_info);
|
|
||||||
deleted_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return deleted_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer)
|
|
||||||
{
|
|
||||||
struct gbproxy_link_info *link_info;
|
|
||||||
|
|
||||||
link_info = talloc_zero(peer, struct gbproxy_link_info);
|
|
||||||
link_info->tlli.ptmsi = GSM_RESERVED_TMSI;
|
|
||||||
link_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
|
|
||||||
|
|
||||||
link_info->vu_gen_tx_bss = GBPROXY_INIT_VU_GEN_TX;
|
|
||||||
|
|
||||||
INIT_LLIST_HEAD(&link_info->stored_msgs);
|
|
||||||
|
|
||||||
return link_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_detach_link_info(
|
|
||||||
struct gbproxy_peer *peer,
|
|
||||||
struct gbproxy_link_info *link_info)
|
|
||||||
{
|
|
||||||
struct gbproxy_patch_state *state = &peer->patch_state;
|
|
||||||
|
|
||||||
llist_del(&link_info->list);
|
|
||||||
OSMO_ASSERT(state->logical_link_count > 0);
|
|
||||||
state->logical_link_count -= 1;
|
|
||||||
|
|
||||||
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
|
|
||||||
state->logical_link_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
|
|
||||||
const uint8_t *imsi, size_t imsi_len)
|
|
||||||
{
|
|
||||||
if (!gprs_is_mi_imsi(imsi, imsi_len))
|
|
||||||
return;
|
|
||||||
|
|
||||||
link_info->imsi_len = imsi_len;
|
|
||||||
link_info->imsi =
|
|
||||||
talloc_realloc_size(link_info, link_info->imsi, imsi_len);
|
|
||||||
OSMO_ASSERT(link_info->imsi != NULL);
|
|
||||||
memcpy(link_info->imsi, imsi, imsi_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
|
|
||||||
struct gbproxy_peer *peer, uint32_t new_tlli)
|
|
||||||
{
|
|
||||||
if (new_tlli == tlli_state->current)
|
|
||||||
return;
|
|
||||||
|
|
||||||
LOGP(DGPRS, LOGL_INFO,
|
|
||||||
"The TLLI has been reassigned from %08x to %08x\n",
|
|
||||||
tlli_state->current, new_tlli);
|
|
||||||
|
|
||||||
/* Remember assigned TLLI */
|
|
||||||
tlli_state->assigned = new_tlli;
|
|
||||||
tlli_state->bss_validated = false;
|
|
||||||
tlli_state->net_validated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = true;
|
|
||||||
else
|
|
||||||
tlli_state->bss_validated = true;
|
|
||||||
|
|
||||||
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 = true;
|
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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 ? true : false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = false;
|
|
||||||
|
|
||||||
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 = false;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,926 +0,0 @@
|
|||||||
/*
|
|
||||||
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
|
|
||||||
* (C) 2010 by On-Waves
|
|
||||||
* All Rights Reserved
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include <osmocom/core/talloc.h>
|
|
||||||
#include <osmocom/core/rate_ctr.h>
|
|
||||||
#include <osmocom/gsm/gsm48.h>
|
|
||||||
|
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
|
||||||
#include <osmocom/gsm/apn.h>
|
|
||||||
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
|
||||||
#include <osmocom/sgsn/gb_proxy.h>
|
|
||||||
#include <osmocom/sgsn/gprs_utils.h>
|
|
||||||
#include <osmocom/sgsn/vty.h>
|
|
||||||
|
|
||||||
#include <osmocom/vty/command.h>
|
|
||||||
#include <osmocom/vty/vty.h>
|
|
||||||
#include <osmocom/vty/misc.h>
|
|
||||||
|
|
||||||
static struct gbproxy_config *g_cfg = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* vty code for gbproxy 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 %s", peer->nsei, peer->bvci, osmo_rai_name(&raid));
|
|
||||||
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_plmn.mcc > 0)
|
|
||||||
vty_out(vty, " core-mobile-country-code %s%s",
|
|
||||||
osmo_mcc_name(g_cfg->core_plmn.mcc), VTY_NEWLINE);
|
|
||||||
if (g_cfg->core_plmn.mnc > 0)
|
|
||||||
vty_out(vty, " core-mobile-network-code %s%s",
|
|
||||||
osmo_mnc_name(g_cfg->core_plmn.mnc, g_cfg->core_plmn.mnc_3_digits), 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->clean_stale_timer_freq > 0)
|
|
||||||
vty_out(vty, " link-list clean-stale-timer %u%s",
|
|
||||||
g_cfg->clean_stale_timer_freq, 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);
|
|
||||||
if (g_cfg->stored_msgs_max_len > 0)
|
|
||||||
vty_out(vty, " link stored-msgs-max-length %"PRIu32"%s",
|
|
||||||
g_cfg->stored_msgs_max_len, 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")
|
|
||||||
{
|
|
||||||
uint16_t mnc;
|
|
||||||
bool mnc_3_digits;
|
|
||||||
if (osmo_mnc_from_str(argv[0], &mnc, &mnc_3_digits)) {
|
|
||||||
vty_out(vty, "%% Invalid MNC: %s%s", argv[0], VTY_NEWLINE);
|
|
||||||
return CMD_WARNING;
|
|
||||||
}
|
|
||||||
g_cfg->core_plmn.mnc = mnc;
|
|
||||||
g_cfg->core_plmn.mnc_3_digits = mnc_3_digits;
|
|
||||||
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_plmn.mnc = 0;
|
|
||||||
g_cfg->core_plmn.mnc_3_digits = false;
|
|
||||||
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_plmn.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_plmn.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 = true;
|
|
||||||
|
|
||||||
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 = false;
|
|
||||||
|
|
||||||
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 = true;
|
|
||||||
|
|
||||||
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 = false;
|
|
||||||
|
|
||||||
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 = true;
|
|
||||||
|
|
||||||
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 = false;
|
|
||||||
|
|
||||||
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 = true;
|
|
||||||
g_cfg->nsip_sgsn2_nsei = nsei;
|
|
||||||
|
|
||||||
g_cfg->patch_ptmsi = true;
|
|
||||||
|
|
||||||
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 = false;
|
|
||||||
g_cfg->nsip_sgsn2_nsei = 0xFFFF;
|
|
||||||
|
|
||||||
g_cfg->patch_ptmsi = false;
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GBPROXY_LINK_LIST_STR "Set TLLI list parameters\n"
|
|
||||||
#define GBPROXY_LINK_STR "Set TLLI parameters\n"
|
|
||||||
|
|
||||||
#define GBPROXY_CLEAN_STALE_TIMER_STR "Periodic timer to clean stale links\n"
|
|
||||||
|
|
||||||
DEFUN(cfg_gbproxy_link_list_clean_stale_timer,
|
|
||||||
cfg_gbproxy_link_list_clean_stale_timer_cmd,
|
|
||||||
"link-list clean-stale-timer <1-999999>",
|
|
||||||
GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR
|
|
||||||
"Frequency at which the periodic timer is fired (in seconds)\n")
|
|
||||||
{
|
|
||||||
struct gbproxy_peer *peer;
|
|
||||||
g_cfg->clean_stale_timer_freq = (unsigned int) atoi(argv[0]);
|
|
||||||
|
|
||||||
/* Re-schedule running timers soon in case prev frequency was really big
|
|
||||||
and new frequency is desired to be lower. After initial run, periodic
|
|
||||||
time is used. Use random() to avoid firing timers for all peers at
|
|
||||||
the same time */
|
|
||||||
llist_for_each_entry(peer, &g_cfg->bts_peers, list)
|
|
||||||
osmo_timer_schedule(&peer->clean_stale_timer,
|
|
||||||
random() % 5, random() % 1000000);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_gbproxy_link_list_no_clean_stale_timer,
|
|
||||||
cfg_gbproxy_link_list_no_clean_stale_timer_cmd,
|
|
||||||
"no link-list clean-stale-timer",
|
|
||||||
NO_STR GBPROXY_LINK_LIST_STR GBPROXY_CLEAN_STALE_TIMER_STR)
|
|
||||||
|
|
||||||
{
|
|
||||||
struct gbproxy_peer *peer;
|
|
||||||
g_cfg->clean_stale_timer_freq = 0;
|
|
||||||
|
|
||||||
llist_for_each_entry(peer, &g_cfg->bts_peers, list)
|
|
||||||
osmo_timer_del(&peer->clean_stale_timer);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#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(cfg_gbproxy_link_stored_msgs_max_len,
|
|
||||||
cfg_gbproxy_link_stored_msgs_max_len_cmd,
|
|
||||||
"link stored-msgs-max-length <1-99999>",
|
|
||||||
GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR
|
|
||||||
"Maximum number of msgb stored in the logical link waiting to acquire its IMSI\n")
|
|
||||||
{
|
|
||||||
g_cfg->stored_msgs_max_len = (uint32_t) atoi(argv[0]);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN(cfg_gbproxy_link_no_stored_msgs_max_len,
|
|
||||||
cfg_gbproxy_link_no_stored_msgs_max_len_cmd,
|
|
||||||
"no link stored-msgs-max-length",
|
|
||||||
NO_STR GBPROXY_LINK_STR GBPROXY_MAX_LEN_STR)
|
|
||||||
{
|
|
||||||
g_cfg->stored_msgs_max_len = 0;
|
|
||||||
|
|
||||||
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,};
|
|
||||||
|
|
||||||
osmo_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;
|
|
||||||
|
|
||||||
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 (link_info->stored_msgs_len)
|
|
||||||
vty_out(vty, ", STORED %"PRIu32"/%"PRIu32,
|
|
||||||
link_info->stored_msgs_len,
|
|
||||||
g_cfg->stored_msgs_max_len);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
osmo_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 = true;
|
|
||||||
|
|
||||||
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);
|
|
||||||
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_clean_stale_timer_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_link_stored_msgs_max_len_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_clean_stale_timer_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);
|
|
||||||
install_element(GBPROXY_NODE, &cfg_gbproxy_link_no_stored_msgs_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;
|
|
||||||
}
|
|
||||||
@@ -437,6 +437,47 @@ int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
|
|||||||
return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx);
|
return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Determine the TLLI from the given BSSGP message.
|
||||||
|
* \param[in] bssgp pointer to start of BSSGP header
|
||||||
|
* \param[in] bssgp_len length of BSSGP message in octets
|
||||||
|
* \param[out] tlli TLLI (if any) in host byte order
|
||||||
|
* \returns 1 if TLLI found; 0 if none found; negative on parse error */
|
||||||
|
int gprs_gb_parse_tlli(const uint8_t *bssgp, size_t bssgp_len, uint32_t *tlli)
|
||||||
|
{
|
||||||
|
const struct bssgp_normal_hdr *bgph;
|
||||||
|
uint8_t pdu_type;
|
||||||
|
|
||||||
|
if (bssgp_len < sizeof(struct bssgp_normal_hdr))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
bgph = (struct bssgp_normal_hdr *)bssgp;
|
||||||
|
pdu_type = bgph->pdu_type;
|
||||||
|
|
||||||
|
if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
|
||||||
|
pdu_type == BSSGP_PDUT_DL_UNITDATA) {
|
||||||
|
const struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *)bssgp;
|
||||||
|
if (bssgp_len < sizeof(struct bssgp_ud_hdr))
|
||||||
|
return -EINVAL;
|
||||||
|
*tlli = osmo_load32be((const uint8_t *)&budh->tlli);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
const uint8_t *data = bgph->data;
|
||||||
|
size_t data_len = bssgp_len - sizeof(*bgph);
|
||||||
|
struct tlv_parsed tp;
|
||||||
|
|
||||||
|
if (bssgp_tlv_parse(&tp, data, data_len) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (TLVP_PRESENT(&tp, BSSGP_IE_TLLI)) {
|
||||||
|
*tlli = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TLLI));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No TLLI present in message */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
|
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
|
||||||
struct gprs_gb_parse_context *parse_ctx)
|
struct gprs_gb_parse_context *parse_ctx)
|
||||||
{
|
{
|
||||||
@@ -604,13 +645,12 @@ void gprs_gb_log_parse_context(int log_level,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parse_ctx->imsi) {
|
if (parse_ctx->imsi) {
|
||||||
char mi_buf[200];
|
struct osmo_mobile_identity mi;
|
||||||
mi_buf[0] = '\0';
|
if (osmo_mobile_identity_decode(&mi, parse_ctx->imsi, parse_ctx->imsi_len, false) == 0
|
||||||
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
|
&& mi.type == GSM_MI_TYPE_IMSI) {
|
||||||
parse_ctx->imsi, parse_ctx->imsi_len);
|
LOGPC(DGPRS, log_level, "%s IMSI %s", sep, mi.imsi);
|
||||||
LOGPC(DGPRS, log_level, "%s IMSI %s",
|
sep = ",";
|
||||||
sep, mi_buf);
|
}
|
||||||
sep = ",";
|
|
||||||
}
|
}
|
||||||
if (parse_ctx->invalidate_tlli) {
|
if (parse_ctx->invalidate_tlli) {
|
||||||
LOGPC(DGPRS, log_level, "%s invalidate", sep);
|
LOGPC(DGPRS, log_level, "%s invalidate", sep);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#include <osmocom/sgsn/gprs_utils.h>
|
#include <osmocom/sgsn/gprs_utils.h>
|
||||||
|
|
||||||
#include <osmocom/core/msgb.h>
|
#include <osmocom/core/msgb.h>
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
#include <osmocom/gprs/gprs_ns2.h>
|
||||||
|
|
||||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ 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);
|
LOGP(DGPRS, LOGL_DEBUG, "C-ares fd(%d) ready(%d)\n", fd->fd, what);
|
||||||
|
|
||||||
ares_process_fd(sgsn->ares_channel,
|
ares_process_fd(sgsn->ares_channel,
|
||||||
(what & BSC_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
|
(what & OSMO_FD_READ) ? fd->fd : ARES_SOCKET_BAD,
|
||||||
(what & BSC_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD);
|
(what & OSMO_FD_WRITE) ? fd->fd : ARES_SOCKET_BAD);
|
||||||
osmo_ares_reschedule(sgsn);
|
osmo_ares_reschedule(sgsn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -120,14 +120,14 @@ static void setup_ares_osmo_fd(void *data, int fd, int read, int write)
|
|||||||
|
|
||||||
update_fd:
|
update_fd:
|
||||||
if (read)
|
if (read)
|
||||||
ufd->fd.when |= BSC_FD_READ;
|
osmo_fd_read_enable(&ufd->fd);
|
||||||
else
|
else
|
||||||
ufd->fd.when &= ~BSC_FD_READ;
|
osmo_fd_read_disable(&ufd->fd);
|
||||||
|
|
||||||
if (write)
|
if (write)
|
||||||
ufd->fd.when |= BSC_FD_WRITE;
|
osmo_fd_write_enable(&ufd->fd);
|
||||||
else
|
else
|
||||||
ufd->fd.when &= ~BSC_FD_WRITE;
|
osmo_fd_write_disable(&ufd->fd);
|
||||||
|
|
||||||
osmo_ares_reschedule(sgsn);
|
osmo_ares_reschedule(sgsn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,12 +167,12 @@ void gsn_addr_copy(struct gsn_addr *gsna, const struct gsn_addr *src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
|
int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port,
|
||||||
const struct osmo_sockaddr *sa)
|
const struct sgsn_sockaddr *sa)
|
||||||
{
|
{
|
||||||
char addr_str[256];
|
char addr_str[256];
|
||||||
char port_str[6];
|
char port_str[6];
|
||||||
|
|
||||||
if (osmo_sockaddr_to_strs(addr_str, sizeof(addr_str),
|
if (sgsn_sockaddr_to_strs(addr_str, sizeof(addr_str),
|
||||||
port_str, sizeof(port_str),
|
port_str, sizeof(port_str),
|
||||||
sa, (NI_NUMERICHOST | NI_NUMERICSERV))
|
sa, (NI_NUMERICHOST | NI_NUMERICSERV))
|
||||||
!= 0) {
|
!= 0) {
|
||||||
@@ -853,10 +853,7 @@ static int gtphub_sock_init(struct osmo_fd *ofd,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ofd->when = BSC_FD_READ;
|
osmo_fd_setup(ofd, -1, OSMO_FD_READ, cb, data, ofd_id);
|
||||||
ofd->cb = cb;
|
|
||||||
ofd->data = data;
|
|
||||||
ofd->priv_nr = ofd_id;
|
|
||||||
|
|
||||||
int rc;
|
int rc;
|
||||||
rc = osmo_sock_init_ofd(ofd,
|
rc = osmo_sock_init_ofd(ofd,
|
||||||
@@ -925,7 +922,7 @@ static void gtphub_bind_stop(struct gtphub_bind *b) {
|
|||||||
/* Recv datagram from from->fd, write sender's address to *from_addr.
|
/* Recv datagram from from->fd, write sender's address to *from_addr.
|
||||||
* Return the number of bytes read, zero on error. */
|
* Return the number of bytes read, zero on error. */
|
||||||
static int gtphub_read(const struct osmo_fd *from,
|
static int gtphub_read(const struct osmo_fd *from,
|
||||||
struct osmo_sockaddr *from_addr,
|
struct sgsn_sockaddr *from_addr,
|
||||||
uint8_t *buf, size_t buf_len)
|
uint8_t *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(from_addr);
|
OSMO_ASSERT(from_addr);
|
||||||
@@ -946,7 +943,7 @@ static int gtphub_read(const struct osmo_fd *from,
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG(LOGL_DEBUG, "Received %d bytes from %s: %s%s\n",
|
LOG(LOGL_DEBUG, "Received %d bytes from %s: %s%s\n",
|
||||||
(int)received, osmo_sockaddr_to_str(from_addr),
|
(int)received, sgsn_sockaddr_to_str(from_addr),
|
||||||
osmo_hexdump(buf, received > 1000? 1000 : received),
|
osmo_hexdump(buf, received > 1000? 1000 : received),
|
||||||
received > 1000 ? "..." : "");
|
received > 1000 ? "..." : "");
|
||||||
|
|
||||||
@@ -1948,14 +1945,14 @@ static int from_sgsns_read_cb(struct osmo_fd *from_sgsns_ofd, unsigned int what)
|
|||||||
LOG(LOGL_DEBUG, "=== reading from SGSN (%s)\n",
|
LOG(LOGL_DEBUG, "=== reading from SGSN (%s)\n",
|
||||||
gtphub_plane_idx_names[plane_idx]);
|
gtphub_plane_idx_names[plane_idx]);
|
||||||
|
|
||||||
if (!(what & BSC_FD_READ))
|
if (!(what & OSMO_FD_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
struct gtphub *hub = from_sgsns_ofd->data;
|
struct gtphub *hub = from_sgsns_ofd->data;
|
||||||
|
|
||||||
static uint8_t buf[4096];
|
static uint8_t buf[4096];
|
||||||
struct osmo_sockaddr from_addr;
|
struct sgsn_sockaddr from_addr;
|
||||||
struct osmo_sockaddr to_addr;
|
struct sgsn_sockaddr to_addr;
|
||||||
struct osmo_fd *to_ofd;
|
struct osmo_fd *to_ofd;
|
||||||
int len;
|
int len;
|
||||||
uint8_t *reply_buf;
|
uint8_t *reply_buf;
|
||||||
@@ -1979,14 +1976,14 @@ static int from_ggsns_read_cb(struct osmo_fd *from_ggsns_ofd, unsigned int what)
|
|||||||
OSMO_ASSERT(plane_idx < GTPH_PLANE_N);
|
OSMO_ASSERT(plane_idx < GTPH_PLANE_N);
|
||||||
LOG(LOGL_DEBUG, "=== reading from GGSN (%s)\n",
|
LOG(LOGL_DEBUG, "=== reading from GGSN (%s)\n",
|
||||||
gtphub_plane_idx_names[plane_idx]);
|
gtphub_plane_idx_names[plane_idx]);
|
||||||
if (!(what & BSC_FD_READ))
|
if (!(what & OSMO_FD_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
struct gtphub *hub = from_ggsns_ofd->data;
|
struct gtphub *hub = from_ggsns_ofd->data;
|
||||||
|
|
||||||
static uint8_t buf[4096];
|
static uint8_t buf[4096];
|
||||||
struct osmo_sockaddr from_addr;
|
struct sgsn_sockaddr from_addr;
|
||||||
struct osmo_sockaddr to_addr;
|
struct sgsn_sockaddr to_addr;
|
||||||
struct osmo_fd *to_ofd;
|
struct osmo_fd *to_ofd;
|
||||||
int len;
|
int len;
|
||||||
uint8_t *reply_buf;
|
uint8_t *reply_buf;
|
||||||
@@ -2071,9 +2068,9 @@ static int gtphub_unmap(struct gtphub *hub,
|
|||||||
|
|
||||||
static int gsn_addr_to_sockaddr(struct gsn_addr *src,
|
static int gsn_addr_to_sockaddr(struct gsn_addr *src,
|
||||||
uint16_t port,
|
uint16_t port,
|
||||||
struct osmo_sockaddr *dst)
|
struct sgsn_sockaddr *dst)
|
||||||
{
|
{
|
||||||
return osmo_sockaddr_init_udp(dst, gsn_addr_to_str(src), port);
|
return sgsn_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
|
/* If p is an Echo request, replace p's data with the matching response and
|
||||||
@@ -2107,7 +2104,7 @@ static int gtphub_handle_echo_req(struct gtphub *hub, struct gtp_packet_desc *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
|
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
|
||||||
const struct osmo_sockaddr *addr);
|
const struct sgsn_sockaddr *addr);
|
||||||
|
|
||||||
/* Parse buffer as GTP packet, replace elements in-place and return the ofd and
|
/* 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
|
* address to forward to. Return a pointer to the osmo_fd, but copy the
|
||||||
@@ -2117,13 +2114,13 @@ struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *b
|
|||||||
int gtphub_handle_buf(struct gtphub *hub,
|
int gtphub_handle_buf(struct gtphub *hub,
|
||||||
unsigned int side_idx,
|
unsigned int side_idx,
|
||||||
unsigned int plane_idx,
|
unsigned int plane_idx,
|
||||||
const struct osmo_sockaddr *from_addr,
|
const struct sgsn_sockaddr *from_addr,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t received,
|
size_t received,
|
||||||
time_t now,
|
time_t now,
|
||||||
uint8_t **reply_buf,
|
uint8_t **reply_buf,
|
||||||
struct osmo_fd **to_ofd,
|
struct osmo_fd **to_ofd,
|
||||||
struct osmo_sockaddr *to_addr)
|
struct sgsn_sockaddr *to_addr)
|
||||||
{
|
{
|
||||||
struct gtphub_bind *from_bind = &hub->to_gsns[side_idx][plane_idx];
|
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];
|
struct gtphub_bind *to_bind = &hub->to_gsns[other_side_idx(side_idx)][plane_idx];
|
||||||
@@ -2138,7 +2135,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
(side_idx == GTPH_SIDE_GGSN)? "<-" : "->",
|
(side_idx == GTPH_SIDE_GGSN)? "<-" : "->",
|
||||||
gtphub_plane_idx_names[plane_idx],
|
gtphub_plane_idx_names[plane_idx],
|
||||||
gtphub_side_idx_names[side_idx],
|
gtphub_side_idx_names[side_idx],
|
||||||
osmo_sockaddr_to_str(from_addr),
|
sgsn_sockaddr_to_str(from_addr),
|
||||||
gtp_type_str(p.type));
|
gtp_type_str(p.type));
|
||||||
|
|
||||||
if (p.rc <= 0) {
|
if (p.rc <= 0) {
|
||||||
@@ -2146,7 +2143,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
gtp_type_str(p.type),
|
gtp_type_str(p.type),
|
||||||
gtphub_side_idx_names[side_idx],
|
gtphub_side_idx_names[side_idx],
|
||||||
gtphub_plane_idx_names[plane_idx],
|
gtphub_plane_idx_names[plane_idx],
|
||||||
osmo_sockaddr_to_str(from_addr));
|
sgsn_sockaddr_to_str(from_addr));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2156,7 +2153,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
|
reply_len = gtphub_handle_echo_req(hub, &p, reply_buf);
|
||||||
if (reply_len > 0) {
|
if (reply_len > 0) {
|
||||||
/* It was an echo. Nothing left to do. */
|
/* It was an echo. Nothing left to do. */
|
||||||
osmo_sockaddr_copy(to_addr, from_addr);
|
sgsn_sockaddr_copy(to_addr, from_addr);
|
||||||
*to_ofd = &from_bind->ofd;
|
*to_ofd = &from_bind->ofd;
|
||||||
|
|
||||||
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
rate_ctr_inc(&from_bind->counters_io->ctr[GTPH_CTR_PKTS_OUT]);
|
||||||
@@ -2165,7 +2162,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
|
LOG(LOGL_DEBUG, "%s Echo response to %s: %d bytes to %s\n",
|
||||||
(side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
|
(side_idx == GTPH_SIDE_GGSN)? "-->" : "<--",
|
||||||
gtphub_side_idx_names[side_idx],
|
gtphub_side_idx_names[side_idx],
|
||||||
(int)reply_len, osmo_sockaddr_to_str(to_addr));
|
(int)reply_len, sgsn_sockaddr_to_str(to_addr));
|
||||||
return reply_len;
|
return reply_len;
|
||||||
}
|
}
|
||||||
if (reply_len < 0)
|
if (reply_len < 0)
|
||||||
@@ -2178,7 +2175,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
* so no-one else is allowed to talk to us from that side. */
|
* 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];
|
struct gtphub_peer_port *from_peer = hub->proxy[side_idx][plane_idx];
|
||||||
if (from_peer) {
|
if (from_peer) {
|
||||||
if (osmo_sockaddr_cmp(&from_peer->sa, from_addr) != 0) {
|
if (sgsn_sockaddr_cmp(&from_peer->sa, from_addr) != 0) {
|
||||||
LOG(LOGL_ERROR,
|
LOG(LOGL_ERROR,
|
||||||
"Rejecting: %s proxy configured, but GTP packet"
|
"Rejecting: %s proxy configured, but GTP packet"
|
||||||
" received on %s bind is from another sender:"
|
" received on %s bind is from another sender:"
|
||||||
@@ -2186,7 +2183,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
gtphub_side_idx_names[side_idx],
|
gtphub_side_idx_names[side_idx],
|
||||||
gtphub_side_idx_names[side_idx],
|
gtphub_side_idx_names[side_idx],
|
||||||
gtphub_port_str(from_peer),
|
gtphub_port_str(from_peer),
|
||||||
osmo_sockaddr_to_str(from_addr));
|
sgsn_sockaddr_to_str(from_addr));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2204,7 +2201,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
if (side_idx == GTPH_SIDE_GGSN) {
|
if (side_idx == GTPH_SIDE_GGSN) {
|
||||||
LOG(LOGL_ERROR, "Dropping packet%s: unknown GGSN peer: %s\n",
|
LOG(LOGL_ERROR, "Dropping packet%s: unknown GGSN peer: %s\n",
|
||||||
gtp_type_str(p.type),
|
gtp_type_str(p.type),
|
||||||
osmo_sockaddr_to_str(from_addr));
|
sgsn_sockaddr_to_str(from_addr));
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
/* SGSN */
|
/* SGSN */
|
||||||
@@ -2216,7 +2213,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
"Dropping packet%s: User plane peer was not"
|
"Dropping packet%s: User plane peer was not"
|
||||||
"announced by PDP Context: %s\n",
|
"announced by PDP Context: %s\n",
|
||||||
gtp_type_str(p.type),
|
gtp_type_str(p.type),
|
||||||
osmo_sockaddr_to_str(from_addr));
|
sgsn_sockaddr_to_str(from_addr));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2235,7 +2232,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
LOG(LOGL_ERROR, "Dropping packet%s: invalid %s peer: %s\n",
|
LOG(LOGL_ERROR, "Dropping packet%s: invalid %s peer: %s\n",
|
||||||
gtp_type_str(p.type),
|
gtp_type_str(p.type),
|
||||||
gtphub_side_idx_names[side_idx],
|
gtphub_side_idx_names[side_idx],
|
||||||
osmo_sockaddr_to_str(from_addr));
|
sgsn_sockaddr_to_str(from_addr));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2309,7 +2306,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
if (!to_peer_from_seq)
|
if (!to_peer_from_seq)
|
||||||
gtphub_map_seq(&p, from_peer, to_peer);
|
gtphub_map_seq(&p, from_peer, to_peer);
|
||||||
|
|
||||||
osmo_sockaddr_copy(to_addr, &to_peer->sa);
|
sgsn_sockaddr_copy(to_addr, &to_peer->sa);
|
||||||
|
|
||||||
*reply_buf = (uint8_t*)p.data;
|
*reply_buf = (uint8_t*)p.data;
|
||||||
|
|
||||||
@@ -2335,7 +2332,7 @@ int gtphub_handle_buf(struct gtphub *hub,
|
|||||||
(side_idx == GTPH_SIDE_SGSN)? "-->" : "<--",
|
(side_idx == GTPH_SIDE_SGSN)? "-->" : "<--",
|
||||||
gtphub_side_idx_names[other_side_idx(side_idx)],
|
gtphub_side_idx_names[other_side_idx(side_idx)],
|
||||||
p.header_tei, p.seq,
|
p.header_tei, p.seq,
|
||||||
(int)received, osmo_sockaddr_to_str(to_addr));
|
(int)received, sgsn_sockaddr_to_str(to_addr));
|
||||||
return received;
|
return received;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2645,7 +2642,7 @@ static struct gtphub_peer_port *gtphub_port_find(const struct gtphub_bind *bind,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
|
struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind,
|
||||||
const struct osmo_sockaddr *addr)
|
const struct sgsn_sockaddr *addr)
|
||||||
{
|
{
|
||||||
struct gsn_addr gsna;
|
struct gsn_addr gsna;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
@@ -2762,7 +2759,7 @@ struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub,
|
|||||||
/* Find a GGSN peer with a matching address. If the address is known but the
|
/* 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. */
|
* port not, create a new port for that peer address. */
|
||||||
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
|
struct gtphub_peer_port *gtphub_known_addr_have_port(const struct gtphub_bind *bind,
|
||||||
const struct osmo_sockaddr *addr)
|
const struct sgsn_sockaddr *addr)
|
||||||
{
|
{
|
||||||
struct gtphub_peer_addr *pa;
|
struct gtphub_peer_addr *pa;
|
||||||
struct gtphub_peer_port *pp;
|
struct gtphub_peer_port *pp;
|
||||||
@@ -2817,7 +2814,7 @@ static int gtphub_resolve_ggsn(struct gtphub *hub,
|
|||||||
|
|
||||||
/* TODO move to osmocom/core/socket.c ? */
|
/* TODO move to osmocom/core/socket.c ? */
|
||||||
/* use this in osmo_sock_init() to remove dup. */
|
/* use this in osmo_sock_init() to remove dup. */
|
||||||
/* Internal: call getaddrinfo for osmo_sockaddr_init(). The caller is required
|
/* Internal: call getaddrinfo for sgsn_sockaddr_init(). The caller is required
|
||||||
to call freeaddrinfo(*result), iff zero is returned. */
|
to call freeaddrinfo(*result), iff zero is returned. */
|
||||||
static int _osmo_getaddrinfo(struct addrinfo **result,
|
static int _osmo_getaddrinfo(struct addrinfo **result,
|
||||||
uint16_t family, uint16_t type, uint8_t proto,
|
uint16_t family, uint16_t type, uint8_t proto,
|
||||||
@@ -2844,7 +2841,7 @@ static int _osmo_getaddrinfo(struct addrinfo **result,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO move to osmocom/core/socket.c ? */
|
/* TODO move to osmocom/core/socket.c ? */
|
||||||
int osmo_sockaddr_init(struct osmo_sockaddr *addr,
|
int sgsn_sockaddr_init(struct sgsn_sockaddr *addr,
|
||||||
uint16_t family, uint16_t type, uint8_t proto,
|
uint16_t family, uint16_t type, uint8_t proto,
|
||||||
const char *host, uint16_t port)
|
const char *host, uint16_t port)
|
||||||
{
|
{
|
||||||
@@ -2865,9 +2862,9 @@ int osmo_sockaddr_init(struct osmo_sockaddr *addr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
|
int sgsn_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
|
||||||
char *port_str, size_t port_str_len,
|
char *port_str, size_t port_str_len,
|
||||||
const struct osmo_sockaddr *addr,
|
const struct sgsn_sockaddr *addr,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -2896,14 +2893,14 @@ int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
|
const char *sgsn_sockaddr_to_strb(const struct sgsn_sockaddr *addr,
|
||||||
char *buf, size_t buf_len)
|
char *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
|
char portbuf[6];
|
||||||
const int portbuf_len = 6;
|
const int portbuf_len = 6;
|
||||||
OSMO_ASSERT(buf_len > portbuf_len);
|
OSMO_ASSERT(buf_len > portbuf_len);
|
||||||
char *portbuf = buf + buf_len - portbuf_len;
|
|
||||||
buf_len -= portbuf_len;
|
buf_len -= portbuf_len;
|
||||||
if (osmo_sockaddr_to_strs(buf, buf_len,
|
if (sgsn_sockaddr_to_strs(buf, buf_len,
|
||||||
portbuf, portbuf_len,
|
portbuf, portbuf_len,
|
||||||
addr,
|
addr,
|
||||||
NI_NUMERICHOST | NI_NUMERICSERV))
|
NI_NUMERICHOST | NI_NUMERICSERV))
|
||||||
@@ -2918,17 +2915,17 @@ const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr,
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr)
|
const char *sgsn_sockaddr_to_str(const struct sgsn_sockaddr *addr)
|
||||||
{
|
{
|
||||||
static char buf[256];
|
static char buf[256];
|
||||||
const char *result = osmo_sockaddr_to_strb(addr, buf, sizeof(buf));
|
const char *result = sgsn_sockaddr_to_strb(addr, buf, sizeof(buf));
|
||||||
if (! result)
|
if (! result)
|
||||||
return "(invalid)";
|
return "(invalid)";
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
|
int sgsn_sockaddr_cmp(const struct sgsn_sockaddr *a,
|
||||||
const struct osmo_sockaddr *b)
|
const struct sgsn_sockaddr *b)
|
||||||
{
|
{
|
||||||
if (a == b)
|
if (a == b)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2938,7 +2935,7 @@ int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
|
|||||||
return 1;
|
return 1;
|
||||||
if (a->l != b->l) {
|
if (a->l != b->l) {
|
||||||
/* Lengths are not the same, but determine the order. Will
|
/* Lengths are not the same, but determine the order. Will
|
||||||
* anyone ever sort a list by osmo_sockaddr though...? */
|
* anyone ever sort a list by sgsn_sockaddr though...? */
|
||||||
int cmp = memcmp(&a->a, &b->a, (a->l < b->l)? a->l : b->l);
|
int cmp = memcmp(&a->a, &b->a, (a->l < b->l)? a->l : b->l);
|
||||||
if (cmp == 0) {
|
if (cmp == 0) {
|
||||||
if (a->l < b->l)
|
if (a->l < b->l)
|
||||||
@@ -2951,8 +2948,8 @@ int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
|
|||||||
return memcmp(&a->a, &b->a, a->l);
|
return memcmp(&a->a, &b->a, a->l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void osmo_sockaddr_copy(struct osmo_sockaddr *dst,
|
void sgsn_sockaddr_copy(struct sgsn_sockaddr *dst,
|
||||||
const struct osmo_sockaddr *src)
|
const struct sgsn_sockaddr *src)
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(src->l <= sizeof(dst->a));
|
OSMO_ASSERT(src->l <= sizeof(dst->a));
|
||||||
memcpy(&dst->a, &src->a, src->l);
|
memcpy(&dst->a, &src->a, src->l);
|
||||||
|
|||||||
@@ -95,11 +95,11 @@ void log_cfg(struct gtphub_cfg *cfg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_handler(int signal)
|
static void signal_handler(int signum)
|
||||||
{
|
{
|
||||||
fprintf(stdout, "signal %d received\n", signal);
|
fprintf(stdout, "signal %d received\n", signum);
|
||||||
|
|
||||||
switch (signal) {
|
switch (signum) {
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
|
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
|
||||||
@@ -107,8 +107,16 @@ static void signal_handler(int signal)
|
|||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
/* in case of abort, we want to obtain a talloc report
|
/* in case of abort, we want to obtain a talloc report and
|
||||||
* and then return to the caller, who will abort the process */
|
* then run default SIGABRT handler, who will generate coredump
|
||||||
|
* and abort the process. abort() should do this for us after we
|
||||||
|
* return, but program wouldn't exit if an external SIGABRT is
|
||||||
|
* received.
|
||||||
|
*/
|
||||||
|
talloc_report_full(osmo_gtphub_ctx, stderr);
|
||||||
|
signal(SIGABRT, SIG_DFL);
|
||||||
|
raise(SIGABRT);
|
||||||
|
break;
|
||||||
case SIGUSR1:
|
case SIGUSR1:
|
||||||
case SIGUSR2:
|
case SIGUSR2:
|
||||||
talloc_report_full(osmo_gtphub_ctx, stderr);
|
talloc_report_full(osmo_gtphub_ctx, stderr);
|
||||||
@@ -118,44 +126,12 @@ static void signal_handler(int signal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BUILD_IU
|
|
||||||
int gtphub_vty_go_parent(struct vty *vty)
|
|
||||||
{
|
|
||||||
switch (vty->node) {
|
|
||||||
default:
|
|
||||||
osmo_ss7_vty_go_parent(vty);
|
|
||||||
}
|
|
||||||
|
|
||||||
return vty->node;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int gtphub_vty_is_config_node(struct vty *vty, int node)
|
|
||||||
{
|
|
||||||
/* Check if libosmo-sccp declares the node in
|
|
||||||
* question as config node */
|
|
||||||
#if BUILD_IU
|
|
||||||
if (osmo_ss7_is_config_node(vty, node))
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (node) {
|
|
||||||
/* add items that are not config */
|
|
||||||
case CONFIG_NODE:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct vty_app_info vty_info = {
|
static struct vty_app_info vty_info = {
|
||||||
.name = "OsmoGTPhub",
|
.name = "OsmoGTPhub",
|
||||||
.version = PACKAGE_VERSION,
|
.version = PACKAGE_VERSION,
|
||||||
#if BUILD_IU
|
#if BUILD_IU
|
||||||
.go_parent_cb = gtphub_vty_go_parent,
|
.go_parent_cb = osmo_ss7_vty_go_parent,
|
||||||
#endif
|
#endif
|
||||||
.is_config_node = gtphub_vty_is_config_node,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cmdline_cfg {
|
struct cmdline_cfg {
|
||||||
|
|||||||
@@ -33,13 +33,13 @@
|
|||||||
LOGP(DGTPHUB, level, fmt, ##args)
|
LOGP(DGTPHUB, level, fmt, ##args)
|
||||||
|
|
||||||
int gtphub_write(const struct osmo_fd *to,
|
int gtphub_write(const struct osmo_fd *to,
|
||||||
const struct osmo_sockaddr *to_addr,
|
const struct sgsn_sockaddr *to_addr,
|
||||||
const uint8_t *buf, size_t buf_len)
|
const uint8_t *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ssize_t sent = sendto(to->fd, buf, buf_len, 0,
|
ssize_t sent = sendto(to->fd, buf, buf_len, 0,
|
||||||
(struct sockaddr*)&to_addr->a, to_addr->l);
|
(struct sockaddr*)&to_addr->a, to_addr->l);
|
||||||
LOG(LOGL_DEBUG, "to %s\n", osmo_sockaddr_to_str(to_addr));
|
LOG(LOGL_DEBUG, "to %s\n", sgsn_sockaddr_to_str(to_addr));
|
||||||
|
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
LOG(LOGL_ERROR, "error: %s\n", strerror(errno));
|
LOG(LOGL_ERROR, "error: %s\n", strerror(errno));
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ osmo_sgsn_SOURCES = \
|
|||||||
sgsn_auth.c \
|
sgsn_auth.c \
|
||||||
gprs_subscriber.c \
|
gprs_subscriber.c \
|
||||||
sgsn_cdr.c \
|
sgsn_cdr.c \
|
||||||
|
sgsn_rim.c \
|
||||||
slhc.c \
|
slhc.c \
|
||||||
gprs_llc_xid.c \
|
gprs_llc_xid.c \
|
||||||
v42bis.c \
|
v42bis.c \
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
|
|
||||||
#include <osmocom/gprs/gprs_msgb.h>
|
#include <osmocom/gprs/gprs_msgb.h>
|
||||||
#include <osmocom/gprs/gprs_bssgp.h>
|
#include <osmocom/gprs/gprs_bssgp.h>
|
||||||
|
#include <osmocom/gprs/gprs_ns2.h>
|
||||||
|
#include <osmocom/gprs/gprs_bssgp_bss.h>
|
||||||
|
#include <osmocom/sgsn/gprs_llc.h>
|
||||||
|
|
||||||
#include "bscconfig.h"
|
#include "bscconfig.h"
|
||||||
|
|
||||||
@@ -35,7 +38,8 @@
|
|||||||
#include <osmocom/sgsn/debug.h>
|
#include <osmocom/sgsn/debug.h>
|
||||||
|
|
||||||
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
|
/* Has to be called whenever any PDU (signaling, data, ...) has been received */
|
||||||
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx) {
|
void gprs_gb_recv_pdu(struct sgsn_mm_ctx *mmctx, const struct msgb *msg) {
|
||||||
|
msgid2mmctx(mmctx, msg);
|
||||||
if (mmctx->gb.llme)
|
if (mmctx->gb.llme)
|
||||||
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
|
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
|
||||||
}
|
}
|
||||||
@@ -53,10 +57,9 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
|
|||||||
bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
|
bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
|
||||||
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
|
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
|
||||||
if (mmctx) {
|
if (mmctx) {
|
||||||
msgid2mmctx(mmctx, msg);
|
|
||||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||||
mmctx->gb.llme = llme;
|
mmctx->gb.llme = llme;
|
||||||
gprs_gb_recv_pdu(mmctx);
|
gprs_gb_recv_pdu(mmctx, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MMCTX can be NULL */
|
/* MMCTX can be NULL */
|
||||||
@@ -103,3 +106,83 @@ int gprs_gb_page_ps_ra(struct sgsn_mm_ctx *mmctx)
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called by the bssgp layer to send NS PDUs */
|
||||||
|
int gprs_gb_send_cb(void *ctx, struct msgb *msg)
|
||||||
|
{
|
||||||
|
struct gprs_ns2_inst *nsi = (struct gprs_ns2_inst *) ctx;
|
||||||
|
struct osmo_gprs_ns2_prim nsp = {};
|
||||||
|
nsp.nsei = msgb_nsei(msg);
|
||||||
|
nsp.bvci = msgb_bvci(msg);
|
||||||
|
osmo_prim_init(&nsp.oph, SAP_NS, GPRS_NS2_PRIM_UNIT_DATA, PRIM_OP_REQUEST, msg);
|
||||||
|
return gprs_ns2_recv_prim(nsi, &nsp.oph);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gprs_ns_prim_status_cb(struct osmo_gprs_ns2_prim *nsp)
|
||||||
|
{
|
||||||
|
switch (nsp->u.status.cause) {
|
||||||
|
case GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED:
|
||||||
|
LOGP(DGPRS, LOGL_NOTICE, "NS-E %d SNS configured.\n", nsp->nsei);
|
||||||
|
break;
|
||||||
|
case GPRS_NS2_AFF_CAUSE_RECOVERY:
|
||||||
|
LOGP(DGPRS, LOGL_NOTICE, "NS-E %d became available\n", nsp->nsei);
|
||||||
|
/* workaround for broken BSS which doesn't respond correct to BSSGP status message.
|
||||||
|
* Sent a BSSGP Reset when a persistent NSVC comes up for the first time. */
|
||||||
|
if (nsp->u.status.first && nsp->u.status.persistent) {
|
||||||
|
struct bssgp_bvc_ctx bctx = {
|
||||||
|
.nsei = nsp->nsei,
|
||||||
|
};
|
||||||
|
bssgp_tx_bvc_reset2(&bctx, BVCI_SIGNALLING, BSSGP_CAUSE_EQUIP_FAIL, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GPRS_NS2_AFF_CAUSE_FAILURE:
|
||||||
|
LOGP(DGPRS, LOGL_NOTICE, "NS-E %d became unavailable\n", nsp->nsei);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DGPRS, LOGL_NOTICE, "NS: %s Unknown prim %d from NS\n",
|
||||||
|
get_value_string(osmo_prim_op_names, nsp->oph.operation), nsp->oph.primitive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call-back function for the NS protocol */
|
||||||
|
int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
|
||||||
|
{
|
||||||
|
struct osmo_gprs_ns2_prim *nsp;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (oph->sap != SAP_NS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
|
||||||
|
|
||||||
|
if (oph->operation != PRIM_OP_INDICATION) {
|
||||||
|
LOGP(DGPRS, LOGL_NOTICE, "NS: %s Unknown prim %d from NS\n",
|
||||||
|
get_value_string(osmo_prim_op_names, oph->operation),
|
||||||
|
oph->operation);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (oph->primitive) {
|
||||||
|
case GPRS_NS2_PRIM_UNIT_DATA:
|
||||||
|
/* hand the message into the BSSGP implementation */
|
||||||
|
/* add required msg fields for Gb layer */
|
||||||
|
msgb_bssgph(oph->msg) = oph->msg->l3h;
|
||||||
|
msgb_bvci(oph->msg) = nsp->bvci;
|
||||||
|
msgb_nsei(oph->msg) = nsp->nsei;
|
||||||
|
rc = bssgp_rcvmsg(oph->msg);
|
||||||
|
break;
|
||||||
|
case GPRS_NS2_PRIM_STATUS:
|
||||||
|
gprs_ns_prim_status_cb(nsp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGP(DGPRS, LOGL_NOTICE, "NS: %s Unknown prim %d from NS\n",
|
||||||
|
get_value_string(osmo_prim_op_names, oph->operation), oph->primitive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oph->msg)
|
||||||
|
msgb_free(oph->msg);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|||||||
@@ -280,8 +280,12 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
|
|||||||
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT ACK");
|
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ATT ACK");
|
||||||
struct gsm48_hdr *gh;
|
struct gsm48_hdr *gh;
|
||||||
struct gsm48_attach_ack *aa;
|
struct gsm48_attach_ack *aa;
|
||||||
uint8_t *mid;
|
|
||||||
unsigned long t;
|
unsigned long t;
|
||||||
|
#ifdef PTMSI_ALLOC
|
||||||
|
struct osmo_mobile_identity mi;
|
||||||
|
uint8_t *l;
|
||||||
|
int rc;
|
||||||
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
uint8_t *ptsig;
|
uint8_t *ptsig;
|
||||||
#endif
|
#endif
|
||||||
@@ -300,7 +304,7 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
|
|||||||
aa->att_result = 1; /* GPRS only */
|
aa->att_result = 1; /* GPRS only */
|
||||||
t = osmo_tdef_get(sgsn->cfg.T_defs, 3312, OSMO_TDEF_S, -1);
|
t = osmo_tdef_get(sgsn->cfg.T_defs, 3312, OSMO_TDEF_S, -1);
|
||||||
aa->ra_upd_timer = gprs_secs_to_tmr_floor(t);
|
aa->ra_upd_timer = gprs_secs_to_tmr_floor(t);
|
||||||
aa->radio_prio = 4; /* lowest */
|
aa->radio_prio = 0x44; /* lowest */
|
||||||
gsm48_encode_ra(&aa->ra_id, &mm->ra);
|
gsm48_encode_ra(&aa->ra_id, &mm->ra);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -321,14 +325,26 @@ int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm)
|
|||||||
|
|
||||||
#ifdef PTMSI_ALLOC
|
#ifdef PTMSI_ALLOC
|
||||||
/* Optional: Allocated P-TMSI */
|
/* Optional: Allocated P-TMSI */
|
||||||
mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
|
mi = (struct osmo_mobile_identity){
|
||||||
gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
|
.type = GSM_MI_TYPE_TMSI,
|
||||||
mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
|
.tmsi = mm->p_tmsi,
|
||||||
|
};
|
||||||
|
l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);
|
||||||
|
rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);
|
||||||
|
if (rc < 0) {
|
||||||
|
LOGMMCTXP(LOGL_ERROR, mm, "Cannot encode Mobile Identity\n");
|
||||||
|
msgb_free(msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*l = rc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Optional: MS-identity (combined attach) */
|
/* Optional: MS-identity (combined attach) */
|
||||||
/* Optional: GMM cause (partial attach result for combined attach) */
|
/* Optional: GMM cause (partial attach result for combined attach) */
|
||||||
|
|
||||||
|
/* Optional: Network feature support 10.5.5.23 */
|
||||||
|
/* msgb_v_put(msg, GSM48_IE_GMM_NET_FEAT_SUPPORT | 0x00);*/
|
||||||
|
|
||||||
return gsm48_gmm_sendmsg(msg, 0, mm, true);
|
return gsm48_gmm_sendmsg(msg, 0, mm, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -911,9 +927,9 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
|
|||||||
ctx->t3350_mode = GMM_T3350_MODE_ATT;
|
ctx->t3350_mode = GMM_T3350_MODE_ATT;
|
||||||
#else
|
#else
|
||||||
memset(&sig_data, 0, sizeof(sig_data));
|
memset(&sig_data, 0, sizeof(sig_data));
|
||||||
sig_data.mm = mmctx;
|
sig_data.mm = ctx;
|
||||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
|
osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
|
||||||
osmo_fsm_inst_dispatch(mm->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
|
osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return gsm48_tx_gmm_att_ack(ctx);
|
return gsm48_tx_gmm_att_ack(ctx);
|
||||||
@@ -1026,31 +1042,35 @@ void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *ctx, int gmm_cause)
|
|||||||
static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
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);
|
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||||
uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
|
long mi_typel;
|
||||||
long mi_typel = mi_type;
|
char mi_log_string[32];
|
||||||
char mi_string[GSM48_MI_SIZE];
|
struct osmo_mobile_identity mi;
|
||||||
|
|
||||||
gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
|
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
DEBUGP(DMM, "from unknown TLLI 0x%08x?!? This should not happen\n", msgb_tlli(msg));
|
DEBUGP(DMM, "from unknown TLLI 0x%08x?!? This should not happen\n", msgb_tlli(msg));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI(%s)=%s\n",
|
if (osmo_mobile_identity_decode(&mi, &gh->data[1], gh->data[0], false)) {
|
||||||
gsm48_mi_type_name(mi_type), mi_string);
|
LOGMMCTXP(LOGL_ERROR, ctx, "-> GMM IDENTITY RESPONSE: cannot decode Mobile Identity\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
|
||||||
|
|
||||||
|
LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI=%s\n", mi_log_string);
|
||||||
|
|
||||||
if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) {
|
if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) {
|
||||||
LOGMMCTXP(LOGL_NOTICE, ctx,
|
LOGMMCTXP(LOGL_NOTICE, ctx,
|
||||||
"Got unexpected IDENTITY RESPONSE: MI(%s)=%s, "
|
"Got unexpected IDENTITY RESPONSE: MI=%s, "
|
||||||
"ignoring message\n",
|
"ignoring message\n",
|
||||||
gsm48_mi_type_name(mi_type), mi_string);
|
mi_log_string);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mi_type == ctx->t3370_id_type)
|
if (mi.type == ctx->t3370_id_type)
|
||||||
mmctx_timer_stop(ctx, 3370);
|
mmctx_timer_stop(ctx, 3370);
|
||||||
|
|
||||||
switch (mi_type) {
|
switch (mi.type) {
|
||||||
case GSM_MI_TYPE_IMSI:
|
case GSM_MI_TYPE_IMSI:
|
||||||
/* we already have a mm context with current TLLI, but no
|
/* we already have a mm context with current TLLI, but no
|
||||||
* P-TMSI / IMSI yet. What we now need to do is to fill
|
* P-TMSI / IMSI yet. What we now need to do is to fill
|
||||||
@@ -1058,7 +1078,7 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||||||
if (strlen(ctx->imsi) == 0) {
|
if (strlen(ctx->imsi) == 0) {
|
||||||
/* Check if we already have a MM context for this IMSI */
|
/* Check if we already have a MM context for this IMSI */
|
||||||
struct sgsn_mm_ctx *ictx;
|
struct sgsn_mm_ctx *ictx;
|
||||||
ictx = sgsn_mm_ctx_by_imsi(mi_string);
|
ictx = sgsn_mm_ctx_by_imsi(mi.imsi);
|
||||||
if (ictx) {
|
if (ictx) {
|
||||||
/* Handle it like in gsm48_rx_gmm_det_req,
|
/* Handle it like in gsm48_rx_gmm_det_req,
|
||||||
* except that no messages are sent to the BSS */
|
* except that no messages are sent to the BSS */
|
||||||
@@ -1070,16 +1090,17 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||||||
mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
|
mm_ctx_cleanup_free(ictx, "GPRS IMSI re-use");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
|
OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
|
||||||
break;
|
break;
|
||||||
case GSM_MI_TYPE_IMEI:
|
case GSM_MI_TYPE_IMEI:
|
||||||
osmo_strlcpy(ctx->imei, mi_string, sizeof(ctx->imei));
|
OSMO_STRLCPY_ARRAY(ctx->imei, mi.imei);
|
||||||
break;
|
break;
|
||||||
case GSM_MI_TYPE_IMEISV:
|
case GSM_MI_TYPE_IMEISV:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we can let the mobile station enter */
|
/* Check if we can let the mobile station enter */
|
||||||
|
mi_typel = mi.type;
|
||||||
return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_IDEN_RESP_RECV, (void *)mi_typel);
|
return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_IDEN_RESP_RECV, (void *)mi_typel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1099,19 +1120,46 @@ static inline void ptmsi_update(struct sgsn_mm_ctx *ctx)
|
|||||||
osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
|
osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Detect if RAT has changed */
|
||||||
|
static bool mmctx_did_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
|
||||||
|
{
|
||||||
|
if (MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_UTRAN_Iu)
|
||||||
|
return true;
|
||||||
|
if (!MSG_IU_UE_CTX(msg) && mmctx->ran_type != MM_CTX_T_GERAN_Gb)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify the FSM of a RAT change */
|
||||||
|
static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg, struct gprs_llc_llme *llme)
|
||||||
|
{
|
||||||
|
struct gmm_rat_change_data rat_chg = {
|
||||||
|
.llme = llme
|
||||||
|
};
|
||||||
|
|
||||||
|
rat_chg.new_ran_type = MSG_IU_UE_CTX(msg) ? MM_CTX_T_UTRAN_Iu : MM_CTX_T_GERAN_Gb;
|
||||||
|
|
||||||
|
if (rat_chg.new_ran_type != mmctx->ran_type)
|
||||||
|
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RAT_CHANGE, (void *) &rat_chg);
|
||||||
|
else
|
||||||
|
LOGMMCTXP(LOGL_ERROR, mmctx, "RAT didn't change or not implemented (ran_type=%u, "
|
||||||
|
"msg_iu_ue_ctx=%p\n", mmctx->ran_type, MSG_IU_UE_CTX(msg));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* 3GPP TS 24.008 § 9.4.1 Attach request */
|
/* 3GPP TS 24.008 § 9.4.1 Attach request */
|
||||||
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
||||||
struct gprs_llc_llme *llme)
|
struct gprs_llc_llme *llme)
|
||||||
{
|
{
|
||||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||||
uint8_t *cur = gh->data, *msnc, *mi, *ms_ra_acc_cap;
|
uint8_t *cur = gh->data, *msnc, *mi_data, *ms_ra_acc_cap;
|
||||||
uint8_t msnc_len, att_type, mi_len, mi_type, ms_ra_acc_cap_len;
|
uint8_t msnc_len, att_type, mi_len, ms_ra_acc_cap_len;
|
||||||
uint16_t drx_par;
|
uint16_t drx_par;
|
||||||
uint32_t tmsi;
|
char mi_log_string[32];
|
||||||
char mi_string[GSM48_MI_SIZE];
|
|
||||||
struct gprs_ra_id ra_id;
|
struct gprs_ra_id ra_id;
|
||||||
uint16_t cid = 0;
|
uint16_t cid = 0;
|
||||||
enum gsm48_gmm_cause reject_cause;
|
enum gsm48_gmm_cause reject_cause;
|
||||||
|
struct osmo_mobile_identity mi;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
|
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
|
||||||
@@ -1155,15 +1203,15 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||||||
|
|
||||||
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
|
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
|
||||||
mi_len = *cur++;
|
mi_len = *cur++;
|
||||||
mi = cur;
|
mi_data = cur;
|
||||||
if (mi_len > 8)
|
|
||||||
goto err_inval;
|
|
||||||
mi_type = *mi & GSM_MI_TYPE_MASK;
|
|
||||||
cur += mi_len;
|
cur += mi_len;
|
||||||
|
|
||||||
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
|
rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
|
||||||
|
if (rc)
|
||||||
|
goto err_inval;
|
||||||
|
osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
|
||||||
|
|
||||||
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
|
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,
|
||||||
get_value_string(gprs_att_t_strs, att_type));
|
get_value_string(gprs_att_t_strs, att_type));
|
||||||
|
|
||||||
/* Old routing area identification 10.5.5.15. Skip it */
|
/* Old routing area identification 10.5.5.15. Skip it */
|
||||||
@@ -1180,11 +1228,11 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||||||
|
|
||||||
/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */
|
/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */
|
||||||
|
|
||||||
switch (mi_type) {
|
switch (mi.type) {
|
||||||
case GSM_MI_TYPE_IMSI:
|
case GSM_MI_TYPE_IMSI:
|
||||||
/* Try to find MM context based on IMSI */
|
/* Try to find MM context based on IMSI */
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
ctx = sgsn_mm_ctx_by_imsi(mi_string);
|
ctx = sgsn_mm_ctx_by_imsi(mi.imsi);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
if (MSG_IU_UE_CTX(msg))
|
if (MSG_IU_UE_CTX(msg))
|
||||||
ctx = sgsn_mm_ctx_alloc_iu(MSG_IU_UE_CTX(msg));
|
ctx = sgsn_mm_ctx_alloc_iu(MSG_IU_UE_CTX(msg));
|
||||||
@@ -1194,15 +1242,13 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||||||
reject_cause = GMM_CAUSE_NET_FAIL;
|
reject_cause = GMM_CAUSE_NET_FAIL;
|
||||||
goto rejected;
|
goto rejected;
|
||||||
}
|
}
|
||||||
osmo_strlcpy(ctx->imsi, mi_string, sizeof(ctx->imsi));
|
OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GSM_MI_TYPE_TMSI:
|
case GSM_MI_TYPE_TMSI:
|
||||||
memcpy(&tmsi, mi+1, 4);
|
|
||||||
tmsi = ntohl(tmsi);
|
|
||||||
/* Try to find MM context based on P-TMSI */
|
/* Try to find MM context based on P-TMSI */
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
|
ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
/* Allocate a context as most of our code expects one.
|
/* Allocate a context as most of our code expects one.
|
||||||
* Context will not have an IMSI ultil ID RESP is received */
|
* Context will not have an IMSI ultil ID RESP is received */
|
||||||
@@ -1214,16 +1260,19 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||||||
reject_cause = GMM_CAUSE_NET_FAIL;
|
reject_cause = GMM_CAUSE_NET_FAIL;
|
||||||
goto rejected;
|
goto rejected;
|
||||||
}
|
}
|
||||||
ctx->p_tmsi = tmsi;
|
ctx->p_tmsi = mi.tmsi;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with "
|
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with "
|
||||||
"MI type %s\n", gsm48_mi_type_name(mi_type));
|
"MI %s\n", mi_log_string);
|
||||||
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
|
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
|
||||||
goto rejected;
|
goto rejected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mmctx_did_rat_change(ctx, msg))
|
||||||
|
mmctx_handle_rat_change(ctx, msg, llme);
|
||||||
|
|
||||||
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
||||||
ctx->gb.tlli = msgb_tlli(msg);
|
ctx->gb.tlli = msgb_tlli(msg);
|
||||||
ctx->gb.llme = llme;
|
ctx->gb.llme = llme;
|
||||||
@@ -1245,8 +1294,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
|
|||||||
ctx->ciph_algo)) {
|
ctx->ciph_algo)) {
|
||||||
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
|
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
|
||||||
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
|
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "
|
||||||
"type %s because MS do not support required %s "
|
"%s because MS do not support required %s "
|
||||||
"encryption\n", gsm48_mi_type_name(mi_type),
|
"encryption\n", mi_log_string,
|
||||||
get_value_string(gprs_cipher_names,ctx->ciph_algo));
|
get_value_string(gprs_cipher_names,ctx->ciph_algo));
|
||||||
goto rejected;
|
goto rejected;
|
||||||
}
|
}
|
||||||
@@ -1393,8 +1442,12 @@ 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 msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 UPD ACK");
|
||||||
struct gsm48_hdr *gh;
|
struct gsm48_hdr *gh;
|
||||||
struct gsm48_ra_upd_ack *rua;
|
struct gsm48_ra_upd_ack *rua;
|
||||||
uint8_t *mid;
|
|
||||||
unsigned long t;
|
unsigned long t;
|
||||||
|
#ifdef PTMSI_ALLOC
|
||||||
|
uint8_t *l;
|
||||||
|
int rc;
|
||||||
|
struct osmo_mobile_identity mi;
|
||||||
|
#endif
|
||||||
|
|
||||||
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
|
rate_ctr_inc(&sgsn->rate_ctrs->ctr[CTR_GPRS_ROUTING_AREA_ACKED]);
|
||||||
LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
|
LOGMMCTXP(LOGL_INFO, mm, "<- ROUTING AREA UPDATE ACCEPT\n");
|
||||||
@@ -1424,9 +1477,17 @@ static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
|
|||||||
|
|
||||||
#ifdef PTMSI_ALLOC
|
#ifdef PTMSI_ALLOC
|
||||||
/* Optional: Allocated P-TMSI */
|
/* Optional: Allocated P-TMSI */
|
||||||
mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
|
mi = (struct osmo_mobile_identity){
|
||||||
gsm48_generate_mid_from_tmsi(mid, mm->p_tmsi);
|
.type = GSM_MI_TYPE_TMSI,
|
||||||
mid[0] = GSM48_IE_GMM_ALLOC_PTMSI;
|
.tmsi = mm->p_tmsi,
|
||||||
|
};
|
||||||
|
l = msgb_tl_put(msg, GSM48_IE_GMM_ALLOC_PTMSI);
|
||||||
|
rc = osmo_mobile_identity_encode_msgb(msg, &mi, false);
|
||||||
|
if (rc < 0) {
|
||||||
|
msgb_free(msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*l = rc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Optional: Negotiated READY timer value */
|
/* Optional: Negotiated READY timer value */
|
||||||
@@ -1470,21 +1531,19 @@ static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
|
|||||||
* being in state PDP-INACTIVE. */
|
* being in state PDP-INACTIVE. */
|
||||||
|
|
||||||
llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
|
llist_for_each_entry_safe(pdp, pdp2, &mmctx->pdp_list, list) {
|
||||||
if (pdp->nsapi < 8) {
|
bool inactive = (pdp->nsapi < 8) ?
|
||||||
if (!(pdp_status[0] & (1 << pdp->nsapi))) {
|
!(pdp_status[0] & (1 << pdp->nsapi)) :
|
||||||
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
|
!(pdp_status[1] & (1 << (pdp->nsapi - 8)));
|
||||||
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
|
if (!inactive)
|
||||||
pdp->nsapi, pdp_status[1], pdp_status[0]);
|
continue;
|
||||||
sgsn_delete_pdp_ctx(pdp);
|
|
||||||
}
|
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
|
||||||
} else {
|
"due to PDP CTX STATUS IE=0x%02x%02x\n",
|
||||||
if (!(pdp_status[1] & (1 << (pdp->nsapi - 8)))) {
|
pdp->nsapi, pdp_status[1], pdp_status[0]);
|
||||||
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping PDP context for NSAPI=%u "
|
if (pdp->ggsn)
|
||||||
"due to PDP CTX STATUS IE= 0x%02x%02x\n",
|
sgsn_delete_pdp_ctx(pdp);
|
||||||
pdp->nsapi, pdp_status[1], pdp_status[0]);
|
else /* GTP side already detached, freeing */
|
||||||
sgsn_delete_pdp_ctx(pdp);
|
sgsn_pdp_ctx_free(pdp);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1576,19 +1635,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||||||
} else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
|
} else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
|
||||||
#ifdef BUILD_IU
|
#ifdef BUILD_IU
|
||||||
/* In Iu mode search only for ptmsi */
|
/* In Iu mode search only for ptmsi */
|
||||||
char mi_string[GSM48_MI_SIZE];
|
struct osmo_mobile_identity mi;
|
||||||
uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
|
if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI),
|
||||||
const uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
|
TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI), false)
|
||||||
uint8_t mi_type = *mi & GSM_MI_TYPE_MASK;
|
|| mi.type != GSM_MI_TYPE_TMSI) {
|
||||||
uint32_t tmsi;
|
LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n");
|
||||||
|
goto rejected;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
mmctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
|
||||||
#else
|
#else
|
||||||
LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR,
|
LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR,
|
||||||
"Rejecting GMM RA Update Request: No Iu support\n");
|
"Rejecting GMM RA Update Request: No Iu support\n");
|
||||||
@@ -1604,21 +1658,36 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||||||
mmctx->p_tmsi, mmctx->p_tmsi_old,
|
mmctx->p_tmsi, mmctx->p_tmsi_old,
|
||||||
mmctx->gb.tlli, mmctx->gb.tlli_new,
|
mmctx->gb.tlli, mmctx->gb.tlli_new,
|
||||||
osmo_rai_name(&mmctx->ra));
|
osmo_rai_name(&mmctx->ra));
|
||||||
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
|
/* A RAT change will trigger the common procedure
|
||||||
|
* below after handling the RAT change. Protect it
|
||||||
|
* here from being called twice */
|
||||||
|
if (!mmctx_did_rat_change(mmctx, msg))
|
||||||
|
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (!gprs_ra_id_equals(&mmctx->ra, &old_ra_id) ||
|
} else if (!gprs_ra_id_equals(&mmctx->ra, &old_ra_id) ||
|
||||||
mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
|
mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
|
||||||
{
|
{
|
||||||
/* We cannot use the mmctx */
|
/* We've received either a RAU for a MS which isn't registered
|
||||||
LOGMMCTXP(LOGL_INFO, mmctx,
|
* or a RAU with an unknown RA ID. As long the SGSN doesn't support
|
||||||
"The MM context cannot be used, RA: %s\n",
|
* PS handover we treat this as invalid RAU */
|
||||||
osmo_rai_name(&mmctx->ra));
|
struct gprs_ra_id new_ra_id;
|
||||||
/* mmctx is set to NULL and gprs_llgmm_unassign(llme) will be
|
char new_ra[32];
|
||||||
called below, let's make sure we don't keep dangling llme
|
|
||||||
pointers in mmctx (OS#3957, OS#4245). */
|
bssgp_parse_cell_id(&new_ra_id, msgb_bcid(msg));
|
||||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
|
osmo_rai_name_buf(new_ra, sizeof(new_ra), &new_ra_id);
|
||||||
mmctx->gb.llme = NULL;
|
|
||||||
mmctx = NULL;
|
if (mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
|
||||||
|
LOGMMCTXP(LOGL_INFO, mmctx,
|
||||||
|
"Rejecting RAU - GMM state is deregistered. Old RA: %s New RA: %s\n",
|
||||||
|
osmo_rai_name(&old_ra_id), new_ra);
|
||||||
|
else
|
||||||
|
LOGMMCTXP(LOGL_INFO, mmctx,
|
||||||
|
"Rejecting RAU - Old RA doesn't match MM. Old RA: %s New RA: %s\n",
|
||||||
|
osmo_rai_name(&old_ra_id), new_ra);
|
||||||
|
|
||||||
|
reject_cause = GMM_CAUSE_IMPL_DETACHED;
|
||||||
|
goto rejected;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mmctx) {
|
if (!mmctx) {
|
||||||
@@ -1636,13 +1705,18 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||||||
goto rejected;
|
goto rejected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mmctx_did_rat_change(mmctx, msg)) {
|
||||||
|
mmctx_handle_rat_change(mmctx, msg, llme);
|
||||||
|
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
|
/* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */
|
||||||
msgid2mmctx(mmctx, msg);
|
msgid2mmctx(mmctx, msg);
|
||||||
/* Bump the statistics of received signalling msgs for this MM context */
|
/* Bump the statistics of received signalling msgs for this MM context */
|
||||||
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
|
||||||
|
|
||||||
/* Update the MM context with the new RA-ID */
|
/* Update the MM context with the new RA-ID */
|
||||||
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
|
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb && msgb_bcid(msg)) {
|
||||||
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
|
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
|
||||||
/* Update the MM context with the new (i.e. foreign) TLLI */
|
/* Update the MM context with the new (i.e. foreign) TLLI */
|
||||||
mmctx->gb.tlli = msgb_tlli(msg);
|
mmctx->gb.tlli = msgb_tlli(msg);
|
||||||
@@ -1660,7 +1734,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||||||
mmctx_timer_start(mmctx, 3350);
|
mmctx_timer_start(mmctx, 3350);
|
||||||
#else
|
#else
|
||||||
/* Make sure we are NORMAL (i.e. not SUSPENDED anymore) */
|
/* Make sure we are NORMAL (i.e. not SUSPENDED anymore) */
|
||||||
osmo_fsm_inst_dispatch(mm->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
|
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
|
||||||
|
|
||||||
memset(&sig_data, 0, sizeof(sig_data));
|
memset(&sig_data, 0, sizeof(sig_data));
|
||||||
sig_data.mm = mmctx;
|
sig_data.mm = mmctx;
|
||||||
@@ -1762,11 +1836,11 @@ static int gsm48_rx_gmm_ptmsi_reall_compl(struct sgsn_mm_ctx *mmctx)
|
|||||||
static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
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);
|
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
|
||||||
uint8_t *cur = gh->data, *mi;
|
uint8_t *cur = gh->data, *mi_data;
|
||||||
uint8_t service_type, mi_len, mi_type;
|
uint8_t service_type, mi_len;
|
||||||
uint32_t tmsi;
|
|
||||||
struct tlv_parsed tp;
|
struct tlv_parsed tp;
|
||||||
char mi_string[GSM48_MI_SIZE];
|
struct osmo_mobile_identity mi;
|
||||||
|
char mi_log_string[32];
|
||||||
enum gsm48_gmm_cause reject_cause;
|
enum gsm48_gmm_cause reject_cause;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -1786,15 +1860,14 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||||||
|
|
||||||
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
|
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
|
||||||
mi_len = *cur++;
|
mi_len = *cur++;
|
||||||
mi = cur;
|
mi_data = cur;
|
||||||
if (mi_len > 8)
|
|
||||||
goto err_inval;
|
|
||||||
mi_type = *mi & GSM_MI_TYPE_MASK;
|
|
||||||
cur += mi_len;
|
cur += mi_len;
|
||||||
|
rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
|
||||||
|
if (rc)
|
||||||
|
goto err_inval;
|
||||||
|
osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
|
||||||
|
|
||||||
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
|
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,
|
||||||
|
|
||||||
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
|
|
||||||
get_value_string(gprs_service_t_strs, service_type));
|
get_value_string(gprs_service_t_strs, service_type));
|
||||||
|
|
||||||
LOGPC(DMM, LOGL_INFO, "\n");
|
LOGPC(DMM, LOGL_INFO, "\n");
|
||||||
@@ -1802,11 +1875,11 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||||||
/* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */
|
/* 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);
|
tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0);
|
||||||
|
|
||||||
switch (mi_type) {
|
switch (mi.type) {
|
||||||
case GSM_MI_TYPE_IMSI:
|
case GSM_MI_TYPE_IMSI:
|
||||||
/* Try to find MM context based on IMSI */
|
/* Try to find MM context based on IMSI */
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
ctx = sgsn_mm_ctx_by_imsi(mi_string);
|
ctx = sgsn_mm_ctx_by_imsi(mi.imsi);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
/* FIXME: We need to have a context for service request? */
|
/* FIXME: We need to have a context for service request? */
|
||||||
reject_cause = GMM_CAUSE_IMPL_DETACHED;
|
reject_cause = GMM_CAUSE_IMPL_DETACHED;
|
||||||
@@ -1815,11 +1888,9 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||||||
msgid2mmctx(ctx, msg);
|
msgid2mmctx(ctx, msg);
|
||||||
break;
|
break;
|
||||||
case GSM_MI_TYPE_TMSI:
|
case GSM_MI_TYPE_TMSI:
|
||||||
memcpy(&tmsi, mi+1, 4);
|
|
||||||
tmsi = ntohl(tmsi);
|
|
||||||
/* Try to find MM context based on P-TMSI */
|
/* Try to find MM context based on P-TMSI */
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
|
ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
/* FIXME: We need to have a context for service request? */
|
/* FIXME: We need to have a context for service request? */
|
||||||
reject_cause = GMM_CAUSE_IMPL_DETACHED;
|
reject_cause = GMM_CAUSE_IMPL_DETACHED;
|
||||||
@@ -1829,7 +1900,7 @@ static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "
|
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "
|
||||||
"MI type %s\n", gsm48_mi_type_name(mi_type));
|
"MI %s\n", mi_log_string);
|
||||||
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
|
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
|
||||||
goto rejected;
|
goto rejected;
|
||||||
}
|
}
|
||||||
@@ -1944,6 +2015,23 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A RAT change is only expected/allowed for RAU/Attach Req */
|
||||||
|
if (mmctx && mmctx_did_rat_change(mmctx, msg)) {
|
||||||
|
switch (gh->msg_type) {
|
||||||
|
case GSM48_MT_GMM_RA_UPD_REQ:
|
||||||
|
case GSM48_MT_GMM_ATTACH_REQ:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* This shouldn't happen with other message types and
|
||||||
|
* we need to error out to prevent a crash */
|
||||||
|
LOGMMCTXP(LOGL_NOTICE, mmctx, "Dropping GMM %s which was received on different "
|
||||||
|
"RAT (mmctx ran_type=%u, msg_iu_ue_ctx=%p\n",
|
||||||
|
get_value_string(gprs_msgt_gmm_names, gh->msg_type),
|
||||||
|
mmctx->ran_type, MSG_IU_UE_CTX(msg));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For a few messages, mmctx may be NULL. For most, we want to ensure a
|
* 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
|
* non-NULL mmctx. At the same time, we want to keep the message
|
||||||
|
|||||||
@@ -1,6 +1,30 @@
|
|||||||
|
/* GMM mobility management states on the network side, 3GPP TS 24.008 § 4.1.3.3 */
|
||||||
|
/*
|
||||||
|
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
#include <osmocom/core/tdef.h>
|
#include <osmocom/core/tdef.h>
|
||||||
|
|
||||||
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
#include <osmocom/sgsn/gprs_gmm_fsm.h>
|
||||||
|
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
|
||||||
|
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
|
||||||
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
#include <osmocom/sgsn/debug.h>
|
||||||
#include <osmocom/sgsn/sgsn.h>
|
#include <osmocom/sgsn/sgsn.h>
|
||||||
@@ -67,9 +91,12 @@ static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, v
|
|||||||
static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
static void st_gmm_registered_suspended(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||||
{
|
{
|
||||||
switch(event) {
|
switch(event) {
|
||||||
case E_GMM_RESUME:
|
case E_GMM_RESUME: /* explicit BSSGP RESUME from BSS */
|
||||||
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
|
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
|
||||||
break;
|
break;
|
||||||
|
case E_GMM_COMMON_PROC_INIT_REQ: /* implicit resume from MS */
|
||||||
|
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,10 +148,12 @@ static struct osmo_fsm_state gmm_fsm_states[] = {
|
|||||||
.action = st_gmm_registered_normal,
|
.action = st_gmm_registered_normal,
|
||||||
},
|
},
|
||||||
[ST_GMM_REGISTERED_SUSPENDED] = {
|
[ST_GMM_REGISTERED_SUSPENDED] = {
|
||||||
.in_event_mask = X(E_GMM_RESUME),
|
.in_event_mask = X(E_GMM_RESUME) |
|
||||||
|
X(E_GMM_COMMON_PROC_INIT_REQ),
|
||||||
.out_state_mask =
|
.out_state_mask =
|
||||||
X(ST_GMM_DEREGISTERED) |
|
X(ST_GMM_DEREGISTERED) |
|
||||||
X(ST_GMM_REGISTERED_NORMAL),
|
X(ST_GMM_REGISTERED_NORMAL) |
|
||||||
|
X(ST_GMM_COMMON_PROC_INIT),
|
||||||
.name = "Registered.SUSPENDED",
|
.name = "Registered.SUSPENDED",
|
||||||
.action = st_gmm_registered_suspended,
|
.action = st_gmm_registered_suspended,
|
||||||
},
|
},
|
||||||
@@ -149,11 +178,32 @@ const struct value_string gmm_fsm_event_names[] = {
|
|||||||
/* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
|
/* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
|
||||||
OSMO_VALUE_STRING(E_GMM_SUSPEND),
|
OSMO_VALUE_STRING(E_GMM_SUSPEND),
|
||||||
OSMO_VALUE_STRING(E_GMM_CLEANUP),
|
OSMO_VALUE_STRING(E_GMM_CLEANUP),
|
||||||
|
OSMO_VALUE_STRING(E_GMM_RAT_CHANGE),
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
|
void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
|
||||||
|
struct sgsn_mm_ctx *mmctx = fi->priv;
|
||||||
|
struct gmm_rat_change_data *rat_chg = (struct gmm_rat_change_data *)data;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
case E_GMM_RAT_CHANGE:
|
||||||
|
|
||||||
|
switch (fi->state) {
|
||||||
|
case ST_GMM_COMMON_PROC_INIT:
|
||||||
|
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
|
||||||
|
default:
|
||||||
|
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
|
||||||
|
osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
|
||||||
|
else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) {
|
||||||
|
osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
|
||||||
|
mmctx->gb.llme = rat_chg->llme;
|
||||||
|
}
|
||||||
|
|
||||||
|
mmctx->ran_type = rat_chg->new_ran_type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case E_GMM_CLEANUP:
|
case E_GMM_CLEANUP:
|
||||||
switch (fi->state) {
|
switch (fi->state) {
|
||||||
case ST_GMM_DEREGISTERED:
|
case ST_GMM_DEREGISTERED:
|
||||||
@@ -175,7 +225,7 @@ struct osmo_fsm gmm_fsm = {
|
|||||||
.states = gmm_fsm_states,
|
.states = gmm_fsm_states,
|
||||||
.num_states = ARRAY_SIZE(gmm_fsm_states),
|
.num_states = ARRAY_SIZE(gmm_fsm_states),
|
||||||
.event_names = gmm_fsm_event_names,
|
.event_names = gmm_fsm_event_names,
|
||||||
.allstate_event_mask = X(E_GMM_CLEANUP),
|
.allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE),
|
||||||
.allstate_action = gmm_fsm_allstate_action,
|
.allstate_action = gmm_fsm_allstate_action,
|
||||||
.log_subsys = DMM,
|
.log_subsys = DMM,
|
||||||
.timer_cb = gmm_fsm_timer_cb,
|
.timer_cb = gmm_fsm_timer_cb,
|
||||||
|
|||||||
@@ -376,20 +376,24 @@ static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
|
|||||||
* not yet have a MMC context (e.g. XID negotiation of primarly
|
* not yet have a MMC context (e.g. XID negotiation of primarly
|
||||||
* LLC connection from GMM sapi). */
|
* LLC connection from GMM sapi). */
|
||||||
if (mmctx) {
|
if (mmctx) {
|
||||||
|
/* In rare cases the LLME is NULL in those cases don't
|
||||||
|
* use the mm radio capabilities */
|
||||||
dup.imsi = mmctx->imsi;
|
dup.imsi = mmctx->imsi;
|
||||||
dup.drx_parms = mmctx->drx_parms;
|
if (mmctx->gb.llme) {
|
||||||
dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
|
dup.drx_parms = mmctx->drx_parms;
|
||||||
dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
|
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 */
|
/* make sure we only send it to the right llme */
|
||||||
if (!(msgb_tlli(msg) == mmctx->gb.llme->tlli
|
if (!(msgb_tlli(msg) == mmctx->gb.llme->tlli
|
||||||
|| msgb_tlli(msg) == mmctx->gb.llme->old_tlli)) {
|
|| msgb_tlli(msg) == mmctx->gb.llme->old_tlli)) {
|
||||||
LOGP(DLLC, LOGL_ERROR,
|
LOGP(DLLC, LOGL_ERROR,
|
||||||
"_bssgp_tx_dl_ud(): Attempt to send Downlink Unitdata to wrong LLME:"
|
"_bssgp_tx_dl_ud(): Attempt to send Downlink Unitdata to wrong LLME:"
|
||||||
" msgb_tlli=0x%x mmctx->gb.llme->tlli=0x%x ->old_tlli=0x%x\n",
|
" msgb_tlli=0x%x mmctx->gb.llme->tlli=0x%x ->old_tlli=0x%x\n",
|
||||||
msgb_tlli(msg), mmctx->gb.llme->tlli, mmctx->gb.llme->old_tlli);
|
msgb_tlli(msg), mmctx->gb.llme->tlli, mmctx->gb.llme->old_tlli);
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(&dup.qos_profile, qos_profile_default,
|
memcpy(&dup.qos_profile, qos_profile_default,
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||||||
case E_MM_PDU_RECEPTION:
|
case E_MM_PDU_RECEPTION:
|
||||||
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
|
mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
|
||||||
break;
|
break;
|
||||||
|
case E_MM_IMPLICIT_DETACH:
|
||||||
|
mm_state_gb_fsm_state_chg(fi, ST_MM_IDLE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +89,7 @@ static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
|
|||||||
.action = st_mm_ready,
|
.action = st_mm_ready,
|
||||||
},
|
},
|
||||||
[ST_MM_STANDBY] = {
|
[ST_MM_STANDBY] = {
|
||||||
.in_event_mask = X(E_MM_PDU_RECEPTION),
|
.in_event_mask = X(E_MM_PDU_RECEPTION) | X(E_MM_IMPLICIT_DETACH),
|
||||||
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
|
.out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
|
||||||
.name = "Standby",
|
.name = "Standby",
|
||||||
.action = st_mm_standby,
|
.action = st_mm_standby,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <osmocom/core/rate_ctr.h>
|
#include <osmocom/core/rate_ctr.h>
|
||||||
#include <osmocom/core/tdef.h>
|
#include <osmocom/core/tdef.h>
|
||||||
|
#include <osmocom/gprs/gprs_msgb.h>
|
||||||
|
|
||||||
#include <osmocom/ranap/ranap_common.h>
|
#include <osmocom/ranap/ranap_common.h>
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include <osmocom/core/rate_ctr.h>
|
#include <osmocom/core/rate_ctr.h>
|
||||||
#include <osmocom/core/stats.h>
|
#include <osmocom/core/stats.h>
|
||||||
#include <osmocom/core/backtrace.h>
|
#include <osmocom/core/backtrace.h>
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
#include <osmocom/gprs/gprs_ns2.h>
|
||||||
#include <osmocom/gprs/gprs_bssgp.h>
|
#include <osmocom/gprs/gprs_bssgp.h>
|
||||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||||
#include <osmocom/gsm/apn.h>
|
#include <osmocom/gsm/apn.h>
|
||||||
@@ -511,6 +511,11 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
|
|||||||
sig_data.pdp = pdp;
|
sig_data.pdp = pdp;
|
||||||
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
|
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_FREE, &sig_data);
|
||||||
|
|
||||||
|
if (osmo_timer_pending(&pdp->timer)) {
|
||||||
|
LOGPDPCTXP(LOGL_ERROR, pdp, "Freeing PDP ctx with timer %u pending\n", pdp->T);
|
||||||
|
osmo_timer_del(&pdp->timer);
|
||||||
|
}
|
||||||
|
|
||||||
rate_ctr_group_free(pdp->ctrg);
|
rate_ctr_group_free(pdp->ctrg);
|
||||||
if (pdp->mm)
|
if (pdp->mm)
|
||||||
llist_del(&pdp->list);
|
llist_del(&pdp->list);
|
||||||
|
|||||||
@@ -639,7 +639,11 @@ static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *mm, struct msgb *msg)
|
|||||||
return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);
|
return _gsm48_tx_gsm_deact_pdp_acc(mm, transaction_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sgsn_delete_pdp_ctx(pdp);
|
if (pdp->ggsn)
|
||||||
|
return sgsn_delete_pdp_ctx(pdp);
|
||||||
|
/* GTP side already detached, freeing */
|
||||||
|
sgsn_pdp_ctx_free(pdp);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */
|
/* 3GPP TS 24.008 § 9.5.9: Deactivate PDP Context Accept */
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <osmocom/core/linuxlist.h>
|
#include <osmocom/core/linuxlist.h>
|
||||||
#include <osmocom/core/timer.h>
|
#include <osmocom/core/timer.h>
|
||||||
#include <osmocom/core/talloc.h>
|
#include <osmocom/core/talloc.h>
|
||||||
|
#include <osmocom/core/endian.h>
|
||||||
#include <osmocom/gprs/gprs_bssgp.h>
|
#include <osmocom/gprs/gprs_bssgp.h>
|
||||||
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
#include <osmocom/sgsn/debug.h>
|
||||||
@@ -164,27 +165,43 @@ static void debug_ip_packet(uint8_t *data, int len, int dir, char *info)
|
|||||||
|
|
||||||
/* Chapter 7.2: SN-PDU Formats */
|
/* Chapter 7.2: SN-PDU Formats */
|
||||||
struct sndcp_common_hdr {
|
struct sndcp_common_hdr {
|
||||||
|
#if OSMO_IS_LITTLE_ENDIAN
|
||||||
/* octet 1 */
|
/* octet 1 */
|
||||||
uint8_t nsapi:4;
|
uint8_t nsapi:4;
|
||||||
uint8_t more:1;
|
uint8_t more:1;
|
||||||
uint8_t type:1;
|
uint8_t type:1;
|
||||||
uint8_t first:1;
|
uint8_t first:1;
|
||||||
uint8_t spare:1;
|
uint8_t spare:1;
|
||||||
|
#elif OSMO_IS_BIG_ENDIAN
|
||||||
|
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
|
||||||
|
uint8_t spare:1, first:1, type:1, more:1, nsapi:4;
|
||||||
|
#endif
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/* PCOMP / DCOMP only exist in first fragment */
|
/* PCOMP / DCOMP only exist in first fragment */
|
||||||
struct sndcp_comp_hdr {
|
struct sndcp_comp_hdr {
|
||||||
|
#if OSMO_IS_LITTLE_ENDIAN
|
||||||
/* octet 2 */
|
/* octet 2 */
|
||||||
uint8_t pcomp:4;
|
uint8_t pcomp:4;
|
||||||
uint8_t dcomp:4;
|
uint8_t dcomp:4;
|
||||||
|
#elif OSMO_IS_BIG_ENDIAN
|
||||||
|
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
|
||||||
|
uint8_t dcomp:4, pcomp:4;
|
||||||
|
#endif
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct sndcp_udata_hdr {
|
struct sndcp_udata_hdr {
|
||||||
|
#if OSMO_IS_LITTLE_ENDIAN
|
||||||
/* octet 3 */
|
/* octet 3 */
|
||||||
uint8_t npdu_high:4;
|
uint8_t npdu_high:4;
|
||||||
uint8_t seg_nr:4;
|
uint8_t seg_nr:4;
|
||||||
/* octet 4 */
|
/* octet 4 */
|
||||||
uint8_t npdu_low;
|
uint8_t npdu_low;
|
||||||
|
#elif OSMO_IS_BIG_ENDIAN
|
||||||
|
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
|
||||||
|
uint8_t seg_nr:4, npdu_high:4;
|
||||||
|
uint8_t npdu_low;
|
||||||
|
#endif
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
@@ -366,8 +383,12 @@ static int defrag_segments(struct gprs_sndcp_entity *sne)
|
|||||||
rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli,
|
rc = sgsn_rx_sndcp_ud_ind(&sne->ra_id, sne->lle->llme->tlli,
|
||||||
sne->nsapi, msg, npdu_len, expnd);
|
sne->nsapi, msg, npdu_len, expnd);
|
||||||
|
|
||||||
if (any_pcomp_or_dcomp_active(sgsn))
|
/* we must free the memory we allocated above; ownership is not transferred
|
||||||
talloc_free(expnd);
|
* downwards in the call above */
|
||||||
|
msgb_free(msg);
|
||||||
|
|
||||||
|
/* Note: We do not have to free expnd explicitly, because it is created
|
||||||
|
* within the talloc context of msg, which we just freed. */
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -787,7 +808,7 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
|
|||||||
lle, lle->llme->tlli, lle->sapi, sch->nsapi);
|
lle, lle->llme->tlli, lle->sapi, sch->nsapi);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
gprs_gb_recv_pdu(mmctx);
|
gprs_gb_recv_pdu(mmctx, msg);
|
||||||
|
|
||||||
if (scomph) {
|
if (scomph) {
|
||||||
sne->defrag.pcomp = scomph->pcomp;
|
sne->defrag.pcomp = scomph->pcomp;
|
||||||
|
|||||||
@@ -812,7 +812,7 @@ static int gprs_subscr_query_auth_info(struct gprs_subscr *subscr,
|
|||||||
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
|
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gprs_subscr_location_update(struct gprs_subscr *subscr)
|
int gprs_subscr_location_update(struct gprs_subscr *subscr, enum sgsn_ran_type ran_type)
|
||||||
{
|
{
|
||||||
struct osmo_gsup_message gsup_msg = {0};
|
struct osmo_gsup_message gsup_msg = {0};
|
||||||
|
|
||||||
@@ -820,6 +820,18 @@ int gprs_subscr_location_update(struct gprs_subscr *subscr)
|
|||||||
"subscriber data is not available\n");
|
"subscriber data is not available\n");
|
||||||
|
|
||||||
gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
|
gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
|
||||||
|
|
||||||
|
switch (ran_type) {
|
||||||
|
case MM_CTX_T_GERAN_Gb:
|
||||||
|
gsup_msg.current_rat_type = OSMO_RAT_GERAN_A;
|
||||||
|
break;
|
||||||
|
case MM_CTX_T_UTRAN_Iu:
|
||||||
|
gsup_msg.current_rat_type = OSMO_RAT_UTRAN_IU;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
|
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,6 +870,8 @@ struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx
|
|||||||
|
|
||||||
if (!subscr) {
|
if (!subscr) {
|
||||||
subscr = gprs_subscr_get_or_create(mmctx->imsi);
|
subscr = gprs_subscr_get_or_create(mmctx->imsi);
|
||||||
|
if (!subscr)
|
||||||
|
return NULL;
|
||||||
subscr->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT;
|
subscr->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT;
|
||||||
subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
|
subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
|
||||||
}
|
}
|
||||||
@@ -881,10 +895,12 @@ int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
|
|||||||
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
|
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
|
||||||
|
|
||||||
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
|
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
|
||||||
|
if (!subscr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
|
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
|
||||||
|
|
||||||
rc = gprs_subscr_location_update(subscr);
|
rc = gprs_subscr_location_update(subscr, mmctx->ran_type);
|
||||||
gprs_subscr_put(subscr);
|
gprs_subscr_put(subscr);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -906,6 +922,8 @@ int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
|
|||||||
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
|
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
|
||||||
|
|
||||||
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
|
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
|
||||||
|
if (!subscr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
|
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
|||||||
pdp->hisaddr0 = ggsn->remote_addr;
|
pdp->hisaddr0 = ggsn->remote_addr;
|
||||||
pdp->hisaddr1 = ggsn->remote_addr;
|
pdp->hisaddr1 = ggsn->remote_addr;
|
||||||
//pdp->cch_pdp = 512; /* Charging Flat Rate */
|
//pdp->cch_pdp = 512; /* Charging Flat Rate */
|
||||||
|
pdp->radio_pri = 0x4;
|
||||||
|
|
||||||
/* MS provided APN, subscription was verified by the caller */
|
/* MS provided APN, subscription was verified by the caller */
|
||||||
pdp->selmode = 0xFC | 0x00;
|
pdp->selmode = 0xFC | 0x00;
|
||||||
@@ -311,11 +312,16 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
|
|||||||
return pctx;
|
return pctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SGSN wants to delete a PDP context */
|
/* SGSN wants to delete a PDP context, send first DeleteCtxReq on the GTP side,
|
||||||
|
then upon DeleteCtx ACK it will send DeactPdpAcc to the MS if still
|
||||||
|
connected. */
|
||||||
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx)
|
int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx)
|
||||||
{
|
{
|
||||||
LOGPDPCTXP(LOGL_INFO, pctx, "Delete PDP Context\n");
|
LOGPDPCTXP(LOGL_INFO, pctx, "Delete PDP Context\n");
|
||||||
|
|
||||||
|
OSMO_ASSERT(pctx->ggsn);
|
||||||
|
OSMO_ASSERT(pctx->lib);
|
||||||
|
|
||||||
/* FIXME: decide if we need teardown or not ! */
|
/* FIXME: decide if we need teardown or not ! */
|
||||||
return gtp_delete_context_req2(pctx->ggsn->gsn, pctx->lib, pctx, 1);
|
return gtp_delete_context_req2(pctx->ggsn->gsn, pctx->lib, pctx, 1);
|
||||||
}
|
}
|
||||||
@@ -660,14 +666,18 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
|
|||||||
|
|
||||||
switch (mm->gmm_fsm->state) {
|
switch (mm->gmm_fsm->state) {
|
||||||
case ST_GMM_REGISTERED_SUSPENDED:
|
case ST_GMM_REGISTERED_SUSPENDED:
|
||||||
/* initiate PS PAGING procedure */
|
LOGMMCTXP(LOGL_INFO, mm, "Dropping DL packet for MS in GMM state %s\n",
|
||||||
gprs_gb_page_ps_ra(mm);
|
osmo_fsm_inst_state_name(mm->gmm_fsm));
|
||||||
/* FIXME: queue the packet we received from GTP */
|
msgb_free(msg);
|
||||||
break;
|
return -1;
|
||||||
case ST_GMM_REGISTERED_NORMAL:
|
case ST_GMM_REGISTERED_NORMAL:
|
||||||
OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE);
|
OSMO_ASSERT(mm->gb.mm_state_fsm->state != ST_MM_IDLE);
|
||||||
if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY)
|
if (mm->gb.mm_state_fsm->state == ST_MM_STANDBY) {
|
||||||
|
LOGMMCTXP(LOGL_INFO, mm, "Paging MS in GMM state %s, MM state %s\n",
|
||||||
|
osmo_fsm_inst_state_name(mm->gmm_fsm),
|
||||||
|
osmo_fsm_inst_state_name(mm->gb.mm_state_fsm));
|
||||||
gprs_gb_page_ps_ra(mm);
|
gprs_gb_page_ps_ra(mm);
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: queue the packet we received from GTP */
|
/* FIXME: queue the packet we received from GTP */
|
||||||
break;
|
break;
|
||||||
@@ -733,7 +743,7 @@ static int sgsn_gtp_fd_cb(struct osmo_fd *fd, unsigned int what)
|
|||||||
struct sgsn_instance *sgi = fd->data;
|
struct sgsn_instance *sgi = fd->data;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!(what & BSC_FD_READ))
|
if (!(what & OSMO_FD_READ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (fd->priv_nr) {
|
switch (fd->priv_nr) {
|
||||||
@@ -771,31 +781,19 @@ int sgsn_gtp_init(struct sgsn_instance *sgi)
|
|||||||
if (gsn->mode != GTP_MODE_SGSN)
|
if (gsn->mode != GTP_MODE_SGSN)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
sgi->gtp_fd0.fd = gsn->fd0;
|
osmo_fd_setup(&sgi->gtp_fd0, gsn->fd0, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 0);
|
||||||
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);
|
rc = osmo_fd_register(&sgi->gtp_fd0);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
sgi->gtp_fd1c.fd = gsn->fd1c;
|
osmo_fd_setup(&sgi->gtp_fd1c, gsn->fd1c, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 1);
|
||||||
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);
|
rc = osmo_fd_register(&sgi->gtp_fd1c);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
osmo_fd_unregister(&sgi->gtp_fd0);
|
osmo_fd_unregister(&sgi->gtp_fd0);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
sgi->gtp_fd1u.fd = gsn->fd1u;
|
osmo_fd_setup(&sgi->gtp_fd1u, gsn->fd1u, OSMO_FD_READ, sgsn_gtp_fd_cb, sgi, 2);
|
||||||
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);
|
rc = osmo_fd_register(&sgi->gtp_fd1u);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
osmo_fd_unregister(&sgi->gtp_fd0);
|
osmo_fd_unregister(&sgi->gtp_fd0);
|
||||||
|
|||||||
@@ -39,15 +39,18 @@
|
|||||||
#include <osmocom/core/rate_ctr.h>
|
#include <osmocom/core/rate_ctr.h>
|
||||||
#include <osmocom/core/logging.h>
|
#include <osmocom/core/logging.h>
|
||||||
#include <osmocom/core/stats.h>
|
#include <osmocom/core/stats.h>
|
||||||
|
#include <osmocom/core/sockaddr_str.h>
|
||||||
|
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
#include <osmocom/gprs/gprs_ns2.h>
|
||||||
#include <osmocom/gprs/gprs_bssgp.h>
|
#include <osmocom/gprs/gprs_bssgp.h>
|
||||||
|
#include <osmocom/gprs/gprs_bssgp_bss.h>
|
||||||
|
|
||||||
#include <osmocom/vty/telnet_interface.h>
|
#include <osmocom/vty/telnet_interface.h>
|
||||||
#include <osmocom/vty/logging.h>
|
#include <osmocom/vty/logging.h>
|
||||||
#include <osmocom/vty/stats.h>
|
#include <osmocom/vty/stats.h>
|
||||||
#include <osmocom/vty/ports.h>
|
#include <osmocom/vty/ports.h>
|
||||||
#include <osmocom/vty/misc.h>
|
#include <osmocom/vty/misc.h>
|
||||||
|
#include <osmocom/vty/cpu_sched_vty.h>
|
||||||
|
|
||||||
#include <osmocom/ctrl/control_vty.h>
|
#include <osmocom/ctrl/control_vty.h>
|
||||||
|
|
||||||
@@ -58,11 +61,13 @@
|
|||||||
#include <osmocom/sgsn/gprs_llc.h>
|
#include <osmocom/sgsn/gprs_llc.h>
|
||||||
#include <osmocom/sgsn/gprs_gmm.h>
|
#include <osmocom/sgsn/gprs_gmm.h>
|
||||||
#include <osmocom/sgsn/gprs_ranap.h>
|
#include <osmocom/sgsn/gprs_ranap.h>
|
||||||
|
#include <osmocom/sgsn/gprs_gb.h>
|
||||||
|
|
||||||
#include <osmocom/ctrl/control_if.h>
|
#include <osmocom/ctrl/control_if.h>
|
||||||
#include <osmocom/ctrl/ports.h>
|
#include <osmocom/ctrl/ports.h>
|
||||||
|
|
||||||
#include <gtp.h>
|
#include <gtp.h>
|
||||||
|
#include <osmocom/sgsn/sgsn_rim.h>
|
||||||
|
|
||||||
#include "../../bscconfig.h"
|
#include "../../bscconfig.h"
|
||||||
|
|
||||||
@@ -78,7 +83,7 @@
|
|||||||
void *tall_sgsn_ctx;
|
void *tall_sgsn_ctx;
|
||||||
struct ctrl_handle *g_ctrlh;
|
struct ctrl_handle *g_ctrlh;
|
||||||
|
|
||||||
struct gprs_ns_inst *sgsn_nsi;
|
struct gprs_ns2_inst *sgsn_nsi;
|
||||||
static int daemonize = 0;
|
static int daemonize = 0;
|
||||||
const char *openbsc_copyright =
|
const char *openbsc_copyright =
|
||||||
"Copyright (C) 2010 Harald Welte and On-Waves\r\n"
|
"Copyright (C) 2010 Harald Welte and On-Waves\r\n"
|
||||||
@@ -92,27 +97,6 @@ const char *openbsc_copyright =
|
|||||||
|
|
||||||
struct sgsn_instance *sgsn;
|
struct sgsn_instance *sgsn;
|
||||||
|
|
||||||
/* 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 */
|
/* call-back function for the BSSGP protocol */
|
||||||
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
|
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
|
||||||
{
|
{
|
||||||
@@ -137,15 +121,17 @@ int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
|
|||||||
break;
|
break;
|
||||||
case SAP_BSSGP_NM:
|
case SAP_BSSGP_NM:
|
||||||
break;
|
break;
|
||||||
|
case SAP_BSSGP_RIM:
|
||||||
|
return sgsn_rim_rx(bp, oph->msg);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_handler(int signal)
|
static void signal_handler(int signum)
|
||||||
{
|
{
|
||||||
fprintf(stdout, "signal %u received\n", signal);
|
fprintf(stdout, "signal %u received\n", signum);
|
||||||
|
|
||||||
switch (signal) {
|
switch (signum) {
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
|
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
|
||||||
@@ -153,8 +139,17 @@ static void signal_handler(int signal)
|
|||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
/* in case of abort, we want to obtain a talloc report
|
/* in case of abort, we want to obtain a talloc report and
|
||||||
* and then return to the caller, who will abort the process */
|
* then run default SIGABRT handler, who will generate coredump
|
||||||
|
* and abort the process. abort() should do this for us after we
|
||||||
|
* return, but program wouldn't exit if an external SIGABRT is
|
||||||
|
* received.
|
||||||
|
*/
|
||||||
|
talloc_report(tall_vty_ctx, stderr);
|
||||||
|
talloc_report_full(tall_sgsn_ctx, stderr);
|
||||||
|
signal(SIGABRT, SIG_DFL);
|
||||||
|
raise(SIGABRT);
|
||||||
|
break;
|
||||||
case SIGUSR1:
|
case SIGUSR1:
|
||||||
talloc_report(tall_vty_ctx, stderr);
|
talloc_report(tall_vty_ctx, stderr);
|
||||||
talloc_report_full(tall_sgsn_ctx, stderr);
|
talloc_report_full(tall_sgsn_ctx, stderr);
|
||||||
@@ -170,40 +165,12 @@ static void signal_handler(int signal)
|
|||||||
/* NSI that BSSGP uses when transmitting on NS */
|
/* NSI that BSSGP uses when transmitting on NS */
|
||||||
extern struct gprs_ns_inst *bssgp_nsi;
|
extern struct gprs_ns_inst *bssgp_nsi;
|
||||||
|
|
||||||
int sgsn_vty_is_config_node(struct vty *vty, int node)
|
|
||||||
{
|
|
||||||
/* So far the SGSN has no nested nodes that need parent node
|
|
||||||
* declaration, except for the ss7 vty nodes. */
|
|
||||||
switch (node) {
|
|
||||||
case SGSN_NODE:
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
#if BUILD_IU
|
|
||||||
return osmo_ss7_is_config_node(vty, node);
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int sgsn_vty_go_parent(struct vty *vty)
|
|
||||||
{
|
|
||||||
/* So far the SGSN has no nested nodes that need parent node
|
|
||||||
* declaration, except for the ss7 vty nodes. */
|
|
||||||
#if BUILD_IU
|
|
||||||
return osmo_ss7_vty_go_parent(vty);
|
|
||||||
#else
|
|
||||||
vty->node = CONFIG_NODE;
|
|
||||||
vty->index = NULL;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct vty_app_info vty_info = {
|
static struct vty_app_info vty_info = {
|
||||||
.name = "OsmoSGSN",
|
.name = "OsmoSGSN",
|
||||||
.version = PACKAGE_VERSION,
|
.version = PACKAGE_VERSION,
|
||||||
.go_parent_cb = sgsn_vty_go_parent,
|
#if BUILD_IU
|
||||||
.is_config_node = sgsn_vty_is_config_node,
|
.go_parent_cb = osmo_ss7_vty_go_parent,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void print_help(void)
|
static void print_help(void)
|
||||||
@@ -216,12 +183,43 @@ static void print_help(void)
|
|||||||
printf(" -s --disable-color\n");
|
printf(" -s --disable-color\n");
|
||||||
printf(" -c --config-file\tThe config file to use [%s]\n", CONFIG_FILE_DEFAULT);
|
printf(" -c --config-file\tThe config file to use [%s]\n", CONFIG_FILE_DEFAULT);
|
||||||
printf(" -e --log-level number\tSet a global log level\n");
|
printf(" -e --log-level number\tSet a global log level\n");
|
||||||
|
|
||||||
|
printf("\nVTY reference generation:\n");
|
||||||
|
printf(" --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n");
|
||||||
|
printf(" --vty-ref-xml Generate the VTY reference XML output and exit.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_long_options(const char *prog_name, const int long_option)
|
||||||
|
{
|
||||||
|
static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
|
||||||
|
|
||||||
|
switch (long_option) {
|
||||||
|
case 1:
|
||||||
|
vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
|
||||||
|
if (vty_ref_mode < 0) {
|
||||||
|
fprintf(stderr, "%s: Unknown VTY reference generation "
|
||||||
|
"mode '%s'\n", prog_name, optarg);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
|
||||||
|
get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
|
||||||
|
get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
|
||||||
|
vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
|
||||||
|
exit(0);
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void handle_options(int argc, char **argv)
|
static void handle_options(int argc, char **argv)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0, c;
|
int option_index = 0, c;
|
||||||
|
static int long_option = 0;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"help", 0, 0, 'h'},
|
{"help", 0, 0, 'h'},
|
||||||
{"debug", 1, 0, 'd'},
|
{"debug", 1, 0, 'd'},
|
||||||
@@ -231,6 +229,8 @@ static void handle_options(int argc, char **argv)
|
|||||||
{"timestamp", 0, 0, 'T'},
|
{"timestamp", 0, 0, 'T'},
|
||||||
{ "version", 0, 0, 'V' },
|
{ "version", 0, 0, 'V' },
|
||||||
{"log-level", 1, 0, 'e'},
|
{"log-level", 1, 0, 'e'},
|
||||||
|
{"vty-ref-mode", 1, &long_option, 1},
|
||||||
|
{"vty-ref-xml", 0, &long_option, 2},
|
||||||
{NULL, 0, 0, 0}
|
{NULL, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -240,6 +240,9 @@ static void handle_options(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 0:
|
||||||
|
handle_long_options(argv[0], long_option);
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
//print_usage();
|
//print_usage();
|
||||||
print_help();
|
print_help();
|
||||||
@@ -312,11 +315,6 @@ static struct log_info_cat gprs_categories[] = {
|
|||||||
.description = "GPRS Network Service (NS)",
|
.description = "GPRS Network Service (NS)",
|
||||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
},
|
},
|
||||||
[DBSSGP] = {
|
|
||||||
.name = "DBSSGP",
|
|
||||||
.description = "GPRS BSS Gateway Protocol (BSSGP)",
|
|
||||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
|
||||||
},
|
|
||||||
[DLLC] = {
|
[DLLC] = {
|
||||||
.name = "DLLC",
|
.name = "DLLC",
|
||||||
.description = "GPRS Logical Link Control Protocol (LLC)",
|
.description = "GPRS Logical Link Control Protocol (LLC)",
|
||||||
@@ -352,6 +350,11 @@ static struct log_info_cat gprs_categories[] = {
|
|||||||
.description = "GPRS Tunnelling Protocol (GTP)",
|
.description = "GPRS Tunnelling Protocol (GTP)",
|
||||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
},
|
},
|
||||||
|
[DRIM] = {
|
||||||
|
.name = "DRIM",
|
||||||
|
.description = "RAN Information Management (RIM)",
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct log_info gprs_log_info = {
|
static const struct log_info gprs_log_info = {
|
||||||
@@ -396,6 +399,7 @@ int main(int argc, char **argv)
|
|||||||
osmo_stats_vty_add_cmds();
|
osmo_stats_vty_add_cmds();
|
||||||
sgsn_vty_init(&sgsn->cfg);
|
sgsn_vty_init(&sgsn->cfg);
|
||||||
ctrl_vty_init(tall_sgsn_ctx);
|
ctrl_vty_init(tall_sgsn_ctx);
|
||||||
|
osmo_cpu_sched_vty_init(tall_sgsn_ctx);
|
||||||
|
|
||||||
#if BUILD_IU
|
#if BUILD_IU
|
||||||
OSMO_ASSERT(osmo_ss7_init() == 0);
|
OSMO_ASSERT(osmo_ss7_init() == 0);
|
||||||
@@ -403,6 +407,30 @@ int main(int argc, char **argv)
|
|||||||
osmo_sccp_vty_init();
|
osmo_sccp_vty_init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
rate_ctr_init(tall_sgsn_ctx);
|
||||||
|
|
||||||
|
logging_vty_add_deprecated_subsys(tall_sgsn_ctx, "bssgp");
|
||||||
|
|
||||||
|
sgsn_nsi = gprs_ns2_instantiate(tall_sgsn_ctx, &gprs_ns_prim_cb, NULL);
|
||||||
|
if (!sgsn_nsi) {
|
||||||
|
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
sgsn->cfg.nsi = sgsn_nsi;
|
||||||
|
bssgp_set_bssgp_callback(gprs_gb_send_cb, sgsn_nsi);
|
||||||
|
|
||||||
|
gprs_llc_init("/usr/local/lib/osmocom/crypt/");
|
||||||
|
sgsn_rate_ctr_init();
|
||||||
|
sgsn_inst_init(sgsn);
|
||||||
|
|
||||||
|
|
||||||
|
gprs_ns2_vty_init(sgsn_nsi);
|
||||||
|
bssgp_vty_init();
|
||||||
|
gprs_llc_vty_init();
|
||||||
|
gprs_sndcp_vty_init();
|
||||||
|
sgsn_auth_init(sgsn);
|
||||||
|
sgsn_cdr_init(sgsn);
|
||||||
|
|
||||||
handle_options(argc, argv);
|
handle_options(argc, argv);
|
||||||
|
|
||||||
/* Backwards compatibility: for years, the default config file name was
|
/* Backwards compatibility: for years, the default config file name was
|
||||||
@@ -420,30 +448,6 @@ int main(int argc, char **argv)
|
|||||||
osmo_talloc_replace_string(sgsn, &sgsn->config_file, CONFIG_FILE_DEFAULT);
|
osmo_talloc_replace_string(sgsn, &sgsn->config_file, CONFIG_FILE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
rate_ctr_init(tall_sgsn_ctx);
|
|
||||||
|
|
||||||
gprs_ns_set_log_ss(DNS);
|
|
||||||
bssgp_set_log_ss(DBSSGP);
|
|
||||||
|
|
||||||
sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb, tall_sgsn_ctx);
|
|
||||||
if (!sgsn_nsi) {
|
|
||||||
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
bssgp_nsi = sgsn->cfg.nsi = sgsn_nsi;
|
|
||||||
|
|
||||||
gprs_llc_init("/usr/local/lib/osmocom/crypt/");
|
|
||||||
sgsn_rate_ctr_init();
|
|
||||||
sgsn_inst_init(sgsn);
|
|
||||||
|
|
||||||
gprs_ns_vty_init(bssgp_nsi);
|
|
||||||
bssgp_vty_init();
|
|
||||||
gprs_llc_vty_init();
|
|
||||||
gprs_sndcp_vty_init();
|
|
||||||
sgsn_auth_init(sgsn);
|
|
||||||
sgsn_cdr_init(sgsn);
|
|
||||||
/* FIXME: register signal handler for SS_L_NS */
|
|
||||||
|
|
||||||
rc = sgsn_parse_config(sgsn->config_file);
|
rc = sgsn_parse_config(sgsn->config_file);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGP(DGPRS, LOGL_FATAL, "Error in config file\n");
|
LOGP(DGPRS, LOGL_FATAL, "Error in config file\n");
|
||||||
@@ -484,19 +488,6 @@ int main(int argc, char **argv)
|
|||||||
exit(2);
|
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->cfg.dynamic_lookup) {
|
||||||
if (sgsn_ares_init(sgsn) != 0) {
|
if (sgsn_ares_init(sgsn) != 0) {
|
||||||
LOGP(DGPRS, LOGL_FATAL,
|
LOGP(DGPRS, LOGL_FATAL,
|
||||||
@@ -512,8 +503,8 @@ int main(int argc, char **argv)
|
|||||||
"OsmoSGSN",
|
"OsmoSGSN",
|
||||||
(23 << 3) + 4,
|
(23 << 3) + 4,
|
||||||
OSMO_SS7_ASP_PROT_M3UA,
|
OSMO_SS7_ASP_PROT_M3UA,
|
||||||
0, NULL,
|
0, "localhost",
|
||||||
0, "127.0.0.1");
|
0, "localhost");
|
||||||
if (!sccp) {
|
if (!sccp) {
|
||||||
printf("Setting up SCCP client failed.\n");
|
printf("Setting up SCCP client failed.\n");
|
||||||
return 8;
|
return 8;
|
||||||
|
|||||||
67
src/sgsn/sgsn_rim.c
Normal file
67
src/sgsn/sgsn_rim.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/msgb.h>
|
||||||
|
#include <osmocom/gsm/tlv.h>
|
||||||
|
#include <osmocom/vty/logging.h>
|
||||||
|
#include <osmocom/gprs/gprs_ns.h>
|
||||||
|
#include <osmocom/gprs/gprs_bssgp.h>
|
||||||
|
#include <osmocom/gprs/gprs_bssgp_rim.h>
|
||||||
|
#include <osmocom/sgsn/sgsn_rim.h>
|
||||||
|
#include <osmocom/sgsn/debug.h>
|
||||||
|
|
||||||
|
/* Find an NSEI for the destination cell, this function works only for GERAN! */
|
||||||
|
static int find_dest_nsei_geran(struct bssgp_rim_routing_info *dest_rim_ri, uint16_t nsei)
|
||||||
|
{
|
||||||
|
struct bssgp_bvc_ctx *bvc_ctx;
|
||||||
|
|
||||||
|
OSMO_ASSERT(dest_rim_ri->discr == BSSGP_RIM_ROUTING_INFO_GERAN);
|
||||||
|
|
||||||
|
bvc_ctx = btsctx_by_raid_cid(&dest_rim_ri->geran.raid, dest_rim_ri->geran.cid);
|
||||||
|
if (!bvc_ctx) {
|
||||||
|
LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) cannot find NSEI for destination cell\n", nsei);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bvc_ctx->nsei;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg)
|
||||||
|
{
|
||||||
|
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
|
||||||
|
int d_nsei;
|
||||||
|
uint16_t nsei = msgb_nsei(msg);
|
||||||
|
|
||||||
|
/* At the moment we only support GERAN, so we block all other network
|
||||||
|
* types here. */
|
||||||
|
if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
|
||||||
|
LOGP(DRIM, LOGL_ERROR,
|
||||||
|
"BSSGP RIM (NSEI=%u) only GERAN supported, destination cell is not a GERAN cell -- rejected.\n",
|
||||||
|
nsei);
|
||||||
|
/* At the moment we can only handle GERAN addresses, any other
|
||||||
|
* type of address will be consideres as an invalid address.
|
||||||
|
* see also: 3GPP TS 48.018, section 8c.3.1.3 */
|
||||||
|
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
|
||||||
|
}
|
||||||
|
if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
|
||||||
|
LOGP(DRIM, LOGL_ERROR,
|
||||||
|
"BSSGP RIM (NSEI=%u) only GERAN supported, source cell is not a GERAN cell -- rejected.\n", nsei);
|
||||||
|
/* See comment above */
|
||||||
|
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
d_nsei = find_dest_nsei_geran(&pdu->routing_info_dest, nsei);
|
||||||
|
if (d_nsei < 0) {
|
||||||
|
LOGP(DRIM, LOGL_NOTICE, "BSSGP RIM (NSEI=%u) Cell %s unknown to this sgsn\n",
|
||||||
|
nsei, bssgp_rim_ri_name(&pdu->routing_info_dest));
|
||||||
|
/* In case of an invalid destination address we respond with
|
||||||
|
* a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
|
||||||
|
return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forward PDU as it is to the correct interface */
|
||||||
|
return bssgp_tx_rim(pdu, (uint16_t) d_nsei);
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
#include <osmocom/sgsn/debug.h>
|
#include <osmocom/sgsn/debug.h>
|
||||||
#include <osmocom/sgsn/sgsn.h>
|
#include <osmocom/sgsn/sgsn.h>
|
||||||
#include <osmocom/gprs/gprs_ns.h>
|
#include <osmocom/gprs/gprs_ns2.h>
|
||||||
#include <osmocom/sgsn/gprs_gmm.h>
|
#include <osmocom/sgsn/gprs_gmm.h>
|
||||||
#include <osmocom/sgsn/gprs_sgsn.h>
|
#include <osmocom/sgsn/gprs_sgsn.h>
|
||||||
#include <osmocom/sgsn/vty.h>
|
#include <osmocom/sgsn/vty.h>
|
||||||
@@ -186,6 +186,8 @@ static int config_write_sgsn(struct vty *vty)
|
|||||||
|
|
||||||
vty_out(vty, "sgsn%s", VTY_NEWLINE);
|
vty_out(vty, "sgsn%s", VTY_NEWLINE);
|
||||||
|
|
||||||
|
vty_out(vty, " gtp state-dir %s%s",
|
||||||
|
g_cfg->gtp_statedir, VTY_NEWLINE);
|
||||||
vty_out(vty, " gtp local-ip %s%s",
|
vty_out(vty, " gtp local-ip %s%s",
|
||||||
inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
|
inet_ntoa(g_cfg->gtp_listenaddr.sin_addr), VTY_NEWLINE);
|
||||||
|
|
||||||
@@ -315,6 +317,17 @@ DEFUN(cfg_sgsn, cfg_sgsn_cmd,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_sgsn_state_dir, cfg_sgsn_state_dir_cmd,
|
||||||
|
"gtp state-dir PATH",
|
||||||
|
"GTP Parameters\n"
|
||||||
|
"Set the directory for the GTP State file\n"
|
||||||
|
"Local Directory\n")
|
||||||
|
{
|
||||||
|
osmo_talloc_replace_string(sgsn, &sgsn->cfg.gtp_statedir, argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
|
DEFUN(cfg_sgsn_bind_addr, cfg_sgsn_bind_addr_cmd,
|
||||||
"gtp local-ip A.B.C.D",
|
"gtp local-ip A.B.C.D",
|
||||||
"GTP Parameters\n"
|
"GTP Parameters\n"
|
||||||
@@ -1007,6 +1020,10 @@ DEFUN(update_subscr_create, update_subscr_create_cmd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
subscr = gprs_subscr_get_or_create(imsi);
|
subscr = gprs_subscr_get_or_create(imsi);
|
||||||
|
if (!subscr) {
|
||||||
|
vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
subscr->keep_in_ram = 1;
|
subscr->keep_in_ram = 1;
|
||||||
gprs_subscr_put(subscr);
|
gprs_subscr_put(subscr);
|
||||||
|
|
||||||
@@ -1432,6 +1449,7 @@ int sgsn_vty_init(struct sgsn_config *cfg)
|
|||||||
|
|
||||||
install_element(CONFIG_NODE, &cfg_sgsn_cmd);
|
install_element(CONFIG_NODE, &cfg_sgsn_cmd);
|
||||||
install_node(&sgsn_node, config_write_sgsn);
|
install_node(&sgsn_node, config_write_sgsn);
|
||||||
|
install_element(SGSN_NODE, &cfg_sgsn_state_dir_cmd);
|
||||||
install_element(SGSN_NODE, &cfg_sgsn_bind_addr_cmd);
|
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_ip_cmd);
|
||||||
//install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
|
//install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
gprs \
|
gprs \
|
||||||
gbproxy \
|
|
||||||
gtphub \
|
gtphub \
|
||||||
sgsn \
|
sgsn \
|
||||||
xid \
|
xid \
|
||||||
@@ -33,7 +32,7 @@ EXTRA_DIST = \
|
|||||||
$(TESTSUITE) \
|
$(TESTSUITE) \
|
||||||
vty_test_runner.py \
|
vty_test_runner.py \
|
||||||
ctrl_test_runner.py \
|
ctrl_test_runner.py \
|
||||||
test_nodes.vty \
|
osmo-sgsn_test-nodes.vty \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
TESTSUITE = $(srcdir)/testsuite
|
TESTSUITE = $(srcdir)/testsuite
|
||||||
@@ -64,7 +63,7 @@ vty-transcript-test:
|
|||||||
osmo_verify_transcript_vty.py -v \
|
osmo_verify_transcript_vty.py -v \
|
||||||
-n OsmoSGSN -p 4245 \
|
-n OsmoSGSN -p 4245 \
|
||||||
-r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \
|
-r "$(top_builddir)/src/sgsn/osmo-sgsn -c $(top_srcdir)/doc/examples/osmo-sgsn/osmo-sgsn.cfg" \
|
||||||
$(U) $${T:-$(srcdir)/*.vty}
|
$(U) $${T:-$(srcdir)/osmo-sgsn*.vty}
|
||||||
rm -f $(builddir)/sms.db $(builddir)/gsn_restart
|
rm -f $(builddir)/sms.db $(builddir)/gsn_restart
|
||||||
|
|
||||||
# don't run multiple tests concurrently so that the ports don't conflict
|
# don't run multiple tests concurrently so that the ports don't conflict
|
||||||
|
|||||||
@@ -1,50 +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=osmo_get_rand_id \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
gbproxy_test_LDADD = \
|
|
||||||
$(top_builddir)/src/gbproxy/gb_proxy.o \
|
|
||||||
$(top_builddir)/src/gbproxy/gb_proxy_patch.o \
|
|
||||||
$(top_builddir)/src/gbproxy/gb_proxy_peer.o \
|
|
||||||
$(top_builddir)/src/gbproxy/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 \
|
|
||||||
$(LIBOSMOCORE_LIBS) \
|
|
||||||
$(LIBOSMOGB_LIBS) \
|
|
||||||
$(LIBOSMOGSM_LIBS) \
|
|
||||||
$(LIBOSMOVTY_LIBS) \
|
|
||||||
$(LIBOSMOABIS_LIBS) \
|
|
||||||
$(LIBRARY_DL) \
|
|
||||||
-lrt \
|
|
||||||
$(NULL)
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -54,7 +54,7 @@
|
|||||||
void gtphub_init(struct gtphub *hub);
|
void gtphub_init(struct gtphub *hub);
|
||||||
void gtphub_free(struct gtphub *hub);
|
void gtphub_free(struct gtphub *hub);
|
||||||
|
|
||||||
void *osmo_gtphub_ctx;
|
extern void *osmo_gtphub_ctx;
|
||||||
|
|
||||||
static void nr_mapping_free(struct expiring_item *e)
|
static void nr_mapping_free(struct expiring_item *e)
|
||||||
{
|
{
|
||||||
@@ -378,37 +378,37 @@ static void test_expiry(void)
|
|||||||
char resolve_ggsn_got_imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
char resolve_ggsn_got_imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
||||||
char resolve_ggsn_got_ni[GSM_APN_LENGTH];
|
char resolve_ggsn_got_ni[GSM_APN_LENGTH];
|
||||||
|
|
||||||
struct osmo_sockaddr resolved_ggsn_addr;
|
struct sgsn_sockaddr resolved_ggsn_addr;
|
||||||
static int resolve_to_ggsn(const char *addr, uint16_t port)
|
static int resolve_to_ggsn(const char *addr, uint16_t port)
|
||||||
{
|
{
|
||||||
LVL2_ASSERT(osmo_sockaddr_init_udp(&resolved_ggsn_addr,
|
LVL2_ASSERT(sgsn_sockaddr_init_udp(&resolved_ggsn_addr,
|
||||||
addr, port)
|
addr, port)
|
||||||
== 0);
|
== 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct osmo_sockaddr resolved_sgsn_addr;
|
struct sgsn_sockaddr resolved_sgsn_addr;
|
||||||
static int resolve_to_sgsn(const char *addr, uint16_t port)
|
static int resolve_to_sgsn(const char *addr, uint16_t port)
|
||||||
{
|
{
|
||||||
LVL2_ASSERT(osmo_sockaddr_init_udp(&resolved_sgsn_addr,
|
LVL2_ASSERT(sgsn_sockaddr_init_udp(&resolved_sgsn_addr,
|
||||||
addr, port)
|
addr, port)
|
||||||
== 0);
|
== 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct osmo_sockaddr sgsn_sender;
|
struct sgsn_sockaddr sgsn_sender;
|
||||||
static int send_from_sgsn(const char *addr, uint16_t port)
|
static int send_from_sgsn(const char *addr, uint16_t port)
|
||||||
{
|
{
|
||||||
LVL2_ASSERT(osmo_sockaddr_init_udp(&sgsn_sender,
|
LVL2_ASSERT(sgsn_sockaddr_init_udp(&sgsn_sender,
|
||||||
addr, port)
|
addr, port)
|
||||||
== 0);
|
== 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct osmo_sockaddr ggsn_sender;
|
struct sgsn_sockaddr ggsn_sender;
|
||||||
static int send_from_ggsn(const char *addr, uint16_t port)
|
static int send_from_ggsn(const char *addr, uint16_t port)
|
||||||
{
|
{
|
||||||
LVL2_ASSERT(osmo_sockaddr_init_udp(&ggsn_sender,
|
LVL2_ASSERT(sgsn_sockaddr_init_udp(&ggsn_sender,
|
||||||
addr, port)
|
addr, port)
|
||||||
== 0);
|
== 0);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -491,18 +491,18 @@ int __wrap_gtphub_ares_init(struct gtphub *hub)
|
|||||||
|
|
||||||
/* override, requires '-Wl,--wrap=gtphub_write' */
|
/* override, requires '-Wl,--wrap=gtphub_write' */
|
||||||
int __real_gtphub_write(const struct osmo_fd *to,
|
int __real_gtphub_write(const struct osmo_fd *to,
|
||||||
const struct osmo_sockaddr *to_addr,
|
const struct sgsn_sockaddr *to_addr,
|
||||||
const uint8_t *buf, size_t buf_len);
|
const uint8_t *buf, size_t buf_len);
|
||||||
|
|
||||||
int __wrap_gtphub_write(const struct osmo_fd *to,
|
int __wrap_gtphub_write(const struct osmo_fd *to,
|
||||||
const struct osmo_sockaddr *to_addr,
|
const struct sgsn_sockaddr *to_addr,
|
||||||
const uint8_t *buf, size_t buf_len)
|
const uint8_t *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
printf("Out-of-band gtphub_write(%d):\n"
|
printf("Out-of-band gtphub_write(%d):\n"
|
||||||
"to %s\n"
|
"to %s\n"
|
||||||
"%s\n",
|
"%s\n",
|
||||||
(int)buf_len,
|
(int)buf_len,
|
||||||
osmo_sockaddr_to_str(to_addr),
|
sgsn_sockaddr_to_str(to_addr),
|
||||||
osmo_hexdump(buf, buf_len));
|
osmo_hexdump(buf, buf_len));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -529,6 +529,8 @@ static int _reply_is(const char *hex, const char *file, int line)
|
|||||||
const char *dump = osmo_hexdump_nospc(reply_buf, len);
|
const char *dump = osmo_hexdump_nospc(reply_buf, len);
|
||||||
int cmp = strcmp(dump, hex);
|
int cmp = strcmp(dump, hex);
|
||||||
|
|
||||||
|
OSMO_ASSERT(dump && hex);
|
||||||
|
|
||||||
if (cmp != 0) {
|
if (cmp != 0) {
|
||||||
printf("\n%s:%d: reply_is(): MISMATCH\n"
|
printf("\n%s:%d: reply_is(): MISMATCH\n"
|
||||||
" expecting:\n'%s'\n"
|
" expecting:\n'%s'\n"
|
||||||
@@ -553,11 +555,11 @@ static int _reply_is(const char *hex, const char *file, int line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define same_addr(GOT, EXPECTED) _same_addr((GOT),(EXPECTED), __FILE__, __LINE__)
|
#define same_addr(GOT, EXPECTED) _same_addr((GOT),(EXPECTED), __FILE__, __LINE__)
|
||||||
static int _same_addr(const struct osmo_sockaddr *got,
|
static int _same_addr(const struct sgsn_sockaddr *got,
|
||||||
const struct osmo_sockaddr *expected,
|
const struct sgsn_sockaddr *expected,
|
||||||
const char *file, int line)
|
const char *file, int line)
|
||||||
{
|
{
|
||||||
int cmp = osmo_sockaddr_cmp(got, expected);
|
int cmp = sgsn_sockaddr_cmp(got, expected);
|
||||||
if (!cmp)
|
if (!cmp)
|
||||||
return 1;
|
return 1;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
@@ -565,8 +567,8 @@ static int _same_addr(const struct osmo_sockaddr *got,
|
|||||||
" expecting: '%s'\n"
|
" expecting: '%s'\n"
|
||||||
" got: '%s'\n\n",
|
" got: '%s'\n\n",
|
||||||
file, line,
|
file, line,
|
||||||
osmo_sockaddr_to_str(expected),
|
sgsn_sockaddr_to_str(expected),
|
||||||
osmo_sockaddr_to_strb(got, buf, sizeof(buf)));
|
sgsn_sockaddr_to_strb(got, buf, sizeof(buf)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,7 +670,7 @@ static void test_echo(void)
|
|||||||
now = 123;
|
now = 123;
|
||||||
|
|
||||||
struct osmo_fd *to_ofd;
|
struct osmo_fd *to_ofd;
|
||||||
struct osmo_sockaddr to_addr;
|
struct sgsn_sockaddr to_addr;
|
||||||
struct gtphub_peer_port *pp;
|
struct gtphub_peer_port *pp;
|
||||||
int send;
|
int send;
|
||||||
|
|
||||||
@@ -855,13 +857,13 @@ static void test_echo(void)
|
|||||||
#define msg_from_sgsn_c(A,B,C,D) msg_from_sgsn(GTPH_PLANE_CTRL, A,B,C,D)
|
#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)
|
#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,
|
static int msg_from_sgsn(int plane_idx,
|
||||||
struct osmo_sockaddr *_sgsn_sender,
|
struct sgsn_sockaddr *_sgsn_sender,
|
||||||
struct osmo_sockaddr *ggsn_receiver,
|
struct sgsn_sockaddr *ggsn_receiver,
|
||||||
const char *hex_from_sgsn,
|
const char *hex_from_sgsn,
|
||||||
const char *hex_to_ggsn)
|
const char *hex_to_ggsn)
|
||||||
{
|
{
|
||||||
struct osmo_fd *ggsn_ofd = NULL;
|
struct osmo_fd *ggsn_ofd = NULL;
|
||||||
struct osmo_sockaddr ggsn_addr;
|
struct sgsn_sockaddr ggsn_addr;
|
||||||
int send;
|
int send;
|
||||||
send = gtphub_handle_buf(hub, GTPH_SIDE_SGSN, plane_idx, _sgsn_sender,
|
send = gtphub_handle_buf(hub, GTPH_SIDE_SGSN, plane_idx, _sgsn_sender,
|
||||||
buf, msg(hex_from_sgsn), now,
|
buf, msg(hex_from_sgsn), now,
|
||||||
@@ -875,13 +877,13 @@ static int msg_from_sgsn(int plane_idx,
|
|||||||
#define msg_from_ggsn_c(A,B,C,D) msg_from_ggsn(GTPH_PLANE_CTRL, A,B,C,D)
|
#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)
|
#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,
|
static int msg_from_ggsn(int plane_idx,
|
||||||
struct osmo_sockaddr *ggsn_sender,
|
struct sgsn_sockaddr *ggsn_sender,
|
||||||
struct osmo_sockaddr *sgsn_receiver,
|
struct sgsn_sockaddr *sgsn_receiver,
|
||||||
const char *msg_from_ggsn,
|
const char *msg_from_ggsn,
|
||||||
const char *msg_to_sgsn)
|
const char *msg_to_sgsn)
|
||||||
{
|
{
|
||||||
struct osmo_fd *sgsn_ofd;
|
struct osmo_fd *sgsn_ofd;
|
||||||
struct osmo_sockaddr sgsn_addr;
|
struct sgsn_sockaddr sgsn_addr;
|
||||||
int send;
|
int send;
|
||||||
send = gtphub_handle_buf(hub, GTPH_SIDE_GGSN, plane_idx, ggsn_sender,
|
send = gtphub_handle_buf(hub, GTPH_SIDE_GGSN, plane_idx, ggsn_sender,
|
||||||
buf, msg(msg_from_ggsn), now,
|
buf, msg(msg_from_ggsn), now,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ OsmoSGSN(config)# list
|
|||||||
OsmoSGSN(config)# sgsn
|
OsmoSGSN(config)# sgsn
|
||||||
OsmoSGSN(config-sgsn)# list
|
OsmoSGSN(config-sgsn)# list
|
||||||
...
|
...
|
||||||
|
gtp state-dir PATH
|
||||||
gtp local-ip A.B.C.D
|
gtp local-ip A.B.C.D
|
||||||
ggsn <0-255> remote-ip A.B.C.D
|
ggsn <0-255> remote-ip A.B.C.D
|
||||||
ggsn <0-255> gtp-version (0|1)
|
ggsn <0-255> gtp-version (0|1)
|
||||||
@@ -1625,11 +1625,6 @@ static struct log_info_cat gprs_categories[] = {
|
|||||||
.description = "GPRS Network Service (NS)",
|
.description = "GPRS Network Service (NS)",
|
||||||
.enabled = 1, .loglevel = LOGL_INFO,
|
.enabled = 1, .loglevel = LOGL_INFO,
|
||||||
},
|
},
|
||||||
[DBSSGP] = {
|
|
||||||
.name = "DBSSGP",
|
|
||||||
.description = "GPRS BSS Gateway Protocol (BSSGP)",
|
|
||||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
|
||||||
},
|
|
||||||
[DLLC] = {
|
[DLLC] = {
|
||||||
.name = "DLLC",
|
.name = "DLLC",
|
||||||
.description = "GPRS Logical Link Control Protocol (LLC)",
|
.description = "GPRS Logical Link Control Protocol (LLC)",
|
||||||
|
|||||||
@@ -7,12 +7,6 @@ cat $abs_srcdir/gprs/gprs_test.ok > expout
|
|||||||
AT_CHECK([$abs_top_builddir/tests/gprs/gprs_test], [], [expout], [ignore])
|
AT_CHECK([$abs_top_builddir/tests/gprs/gprs_test], [], [expout], [ignore])
|
||||||
AT_CLEANUP
|
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([sgsn])
|
AT_SETUP([sgsn])
|
||||||
AT_KEYWORDS([sgsn])
|
AT_KEYWORDS([sgsn])
|
||||||
AT_CHECK([test "$enable_sgsn_test" != no || exit 77])
|
AT_CHECK([test "$enable_sgsn_test" != no || exit 77])
|
||||||
|
|||||||
@@ -67,55 +67,6 @@ class TestVTYBase(unittest.TestCase):
|
|||||||
self.vty = None
|
self.vty = None
|
||||||
osmoutil.end_proc(self.proc)
|
osmoutil.end_proc(self.proc)
|
||||||
|
|
||||||
|
|
||||||
class TestVTYGbproxy(TestVTYBase):
|
|
||||||
|
|
||||||
def vty_command(self):
|
|
||||||
return ["./src/gbproxy/osmo-gbproxy", "-c",
|
|
||||||
"doc/examples/osmo-gbproxy/osmo-gbproxy.cfg"]
|
|
||||||
|
|
||||||
def vty_app(self):
|
|
||||||
return (4246, "./src/gbproxy/osmo-gbproxy", "OsmoGbProxy", "gbproxy")
|
|
||||||
|
|
||||||
def testVtyTree(self):
|
|
||||||
self.vty.enable()
|
|
||||||
self.assertTrue(self.vty.verify('configure terminal', ['']))
|
|
||||||
self.assertEqual(self.vty.node(), 'config')
|
|
||||||
self.checkForEndAndExit()
|
|
||||||
self.assertTrue(self.vty.verify('ns', ['']))
|
|
||||||
self.assertEqual(self.vty.node(), 'config-ns')
|
|
||||||
self.checkForEndAndExit()
|
|
||||||
self.assertTrue(self.vty.verify('exit', ['']))
|
|
||||||
self.assertEqual(self.vty.node(), 'config')
|
|
||||||
self.assertTrue(self.vty.verify('gbproxy', ['']))
|
|
||||||
self.assertEqual(self.vty.node(), 'config-gbproxy')
|
|
||||||
self.checkForEndAndExit()
|
|
||||||
self.assertTrue(self.vty.verify('exit', ['']))
|
|
||||||
self.assertEqual(self.vty.node(), 'config')
|
|
||||||
|
|
||||||
def testVtyShow(self):
|
|
||||||
res = self.vty.command("show ns")
|
|
||||||
self.assertTrue(res.find('Encapsulation NS-UDP-IP') >= 0)
|
|
||||||
|
|
||||||
res = self.vty.command("show gbproxy stats")
|
|
||||||
self.assertTrue(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.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
|
|
||||||
self.assertTrue(res.find('Not Deleted 0 NS-VC') >= 0)
|
|
||||||
res = self.vty.command("delete-gbproxy-peer 9999 only-bvc dry-run")
|
|
||||||
self.assertTrue(res.find('Not Deleted 0 BVC') >= 0)
|
|
||||||
self.assertTrue(res.find('Not Deleted 0 NS-VC') < 0)
|
|
||||||
res = self.vty.command("delete-gbproxy-peer 9999 only-nsvc dry-run")
|
|
||||||
self.assertTrue(res.find('Not Deleted 0 BVC') < 0)
|
|
||||||
self.assertTrue(res.find('Not Deleted 0 NS-VC') >= 0)
|
|
||||||
res = self.vty.command("delete-gbproxy-peer 9999 all")
|
|
||||||
self.assertTrue(res.find('Deleted 0 BVC') >= 0)
|
|
||||||
self.assertTrue(res.find('Deleted 0 NS-VC') >= 0)
|
|
||||||
|
|
||||||
class TestVTYSGSN(TestVTYBase):
|
class TestVTYSGSN(TestVTYBase):
|
||||||
|
|
||||||
def vty_command(self):
|
def vty_command(self):
|
||||||
@@ -143,7 +94,7 @@ class TestVTYSGSN(TestVTYBase):
|
|||||||
|
|
||||||
def testVtyShow(self):
|
def testVtyShow(self):
|
||||||
res = self.vty.command("show ns")
|
res = self.vty.command("show ns")
|
||||||
self.assertTrue(res.find('Encapsulation NS-UDP-IP') >= 0)
|
self.assertTrue(res.find('0 NS-VC:') >= 0)
|
||||||
self.assertTrue(self.vty.verify('show bssgp', ['']))
|
self.assertTrue(self.vty.verify('show bssgp', ['']))
|
||||||
self.assertTrue(self.vty.verify('show bssgp stats', ['']))
|
self.assertTrue(self.vty.verify('show bssgp stats', ['']))
|
||||||
self.assertTrue(self.vty.verify('show bssgp nsei 123', ['']))
|
self.assertTrue(self.vty.verify('show bssgp nsei 123', ['']))
|
||||||
@@ -276,13 +227,6 @@ class TestVTYSGSN(TestVTYBase):
|
|||||||
for t in [3312, 3322, 3350, 3360, 3370, 3313, 3314, 3316, 3385, 3395, 3397]:
|
for t in [3312, 3322, 3350, 3360, 3370, 3313, 3314, 3316, 3385, 3395, 3397]:
|
||||||
self.assertTrue(self.vty.verify('timer t%d 10' % t, ['']))
|
self.assertTrue(self.vty.verify('timer t%d 10' % t, ['']))
|
||||||
|
|
||||||
def add_gbproxy_test(suite, workdir):
|
|
||||||
if not os.path.isfile(os.path.join(workdir, "src/gbproxy/osmo-gbproxy")):
|
|
||||||
print("Skipping the Gb-Proxy test")
|
|
||||||
return
|
|
||||||
test = unittest.TestLoader().loadTestsFromTestCase(TestVTYGbproxy)
|
|
||||||
suite.addTest(test)
|
|
||||||
|
|
||||||
def add_sgsn_test(suite, workdir):
|
def add_sgsn_test(suite, workdir):
|
||||||
if not os.path.isfile(os.path.join(workdir, "src/sgsn/osmo-sgsn")):
|
if not os.path.isfile(os.path.join(workdir, "src/sgsn/osmo-sgsn")):
|
||||||
print("Skipping the SGSN test")
|
print("Skipping the SGSN test")
|
||||||
@@ -320,7 +264,6 @@ if __name__ == '__main__':
|
|||||||
os.chdir(workdir)
|
os.chdir(workdir)
|
||||||
print("Running tests for specific VTY commands")
|
print("Running tests for specific VTY commands")
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
add_gbproxy_test(suite, workdir)
|
|
||||||
add_sgsn_test(suite, workdir)
|
add_sgsn_test(suite, workdir)
|
||||||
|
|
||||||
if args.test_name:
|
if args.test_name:
|
||||||
|
|||||||
Reference in New Issue
Block a user