mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
				synced 2025-11-03 21:53:30 +00:00 
			
		
		
		
	Compare commits
	
		
			54 Commits
		
	
	
		
			neels/db_t
			...
			0.2.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cb360f06c8 | ||
| 
						 | 
					1cb489231a | ||
| 
						 | 
					93c5b10310 | ||
| 
						 | 
					ec9440f1bc | ||
| 
						 | 
					51530311a8 | ||
| 
						 | 
					f162252a08 | ||
| 
						 | 
					8f8401453c | ||
| 
						 | 
					70e7f21cb1 | ||
| 
						 | 
					2e78858756 | ||
| 
						 | 
					3f2a9a2ab1 | ||
| 
						 | 
					880a34d2ef | ||
| 
						 | 
					7ee6e554af | ||
| 
						 | 
					9214c6c7ef | ||
| 
						 | 
					79fc6984ac | ||
| 
						 | 
					ba1605afdc | ||
| 
						 | 
					b6265d1a55 | ||
| 
						 | 
					6c84da5942 | ||
| 
						 | 
					84c2f43d00 | ||
| 
						 | 
					63f68ccc4c | ||
| 
						 | 
					b5d77012d1 | ||
| 
						 | 
					fc96f688d4 | ||
| 
						 | 
					43bd6069e8 | ||
| 
						 | 
					2dee60ef44 | ||
| 
						 | 
					ab4d509a83 | ||
| 
						 | 
					bd1dca0859 | ||
| 
						 | 
					33eeeef9dc | ||
| 
						 | 
					33cbde9ced | ||
| 
						 | 
					671db90ac3 | ||
| 
						 | 
					d3814b936b | ||
| 
						 | 
					6f3e8d6297 | ||
| 
						 | 
					db5dae6c99 | ||
| 
						 | 
					38f08770a3 | ||
| 
						 | 
					aee7be901b | ||
| 
						 | 
					8db490695d | ||
| 
						 | 
					c82e6ad190 | ||
| 
						 | 
					0959e8b354 | ||
| 
						 | 
					4f3841c153 | ||
| 
						 | 
					bd0d5bf5d8 | ||
| 
						 | 
					87a04b6b95 | ||
| 
						 | 
					85e8a64bb4 | ||
| 
						 | 
					0dcbd47a1e | ||
| 
						 | 
					71b5f5b923 | ||
| 
						 | 
					73d14af278 | ||
| 
						 | 
					6eb231eccc | ||
| 
						 | 
					dbced93b5f | ||
| 
						 | 
					88c91f6fb2 | ||
| 
						 | 
					7750d2cedc | ||
| 
						 | 
					cd7fa4502c | ||
| 
						 | 
					99a14c8ca1 | ||
| 
						 | 
					c6a6d26f50 | ||
| 
						 | 
					3f697cdc71 | ||
| 
						 | 
					446eb0f1bc | ||
| 
						 | 
					234f9cb701 | ||
| 
						 | 
					16140f70c5 | 
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -22,10 +22,15 @@ m4
 | 
			
		||||
missing
 | 
			
		||||
.deps
 | 
			
		||||
 | 
			
		||||
src/osmo-hlr
 | 
			
		||||
src/db_test
 | 
			
		||||
src/db_bootstrap.h
 | 
			
		||||
src/osmo-hlr
 | 
			
		||||
src/osmo-hlr-db-tool
 | 
			
		||||
 | 
			
		||||
tests/atconfig
 | 
			
		||||
tests/testsuite
 | 
			
		||||
tests/auc/auc_3g_test
 | 
			
		||||
tests/auc/auc_ts_55_205_test_sets.c
 | 
			
		||||
tests/auc/auc_ts_55_205_test_sets
 | 
			
		||||
tests/auc/auc_test
 | 
			
		||||
tests/gsup_server/gsup_server_test
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
AUTOMAKE_OPTIONS = foreign dist-bzip2
 | 
			
		||||
 | 
			
		||||
SUBDIRS = \
 | 
			
		||||
	doc \
 | 
			
		||||
	src \
 | 
			
		||||
	sql \
 | 
			
		||||
	tests \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								configure.ac
									
									
									
									
									
								
							@@ -34,11 +34,11 @@ PKG_PROG_PKG_CONFIG([0.20])
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.9.5)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.9.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.9.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.3.2)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 0.11.0)
 | 
			
		||||
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.5.0)
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES(SQLITE3, sqlite3)
 | 
			
		||||
 | 
			
		||||
@@ -47,6 +47,36 @@ AC_CONFIG_MACRO_DIR([m4])
 | 
			
		||||
dnl checks for header files
 | 
			
		||||
AC_HEADER_STDC
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(sanitize,
 | 
			
		||||
	[AS_HELP_STRING(
 | 
			
		||||
		[--enable-sanitize],
 | 
			
		||||
		[Compile with address sanitizer enabled],
 | 
			
		||||
	)],
 | 
			
		||||
	[sanitize=$enableval], [sanitize="no"])
 | 
			
		||||
if test x"$sanitize" = x"yes"
 | 
			
		||||
then
 | 
			
		||||
	CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
 | 
			
		||||
	CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE(werror,
 | 
			
		||||
	[AS_HELP_STRING(
 | 
			
		||||
		[--enable-werror],
 | 
			
		||||
		[Turn all compiler warnings into errors, with exceptions:
 | 
			
		||||
		 a) deprecation (allow upstream to mark deprecation without breaking builds);
 | 
			
		||||
		 b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
 | 
			
		||||
		]
 | 
			
		||||
	)],
 | 
			
		||||
	[werror=$enableval], [werror="no"])
 | 
			
		||||
if test x"$werror" = x"yes"
 | 
			
		||||
then
 | 
			
		||||
	WERROR_FLAGS="-Werror"
 | 
			
		||||
	WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
 | 
			
		||||
	WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
 | 
			
		||||
	CFLAGS="$CFLAGS $WERROR_FLAGS"
 | 
			
		||||
	CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
AC_ARG_ENABLE([external_tests],
 | 
			
		||||
		AC_HELP_STRING([--enable-external-tests],
 | 
			
		||||
				[Include the VTY/CTRL tests in make check [default=no]]),
 | 
			
		||||
@@ -62,8 +92,12 @@ AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
 | 
			
		||||
AC_MSG_RESULT([$enable_ext_tests])
 | 
			
		||||
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
 | 
			
		||||
 | 
			
		||||
AC_MSG_RESULT([CFLAGS="$CFLAGS"])
 | 
			
		||||
AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
 | 
			
		||||
 | 
			
		||||
AC_OUTPUT(
 | 
			
		||||
	Makefile
 | 
			
		||||
	doc/Makefile
 | 
			
		||||
	src/Makefile
 | 
			
		||||
	sql/Makefile
 | 
			
		||||
	tests/Makefile
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										278
									
								
								contrib/ipa.py
									
									
									
									
									
								
							
							
						
						
									
										278
									
								
								contrib/ipa.py
									
									
									
									
									
								
							@@ -1,278 +0,0 @@
 | 
			
		||||
#!/usr/bin/python3
 | 
			
		||||
# -*- mode: python-mode; py-indent-tabs-mode: nil -*-
 | 
			
		||||
"""
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2016 sysmocom s.f.m.c. GmbH
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License along
 | 
			
		||||
 * with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
 */
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import struct, random, sys
 | 
			
		||||
 | 
			
		||||
class IPA(object):
 | 
			
		||||
    """
 | 
			
		||||
    Stateless IPA protocol multiplexer: add/remove/parse (extended) header
 | 
			
		||||
    """
 | 
			
		||||
    version = "0.0.5"
 | 
			
		||||
    TCP_PORT_OML = 3002
 | 
			
		||||
    TCP_PORT_RSL = 3003
 | 
			
		||||
    # OpenBSC extensions: OSMO, MGCP_OLD
 | 
			
		||||
    PROTO = dict(RSL=0x00, CCM=0xFE, SCCP=0xFD, OML=0xFF, OSMO=0xEE, MGCP_OLD=0xFC)
 | 
			
		||||
    # ...OML Router Control, GSUP GPRS extension, Osmocom Authn Protocol
 | 
			
		||||
    EXT = dict(CTRL=0, MGCP=1, LAC=2, SMSC=3, ORC=4, GSUP=5, OAP=6)
 | 
			
		||||
    # OpenBSC extension: SCCP_OLD
 | 
			
		||||
    MSGT = dict(PING=0x00, PONG=0x01, ID_GET=0x04, ID_RESP=0x05, ID_ACK=0x06, SCCP_OLD=0xFF)
 | 
			
		||||
    _IDTAG = dict(SERNR=0, UNITNAME=1, LOCATION=2, TYPE=3, EQUIPVERS=4, SWVERSION=5, IPADDR=6, MACADDR=7, UNIT=8)
 | 
			
		||||
    CTRL_GET = 'GET'
 | 
			
		||||
    CTRL_SET = 'SET'
 | 
			
		||||
    CTRL_REP = 'REPLY'
 | 
			
		||||
    CTRL_ERR = 'ERR'
 | 
			
		||||
    CTRL_TRAP = 'TRAP'
 | 
			
		||||
 | 
			
		||||
    def _l(self, d, p):
 | 
			
		||||
        """
 | 
			
		||||
        Reverse dictionary lookup: return key for a given value
 | 
			
		||||
        """
 | 
			
		||||
        if p is None:
 | 
			
		||||
            return 'UNKNOWN'
 | 
			
		||||
        return list(d.keys())[list(d.values()).index(p)]
 | 
			
		||||
 | 
			
		||||
    def _tag(self, t, v):
 | 
			
		||||
        """
 | 
			
		||||
        Create TAG as TLV data
 | 
			
		||||
        """
 | 
			
		||||
        return struct.pack(">HB", len(v) + 1, t) + v
 | 
			
		||||
 | 
			
		||||
    def proto(self, p):
 | 
			
		||||
        """
 | 
			
		||||
        Lookup protocol name
 | 
			
		||||
        """
 | 
			
		||||
        return self._l(self.PROTO, p)
 | 
			
		||||
 | 
			
		||||
    def ext(self, p):
 | 
			
		||||
        """
 | 
			
		||||
        Lookup protocol extension name
 | 
			
		||||
        """
 | 
			
		||||
        return self._l(self.EXT, p)
 | 
			
		||||
 | 
			
		||||
    def msgt(self, p):
 | 
			
		||||
        """
 | 
			
		||||
        Lookup message type name
 | 
			
		||||
        """
 | 
			
		||||
        return self._l(self.MSGT, p)
 | 
			
		||||
 | 
			
		||||
    def idtag(self, p):
 | 
			
		||||
        """
 | 
			
		||||
        Lookup ID tag name
 | 
			
		||||
        """
 | 
			
		||||
        return self._l(self._IDTAG, p)
 | 
			
		||||
 | 
			
		||||
    def ext_name(self, proto, exten):
 | 
			
		||||
        """
 | 
			
		||||
        Return proper extension byte name depending on the protocol used
 | 
			
		||||
        """
 | 
			
		||||
        if self.PROTO['CCM'] == proto:
 | 
			
		||||
            return self.msgt(exten)
 | 
			
		||||
        if self.PROTO['OSMO'] == proto:
 | 
			
		||||
            return self.ext(exten)
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
    def add_header(self, data, proto, ext=None):
 | 
			
		||||
        """
 | 
			
		||||
        Add IPA header (with extension if necessary), data must be represented as bytes
 | 
			
		||||
        """
 | 
			
		||||
        if ext is None:
 | 
			
		||||
            return struct.pack(">HB", len(data) + 1, proto) + data
 | 
			
		||||
        return struct.pack(">HBB", len(data) + 1, proto, ext) + data
 | 
			
		||||
 | 
			
		||||
    def del_header(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Strip IPA protocol header correctly removing extension if present
 | 
			
		||||
        Returns data length, IPA protocol, extension (or None if not defined for a give protocol) and the data without header
 | 
			
		||||
        """
 | 
			
		||||
        if not len(data):
 | 
			
		||||
            return None, None, None, None
 | 
			
		||||
        (dlen, proto) = struct.unpack('>HB', data[:3])
 | 
			
		||||
        if self.PROTO['OSMO'] == proto or self.PROTO['CCM'] == proto: # there's extension which we have to unpack
 | 
			
		||||
            return struct.unpack('>HBB', data[:4]) + (data[4:], ) # length, protocol, extension, data
 | 
			
		||||
        return dlen, proto, None, data[3:] # length, protocol, _, data
 | 
			
		||||
 | 
			
		||||
    def split_combined(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Split the data which contains multiple concatenated IPA messages into tuple (first, rest) where rest contains remaining messages, first is the single IPA message
 | 
			
		||||
        """
 | 
			
		||||
        (length, _, _, _) = self.del_header(data)
 | 
			
		||||
        return data[:(length + 3)], data[(length + 3):]
 | 
			
		||||
 | 
			
		||||
    def tag_serial(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for serial number
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['SERNR'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_name(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for unit name
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['UNITNAME'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_loc(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for location
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['LOCATION'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_type(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for unit type
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['TYPE'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_equip(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for equipment version
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['EQUIPVERS'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_sw(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for software version
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['SWVERSION'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_ip(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for IP address
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['IPADDR'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_mac(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for MAC address
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['MACADDR'], data)
 | 
			
		||||
 | 
			
		||||
    def tag_unit(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make TAG for unit ID
 | 
			
		||||
        """
 | 
			
		||||
        return self._tag(self._IDTAG['UNIT'], data)
 | 
			
		||||
 | 
			
		||||
    def identity(self, unit=b'', mac=b'', location=b'', utype=b'', equip=b'', sw=b'', name=b'', serial=b''):
 | 
			
		||||
        """
 | 
			
		||||
        Make IPA IDENTITY tag list, by default returns empty concatenated bytes of tag list
 | 
			
		||||
        """
 | 
			
		||||
        return self.tag_unit(unit) + self.tag_mac(mac) + self.tag_loc(location) + self.tag_type(utype) + self.tag_equip(equip) + self.tag_sw(sw) + self.tag_name(name) + self.tag_serial(serial)
 | 
			
		||||
 | 
			
		||||
    def ping(self):
 | 
			
		||||
        """
 | 
			
		||||
        Make PING message
 | 
			
		||||
        """
 | 
			
		||||
        return self.add_header(b'', self.PROTO['CCM'], self.MSGT['PING'])
 | 
			
		||||
 | 
			
		||||
    def pong(self):
 | 
			
		||||
        """
 | 
			
		||||
        Make PONG message
 | 
			
		||||
        """
 | 
			
		||||
        return self.add_header(b'', self.PROTO['CCM'], self.MSGT['PONG'])
 | 
			
		||||
 | 
			
		||||
    def id_ack(self):
 | 
			
		||||
        """
 | 
			
		||||
        Make ID_ACK CCM message
 | 
			
		||||
        """
 | 
			
		||||
        return self.add_header(b'', self.PROTO['CCM'], self.MSGT['ID_ACK'])
 | 
			
		||||
 | 
			
		||||
    def id_get(self):
 | 
			
		||||
        """
 | 
			
		||||
        Make ID_GET CCM message
 | 
			
		||||
        """
 | 
			
		||||
        return self.add_header(self.identity(), self.PROTO['CCM'], self.MSGT['ID_GET'])
 | 
			
		||||
 | 
			
		||||
    def id_resp(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Make ID_RESP CCM message
 | 
			
		||||
        """
 | 
			
		||||
        return self.add_header(data, self.PROTO['CCM'], self.MSGT['ID_RESP'])
 | 
			
		||||
 | 
			
		||||
class Ctrl(IPA):
 | 
			
		||||
    """
 | 
			
		||||
    Osmocom CTRL protocol implemented on top of IPA multiplexer
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        random.seed()
 | 
			
		||||
 | 
			
		||||
    def add_header(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Add CTRL header
 | 
			
		||||
        """
 | 
			
		||||
        return super(Ctrl, self).add_header(data.encode('utf-8'), IPA.PROTO['OSMO'], IPA.EXT['CTRL'])
 | 
			
		||||
 | 
			
		||||
    def rem_header(self, data):
 | 
			
		||||
        """
 | 
			
		||||
        Remove CTRL header, check for appropriate protocol and extension
 | 
			
		||||
        """
 | 
			
		||||
        (_, proto, ext, d) = super(Ctrl, self).del_header(data)
 | 
			
		||||
        if self.PROTO['OSMO'] != proto or self.EXT['CTRL'] != ext:
 | 
			
		||||
            return None
 | 
			
		||||
        return d
 | 
			
		||||
 | 
			
		||||
    def parse(self, data, op=None):
 | 
			
		||||
        """
 | 
			
		||||
        Parse Ctrl string returning (var, value) pair
 | 
			
		||||
        var could be None in case of ERROR message
 | 
			
		||||
        value could be None in case of GET message
 | 
			
		||||
        """
 | 
			
		||||
        (s, i, v) = data.split(' ', 2)
 | 
			
		||||
        if s == self.CTRL_ERR:
 | 
			
		||||
            return None, v
 | 
			
		||||
        if s == self.CTRL_GET:
 | 
			
		||||
            return v, None
 | 
			
		||||
        (s, i, var, val) = data.split(' ', 3)
 | 
			
		||||
        if s == self.CTRL_TRAP and i != '0':
 | 
			
		||||
            return None, '%s with non-zero id %s' % (s, i)
 | 
			
		||||
        if op is not None and i != op:
 | 
			
		||||
            if s == self.CTRL_GET + '_' + self.CTRL_REP or s == self.CTRL_SET + '_' + self.CTRL_REP:
 | 
			
		||||
                return None, '%s with unexpected id %s' % (s, i)
 | 
			
		||||
        return var, val
 | 
			
		||||
 | 
			
		||||
    def trap(self, var, val):
 | 
			
		||||
        """
 | 
			
		||||
        Make TRAP message with given (vak, val) pair
 | 
			
		||||
        """
 | 
			
		||||
        return self.add_header("%s 0 %s %s" % (self.CTRL_TRAP, var, val))
 | 
			
		||||
 | 
			
		||||
    def cmd(self, var, val=None):
 | 
			
		||||
        """
 | 
			
		||||
        Make SET/GET command message: returns (r, m) tuple where r is random operation id and m is assembled message
 | 
			
		||||
        """
 | 
			
		||||
        r = random.randint(1, sys.maxsize)
 | 
			
		||||
        if val is not None:
 | 
			
		||||
            return r, self.add_header("%s %s %s %s" % (self.CTRL_SET, r, var, val))
 | 
			
		||||
        return r, self.add_header("%s %s %s" % (self.CTRL_GET, r, var))
 | 
			
		||||
 | 
			
		||||
    def verify(self, reply, r, var, val=None):
 | 
			
		||||
        """
 | 
			
		||||
        Verify reply to SET/GET command: returns (b, v) tuple where v is True/False verification result and v is the variable value
 | 
			
		||||
        """
 | 
			
		||||
        (k, v) = self.parse(reply)
 | 
			
		||||
        if k != var or (val is not None and v != val):
 | 
			
		||||
            return False, v
 | 
			
		||||
        return True, v
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    print("IPA multiplexer v%s loaded." % IPA.version)
 | 
			
		||||
@@ -14,8 +14,9 @@ deps="$base/deps"
 | 
			
		||||
inst="$deps/install"
 | 
			
		||||
export deps inst
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
 | 
			
		||||
mkdir "$deps" || true
 | 
			
		||||
rm -rf "$inst"
 | 
			
		||||
 | 
			
		||||
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
 | 
			
		||||
 | 
			
		||||
@@ -35,9 +36,9 @@ set -x
 | 
			
		||||
 | 
			
		||||
cd "$base"
 | 
			
		||||
autoreconf --install --force
 | 
			
		||||
./configure --enable-external-tests
 | 
			
		||||
./configure --enable-sanitize --enable-external-tests --enable-werror
 | 
			
		||||
$MAKE $PARALLEL_MAKE
 | 
			
		||||
if [ "x$label" != "xFreeBSD_amd64" ]; then
 | 
			
		||||
    $MAKE check || cat-testlogs.sh
 | 
			
		||||
    $MAKE distcheck || cat-testlogs.sh
 | 
			
		||||
fi
 | 
			
		||||
$MAKE check || cat-testlogs.sh
 | 
			
		||||
$MAKE distcheck || cat-testlogs.sh
 | 
			
		||||
 | 
			
		||||
osmo-clean-workspace.sh
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										193
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										193
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,196 @@
 | 
			
		||||
osmo-hlr (0.2.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
  * vty: skip installing cmds now always installed by default
 | 
			
		||||
  * hlr_db_tool: fix error log strerror invocation
 | 
			
		||||
  * cosmetic: add comment on ignored return value
 | 
			
		||||
  * db-tool: add command 'create'
 | 
			
		||||
  * db-tool: cosmetic: tweak printf output
 | 
			
		||||
  * db-tool: error-exit on too many arguments
 | 
			
		||||
  * add --enable-sanitize config option
 | 
			
		||||
  * db_test: don't verify SQLite issued error messages, they might change
 | 
			
		||||
  * cosmetic: rx_send_auth_info(): decide error cause with switch()
 | 
			
		||||
  * return GMM_CAUSE_IMSI_UNKNOWN if there is no auth data
 | 
			
		||||
  * db_get_auth_data / db_get_auc: clarify return values
 | 
			
		||||
  * osmo-hlr: log details for unknown IMSI / no auth data / db error
 | 
			
		||||
  * db_test: also test db_get_auc() return values
 | 
			
		||||
  * fix test_subscriber_errors.ctrl after libosmocore change
 | 
			
		||||
  * fix debug log: put 'deriving 2G from 3G' in proper place
 | 
			
		||||
  * ctrl test: fix: adjust expectations after stricter ctrl parsing
 | 
			
		||||
  * fix build: db_test: missing LIBOSMOABIS_CFLAGS and _LIBS
 | 
			
		||||
  * configure: add --enable-werror
 | 
			
		||||
  * jenkins.sh: use --enable-werror configure flag, not CFLAGS
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * hlr.c: Avoid overflow of lu_operation.subscr.imsi
 | 
			
		||||
  * Fix expected test output after new 'logging print file 1' vty command
 | 
			
		||||
  * osmo-hlr: Add talloc context introspection via VTY
 | 
			
		||||
  * vty: Don't print error if removing auth data while none present
 | 
			
		||||
  * Fix responses to PURGE MS
 | 
			
		||||
 | 
			
		||||
  [ Alexander Couzens ]
 | 
			
		||||
  * debian: include systemd service osmo-hlr.service
 | 
			
		||||
  * doc: install example .cfg files to $(docdir)/examples/
 | 
			
		||||
  * debian: install osmo-hlr.cfg to /etc/osmocom
 | 
			
		||||
 | 
			
		||||
  [ Max ]
 | 
			
		||||
  * Remove unused check
 | 
			
		||||
  * Remove unused ipa.py
 | 
			
		||||
  * Enable sanitize for CI tests
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * luop.c: Transform FIXME from warning to pragma message
 | 
			
		||||
  * contrib:jenkins.sh: Enable Werror
 | 
			
		||||
  * use osmo_init_logging2
 | 
			
		||||
  * Remove unused src/db_test.c
 | 
			
		||||
 | 
			
		||||
  [ Alexander Huemer ]
 | 
			
		||||
  * Add missing build products in .gitignore
 | 
			
		||||
 | 
			
		||||
  [ Stefan Sperling ]
 | 
			
		||||
  * more robust usage of osmo_timer API for osmo-hlr luop timer
 | 
			
		||||
  * notify GSUP clients when HLR subscriber information changes
 | 
			
		||||
  * rewrite subscriber_update_notify() without calls into luop
 | 
			
		||||
  * don't forget to mark luop as a packet switched connection
 | 
			
		||||
 | 
			
		||||
 -- Pau Espin Pedrol <pespin@sysmocom.de>  Thu, 03 May 2018 16:27:13 +0200
 | 
			
		||||
 | 
			
		||||
osmo-hlr (0.1.0) unstable; urgency=medium
 | 
			
		||||
 | 
			
		||||
  [ Neels Hofmeyr ]
 | 
			
		||||
  * build with autoconf/automake, add jenkins.sh script
 | 
			
		||||
  * fix build on FreeBSD: eliminate implicitly declared functions
 | 
			
		||||
  * fix various compiler warnings
 | 
			
		||||
  * fix DLGSUP logging cat after change in libosmocore
 | 
			
		||||
  * build: recoin db_test as non-installable program
 | 
			
		||||
  * build: actually make sqlite mandatory
 | 
			
		||||
  * bump required libosmocore version to 0.9.5
 | 
			
		||||
  * gsup: send subscriber MSISDN
 | 
			
		||||
  * debug log: log computed vector kinds
 | 
			
		||||
  * log: move a log from info to debug level
 | 
			
		||||
  * hlr.sql: typo in comment
 | 
			
		||||
  * auc.c: typo in comment
 | 
			
		||||
  * main: add and use root talloc ctx
 | 
			
		||||
  * main: add option parsing with db file and default options
 | 
			
		||||
  * main: add VTY and '-c config-file' option
 | 
			
		||||
  * sql: fix 3g_auc's column K data type
 | 
			
		||||
  * cosmetic: sql: indicate VARCHAR size of key columns as 32
 | 
			
		||||
  * sql: auc_3g: set sqn NOT NULL DEFAULT 0
 | 
			
		||||
  * comment: sql: describe auc_2g and auc_3g columns
 | 
			
		||||
  * Add test suite skeleton with empty test (auc_3g_test)
 | 
			
		||||
  * tests: auc_3g_test: implement vector generation test
 | 
			
		||||
  * auth: verify test sets from 3GPP TS 55.205
 | 
			
		||||
  * sql: add unique constraints to IMSI and MSISDN
 | 
			
		||||
  * UMTS AKA resync: fix argument ordering
 | 
			
		||||
  * auc_3g_test: add AUTS resync test
 | 
			
		||||
  * auc_gen_vectors(): ensure sane arguments, test
 | 
			
		||||
  * auc_3g_test: allow to inc fake rand bytes upon rand request
 | 
			
		||||
  * auc_3g_test: add AUTS test with N vectors, to show bug
 | 
			
		||||
  * cosmetic: refactor auc_compute_vectors(), add debug log
 | 
			
		||||
  * auc_compute_vectors(): fix AUTS resync for multiple vectors
 | 
			
		||||
  * cosmetic: auc_3g_test: improve test debugging tools
 | 
			
		||||
  * cosmetic: rename auc_3g_test.c to auc_test.c
 | 
			
		||||
  * fix: properly handle error rc by osmo_gsup_conn_ccm_get()
 | 
			
		||||
  * auc tests: adjust cosmetically to prepare for SQN changes
 | 
			
		||||
  * auc tests: fix after SQN scheme changes from libosmocore
 | 
			
		||||
  * fix debug log: adjust to new SQN increment scheme
 | 
			
		||||
  * UMTS AKA: implement SQN increment according to SEQ and IND
 | 
			
		||||
  * debug log: output ind slot, previous sqn, and sqn db update
 | 
			
		||||
  * jenkins: add value_string termination check
 | 
			
		||||
  * fix db_subscr_ps error handling
 | 
			
		||||
  * add config example (mostly empty)
 | 
			
		||||
  * install hlr.sql in prefix/doc/osmo-hlr/
 | 
			
		||||
  * use OSMO_GSUP_PORT == 4222 instead of hardcoded 2222
 | 
			
		||||
  * add basic CTRL interface tests
 | 
			
		||||
  * add CTRL tests for enable-/disable-/status-ps
 | 
			
		||||
  * cosmetic: prepend DB_STMT_ to enum stmt_idx entries
 | 
			
		||||
  * cosmetic: rename db_subscr_get() to db_subscr_get_by_imsi()
 | 
			
		||||
  * cosmetic: refactor db_bind_imsi() as db_bind_text()
 | 
			
		||||
  * cosmetic: multi-line DB_STMT_AUC_BY_IMSI
 | 
			
		||||
  * cosmetic: log IMSI='<imsi>', log "no such subscriber"
 | 
			
		||||
  * cosmetic: log: "SQLite" with capital L
 | 
			
		||||
  * cosmetic: db_hlr: SL3_TXT: clarify indenting
 | 
			
		||||
  * ctrl_test_runner.py: use proper constant as test db path
 | 
			
		||||
  * gitignore: tests/package.m4
 | 
			
		||||
  * cosmetic: don't log about missing SQLite log cb
 | 
			
		||||
  * add db_bind_int() and db_bind_int64()
 | 
			
		||||
  * add db_subscr_create(), db_subscr_delete(), db_subscr_update_msisdn_by_imsi()
 | 
			
		||||
  * add initial db_test: creating and deleting subscribers
 | 
			
		||||
  * less noise: simplify db_remove_reset()
 | 
			
		||||
  * db: use int64_t as subscriber id
 | 
			
		||||
  * add db_subscr_get_by_msisdn() and db_subscr_get_by_id()
 | 
			
		||||
  * refactor db_subscr_ps() to db_subscr_nam()
 | 
			
		||||
  * refactor db_subscr_lu()
 | 
			
		||||
  * refactor db_subscr_purge
 | 
			
		||||
  * add db_subscr_update_aud_by_id(), complete db_subscr_delete_by_id()
 | 
			
		||||
  * refactor db_get_auth_data return val
 | 
			
		||||
  * code undup: use db_remove_reset() in db_auc.c
 | 
			
		||||
  * fix db_update_sqn(): reset stmt in all error cases
 | 
			
		||||
  * code undup: use db_bind_text() in db_get_auth_data()
 | 
			
		||||
  * debian: 'make check' needs sqlite3, add to Build-Depends
 | 
			
		||||
  * fix db_subscr_get_by_*(): clear output data; test in db_test.c
 | 
			
		||||
  * implement subscriber vty interface, tests
 | 
			
		||||
  * add test_nodes.vty
 | 
			
		||||
  * replace ctrl_test_runner.py with transcript test_subscriber.ctrl
 | 
			
		||||
  * add lu_op_free(), use in luop.c
 | 
			
		||||
  * luop: fix mem leak upon error in lu_op_alloc_conn()
 | 
			
		||||
  * fix mem leak in handle_cmd_ps(): free luop
 | 
			
		||||
  * api doc: say that lu_op_tx_del_subscr_data() doesn't free
 | 
			
		||||
  * add hlr_subsrc_nam to put GSUP client notification in proper API
 | 
			
		||||
  * vty: fix output of empty IMSI
 | 
			
		||||
  * db api: fix/add API docs
 | 
			
		||||
  * cosmetic: tweak params of hlr_controlif_setup()
 | 
			
		||||
  * ctrl: completely replace all CTRL commands
 | 
			
		||||
  * test_subscriber.ctrl: test against octal/hex interpretation of id
 | 
			
		||||
  * jenkins: use osmo-clean-workspace.sh before and after build
 | 
			
		||||
  * tests/Makefile: use test db var instead of repeating the path
 | 
			
		||||
  * db_test: fix *FLAGS
 | 
			
		||||
  * automatically create db tables on osmo-hlr invocation
 | 
			
		||||
  * cosmetic: sql/hlr.sql: move comments
 | 
			
		||||
  * cosmetic: rename SL3_TXT macro, use osmo_strlcpy()
 | 
			
		||||
  * fix default logging levels to NOTICE, not DEBUG
 | 
			
		||||
  * add osmo-hlr-db-tool, program to migrate from osmo-nitb db
 | 
			
		||||
 | 
			
		||||
  [ Max ]
 | 
			
		||||
  * Add gerrit settings
 | 
			
		||||
  * Add hardcoded APN
 | 
			
		||||
  * Log error cause as a string
 | 
			
		||||
  * Move GSUP msg init into separate function
 | 
			
		||||
  * Use strings for GSUP message type
 | 
			
		||||
  * Move lu_operation into separate file
 | 
			
		||||
  * db: move duplicated code into helper functions
 | 
			
		||||
  * Fix compiler's warning about printf security
 | 
			
		||||
  * Add routines to update nam_ps
 | 
			
		||||
  * Add global HLR struct
 | 
			
		||||
  * Make subscr parameter to db_subscr_get() optional
 | 
			
		||||
  * Add CTRL interface
 | 
			
		||||
  * CTRL: add enable/disable packet service cmds
 | 
			
		||||
  * Add .deb packaging
 | 
			
		||||
  * deb: fix OBS build
 | 
			
		||||
  * debian: remove obsolete dependency
 | 
			
		||||
  * Attempt to fix .deb package
 | 
			
		||||
  * deb: use python in shebang
 | 
			
		||||
  * Another attempt at fixing .deb
 | 
			
		||||
  * Use release helper from libosmocore
 | 
			
		||||
  * Use value string check from osmo-ci
 | 
			
		||||
 | 
			
		||||
  [ Daniel Willmann ]
 | 
			
		||||
  * Add systemd service file
 | 
			
		||||
  * hlr_data.sql: Insert ki and opc instead of op to example data
 | 
			
		||||
  * tests/auc: Don't require python3
 | 
			
		||||
 | 
			
		||||
  [ Pau Espin Pedrol ]
 | 
			
		||||
  * VTY: Add hlr node and bind ip field
 | 
			
		||||
  * debian: remove unneeded dependency libdbd-sqlite3
 | 
			
		||||
 | 
			
		||||
  [ Harald Welte ]
 | 
			
		||||
  * jenkins.sh: Proper error message if local environment isn't set up
 | 
			
		||||
 | 
			
		||||
  [ Alexander Couzens ]
 | 
			
		||||
  * debian/rules: show testsuite.log when tests are failing
 | 
			
		||||
 | 
			
		||||
 -- Harald Welte <laforge@gnumonks.org>  Sat, 28 Oct 2017 20:37:33 +0200
 | 
			
		||||
 | 
			
		||||
osmo-hlr (0.0.1) UNRELEASED; urgency=low
 | 
			
		||||
 | 
			
		||||
     * Initial release (Closes: OS#1948)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								debian/osmo-hlr.install
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								debian/osmo-hlr.install
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,5 @@
 | 
			
		||||
/usr/bin/osmo-hlr
 | 
			
		||||
/usr/bin/osmo-hlr-db-tool
 | 
			
		||||
/usr/share/doc/osmo-hlr/hlr.sql
 | 
			
		||||
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg
 | 
			
		||||
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg /etc/osmocom/
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								debian/osmo-hlr.service
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								debian/osmo-hlr.service
									
									
									
									
										vendored
									
									
										Symbolic link
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
../contrib/systemd/osmo-hlr.service
 | 
			
		||||
							
								
								
									
										22
									
								
								doc/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								doc/Makefile.am
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
CFG_FILES = find $(srcdir) -name '*.cfg*' | sed -e 's,^$(srcdir),,'
 | 
			
		||||
 | 
			
		||||
dist-hook:
 | 
			
		||||
	for f in $$($(CFG_FILES)); do \
 | 
			
		||||
		j="$(distdir)/$$f" && \
 | 
			
		||||
		mkdir -p "$$(dirname $$j)" && \
 | 
			
		||||
		$(INSTALL_DATA) $(srcdir)/$$f $$j; \
 | 
			
		||||
	done
 | 
			
		||||
 | 
			
		||||
install-data-hook:
 | 
			
		||||
	for f in $$($(CFG_FILES)); do \
 | 
			
		||||
		j="$(DESTDIR)$(docdir)/$$f" && \
 | 
			
		||||
		mkdir -p "$$(dirname $$j)" && \
 | 
			
		||||
		$(INSTALL_DATA) $(srcdir)/$$f $$j; \
 | 
			
		||||
	done
 | 
			
		||||
 | 
			
		||||
uninstall-hook:
 | 
			
		||||
	@$(PRE_UNINSTALL)
 | 
			
		||||
	for f in $$($(CFG_FILES)); do \
 | 
			
		||||
		j="$(DESTDIR)$(docdir)/$$f" && \
 | 
			
		||||
		$(RM) $$j; \
 | 
			
		||||
	done
 | 
			
		||||
							
								
								
									
										14
									
								
								sql/hlr.sql
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								sql/hlr.sql
									
									
									
									
									
								
							@@ -1,6 +1,5 @@
 | 
			
		||||
--modelled roughly after TS 23.008 version 13.3.0
 | 
			
		||||
 | 
			
		||||
CREATE TABLE subscriber (
 | 
			
		||||
CREATE TABLE IF NOT EXISTS subscriber (
 | 
			
		||||
-- OsmoHLR's DB scheme is modelled roughly after TS 23.008 version 13.3.0
 | 
			
		||||
	id		INTEGER PRIMARY KEY,
 | 
			
		||||
	-- Chapter 2.1.1.1
 | 
			
		||||
	imsi		VARCHAR(15) UNIQUE NOT NULL,
 | 
			
		||||
@@ -40,24 +39,24 @@ CREATE TABLE subscriber (
 | 
			
		||||
	ms_purged_ps	BOOLEAN NOT NULL DEFAULT 0
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE subscriber_apn (
 | 
			
		||||
CREATE TABLE IF NOT EXISTS subscriber_apn (
 | 
			
		||||
	subscriber_id	INTEGER,		-- subscriber.id
 | 
			
		||||
	apn		VARCHAR(256) NOT NULL
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS subscriber_multi_msisdn (
 | 
			
		||||
-- Chapter 2.1.3
 | 
			
		||||
CREATE TABLE subscriber_multi_msisdn (
 | 
			
		||||
	subscriber_id	INTEGER,		-- subscriber.id
 | 
			
		||||
	msisdn		VARCHAR(15) NOT NULL
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE auc_2g (
 | 
			
		||||
CREATE TABLE IF NOT EXISTS auc_2g (
 | 
			
		||||
	subscriber_id	INTEGER PRIMARY KEY,	-- subscriber.id
 | 
			
		||||
	algo_id_2g	INTEGER NOT NULL,	-- enum osmo_auth_algo value
 | 
			
		||||
	ki		VARCHAR(32) NOT NULL	-- hex string: subscriber's secret key (128bit)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE auc_3g (
 | 
			
		||||
CREATE TABLE IF NOT EXISTS auc_3g (
 | 
			
		||||
	subscriber_id	INTEGER PRIMARY KEY,	-- subscriber.id
 | 
			
		||||
	algo_id_3g	INTEGER NOT NULL,	-- enum osmo_auth_algo value
 | 
			
		||||
	k		VARCHAR(32) NOT NULL,	-- hex string: subscriber's secret key (128bit)
 | 
			
		||||
@@ -68,4 +67,3 @@ CREATE TABLE auc_3g (
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_subscr_imsi ON subscriber (imsi);
 | 
			
		||||
-- SELECT algo_id_2g, ki, algo_id_3g, k, op, opc, sqn FROM subscriber LEFT JOIN auc_2g ON auc_2g.subscriber_id = subscriber.id LEFT JOIN auc_3g ON auc_3g.subscriber_id = subscriber.id WHERE imsi = ?
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,14 @@ AM_CFLAGS = \
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = \
 | 
			
		||||
	populate_hlr_db.pl \
 | 
			
		||||
	db_bootstrap.sed \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
BUILT_SOURCES = \
 | 
			
		||||
	db_bootstrap.h \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
CLEANFILES = $(BUILT_SOURCES)
 | 
			
		||||
 | 
			
		||||
noinst_HEADERS = \
 | 
			
		||||
	auc.h \
 | 
			
		||||
	db.h \
 | 
			
		||||
@@ -24,14 +30,12 @@ noinst_HEADERS = \
 | 
			
		||||
	ctrl.h \
 | 
			
		||||
	hlr_vty.h \
 | 
			
		||||
	hlr_vty_subscr.h \
 | 
			
		||||
	db_bootstrap.h \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
bin_PROGRAMS = \
 | 
			
		||||
	osmo-hlr \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
noinst_PROGRAMS = \
 | 
			
		||||
	db_test \
 | 
			
		||||
	osmo-hlr-db-tool \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
osmo_hlr_SOURCES = \
 | 
			
		||||
@@ -59,6 +63,21 @@ osmo_hlr_LDADD = \
 | 
			
		||||
	$(SQLITE3_LIBS) \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
osmo_hlr_db_tool_SOURCES = \
 | 
			
		||||
	hlr_db_tool.c \
 | 
			
		||||
	db.c \
 | 
			
		||||
	db_hlr.c \
 | 
			
		||||
	logging.c \
 | 
			
		||||
	rand_urandom.c \
 | 
			
		||||
	dbd_decode_binary.c \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
osmo_hlr_db_tool_LDADD = \
 | 
			
		||||
	$(LIBOSMOCORE_LIBS) \
 | 
			
		||||
	$(LIBOSMOGSM_LIBS) \
 | 
			
		||||
	$(SQLITE3_LIBS) \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
db_test_SOURCES = \
 | 
			
		||||
	auc.c \
 | 
			
		||||
	db.c \
 | 
			
		||||
@@ -73,3 +92,14 @@ db_test_LDADD = \
 | 
			
		||||
	$(LIBOSMOGSM_LIBS) \
 | 
			
		||||
	$(SQLITE3_LIBS) \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
BOOTSTRAP_SQL = $(top_srcdir)/sql/hlr.sql
 | 
			
		||||
 | 
			
		||||
db_bootstrap.h: $(BOOTSTRAP_SQL) $(srcdir)/db_bootstrap.sed
 | 
			
		||||
	echo "/* DO NOT EDIT THIS FILE. It is generated from osmo-hlr.git/sql/hlr.sql */" > "$@"
 | 
			
		||||
	echo "#pragma once" >> "$@"
 | 
			
		||||
	echo "static const char *stmt_bootstrap_sql[] = {" >> "$@"
 | 
			
		||||
	cat "$(BOOTSTRAP_SQL)" \
 | 
			
		||||
		| sed -f "$(srcdir)/db_bootstrap.sed" \
 | 
			
		||||
		>> "$@"
 | 
			
		||||
	echo "};" >> "$@"
 | 
			
		||||
 
 | 
			
		||||
@@ -144,6 +144,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
 | 
			
		||||
 | 
			
		||||
			if (!aud2g) {
 | 
			
		||||
				/* use the 2G tokens from 3G keys */
 | 
			
		||||
				DBGP("vector [%u]: deriving 2G from 3G\n", i);
 | 
			
		||||
				DBGVB(kc);
 | 
			
		||||
				DBGVB(sres);
 | 
			
		||||
				DBGVV("0x%x", auth_types);
 | 
			
		||||
@@ -151,7 +152,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
 | 
			
		||||
			}
 | 
			
		||||
			/* calculate 2G separately */
 | 
			
		||||
 | 
			
		||||
			DBGP("vector [%u]: deriving 2G from 3G\n", i);
 | 
			
		||||
			DBGP("vector [%u]: calculating 2G separately\n", i);
 | 
			
		||||
 | 
			
		||||
			rc = osmo_auth_gen_vec(&vtmp, aud2g, rand);
 | 
			
		||||
			if (rc < 0) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										383
									
								
								src/ctrl.c
									
									
									
									
									
								
							
							
						
						
									
										383
									
								
								src/ctrl.c
									
									
									
									
									
								
							@@ -21,87 +21,382 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/ctrl/control_cmd.h>
 | 
			
		||||
#include <osmocom/ctrl/control_if.h>
 | 
			
		||||
#include <osmocom/gsm/gsm23003.h>
 | 
			
		||||
#include <osmocom/ctrl/ports.h>
 | 
			
		||||
 | 
			
		||||
#include "gsup_server.h"
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
#include "db.h"
 | 
			
		||||
#include "hlr.h"
 | 
			
		||||
#include "luop.h"
 | 
			
		||||
#include "ctrl.h"
 | 
			
		||||
#include "db.h"
 | 
			
		||||
 | 
			
		||||
static int handle_cmd_ps(struct hlr *ctx, struct ctrl_cmd *cmd, bool enable)
 | 
			
		||||
#define SEL_BY "by-"
 | 
			
		||||
#define SEL_BY_IMSI SEL_BY "imsi-"
 | 
			
		||||
#define SEL_BY_MSISDN SEL_BY "msisdn-"
 | 
			
		||||
#define SEL_BY_ID SEL_BY "id-"
 | 
			
		||||
 | 
			
		||||
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
 | 
			
		||||
 | 
			
		||||
static bool startswith(const char *str, const char *start)
 | 
			
		||||
{
 | 
			
		||||
	return strncmp(str, start, strlen(start)) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _get_subscriber(struct db_context *dbc,
 | 
			
		||||
			   const char *by_selector,
 | 
			
		||||
			   struct hlr_subscriber *subscr)
 | 
			
		||||
{
 | 
			
		||||
	const char *val;
 | 
			
		||||
	if (startswith(by_selector, SEL_BY_IMSI)) {
 | 
			
		||||
		val = by_selector + strlen(SEL_BY_IMSI);
 | 
			
		||||
		if (!osmo_imsi_str_valid(val))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		return db_subscr_get_by_imsi(dbc, val, subscr);
 | 
			
		||||
	}
 | 
			
		||||
	if (startswith(by_selector, SEL_BY_MSISDN)) {
 | 
			
		||||
		val = by_selector + strlen(SEL_BY_MSISDN);
 | 
			
		||||
		if (!osmo_msisdn_str_valid(val))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		return db_subscr_get_by_msisdn(dbc, val, subscr);
 | 
			
		||||
	}
 | 
			
		||||
	if (startswith(by_selector, SEL_BY_ID)) {
 | 
			
		||||
		int64_t id;
 | 
			
		||||
		char *endptr;
 | 
			
		||||
		val = by_selector + strlen(SEL_BY_ID);
 | 
			
		||||
		if (*val == '+')
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		errno = 0;
 | 
			
		||||
		id = strtoll(val, &endptr, 10);
 | 
			
		||||
		if (errno || *endptr)
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		return db_subscr_get_by_id(dbc, id, subscr);
 | 
			
		||||
	}
 | 
			
		||||
	return -ENOTSUP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool get_subscriber(struct db_context *dbc,
 | 
			
		||||
			   const char *by_selector,
 | 
			
		||||
			   struct hlr_subscriber *subscr,
 | 
			
		||||
			   struct ctrl_cmd *cmd)
 | 
			
		||||
{
 | 
			
		||||
	int rc = _get_subscriber(dbc, by_selector, subscr);
 | 
			
		||||
	switch (rc) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return true;
 | 
			
		||||
	case -ENOTSUP:
 | 
			
		||||
		cmd->reply = "Not a known subscriber 'by-xxx-' selector.";
 | 
			
		||||
		return false;
 | 
			
		||||
	case -EINVAL:
 | 
			
		||||
		cmd->reply = "Invalid value part of 'by-xxx-value' selector.";
 | 
			
		||||
		return false;
 | 
			
		||||
	case -ENOENT:
 | 
			
		||||
		cmd->reply = "No such subscriber.";
 | 
			
		||||
		return false;
 | 
			
		||||
	default:
 | 
			
		||||
		cmd->reply = "An unknown error has occured during get_subscriber().";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Optimization: if a subscriber operation is requested by-imsi, just return
 | 
			
		||||
 * the IMSI right back. */
 | 
			
		||||
static const char *get_subscriber_imsi(struct db_context *dbc,
 | 
			
		||||
				       const char *by_selector,
 | 
			
		||||
				       struct ctrl_cmd *cmd)
 | 
			
		||||
{
 | 
			
		||||
	static struct hlr_subscriber subscr;
 | 
			
		||||
 | 
			
		||||
	if (startswith(by_selector, SEL_BY_IMSI))
 | 
			
		||||
		return by_selector + strlen(SEL_BY_IMSI);
 | 
			
		||||
	if (!get_subscriber(dbc, by_selector, &subscr, cmd))
 | 
			
		||||
		return NULL;
 | 
			
		||||
	return subscr.imsi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* printf fmt and arg to completely omit a string if it is empty. */
 | 
			
		||||
#define FMT_S "%s%s%s%s"
 | 
			
		||||
#define ARG_S(name, val) \
 | 
			
		||||
	(val) && *(val) ? "\n" : "", \
 | 
			
		||||
	(val) && *(val) ? name : "", \
 | 
			
		||||
	(val) && *(val) ? "\t" : "", \
 | 
			
		||||
	(val) && *(val) ? (val) : "" \
 | 
			
		||||
 | 
			
		||||
/* printf fmt and arg to completely omit bool of given value. */
 | 
			
		||||
#define FMT_BOOL "%s"
 | 
			
		||||
#define ARG_BOOL(name, val) \
 | 
			
		||||
	val ? "\n" name "\t1" : "\n" name "\t0"
 | 
			
		||||
 | 
			
		||||
static void print_subscr_info(struct ctrl_cmd *cmd,
 | 
			
		||||
			      struct hlr_subscriber *subscr)
 | 
			
		||||
{
 | 
			
		||||
	ctrl_cmd_reply_printf(cmd,
 | 
			
		||||
		"\nid\t%"PRIu64
 | 
			
		||||
		FMT_S
 | 
			
		||||
		FMT_S
 | 
			
		||||
		FMT_BOOL
 | 
			
		||||
		FMT_BOOL
 | 
			
		||||
		FMT_S
 | 
			
		||||
		FMT_S
 | 
			
		||||
		FMT_S
 | 
			
		||||
		FMT_BOOL
 | 
			
		||||
		FMT_BOOL
 | 
			
		||||
		"\nperiodic_lu_timer\t%u"
 | 
			
		||||
		"\nperiodic_rau_tau_timer\t%u"
 | 
			
		||||
		"\nlmsi\t%08x"
 | 
			
		||||
		,
 | 
			
		||||
		subscr->id,
 | 
			
		||||
		ARG_S("imsi", subscr->imsi),
 | 
			
		||||
		ARG_S("msisdn", subscr->msisdn),
 | 
			
		||||
		ARG_BOOL("nam_cs", subscr->nam_cs),
 | 
			
		||||
		ARG_BOOL("nam_ps", subscr->nam_ps),
 | 
			
		||||
		ARG_S("vlr_number", subscr->vlr_number),
 | 
			
		||||
		ARG_S("sgsn_number", subscr->sgsn_number),
 | 
			
		||||
		ARG_S("sgsn_address", subscr->sgsn_address),
 | 
			
		||||
		ARG_BOOL("ms_purged_cs", subscr->ms_purged_cs),
 | 
			
		||||
		ARG_BOOL("ms_purged_ps", subscr->ms_purged_ps),
 | 
			
		||||
		subscr->periodic_lu_timer,
 | 
			
		||||
		subscr->periodic_rau_tau_timer,
 | 
			
		||||
		subscr->lmsi
 | 
			
		||||
		);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
 | 
			
		||||
{
 | 
			
		||||
	if (aud->algo == OSMO_AUTH_ALG_NONE)
 | 
			
		||||
		return;
 | 
			
		||||
	ctrl_cmd_reply_printf(cmd,
 | 
			
		||||
		"\naud2g.algo\t%s"
 | 
			
		||||
		"\naud2g.ki\t%s"
 | 
			
		||||
		,
 | 
			
		||||
		osmo_auth_alg_name(aud->algo),
 | 
			
		||||
		hexdump_buf(aud->u.gsm.ki));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud)
 | 
			
		||||
{
 | 
			
		||||
	if (aud->algo == OSMO_AUTH_ALG_NONE)
 | 
			
		||||
		return;
 | 
			
		||||
	ctrl_cmd_reply_printf(cmd,
 | 
			
		||||
		"\naud3g.algo\t%s"
 | 
			
		||||
		"\naud3g.k\t%s"
 | 
			
		||||
		,
 | 
			
		||||
		osmo_auth_alg_name(aud->algo),
 | 
			
		||||
		hexdump_buf(aud->u.umts.k));
 | 
			
		||||
	/* hexdump uses a static string buffer, hence only one hexdump per
 | 
			
		||||
	 * printf(). */
 | 
			
		||||
	ctrl_cmd_reply_printf(cmd,
 | 
			
		||||
		"\naud3g.%s\t%s"
 | 
			
		||||
		"\naud3g.ind_bitlen\t%u"
 | 
			
		||||
		"\naud3g.sqn\t%"PRIu64
 | 
			
		||||
		,
 | 
			
		||||
		aud->u.umts.opc_is_op? "op" : "opc",
 | 
			
		||||
		hexdump_buf(aud->u.umts.opc),
 | 
			
		||||
		aud->u.umts.ind_bitlen,
 | 
			
		||||
		aud->u.umts.sqn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_RO(subscr_info, "info");
 | 
			
		||||
static int get_subscr_info(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct hlr_subscriber subscr;
 | 
			
		||||
	struct hlr *hlr = data;
 | 
			
		||||
	const char *by_selector = cmd->node;
 | 
			
		||||
 | 
			
		||||
	if (db_subscr_get_by_imsi(ctx->dbc, cmd->value, &subscr) < 0) {
 | 
			
		||||
		cmd->reply = "Subscriber Unknown in HLR";
 | 
			
		||||
	if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
 | 
			
		||||
	print_subscr_info(cmd, &subscr);
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_RO(subscr_info_aud, "info-aud");
 | 
			
		||||
static int get_subscr_info_aud(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	const char *imsi;
 | 
			
		||||
	struct osmo_sub_auth_data aud2g;
 | 
			
		||||
	struct osmo_sub_auth_data aud3g;
 | 
			
		||||
	struct hlr *hlr = data;
 | 
			
		||||
	const char *by_selector = cmd->node;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	imsi = get_subscriber_imsi(hlr->dbc, by_selector, cmd);
 | 
			
		||||
	if (!imsi)
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
 | 
			
		||||
	rc = db_get_auth_data(hlr->dbc, imsi, &aud2g, &aud3g, NULL);
 | 
			
		||||
 | 
			
		||||
	switch (rc) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		break;
 | 
			
		||||
	case -ENOENT:
 | 
			
		||||
	case -ENOKEY:
 | 
			
		||||
		/* No auth data found, tell the print*() functions about it. */
 | 
			
		||||
		aud2g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
		aud3g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		cmd->reply = "Error retrieving authentication data.";
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hlr_subscr_nam(ctx, &subscr, enable, true) < 0) {
 | 
			
		||||
		cmd->reply = "Error updating DB";
 | 
			
		||||
	print_subscr_info_aud2g(cmd, &aud2g);
 | 
			
		||||
	print_subscr_info_aud3g(cmd, &aud3g);
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_RO(subscr_info_all, "info-all");
 | 
			
		||||
static int get_subscr_info_all(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct hlr_subscriber subscr;
 | 
			
		||||
	struct osmo_sub_auth_data aud2g;
 | 
			
		||||
	struct osmo_sub_auth_data aud3g;
 | 
			
		||||
	struct hlr *hlr = data;
 | 
			
		||||
	const char *by_selector = cmd->node;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
 | 
			
		||||
	rc = db_get_auth_data(hlr->dbc, subscr.imsi, &aud2g, &aud3g, NULL);
 | 
			
		||||
 | 
			
		||||
	switch (rc) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		break;
 | 
			
		||||
	case -ENOENT:
 | 
			
		||||
	case -ENOKEY:
 | 
			
		||||
		/* No auth data found, tell the print*() functions about it. */
 | 
			
		||||
		aud2g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
		aud3g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		cmd->reply = "Error retrieving authentication data.";
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	print_subscr_info(cmd, &subscr);
 | 
			
		||||
	print_subscr_info_aud2g(cmd, &aud2g);
 | 
			
		||||
	print_subscr_info_aud3g(cmd, &aud3g);
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int verify_subscr_cs_ps_enabled(struct ctrl_cmd *cmd, const char *value, void *data)
 | 
			
		||||
{
 | 
			
		||||
	if (!value || !*value
 | 
			
		||||
	    || (strcmp(value, "0") && strcmp(value, "1")))
 | 
			
		||||
		return 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int get_subscr_cs_ps_enabled(struct ctrl_cmd *cmd, void *data,
 | 
			
		||||
				    bool is_ps)
 | 
			
		||||
{
 | 
			
		||||
	struct hlr_subscriber subscr;
 | 
			
		||||
	struct hlr *hlr = data;
 | 
			
		||||
	const char *by_selector = cmd->node;
 | 
			
		||||
 | 
			
		||||
	if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
 | 
			
		||||
	cmd->reply = (is_ps ? subscr.nam_ps : subscr.nam_cs)
 | 
			
		||||
		     ? "1" : "0";
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int set_subscr_cs_ps_enabled(struct ctrl_cmd *cmd, void *data,
 | 
			
		||||
				    bool is_ps)
 | 
			
		||||
{
 | 
			
		||||
	const char *imsi;
 | 
			
		||||
	struct hlr *hlr = data;
 | 
			
		||||
	const char *by_selector = cmd->node;
 | 
			
		||||
 | 
			
		||||
	imsi = get_subscriber_imsi(hlr->dbc, by_selector, cmd);
 | 
			
		||||
	if (!imsi)
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
	if (db_subscr_nam(hlr->dbc, imsi, strcmp(cmd->value, "1") == 0, is_ps))
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
	cmd->reply = "OK";
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_WO_NOVRF(enable_ps, "enable-ps");
 | 
			
		||||
static int set_enable_ps(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
CTRL_CMD_DEFINE(subscr_ps_enabled, "ps-enabled");
 | 
			
		||||
static int verify_subscr_ps_enabled(struct ctrl_cmd *cmd, const char *value, void *data)
 | 
			
		||||
{
 | 
			
		||||
	return handle_cmd_ps(data, cmd, true);
 | 
			
		||||
	return verify_subscr_cs_ps_enabled(cmd, value, data);
 | 
			
		||||
}
 | 
			
		||||
static int get_subscr_ps_enabled(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	return get_subscr_cs_ps_enabled(cmd, data, true);
 | 
			
		||||
}
 | 
			
		||||
static int set_subscr_ps_enabled(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	return set_subscr_cs_ps_enabled(cmd, data, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_WO_NOVRF(disable_ps, "disable-ps");
 | 
			
		||||
static int set_disable_ps(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
CTRL_CMD_DEFINE(subscr_cs_enabled, "cs-enabled");
 | 
			
		||||
static int verify_subscr_cs_enabled(struct ctrl_cmd *cmd, const char *value, void *data)
 | 
			
		||||
{
 | 
			
		||||
	return handle_cmd_ps(data, cmd, false);
 | 
			
		||||
	return verify_subscr_cs_ps_enabled(cmd, value, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CTRL_CMD_DEFINE_WO_NOVRF(status_ps, "status-ps");
 | 
			
		||||
static int set_status_ps(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
static int get_subscr_cs_enabled(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct hlr *ctx = data;
 | 
			
		||||
	struct lu_operation *luop = lu_op_alloc(ctx->gs);
 | 
			
		||||
	if (!luop) {
 | 
			
		||||
		cmd->reply = "Internal HLR error";
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!lu_op_fill_subscr(luop, ctx->dbc, cmd->value)) {
 | 
			
		||||
		cmd->reply = "Subscriber Unknown in HLR";
 | 
			
		||||
		return CTRL_CMD_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd->reply = luop->subscr.nam_ps ? "1" : "0";
 | 
			
		||||
 | 
			
		||||
	return CTRL_CMD_REPLY;
 | 
			
		||||
	return get_subscr_cs_ps_enabled(cmd, data, false);
 | 
			
		||||
}
 | 
			
		||||
static int set_subscr_cs_enabled(struct ctrl_cmd *cmd, void *data)
 | 
			
		||||
{
 | 
			
		||||
	return set_subscr_cs_ps_enabled(cmd, data, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int hlr_ctrl_cmds_install()
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_enable_ps);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_disable_ps);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_status_ps);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_aud);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_info_all);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_ps_enabled);
 | 
			
		||||
	rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_cs_enabled);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *ctx,
 | 
			
		||||
					struct osmo_gsup_server *gs)
 | 
			
		||||
static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
 | 
			
		||||
				void **node_data, int *i)
 | 
			
		||||
{
 | 
			
		||||
	const char *token = vector_slot(vline, *i);
 | 
			
		||||
 | 
			
		||||
	switch (*node_type) {
 | 
			
		||||
	case CTRL_NODE_ROOT:
 | 
			
		||||
		if (strcmp(token, "subscriber") != 0)
 | 
			
		||||
			return 0;
 | 
			
		||||
		*node_data = NULL;
 | 
			
		||||
		*node_type = CTRL_NODE_SUBSCR;
 | 
			
		||||
		break;
 | 
			
		||||
	case CTRL_NODE_SUBSCR:
 | 
			
		||||
		if (!startswith(token, "by-"))
 | 
			
		||||
			return 0;
 | 
			
		||||
		*node_data = (void*)token;
 | 
			
		||||
		*node_type = CTRL_NODE_SUBSCR_BY;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct ctrl_handle *hdl = ctrl_interface_setup_dynip(ctx,
 | 
			
		||||
							     ctx->ctrl_bind_addr,
 | 
			
		||||
							     OSMO_CTRL_PORT_HLR,
 | 
			
		||||
							     NULL);
 | 
			
		||||
	struct ctrl_handle *hdl = ctrl_interface_setup_dynip2(hlr,
 | 
			
		||||
							      hlr->ctrl_bind_addr,
 | 
			
		||||
							      OSMO_CTRL_PORT_HLR,
 | 
			
		||||
							      hlr_ctrl_node_lookup,
 | 
			
		||||
							      _LAST_CTRL_NODE_HLR);
 | 
			
		||||
	if (!hdl)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,11 @@
 | 
			
		||||
 | 
			
		||||
#include <osmocom/ctrl/control_if.h>
 | 
			
		||||
 | 
			
		||||
#include "gsup_server.h"
 | 
			
		||||
enum hlr_ctrl_node {
 | 
			
		||||
	CTRL_NODE_SUBSCR = _LAST_CTRL_NODE,
 | 
			
		||||
	CTRL_NODE_SUBSCR_BY,
 | 
			
		||||
	_LAST_CTRL_NODE_HLR
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int hlr_ctrl_cmds_install();
 | 
			
		||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *ctx,
 | 
			
		||||
					struct osmo_gsup_server *gs);
 | 
			
		||||
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								src/db.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								src/db.c
									
									
									
									
									
								
							@@ -25,6 +25,7 @@
 | 
			
		||||
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
#include "db.h"
 | 
			
		||||
#include "db_bootstrap.h"
 | 
			
		||||
 | 
			
		||||
#define SEL_COLUMNS \
 | 
			
		||||
	"id," \
 | 
			
		||||
@@ -98,6 +99,8 @@ static void sql3_sql_log_cb(void *arg, sqlite3 *s3, const char *stmt, int type)
 | 
			
		||||
void db_remove_reset(sqlite3_stmt *stmt)
 | 
			
		||||
{
 | 
			
		||||
	sqlite3_clear_bindings(stmt);
 | 
			
		||||
	/* sqlite3_reset() just repeats an error code already evaluated during sqlite3_step(). */
 | 
			
		||||
	/* coverity[CHECKED_RETURN] */
 | 
			
		||||
	sqlite3_reset(stmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -179,7 +182,36 @@ void db_close(struct db_context *dbc)
 | 
			
		||||
	talloc_free(dbc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct db_context *db_open(void *ctx, const char *fname)
 | 
			
		||||
static int db_bootstrap(struct db_context *dbc)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(stmt_bootstrap_sql); i++) {
 | 
			
		||||
		int rc;
 | 
			
		||||
		sqlite3_stmt *stmt;
 | 
			
		||||
 | 
			
		||||
		rc = sqlite3_prepare_v2(dbc->db, stmt_bootstrap_sql[i], -1,
 | 
			
		||||
					&stmt, NULL);
 | 
			
		||||
		if (rc != SQLITE_OK) {
 | 
			
		||||
			LOGP(DDB, LOGL_ERROR, "Unable to prepare SQL statement '%s'\n",
 | 
			
		||||
			     stmt_bootstrap_sql[i]);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* execute the statement */
 | 
			
		||||
		rc = sqlite3_step(stmt);
 | 
			
		||||
		db_remove_reset(stmt);
 | 
			
		||||
		if (rc != SQLITE_DONE) {
 | 
			
		||||
			LOGP(DDB, LOGL_ERROR, "Cannot bootstrap database: SQL error: (%d) %s,"
 | 
			
		||||
			     " during stmt '%s'",
 | 
			
		||||
			     rc, sqlite3_errmsg(dbc->db),
 | 
			
		||||
			     stmt_bootstrap_sql[i]);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite_logging)
 | 
			
		||||
{
 | 
			
		||||
	struct db_context *dbc = talloc_zero(ctx, struct db_context);
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
@@ -201,9 +233,11 @@ struct db_context *db_open(void *ctx, const char *fname)
 | 
			
		||||
			has_sqlite_config_sqllog = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = sqlite3_config(SQLITE_CONFIG_LOG, sql3_error_log_cb, NULL);
 | 
			
		||||
	if (rc != SQLITE_OK)
 | 
			
		||||
		LOGP(DDB, LOGL_NOTICE, "Unable to set SQLite3 error log callback\n");
 | 
			
		||||
	if (enable_sqlite_logging) {
 | 
			
		||||
		rc = sqlite3_config(SQLITE_CONFIG_LOG, sql3_error_log_cb, NULL);
 | 
			
		||||
		if (rc != SQLITE_OK)
 | 
			
		||||
			LOGP(DDB, LOGL_NOTICE, "Unable to set SQLite3 error log callback\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (has_sqlite_config_sqllog) {
 | 
			
		||||
		rc = sqlite3_config(SQLITE_CONFIG_SQLLOG, sql3_sql_log_cb, NULL);
 | 
			
		||||
@@ -231,6 +265,8 @@ struct db_context *db_open(void *ctx, const char *fname)
 | 
			
		||||
		LOGP(DDB, LOGL_ERROR, "Unable to set Write-Ahead Logging: %s\n",
 | 
			
		||||
			err_msg);
 | 
			
		||||
 | 
			
		||||
	db_bootstrap(dbc);
 | 
			
		||||
 | 
			
		||||
	/* prepare all SQL statements */
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(dbc->stmt); i++) {
 | 
			
		||||
		rc = sqlite3_prepare_v2(dbc->db, stmt_sql[i], -1,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								src/db.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/db.h
									
									
									
									
									
								
							@@ -38,7 +38,7 @@ bool db_bind_text(sqlite3_stmt *stmt, const char *param_name, const char *text);
 | 
			
		||||
bool db_bind_int(sqlite3_stmt *stmt, const char *param_name, int nr);
 | 
			
		||||
bool db_bind_int64(sqlite3_stmt *stmt, const char *param_name, int64_t nr);
 | 
			
		||||
void db_close(struct db_context *dbc);
 | 
			
		||||
struct db_context *db_open(void *ctx, const char *fname);
 | 
			
		||||
struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite3_logging);
 | 
			
		||||
 | 
			
		||||
#include <osmocom/crypt/auth.h>
 | 
			
		||||
 | 
			
		||||
@@ -129,3 +129,14 @@ int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
 | 
			
		||||
		    bool purge_val, bool is_ps);
 | 
			
		||||
 | 
			
		||||
int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps);
 | 
			
		||||
 | 
			
		||||
/*! Call sqlite3_column_text() and copy result to a char[].
 | 
			
		||||
 * \param[out] buf  A char[] used as sizeof() arg(!) and osmo_strlcpy() target.
 | 
			
		||||
 * \param[in] stmt  An sqlite3_stmt*.
 | 
			
		||||
 * \param[in] idx   Index in stmt's returned columns.
 | 
			
		||||
 */
 | 
			
		||||
#define copy_sqlite3_text_to_buf(buf, stmt, idx) \
 | 
			
		||||
	do { \
 | 
			
		||||
		const char *_txt = (const char *) sqlite3_column_text(stmt, idx); \
 | 
			
		||||
		osmo_strlcpy(buf, _txt, sizeof(buf)); \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/db_auc.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/db_auc.c
									
									
									
									
									
								
							@@ -74,7 +74,9 @@ out:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* obtain the authentication data for a given imsi
 | 
			
		||||
 * returns -1 in case of error, 0 for unknown IMSI, 1 for success */
 | 
			
		||||
 * returns 0 for success, negative value on error:
 | 
			
		||||
 * -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data,
 | 
			
		||||
 * -EIO on db failure */
 | 
			
		||||
int db_get_auth_data(struct db_context *dbc, const char *imsi,
 | 
			
		||||
		     struct osmo_sub_auth_data *aud2g,
 | 
			
		||||
		     struct osmo_sub_auth_data *aud3g,
 | 
			
		||||
@@ -163,15 +165,16 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
 | 
			
		||||
		LOGAUC(imsi, LOGL_DEBUG, "No 3G Auth Data\n");
 | 
			
		||||
 | 
			
		||||
	if (aud2g->type == 0 && aud3g->type == 0)
 | 
			
		||||
		ret = -ENOENT;
 | 
			
		||||
		ret = -ENOKEY;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	db_remove_reset(stmt);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* return -1 in case of error, 0 for unknown imsi, positive for number
 | 
			
		||||
 * of vectors generated */
 | 
			
		||||
/* return number of vectors generated, negative value on error:
 | 
			
		||||
 * -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data,
 | 
			
		||||
 * -EIO on db failure */
 | 
			
		||||
int db_get_auc(struct db_context *dbc, const char *imsi,
 | 
			
		||||
	       unsigned int auc_3g_ind, struct osmo_auth_vector *vec,
 | 
			
		||||
	       unsigned int num_vec, const uint8_t *rand_auts,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								src/db_bootstrap.sed
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/db_bootstrap.sed
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
# Input to this is sql/hlr.sql.
 | 
			
		||||
#
 | 
			
		||||
# We want each SQL statement line wrapped in "...\n", and each end (";") to
 | 
			
		||||
# become a comma:
 | 
			
		||||
#
 | 
			
		||||
#   SOME SQL COMMAND (
 | 
			
		||||
#     that may span )
 | 
			
		||||
#   MULTIPLE LINES;
 | 
			
		||||
#   MORE;
 | 
			
		||||
#
 | 
			
		||||
# -->
 | 
			
		||||
#
 | 
			
		||||
#   "SOME SQL COMMAND (\n"
 | 
			
		||||
#   "  that may span )\n"
 | 
			
		||||
#   "MULTIPLE LINES\n",   <--note the comma here
 | 
			
		||||
#   "MORE\n",
 | 
			
		||||
#
 | 
			
		||||
# just replacing ';' with '\n,' won't work, since sed is bad in printing
 | 
			
		||||
# multiple lines. Also, how to input newlines to sed is not portable across
 | 
			
		||||
# platforms.
 | 
			
		||||
 | 
			
		||||
# Match excluding a trailing ';' as \1, keep any trailing ';' in \2
 | 
			
		||||
s/^\(.*[^;]\)\(;\|\)$/"\1\\n"\2/
 | 
			
		||||
# Replace trailing ';' as ','
 | 
			
		||||
s/;$/,/
 | 
			
		||||
							
								
								
									
										107
									
								
								src/db_hlr.c
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								src/db_hlr.c
									
									
									
									
									
								
							@@ -35,14 +35,11 @@
 | 
			
		||||
 | 
			
		||||
#define LOGHLR(imsi, level, fmt, args ...)	LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)
 | 
			
		||||
 | 
			
		||||
#define SL3_TXT(x, stmt, idx) 					\
 | 
			
		||||
	do {							\
 | 
			
		||||
		const char *_txt = (const char *) sqlite3_column_text(stmt, idx);\
 | 
			
		||||
		if (_txt)					\
 | 
			
		||||
			strncpy(x, _txt, sizeof(x));		\
 | 
			
		||||
		x[sizeof(x)-1] = '\0';				\
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
/*! Add new subscriber record to the HLR database.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] imsi  ASCII string of IMSI digits, is validated.
 | 
			
		||||
 * \returns 0 on success, -EINVAL on invalid IMSI, -EIO on database error.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_create(struct db_context *dbc, const char *imsi)
 | 
			
		||||
{
 | 
			
		||||
	sqlite3_stmt *stmt;
 | 
			
		||||
@@ -71,6 +68,15 @@ int db_subscr_create(struct db_context *dbc, const char *imsi)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Completely delete a subscriber record from the HLR database.
 | 
			
		||||
 * Also remove authentication data.
 | 
			
		||||
 * Future todo: also drop from all other database tables, which aren't used yet
 | 
			
		||||
 * at the time of writing this.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] subscr_id  ID of the subscriber in the HLR db.
 | 
			
		||||
 * \returns if the subscriber was found and removed, -EIO on database error,
 | 
			
		||||
 *          -ENOENT if no such subscriber data exists.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
@@ -127,6 +133,13 @@ int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id)
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Set a subscriber's MSISDN in the HLR database.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] imsi  ASCII string of IMSI digits.
 | 
			
		||||
 * \param[in] msisdn  ASCII string of MSISDN digits.
 | 
			
		||||
 * \returns 0 on success, -EINVAL in case of invalid MSISDN string, -EIO on
 | 
			
		||||
 *          database failure, -ENOENT if no such subscriber exists.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_update_msisdn_by_imsi(struct db_context *dbc, const char *imsi,
 | 
			
		||||
				    const char *msisdn)
 | 
			
		||||
{
 | 
			
		||||
@@ -175,14 +188,17 @@ out:
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Insert or update 2G or 3G authentication tokens in the database.
 | 
			
		||||
/*! Insert or update 2G or 3G authentication tokens in the database.
 | 
			
		||||
 * If aud->type is OSMO_AUTH_TYPE_GSM, the auc_2g table entry for the
 | 
			
		||||
 * subscriber will be added or modified; if aud->algo is OSMO_AUTH_ALG_NONE,
 | 
			
		||||
 * however, the auc_2g entry for the subscriber is deleted. If aud->type is
 | 
			
		||||
 * OSMO_AUTH_TYPE_UMTS, the auc_3g table is updated; again, if aud->algo is
 | 
			
		||||
 * OSMO_AUTH_ALG_NONE, the auc_3g entry is deleted.
 | 
			
		||||
 * Returns 0 if successful, -EINVAL for unknown aud->type, -ENOENT for unknown
 | 
			
		||||
 * subscr_id, -EIO for SQL errors.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] subscr_id  DB ID of the subscriber.
 | 
			
		||||
 * \param[in] aud  Pointer to new auth data (in ASCII string form).
 | 
			
		||||
 * \returns 0 on success, -EINVAL for invalid aud, -ENOENT for unknown
 | 
			
		||||
 *          subscr_id, -EIO for database errors.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
 | 
			
		||||
			       const struct sub_auth_data_str *aud)
 | 
			
		||||
@@ -386,12 +402,12 @@ static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscri
 | 
			
		||||
 | 
			
		||||
	/* obtain the various columns */
 | 
			
		||||
	subscr->id = sqlite3_column_int64(stmt, 0);
 | 
			
		||||
	SL3_TXT(subscr->imsi, stmt, 1);
 | 
			
		||||
	SL3_TXT(subscr->msisdn, stmt, 2);
 | 
			
		||||
	copy_sqlite3_text_to_buf(subscr->imsi, stmt, 1);
 | 
			
		||||
	copy_sqlite3_text_to_buf(subscr->msisdn, stmt, 2);
 | 
			
		||||
	/* FIXME: These should all be BLOBs as they might contain NUL */
 | 
			
		||||
	SL3_TXT(subscr->vlr_number, stmt, 3);
 | 
			
		||||
	SL3_TXT(subscr->sgsn_number, stmt, 4);
 | 
			
		||||
	SL3_TXT(subscr->sgsn_address, stmt, 5);
 | 
			
		||||
	copy_sqlite3_text_to_buf(subscr->vlr_number, stmt, 3);
 | 
			
		||||
	copy_sqlite3_text_to_buf(subscr->sgsn_number, stmt, 4);
 | 
			
		||||
	copy_sqlite3_text_to_buf(subscr->sgsn_address, stmt, 5);
 | 
			
		||||
	subscr->periodic_lu_timer = sqlite3_column_int(stmt, 6);
 | 
			
		||||
	subscr->periodic_rau_tau_timer = sqlite3_column_int(stmt, 7);
 | 
			
		||||
	subscr->nam_cs = sqlite3_column_int(stmt, 8);
 | 
			
		||||
@@ -417,6 +433,13 @@ out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Retrieve subscriber data from the HLR database.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] imsi  ASCII string of IMSI digits.
 | 
			
		||||
 * \param[out] subscr  place retrieved data in this struct.
 | 
			
		||||
 * \returns 0 on success, -ENOENT if no such subscriber was found, -EIO on
 | 
			
		||||
 *          database error.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
 | 
			
		||||
			  struct hlr_subscriber *subscr)
 | 
			
		||||
{
 | 
			
		||||
@@ -434,6 +457,13 @@ int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Retrieve subscriber data from the HLR database.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] msisdn  ASCII string of MSISDN digits.
 | 
			
		||||
 * \param[out] subscr  place retrieved data in this struct.
 | 
			
		||||
 * \returns 0 on success, -ENOENT if no such subscriber was found, -EIO on
 | 
			
		||||
 *          database error.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
 | 
			
		||||
			    struct hlr_subscriber *subscr)
 | 
			
		||||
{
 | 
			
		||||
@@ -451,6 +481,13 @@ int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Retrieve subscriber data from the HLR database.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] id  ID of the subscriber in the HLR db.
 | 
			
		||||
 * \param[out] subscr  place retrieved data in this struct.
 | 
			
		||||
 * \returns 0 on success, -ENOENT if no such subscriber was found, -EIO on
 | 
			
		||||
 *          database error.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_get_by_id(struct db_context *dbc, int64_t id,
 | 
			
		||||
			struct hlr_subscriber *subscr)
 | 
			
		||||
{
 | 
			
		||||
@@ -468,12 +505,14 @@ int db_subscr_get_by_id(struct db_context *dbc, int64_t id,
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Enable or disable PS or CS for a subscriber.
 | 
			
		||||
 * For the subscriber with the given imsi, set nam_ps (when is_ps == true) or
 | 
			
		||||
 * nam_cs (when is_ps == false) to nam_val in the database.
 | 
			
		||||
 * Returns 0 on success, -ENOENT when the given IMSI does not exist, -EINVAL if
 | 
			
		||||
 * the SQL statement could not be composed, -ENOEXEC if running the SQL
 | 
			
		||||
 * statement failed, -EIO if the amount of rows modified is unexpected.
 | 
			
		||||
/*! You should use hlr_subscr_nam() instead; enable or disable PS or CS for a
 | 
			
		||||
 * subscriber without notifying GSUP clients.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] imsi  ASCII string of IMSI digits.
 | 
			
		||||
 * \param[in] nam_val True to enable CS/PS, false to disable.
 | 
			
		||||
 * \param[in] is_ps  when true, set nam_ps, else set nam_cs.
 | 
			
		||||
 * \returns 0 on success, -ENOENT when the given IMSI does not exist, -EIO on
 | 
			
		||||
 *          database errors.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_nam(struct db_context *dbc, const char *imsi, bool nam_val, bool is_ps)
 | 
			
		||||
{
 | 
			
		||||
@@ -522,6 +561,14 @@ out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Record a Location Updating in the database.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] subscr_id  ID of the subscriber in the HLR db.
 | 
			
		||||
 * \param[in] vlr_or_sgsn_number  ASCII string of identifier digits.
 | 
			
		||||
 * \param[in] is_ps  when true, set sgsn_number, else set vlr_number.
 | 
			
		||||
 * \returns 0 on success, -ENOENT when the given subscriber does not exist,
 | 
			
		||||
 *         -EIO on database errors.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
 | 
			
		||||
		 const char *vlr_or_sgsn_number, bool is_ps)
 | 
			
		||||
{
 | 
			
		||||
@@ -565,6 +612,14 @@ out:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Set the ms_purged_cs or ms_purged_ps values in the database.
 | 
			
		||||
 * \param[in,out] dbc  database context.
 | 
			
		||||
 * \param[in] by_imsi  ASCII string of IMSI digits.
 | 
			
		||||
 * \param[in] purge_val  true to purge, false to un-purge.
 | 
			
		||||
 * \param[in] is_ps  when true, set ms_purged_ps, else set ms_purged_cs.
 | 
			
		||||
 * \returns 0 on success, -ENOENT when the given IMSI does not exist, -EIO on
 | 
			
		||||
 *          database errors.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
 | 
			
		||||
		    bool purge_val, bool is_ps)
 | 
			
		||||
{
 | 
			
		||||
@@ -614,10 +669,10 @@ out:
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Update nam_cs/nam_ps in the db and trigger notifications to GSUP clients.
 | 
			
		||||
 * \param hlr     Global hlr context.
 | 
			
		||||
 * \param subscr  Subscriber from a fresh db_subscr_get_by_*() call.
 | 
			
		||||
 * \param nam_val True to enable CS/PS, false to disable.
 | 
			
		||||
 * \param is_ps   True to enable/disable PS, false for CS.
 | 
			
		||||
 * \param[in,out] hlr  Global hlr context.
 | 
			
		||||
 * \param[in] subscr   Subscriber from a fresh db_subscr_get_by_*() call.
 | 
			
		||||
 * \param[in] nam_val  True to enable CS/PS, false to disable.
 | 
			
		||||
 * \param[in] is_ps    True to enable/disable PS, false for CS.
 | 
			
		||||
 * \returns 0 on success, ENOEXEC if there is no need to change, a negative
 | 
			
		||||
 *          value on error.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,87 +0,0 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/core/application.h>
 | 
			
		||||
 | 
			
		||||
#include "db.h"
 | 
			
		||||
#include "hlr.h"
 | 
			
		||||
#include "rand.h"
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
 | 
			
		||||
static struct hlr *g_hlr;
 | 
			
		||||
 | 
			
		||||
static int test(const char *imsi, struct db_context *dbc)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_auth_vector vec[3];
 | 
			
		||||
	int rc, i;
 | 
			
		||||
 | 
			
		||||
	/* initialize all vectors with a known token pattern */
 | 
			
		||||
	memset(vec, 0x55, sizeof(vec));
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(vec); i++)
 | 
			
		||||
		vec[i].res_len = 0;
 | 
			
		||||
 | 
			
		||||
	rc = db_get_auc(dbc, imsi, 0, vec, ARRAY_SIZE(vec), NULL, NULL);
 | 
			
		||||
	if (rc <= 0) {
 | 
			
		||||
		LOGP(DMAIN, LOGL_ERROR, "Cannot obtain auth tuples for '%s'\n", imsi);
 | 
			
		||||
		return rc;
 | 
			
		||||
	}
 | 
			
		||||
	LOGP(DMAIN, LOGL_INFO, "Obtained %u tuples for subscriber IMSI %s\n",
 | 
			
		||||
		rc, imsi);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < rc; i++) {
 | 
			
		||||
		struct osmo_auth_vector *v = vec + i;
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "Tuple %u, auth_types=0x%x\n", i, v->auth_types);
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "RAND=%s\n", osmo_hexdump_nospc(v->rand, sizeof(v->rand)));
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "AUTN=%s\n", osmo_hexdump_nospc(v->autn, sizeof(v->autn)));
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "CK=%s\n", osmo_hexdump_nospc(v->ck, sizeof(v->ck)));
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "IK=%s\n", osmo_hexdump_nospc(v->ik, sizeof(v->ik)));
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "RES=%s\n", osmo_hexdump_nospc(v->res, v->res_len));
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "Kc=%s\n", osmo_hexdump_nospc(v->kc, sizeof(v->kc)));
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "SRES=%s\n", osmo_hexdump_nospc(v->sres, sizeof(v->sres)));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	g_hlr = talloc_zero(NULL, struct hlr);
 | 
			
		||||
 | 
			
		||||
	rc = osmo_init_logging(&hlr_log_info);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "Error initializing logging\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	LOGP(DMAIN, LOGL_NOTICE, "hlr starting\n");
 | 
			
		||||
 | 
			
		||||
	rc = rand_init();
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DMAIN, LOGL_ERROR, "Error initializing random source\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_hlr->dbc = db_open(NULL, "hlr.db");
 | 
			
		||||
	if (!g_hlr->dbc) {
 | 
			
		||||
		LOGP(DMAIN, LOGL_ERROR, "Error opening database\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* non-existing subscriber */
 | 
			
		||||
	rc = test("901990123456789", g_hlr->dbc);
 | 
			
		||||
	/* 2G only AUC data (COMP128v1 / MILENAGE) */
 | 
			
		||||
	rc = test("901990000000001", g_hlr->dbc);
 | 
			
		||||
	/* 2G + 3G AUC data (COMP128v1 / MILENAGE) */
 | 
			
		||||
	rc = test("901990000000002", g_hlr->dbc);
 | 
			
		||||
	/* 3G AUC data (MILENAGE) */
 | 
			
		||||
	rc = test("901990000000003", g_hlr->dbc);
 | 
			
		||||
 | 
			
		||||
	LOGP(DMAIN, LOGL_NOTICE, "Exiting\n");
 | 
			
		||||
 | 
			
		||||
	db_close(g_hlr->dbc);
 | 
			
		||||
 | 
			
		||||
	log_fini();
 | 
			
		||||
 | 
			
		||||
	exit(0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/dbd_decode_binary.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/dbd_decode_binary.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
/* This function is blatantly copied from libdbi, from
 | 
			
		||||
 * https://sourceforge.net/p/libdbi/libdbi/ci/master/tree/src/dbd_helper.c
 | 
			
		||||
 * to save having to depend on the entire libdbi just for KI BLOB decoding.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * libdbi - database independent abstraction layer for C.
 | 
			
		||||
 * Copyright (C) 2001-2003, David Parker and Mark Tobenkin.
 | 
			
		||||
 * http://libdbi.sourceforge.net
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Lesser General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2.1 of the License, or (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public
 | 
			
		||||
 * License along with this library; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
			
		||||
 * 
 | 
			
		||||
 * $Id: dbd_helper.c,v 1.44 2011/08/09 11:14:14 mhoenicka Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
size_t _dbd_decode_binary(const unsigned char *in, unsigned char *out){
 | 
			
		||||
  int i, e;
 | 
			
		||||
  unsigned char c;
 | 
			
		||||
  e = *(in++);
 | 
			
		||||
  i = 0;
 | 
			
		||||
  while( (c = *(in++))!=0 ){
 | 
			
		||||
    if( c==1 ){
 | 
			
		||||
      c = *(in++) - 1;
 | 
			
		||||
    }
 | 
			
		||||
    out[i++] = c + e;
 | 
			
		||||
  }
 | 
			
		||||
  return (size_t)i;
 | 
			
		||||
}
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include <osmocom/core/linuxlist.h>
 | 
			
		||||
#include <osmocom/abis/ipa.h>
 | 
			
		||||
#include <osmocom/abis/ipaccess.h>
 | 
			
		||||
#include <osmocom/gsm/apn.h>
 | 
			
		||||
 | 
			
		||||
#include "gsup_server.h"
 | 
			
		||||
#include "gsup_router.h"
 | 
			
		||||
@@ -333,3 +334,20 @@ void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups)
 | 
			
		||||
	}
 | 
			
		||||
	talloc_free(gsups);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup)
 | 
			
		||||
{
 | 
			
		||||
	int l;
 | 
			
		||||
	uint8_t apn[APN_MAXLEN];
 | 
			
		||||
 | 
			
		||||
	l = osmo_apn_from_str(apn, sizeof(apn), "*");
 | 
			
		||||
	if (l <= 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	gsup->pdp_infos[0].apn_enc = apn;
 | 
			
		||||
	gsup->pdp_infos[0].apn_enc_len = l;
 | 
			
		||||
	gsup->pdp_infos[0].have_info = 1;
 | 
			
		||||
	gsup->num_pdp_infos = 1;
 | 
			
		||||
	/* FIXME: use real value: */
 | 
			
		||||
	gsup->pdp_infos[0].context_id = 1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
#include <osmocom/abis/ipa.h>
 | 
			
		||||
#include <osmocom/abis/ipaccess.h>
 | 
			
		||||
#include <osmocom/gsm/gsup.h>
 | 
			
		||||
 | 
			
		||||
struct osmo_gsup_conn;
 | 
			
		||||
 | 
			
		||||
@@ -33,6 +34,10 @@ struct osmo_gsup_conn {
 | 
			
		||||
	struct tlv_parsed ccm;
 | 
			
		||||
 | 
			
		||||
	unsigned int auc_3g_ind; /*!< IND index used for UMTS AKA SQN */
 | 
			
		||||
 | 
			
		||||
	/* Set when Location Update is received: */
 | 
			
		||||
	bool supports_cs; /* client supports OSMO_GSUP_CN_DOMAIN_CS */
 | 
			
		||||
	bool supports_ps; /* client supports OSMO_GSUP_CN_DOMAIN_PS */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -48,3 +53,4 @@ struct osmo_gsup_server *osmo_gsup_server_create(void *ctx,
 | 
			
		||||
 | 
			
		||||
void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups);
 | 
			
		||||
 | 
			
		||||
void osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										134
									
								
								src/hlr.c
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								src/hlr.c
									
									
									
									
									
								
							@@ -26,7 +26,6 @@
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
#include <osmocom/core/application.h>
 | 
			
		||||
#include <osmocom/gsm/gsup.h>
 | 
			
		||||
#include <osmocom/gsm/apn.h>
 | 
			
		||||
#include <osmocom/gsm/gsm48_ie.h>
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
@@ -46,6 +45,88 @@
 | 
			
		||||
 | 
			
		||||
static struct hlr *g_hlr;
 | 
			
		||||
 | 
			
		||||
/* Trigger 'Insert Subscriber Data' messages to all connected GSUP clients.
 | 
			
		||||
 *
 | 
			
		||||
 * FIXME: In order to support large-scale networks this function should skip
 | 
			
		||||
 * VLRs/SGSNs which do not currently serve the subscriber.
 | 
			
		||||
 *
 | 
			
		||||
 * \param[in] subscr  A subscriber we have new data to send for.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
 | 
			
		||||
{
 | 
			
		||||
        struct osmo_gsup_conn *co;
 | 
			
		||||
 | 
			
		||||
	if (g_hlr->gs == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(co, &g_hlr->gs->clients, list) {
 | 
			
		||||
		struct osmo_gsup_message gsup = {
 | 
			
		||||
			.message_type = OSMO_GSUP_MSGT_INSERT_DATA_REQUEST
 | 
			
		||||
		};
 | 
			
		||||
		uint8_t *peer;
 | 
			
		||||
		int peer_len;
 | 
			
		||||
		uint8_t msisdn_enc[43]; /* TODO use constant; TS 24.008 10.5.4.7 */
 | 
			
		||||
		int len;
 | 
			
		||||
		struct msgb *msg_out;
 | 
			
		||||
 | 
			
		||||
		peer_len = osmo_gsup_conn_ccm_get(co, &peer, IPAC_IDTAG_SERNR);
 | 
			
		||||
		if (peer_len < 0) {
 | 
			
		||||
			LOGP(DMAIN, LOGL_ERROR,
 | 
			
		||||
			       "IMSI='%s': Cannot notify GSUP client, cannot get peer name "
 | 
			
		||||
			       "for %s:%u\n", subscr->imsi,
 | 
			
		||||
			       co && co->conn && co->conn->server? co->conn->server->addr : "unset",
 | 
			
		||||
			       co && co->conn && co->conn->server? co->conn->server->port : 0);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		osmo_strlcpy(gsup.imsi, subscr->imsi, GSM23003_IMSI_MAX_DIGITS + 1);
 | 
			
		||||
 | 
			
		||||
		len = gsm48_encode_bcd_number(msisdn_enc, sizeof(msisdn_enc), 0, subscr->msisdn);
 | 
			
		||||
		if (len < 1) {
 | 
			
		||||
			LOGP(DMAIN, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n",
 | 
			
		||||
			     subscr->imsi, subscr->msisdn);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		gsup.msisdn_enc = msisdn_enc;
 | 
			
		||||
		gsup.msisdn_enc_len = len;
 | 
			
		||||
 | 
			
		||||
		if (co->supports_ps) {
 | 
			
		||||
			gsup.cn_domain = OSMO_GSUP_CN_DOMAIN_PS;
 | 
			
		||||
 | 
			
		||||
			/* FIXME: PDP infos - use more fine-grained access control
 | 
			
		||||
			   instead of wildcard APN */
 | 
			
		||||
			osmo_gsup_configure_wildcard_apn(&gsup);
 | 
			
		||||
		} else if (co->supports_cs) {
 | 
			
		||||
			gsup.cn_domain = OSMO_GSUP_CN_DOMAIN_CS;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* We have not yet received a location update from this subscriber .*/
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Send ISD to MSC/SGSN */
 | 
			
		||||
		msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP ISD UPDATE");
 | 
			
		||||
		if (msg_out == NULL) {
 | 
			
		||||
			LOGP(DMAIN, LOGL_ERROR,
 | 
			
		||||
			       "IMSI='%s': Cannot notify GSUP client; could not allocate msg buffer "
 | 
			
		||||
			       "for %s:%u\n", subscr->imsi,
 | 
			
		||||
			       co && co->conn && co->conn->server? co->conn->server->addr : "unset",
 | 
			
		||||
			       co && co->conn && co->conn->server? co->conn->server->port : 0);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		osmo_gsup_encode(msg_out, &gsup);
 | 
			
		||||
		if (osmo_gsup_addr_send(g_hlr->gs, peer, peer_len, msg_out) < 0) {
 | 
			
		||||
			LOGP(DMAIN, LOGL_ERROR,
 | 
			
		||||
			       "IMSI='%s': Cannot notify GSUP client; send operation failed "
 | 
			
		||||
			       "for %s:%u\n", subscr->imsi,
 | 
			
		||||
			       co && co->conn && co->conn->server? co->conn->server->addr : "unset",
 | 
			
		||||
			       co && co->conn && co->conn->server? co->conn->server->port : 0);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***********************************************************************
 | 
			
		||||
 * Send Auth Info handling
 | 
			
		||||
 ***********************************************************************/
 | 
			
		||||
@@ -67,12 +148,27 @@ static int rx_send_auth_info(struct osmo_gsup_conn *conn,
 | 
			
		||||
			gsup_out.auth_vectors,
 | 
			
		||||
			ARRAY_SIZE(gsup_out.auth_vectors),
 | 
			
		||||
			gsup->rand, gsup->auts);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
	if (rc <= 0) {
 | 
			
		||||
		gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR;
 | 
			
		||||
		gsup_out.cause = GMM_CAUSE_NET_FAIL;
 | 
			
		||||
	} else if (rc == 0) {
 | 
			
		||||
		gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR;
 | 
			
		||||
		gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;
 | 
			
		||||
		switch (rc) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			/* 0 means "0 tuples generated", which shouldn't happen.
 | 
			
		||||
			 * Treat the same as "no auth data". */
 | 
			
		||||
		case -ENOKEY:
 | 
			
		||||
			LOGP(DAUC, LOGL_NOTICE, "%s: IMSI known, but has no auth data;"
 | 
			
		||||
			     " Returning slightly inaccurate cause 'IMSI Unknown' via GSUP\n",
 | 
			
		||||
			     gsup->imsi);
 | 
			
		||||
			gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;
 | 
			
		||||
			break;
 | 
			
		||||
		case -ENOENT:
 | 
			
		||||
			LOGP(DAUC, LOGL_NOTICE, "%s: IMSI not known\n", gsup->imsi);
 | 
			
		||||
			gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			LOGP(DAUC, LOGL_ERROR, "%s: failure to look up IMSI in db\n", gsup->imsi);
 | 
			
		||||
			gsup_out.cause = GMM_CAUSE_NET_FAIL;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT;
 | 
			
		||||
		gsup_out.num_auth_vectors = rc;
 | 
			
		||||
@@ -155,8 +251,19 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
 | 
			
		||||
 | 
			
		||||
	lu_op_statechg(luop, LU_S_LU_RECEIVED);
 | 
			
		||||
 | 
			
		||||
	if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
 | 
			
		||||
	if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_CS)
 | 
			
		||||
		conn->supports_cs = true;
 | 
			
		||||
	if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {
 | 
			
		||||
		conn->supports_ps = true;
 | 
			
		||||
		luop->is_ps = true;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* The client didn't send a CN_DOMAIN IE; assume packet-switched in
 | 
			
		||||
		 * accordance with the GSUP spec in osmo-hlr's user manual (section
 | 
			
		||||
		 * 11.6.15 "CN Domain" says "if no CN Domain IE is present within
 | 
			
		||||
		 * a request, the PS Domain is assumed." */
 | 
			
		||||
		conn->supports_ps = true;
 | 
			
		||||
		luop->is_ps = true;
 | 
			
		||||
	}
 | 
			
		||||
	llist_add(&luop->list, &g_lu_ops);
 | 
			
		||||
 | 
			
		||||
	/* Roughly follwing "Process Update_Location_HLR" of TS 09.02 */
 | 
			
		||||
@@ -164,7 +271,7 @@ static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
 | 
			
		||||
	/* check if subscriber is known at all */
 | 
			
		||||
	if (!lu_op_fill_subscr(luop, g_hlr->dbc, gsup->imsi)) {
 | 
			
		||||
		/* Send Error back: Subscriber Unknown in HLR */
 | 
			
		||||
		strcpy(luop->subscr.imsi, gsup->imsi);
 | 
			
		||||
		osmo_strlcpy(luop->subscr.imsi, gsup->imsi, sizeof(luop->subscr.imsi));
 | 
			
		||||
		lu_op_tx_error(luop, GMM_CAUSE_IMSI_UNKNOWN);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
@@ -223,9 +330,9 @@ static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
 | 
			
		||||
	/* Perform the actual update of the DB */
 | 
			
		||||
	rc = db_subscr_purge(g_hlr->dbc, gsup->imsi, true, is_ps);
 | 
			
		||||
 | 
			
		||||
	if (rc == 1)
 | 
			
		||||
	if (rc == 0)
 | 
			
		||||
		gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT;
 | 
			
		||||
	else if (rc == 0) {
 | 
			
		||||
	else if (rc == -ENOENT) {
 | 
			
		||||
		gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;
 | 
			
		||||
		gsup_reply.cause = GMM_CAUSE_IMSI_UNKNOWN;
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -424,10 +531,11 @@ int main(int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	hlr_ctx = talloc_named_const(NULL, 1, "OsmoHLR");
 | 
			
		||||
	msgb_talloc_ctx_init(hlr_ctx, 0);
 | 
			
		||||
	vty_info.tall_ctx = hlr_ctx;
 | 
			
		||||
 | 
			
		||||
	g_hlr = talloc_zero(hlr_ctx, struct hlr);
 | 
			
		||||
 | 
			
		||||
	rc = osmo_init_logging(&hlr_log_info);
 | 
			
		||||
	rc = osmo_init_logging2(hlr_ctx, &hlr_log_info);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "Error initializing logging\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
@@ -460,7 +568,7 @@ int main(int argc, char **argv)
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_hlr->dbc = db_open(hlr_ctx, cmdline_opts.db_file);
 | 
			
		||||
	g_hlr->dbc = db_open(hlr_ctx, cmdline_opts.db_file, true);
 | 
			
		||||
	if (!g_hlr->dbc) {
 | 
			
		||||
		LOGP(DMAIN, LOGL_FATAL, "Error opening database\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
@@ -474,7 +582,7 @@ int main(int argc, char **argv)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
 | 
			
		||||
	g_hlr->ctrl = hlr_controlif_setup(g_hlr, g_hlr->gs);
 | 
			
		||||
	g_hlr->ctrl = hlr_controlif_setup(g_hlr);
 | 
			
		||||
 | 
			
		||||
	osmo_init_ignore_signals();
 | 
			
		||||
	signal(SIGINT, &signal_hdlr);
 | 
			
		||||
 
 | 
			
		||||
@@ -38,3 +38,7 @@ struct hlr {
 | 
			
		||||
	/* Local bind addr */
 | 
			
		||||
	char *gsup_bind_addr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct hlr_subscriber;
 | 
			
		||||
 | 
			
		||||
void osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										439
									
								
								src/hlr_db_tool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										439
									
								
								src/hlr_db_tool.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,439 @@
 | 
			
		||||
/* (C) 2017 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 | 
			
		||||
 *
 | 
			
		||||
 * All Rights Reserved
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Neels Hofmeyr <nhofmeyr@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 <stdlib.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
#include <osmocom/core/application.h>
 | 
			
		||||
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
#include "db.h"
 | 
			
		||||
#include "rand.h"
 | 
			
		||||
 | 
			
		||||
struct hlr_db_tool_ctx {
 | 
			
		||||
	/* DB context */
 | 
			
		||||
	struct db_context *dbc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct hlr_db_tool_ctx *g_hlr_db_tool_ctx;
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
	const char *db_file;
 | 
			
		||||
	bool bootstrap;
 | 
			
		||||
	const char *import_nitb_db;
 | 
			
		||||
} cmdline_opts = {
 | 
			
		||||
	.db_file = "hlr.db",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void print_help()
 | 
			
		||||
{
 | 
			
		||||
	printf("\n");
 | 
			
		||||
	printf("Usage: osmo-hlr-db-tool [-l <hlr.db>] [create|import-nitb-db <nitb.db>]\n");
 | 
			
		||||
	printf("  -l --database db-name      The OsmoHLR database to use, default '%s'.\n",
 | 
			
		||||
	       cmdline_opts.db_file);
 | 
			
		||||
	printf("  -h --help                  This text.\n");
 | 
			
		||||
	printf("  -d option --debug=DMAIN:DDB:DAUC  Enable debugging.\n");
 | 
			
		||||
	printf("  -s --disable-color         Do not print ANSI colors in the log\n");
 | 
			
		||||
	printf("  -T --timestamp             Prefix every log line with a timestamp.\n");
 | 
			
		||||
	printf("  -e --log-level number      Set a global loglevel.\n");
 | 
			
		||||
	printf("  -V --version               Print the version of OsmoHLR-db-tool.\n");
 | 
			
		||||
	printf("\n");
 | 
			
		||||
	printf("Commands:\n");
 | 
			
		||||
	printf("\n");
 | 
			
		||||
	printf("  create                     Create an empty OsmoHLR database.\n");
 | 
			
		||||
	printf("                             (All commands imply this if none exists yet.)\n");
 | 
			
		||||
	printf("\n");
 | 
			
		||||
	printf("  import-nitb-db <nitb.db>   Add OsmoNITB db's subscribers to OsmoHLR db.\n");
 | 
			
		||||
	printf("                             Be aware that the import is lossy, only the\n");
 | 
			
		||||
	printf("                             IMSI, MSISDN, nam_cs/ps and 2G auth data are set.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_version(int print_copyright)
 | 
			
		||||
{
 | 
			
		||||
	printf("OsmoHLR-db-tool version %s\n", PACKAGE_VERSION);
 | 
			
		||||
	if (print_copyright)
 | 
			
		||||
		printf("\n"
 | 
			
		||||
       "Copyright (C) 2017 by sysmocom - s.f.m.c. GmbH\n"
 | 
			
		||||
       "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\n"
 | 
			
		||||
       "This is free software: you are free to change and redistribute it.\n"
 | 
			
		||||
       "There is NO WARRANTY, to the extent permitted by law.\n"
 | 
			
		||||
       "\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	const char *cmd;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int option_index = 0, c;
 | 
			
		||||
		static struct option long_options[] = {
 | 
			
		||||
			{"help", 0, 0, 'h'},
 | 
			
		||||
			{"database", 1, 0, 'l'},
 | 
			
		||||
			{"debug", 1, 0, 'd'},
 | 
			
		||||
			{"disable-color", 0, 0, 's'},
 | 
			
		||||
			{"timestamp", 0, 0, 'T'},
 | 
			
		||||
			{"log-level", 1, 0, 'e'},
 | 
			
		||||
			{"version", 0, 0, 'V' },
 | 
			
		||||
			{0, 0, 0, 0}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		c = getopt_long(argc, argv, "hl:d:sTe:V",
 | 
			
		||||
				long_options, &option_index);
 | 
			
		||||
		if (c == -1)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'h':
 | 
			
		||||
			print_help();
 | 
			
		||||
			exit(EXIT_SUCCESS);
 | 
			
		||||
		case 'l':
 | 
			
		||||
			cmdline_opts.db_file = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'd':
 | 
			
		||||
			log_parse_category_mask(osmo_stderr_target, optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		case 's':
 | 
			
		||||
			log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'T':
 | 
			
		||||
			log_set_print_timestamp(osmo_stderr_target, 1);
 | 
			
		||||
			break;
 | 
			
		||||
		case 'e':
 | 
			
		||||
			log_set_log_level(osmo_stderr_target, atoi(optarg));
 | 
			
		||||
			break;
 | 
			
		||||
		case 'V':
 | 
			
		||||
			print_version(1);
 | 
			
		||||
			exit(EXIT_SUCCESS);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			/* catch unknown options *as well as* missing arguments. */
 | 
			
		||||
			fprintf(stderr, "Error in command line options. Exiting.\n");
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (argc - optind <= 0) {
 | 
			
		||||
		fprintf(stderr, "Error: You must specify a command.\n");
 | 
			
		||||
		print_help();
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd = argv[optind++];
 | 
			
		||||
 | 
			
		||||
	if (!strcmp(cmd, "create")) {
 | 
			
		||||
		/* Nothing to do, just run the main program to open the database without running any
 | 
			
		||||
		 * action, which will bootstrap all tables. */
 | 
			
		||||
	} else if (!strcmp(cmd, "import-nitb-db")) {
 | 
			
		||||
		if (argc - optind < 1) {
 | 
			
		||||
			fprintf(stderr, "You must specify an input db file\n");
 | 
			
		||||
			print_help();
 | 
			
		||||
			exit(EXIT_FAILURE);
 | 
			
		||||
		}
 | 
			
		||||
		cmdline_opts.import_nitb_db = argv[optind++];
 | 
			
		||||
	} else {
 | 
			
		||||
		fprintf(stderr, "Error: Unknown command `%s'\n", cmd);
 | 
			
		||||
		print_help();
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (argc - optind > 0) {
 | 
			
		||||
		fprintf(stderr, "Too many arguments: '%s'\n", argv[optind]);
 | 
			
		||||
		print_help();
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void signal_hdlr(int signal)
 | 
			
		||||
{
 | 
			
		||||
	switch (signal) {
 | 
			
		||||
	case SIGINT:
 | 
			
		||||
		LOGP(DMAIN, LOGL_NOTICE, "Terminating due to SIGINT\n");
 | 
			
		||||
		db_close(g_hlr_db_tool_ctx->dbc);
 | 
			
		||||
		log_fini();
 | 
			
		||||
		talloc_report_full(g_hlr_db_tool_ctx, stderr);
 | 
			
		||||
		exit(EXIT_SUCCESS);
 | 
			
		||||
		break;
 | 
			
		||||
	case SIGUSR1:
 | 
			
		||||
		LOGP(DMAIN, LOGL_DEBUG, "Talloc Report due to SIGUSR1\n");
 | 
			
		||||
		talloc_report_full(g_hlr_db_tool_ctx, stderr);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sqlite3 *open_nitb_db(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	sqlite3 *nitb_db = NULL;
 | 
			
		||||
 | 
			
		||||
	rc = sqlite3_open(filename, &nitb_db);
 | 
			
		||||
	if (rc != SQLITE_OK) {
 | 
			
		||||
		LOGP(DDB, LOGL_ERROR, "Unable to open OsmoNITB DB %s; rc = %d\n", filename, rc);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nitb_db;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum nitb_stmt {
 | 
			
		||||
	NITB_SELECT_SUBSCR,
 | 
			
		||||
	NITB_SELECT_AUTH_KEYS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *nitb_stmt_sql[] = {
 | 
			
		||||
	[NITB_SELECT_SUBSCR] =
 | 
			
		||||
		"SELECT imsi, id, extension, authorized"
 | 
			
		||||
		" FROM Subscriber"
 | 
			
		||||
		" ORDER BY id",
 | 
			
		||||
	[NITB_SELECT_AUTH_KEYS] =
 | 
			
		||||
		"SELECT algorithm_id, a3a8_ki from authkeys"
 | 
			
		||||
		" WHERE subscriber_id = $subscr_id",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
sqlite3_stmt *nitb_stmt[ARRAY_SIZE(nitb_stmt_sql)] = {};
 | 
			
		||||
 | 
			
		||||
size_t _dbd_decode_binary(const unsigned char *in, unsigned char *out);
 | 
			
		||||
 | 
			
		||||
void import_nitb_subscr_aud(sqlite3 *nitb_db, const char *imsi, int64_t nitb_id, int64_t hlr_id)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct db_context *dbc = g_hlr_db_tool_ctx->dbc;
 | 
			
		||||
	sqlite3_stmt *stmt;
 | 
			
		||||
 | 
			
		||||
	int count = 0;
 | 
			
		||||
 | 
			
		||||
	stmt = nitb_stmt[NITB_SELECT_AUTH_KEYS];
 | 
			
		||||
	if (!db_bind_int(stmt, NULL, nitb_id))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
 | 
			
		||||
		const void *blob;
 | 
			
		||||
		unsigned int blob_size;
 | 
			
		||||
		static unsigned char buf[4096];
 | 
			
		||||
		static char ki[128];
 | 
			
		||||
		int decoded_size;
 | 
			
		||||
		struct sub_auth_data_str aud2g = {
 | 
			
		||||
			.type = OSMO_AUTH_TYPE_GSM,
 | 
			
		||||
			.algo = OSMO_AUTH_ALG_NONE,
 | 
			
		||||
			.u.gsm.ki = ki,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		aud2g.algo = sqlite3_column_int(stmt, 0);
 | 
			
		||||
 | 
			
		||||
		if (count) {
 | 
			
		||||
			LOGP(DDB, LOGL_ERROR,
 | 
			
		||||
			     "Warning: subscriber has more than one auth key,"
 | 
			
		||||
			     " importing only the first key, for IMSI=%s\n",
 | 
			
		||||
			     imsi);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		blob = sqlite3_column_blob(stmt, 1);
 | 
			
		||||
		blob_size = sqlite3_column_bytes(stmt, 1);
 | 
			
		||||
 | 
			
		||||
		if (blob_size > sizeof(buf)) {
 | 
			
		||||
			LOGP(DDB, LOGL_ERROR,
 | 
			
		||||
			     "OsmoNITB import to %s: Cannot import auth data for IMSI %s:"
 | 
			
		||||
			     " too large blob: %u\n",
 | 
			
		||||
			     dbc->fname, imsi, blob_size);
 | 
			
		||||
			db_remove_reset(stmt);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		decoded_size = _dbd_decode_binary(blob, buf);
 | 
			
		||||
		osmo_strlcpy(ki, osmo_hexdump_nospc(buf, decoded_size), sizeof(ki));
 | 
			
		||||
 | 
			
		||||
		db_subscr_update_aud_by_id(dbc, hlr_id, &aud2g);
 | 
			
		||||
		count ++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
 | 
			
		||||
		LOGP(DDB, LOGL_ERROR, "OsmoNITB DB: SQL error: (%d) %s,"
 | 
			
		||||
		     " during stmt '%s'",
 | 
			
		||||
		     rc, sqlite3_errmsg(nitb_db),
 | 
			
		||||
		     nitb_stmt_sql[NITB_SELECT_AUTH_KEYS]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	db_remove_reset(stmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void import_nitb_subscr(sqlite3 *nitb_db, sqlite3_stmt *stmt)
 | 
			
		||||
{
 | 
			
		||||
	struct db_context *dbc = g_hlr_db_tool_ctx->dbc;
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct hlr_subscriber subscr;
 | 
			
		||||
 | 
			
		||||
	int64_t nitb_id;
 | 
			
		||||
	int64_t imsi;
 | 
			
		||||
	char imsi_str[32];
 | 
			
		||||
	bool authorized;
 | 
			
		||||
 | 
			
		||||
	imsi = sqlite3_column_int64(stmt, 0);
 | 
			
		||||
 | 
			
		||||
	snprintf(imsi_str, sizeof(imsi_str), "%"PRId64, imsi);
 | 
			
		||||
 | 
			
		||||
	rc = db_subscr_create(dbc, imsi_str);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DDB, LOGL_ERROR, "OsmoNITB DB import to %s: failed to create IMSI %s: %d: %s\n",
 | 
			
		||||
		     dbc->fname,
 | 
			
		||||
		     imsi_str,
 | 
			
		||||
		     rc,
 | 
			
		||||
		     strerror(-rc));
 | 
			
		||||
		/* on error, still attempt to continue */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nitb_id = sqlite3_column_int64(stmt, 1);
 | 
			
		||||
	copy_sqlite3_text_to_buf(subscr.msisdn, stmt, 2);
 | 
			
		||||
	authorized = sqlite3_column_int(stmt, 3) ? true : false;
 | 
			
		||||
 | 
			
		||||
	db_subscr_update_msisdn_by_imsi(dbc, imsi_str, subscr.msisdn);
 | 
			
		||||
	db_subscr_nam(dbc, imsi_str, authorized, true);
 | 
			
		||||
	db_subscr_nam(dbc, imsi_str, authorized, false);
 | 
			
		||||
 | 
			
		||||
	/* find the just created id */
 | 
			
		||||
	rc = db_subscr_get_by_imsi(dbc, imsi_str, &subscr);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DDB, LOGL_ERROR, "OsmoNITB DB import to %s: created IMSI %s,"
 | 
			
		||||
		     " but failed to get new subscriber id: %d: %s\n",
 | 
			
		||||
		     dbc->fname,
 | 
			
		||||
		     imsi_str,
 | 
			
		||||
		     rc,
 | 
			
		||||
		     strerror(-rc));
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	OSMO_ASSERT(!strcmp(imsi_str, subscr.imsi));
 | 
			
		||||
 | 
			
		||||
	import_nitb_subscr_aud(nitb_db, imsi_str, nitb_id, subscr.id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int import_nitb_db(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int rc;
 | 
			
		||||
	const char *sql;
 | 
			
		||||
	sqlite3_stmt *stmt;
 | 
			
		||||
 | 
			
		||||
	sqlite3 *nitb_db = open_nitb_db(cmdline_opts.import_nitb_db);
 | 
			
		||||
 | 
			
		||||
	if (!nitb_db)
 | 
			
		||||
		return -1;
 | 
			
		||||
	ret = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < ARRAY_SIZE(nitb_stmt_sql); i++) {
 | 
			
		||||
		sql = nitb_stmt_sql[i];
 | 
			
		||||
		rc = sqlite3_prepare_v2(nitb_db, sql, -1, &nitb_stmt[i], NULL);
 | 
			
		||||
		if (rc != SQLITE_OK) {
 | 
			
		||||
			LOGP(DDB, LOGL_ERROR, "OsmoNITB DB: Unable to prepare SQL statement '%s'\n", sql);
 | 
			
		||||
			ret = -1;
 | 
			
		||||
			goto out_free;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stmt = nitb_stmt[NITB_SELECT_SUBSCR];
 | 
			
		||||
 | 
			
		||||
	while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
 | 
			
		||||
		import_nitb_subscr(nitb_db, stmt);
 | 
			
		||||
		/* On failure, carry on with the rest. */
 | 
			
		||||
	}
 | 
			
		||||
	if (rc != SQLITE_DONE) {
 | 
			
		||||
		LOGP(DDB, LOGL_ERROR, "OsmoNITB DB: SQL error: (%d) %s,"
 | 
			
		||||
		     " during stmt '%s'",
 | 
			
		||||
		     rc, sqlite3_errmsg(nitb_db),
 | 
			
		||||
		     nitb_stmt_sql[NITB_SELECT_SUBSCR]);
 | 
			
		||||
		goto out_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	db_remove_reset(stmt);
 | 
			
		||||
	sqlite3_finalize(stmt);
 | 
			
		||||
 | 
			
		||||
out_free:
 | 
			
		||||
	sqlite3_close(nitb_db);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	int (*main_action)(void);
 | 
			
		||||
	main_action = NULL;
 | 
			
		||||
 | 
			
		||||
	g_hlr_db_tool_ctx = talloc_zero(NULL, struct hlr_db_tool_ctx);
 | 
			
		||||
	OSMO_ASSERT(g_hlr_db_tool_ctx);
 | 
			
		||||
	talloc_set_name_const(g_hlr_db_tool_ctx, "OsmoHLR-db-tool");
 | 
			
		||||
 | 
			
		||||
	rc = osmo_init_logging2(g_hlr_db_tool_ctx, &hlr_log_info);
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		fprintf(stderr, "Error initializing logging\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
	if (cmdline_opts.import_nitb_db) {
 | 
			
		||||
		if (main_action)
 | 
			
		||||
			goto too_many_actions;
 | 
			
		||||
		main_action = import_nitb_db;
 | 
			
		||||
	}
 | 
			
		||||
	/* Future: add more main_actions, besides import-nitb-db, here.
 | 
			
		||||
	 * For command 'create', no action is required. */
 | 
			
		||||
 | 
			
		||||
	/* Just in case any db actions need randomness */
 | 
			
		||||
	rc = rand_init();
 | 
			
		||||
	if (rc < 0) {
 | 
			
		||||
		LOGP(DMAIN, LOGL_FATAL, "Error initializing random source\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g_hlr_db_tool_ctx->dbc = db_open(g_hlr_db_tool_ctx, cmdline_opts.db_file, true);
 | 
			
		||||
	if (!g_hlr_db_tool_ctx->dbc) {
 | 
			
		||||
		LOGP(DMAIN, LOGL_FATAL, "Error opening database\n");
 | 
			
		||||
		exit(EXIT_FAILURE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	osmo_init_ignore_signals();
 | 
			
		||||
	signal(SIGINT, &signal_hdlr);
 | 
			
		||||
	signal(SIGUSR1, &signal_hdlr);
 | 
			
		||||
 | 
			
		||||
	rc = 0;
 | 
			
		||||
	if (main_action)
 | 
			
		||||
		rc = (*main_action)();
 | 
			
		||||
 | 
			
		||||
	db_close(g_hlr_db_tool_ctx->dbc);
 | 
			
		||||
	log_fini();
 | 
			
		||||
	exit(rc ? EXIT_FAILURE : EXIT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
too_many_actions:
 | 
			
		||||
	fprintf(stderr, "Too many actions requested.\n");
 | 
			
		||||
	log_fini();
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* stubs */
 | 
			
		||||
void lu_op_alloc_conn(void) { OSMO_ASSERT(0); }
 | 
			
		||||
void lu_op_tx_del_subscr_data(void) { OSMO_ASSERT(0); }
 | 
			
		||||
void lu_op_free(void) { OSMO_ASSERT(0); }
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include <osmocom/vty/vty.h>
 | 
			
		||||
#include <osmocom/vty/command.h>
 | 
			
		||||
#include <osmocom/vty/logging.h>
 | 
			
		||||
#include <osmocom/vty/misc.h>
 | 
			
		||||
 | 
			
		||||
#include "hlr_vty.h"
 | 
			
		||||
#include "hlr_vty_subscr.h"
 | 
			
		||||
@@ -126,14 +127,13 @@ void hlr_vty_init(struct hlr *hlr, const struct log_info *cat)
 | 
			
		||||
	g_hlr = hlr;
 | 
			
		||||
 | 
			
		||||
	logging_vty_add_cmds(cat);
 | 
			
		||||
	osmo_talloc_vty_add_cmds();
 | 
			
		||||
 | 
			
		||||
	install_element(CONFIG_NODE, &cfg_hlr_cmd);
 | 
			
		||||
	install_node(&hlr_node, config_write_hlr);
 | 
			
		||||
	install_default(HLR_NODE);
 | 
			
		||||
 | 
			
		||||
	install_element(HLR_NODE, &cfg_gsup_cmd);
 | 
			
		||||
	install_node(&gsup_node, config_write_hlr_gsup);
 | 
			
		||||
	install_default(GSUP_NODE);
 | 
			
		||||
 | 
			
		||||
	install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -72,14 +72,17 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
 | 
			
		||||
	OSMO_ASSERT(g_hlr);
 | 
			
		||||
	rc = db_get_auth_data(g_hlr->dbc, subscr->imsi, &aud2g, &aud3g, NULL);
 | 
			
		||||
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		if (rc == -ENOENT) {
 | 
			
		||||
			aud2g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
			aud3g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
		} else {
 | 
			
		||||
			vty_out(vty, "%% Error retrieving data from database (%d)%s", rc, VTY_NEWLINE);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	switch (rc) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		break;
 | 
			
		||||
	case -ENOENT:
 | 
			
		||||
	case -ENOKEY:
 | 
			
		||||
		aud2g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
		aud3g.algo = OSMO_AUTH_ALG_NONE;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		vty_out(vty, "%% Error retrieving data from database (%d)%s", rc, VTY_NEWLINE);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (aud2g.type != OSMO_AUTH_TYPE_NONE && aud2g.type != OSMO_AUTH_TYPE_GSM) {
 | 
			
		||||
@@ -254,6 +257,10 @@ DEFUN(subscriber_msisdn,
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "%% Updated subscriber IMSI='%s' to MSISDN='%s'%s",
 | 
			
		||||
		subscr.imsi, msisdn, VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	if (db_subscr_get_by_msisdn(g_hlr->dbc, msisdn, &subscr) == 0)
 | 
			
		||||
		osmo_hlr_subscriber_update_notify(&subscr);
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -331,7 +338,7 @@ DEFUN(subscriber_no_aud2g,
 | 
			
		||||
 | 
			
		||||
	rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud);
 | 
			
		||||
 | 
			
		||||
	if (rc) {
 | 
			
		||||
	if (rc && rc != -ENOENT) {
 | 
			
		||||
		vty_out(vty, "%% Error: cannot disable 2G auth data for IMSI='%s'%s",
 | 
			
		||||
			subscr.imsi, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
@@ -402,7 +409,7 @@ DEFUN(subscriber_no_aud3g,
 | 
			
		||||
 | 
			
		||||
	rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud);
 | 
			
		||||
 | 
			
		||||
	if (rc) {
 | 
			
		||||
	if (rc && rc != -ENOENT) {
 | 
			
		||||
		vty_out(vty, "%% Error: cannot disable 3G auth data for IMSI='%s'%s",
 | 
			
		||||
			subscr.imsi, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,19 +5,19 @@ const struct log_info_cat hlr_log_info_cat[] = {
 | 
			
		||||
	[DMAIN] = {
 | 
			
		||||
		.name = "DMAIN",
 | 
			
		||||
		.description = "Main Program",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DDB] = {
 | 
			
		||||
		.name = "DDB",
 | 
			
		||||
		.description = "Database Layer",
 | 
			
		||||
		.color = "\033[1;31m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
	[DAUC] = {
 | 
			
		||||
		.name = "DAUC",
 | 
			
		||||
		.description = "Authentication Center",
 | 
			
		||||
		.color = "\033[1;33m",
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_DEBUG,
 | 
			
		||||
		.enabled = 1, .loglevel = LOGL_NOTICE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								src/luop.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/luop.c
									
									
									
									
									
								
							@@ -27,7 +27,6 @@
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
#include <osmocom/gsm/gsm48_ie.h>
 | 
			
		||||
#include <osmocom/gsm/gsup.h>
 | 
			
		||||
#include <osmocom/gsm/apn.h>
 | 
			
		||||
 | 
			
		||||
#include "gsup_server.h"
 | 
			
		||||
#include "gsup_router.h"
 | 
			
		||||
@@ -108,8 +107,7 @@ struct lu_operation *lu_op_alloc(struct osmo_gsup_server *srv)
 | 
			
		||||
	luop = talloc_zero(srv, struct lu_operation);
 | 
			
		||||
	OSMO_ASSERT(luop);
 | 
			
		||||
	luop->gsup_server = srv;
 | 
			
		||||
	luop->timer.cb = lu_op_timer_cb;
 | 
			
		||||
	luop->timer.data = luop;
 | 
			
		||||
	osmo_timer_setup(&luop->timer, lu_op_timer_cb, luop);
 | 
			
		||||
 | 
			
		||||
	return luop;
 | 
			
		||||
}
 | 
			
		||||
@@ -119,6 +117,10 @@ void lu_op_free(struct lu_operation *luop)
 | 
			
		||||
	/* Only attempt to remove when it was ever added to a list. */
 | 
			
		||||
	if (luop->list.next)
 | 
			
		||||
		llist_del(&luop->list);
 | 
			
		||||
 | 
			
		||||
	/* Delete timer just in case it is still pending. */
 | 
			
		||||
	osmo_timer_del(&luop->timer);
 | 
			
		||||
 | 
			
		||||
	talloc_free(luop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -230,7 +232,6 @@ void lu_op_tx_cancel_old(struct lu_operation *luop)
 | 
			
		||||
void lu_op_tx_insert_subscr_data(struct lu_operation *luop)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_gsup_message gsup;
 | 
			
		||||
	uint8_t apn[APN_MAXLEN];
 | 
			
		||||
	uint8_t msisdn_enc[43]; /* TODO use constant; TS 24.008 10.5.4.7 */
 | 
			
		||||
	int l;
 | 
			
		||||
 | 
			
		||||
@@ -251,21 +252,12 @@ void lu_op_tx_insert_subscr_data(struct lu_operation *luop)
 | 
			
		||||
	gsup.msisdn_enc = msisdn_enc;
 | 
			
		||||
	gsup.msisdn_enc_len = l;
 | 
			
		||||
 | 
			
		||||
	/* FIXME: deal with encoding the following data */
 | 
			
		||||
	gsup.hlr_enc;
 | 
			
		||||
	#pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"
 | 
			
		||||
 | 
			
		||||
	if (luop->is_ps) {
 | 
			
		||||
		/* FIXME: PDP infos - use more fine-grained access control
 | 
			
		||||
		   instead of wildcard APN */
 | 
			
		||||
		l = osmo_apn_from_str(apn, sizeof(apn), "*");
 | 
			
		||||
		if (l > 0) {
 | 
			
		||||
			gsup.pdp_infos[0].apn_enc = apn;
 | 
			
		||||
			gsup.pdp_infos[0].apn_enc_len = l;
 | 
			
		||||
			gsup.pdp_infos[0].have_info = 1;
 | 
			
		||||
			gsup.num_pdp_infos = 1;
 | 
			
		||||
			/* FIXME: use real value: */
 | 
			
		||||
			gsup.pdp_infos[0].context_id = 1;
 | 
			
		||||
		}
 | 
			
		||||
		osmo_gsup_configure_wildcard_apn(&gsup);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Send ISD to new VLR/SGSN */
 | 
			
		||||
 
 | 
			
		||||
@@ -51,10 +51,9 @@ VTY_TEST_DB = hlr_vty_test.db
 | 
			
		||||
#   make vty-test U=-u
 | 
			
		||||
vty-test:
 | 
			
		||||
	-rm -f $(VTY_TEST_DB)
 | 
			
		||||
	sqlite3 $(VTY_TEST_DB) < $(top_srcdir)/sql/hlr.sql
 | 
			
		||||
	osmo_verify_transcript_vty.py -v \
 | 
			
		||||
		-n OsmoHLR -p 4258 \
 | 
			
		||||
		-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l hlr_vty_test.db" \
 | 
			
		||||
		-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(VTY_TEST_DB)" \
 | 
			
		||||
		$(U) $(srcdir)/*.vty
 | 
			
		||||
	-rm -f $(VTY_TEST_DB)
 | 
			
		||||
 | 
			
		||||
@@ -69,7 +68,7 @@ ctrl-test:
 | 
			
		||||
	sqlite3 $(CTRL_TEST_DB) < $(srcdir)/test_subscriber.sql
 | 
			
		||||
	osmo_verify_transcript_ctrl.py -v \
 | 
			
		||||
		-p 4259 \
 | 
			
		||||
		-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l hlr_ctrl_test.db" \
 | 
			
		||||
		-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(CTRL_TEST_DB)" \
 | 
			
		||||
		$(U) $(srcdir)/*.ctrl
 | 
			
		||||
	-rm -f $(CTRL_TEST_DB)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -610,11 +610,14 @@ int main(int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	handle_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
	osmo_init_logging(&hlr_log_info);
 | 
			
		||||
	void *tall_ctx = talloc_named_const(NULL, 1, "auc_test");
 | 
			
		||||
 | 
			
		||||
	osmo_init_logging2(tall_ctx, &hlr_log_info);
 | 
			
		||||
	log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
 | 
			
		||||
	log_set_print_timestamp(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_category(osmo_stderr_target, 1);
 | 
			
		||||
	log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
 | 
			
		||||
 | 
			
		||||
	test_gen_vectors_2g_only();
 | 
			
		||||
	test_gen_vectors_2g_plus_3g();
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ DAUC vector [0]: ck = f64735036e5871319c679f4742a75ea1
 | 
			
		||||
DAUC vector [0]: ik = 27497388b6cb044648f396aa155b95ef
 | 
			
		||||
DAUC vector [0]: res = e229c19e791f2e410000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: calculating 2G separately
 | 
			
		||||
DAUC vector [0]: kc = 241a5b16aeb8e400
 | 
			
		||||
DAUC vector [0]: sres = 429d5b27
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -55,7 +55,7 @@ DAUC vector [0]: ck = f64735036e5871319c679f4742a75ea1
 | 
			
		||||
DAUC vector [0]: ik = 27497388b6cb044648f396aa155b95ef
 | 
			
		||||
DAUC vector [0]: res = e229c19e791f2e410000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: calculating 2G separately
 | 
			
		||||
DAUC vector [0]: kc = 241a5b16aeb8e400
 | 
			
		||||
DAUC vector [0]: sres = 429d5b27
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -78,6 +78,7 @@ DAUC vector [0]: ck = f64735036e5871319c679f4742a75ea1
 | 
			
		||||
DAUC vector [0]: ik = 27497388b6cb044648f396aa155b95ef
 | 
			
		||||
DAUC vector [0]: res = e229c19e791f2e410000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 059a4f668f6fbe39
 | 
			
		||||
DAUC vector [0]: sres = 9b36efdf
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -96,6 +97,7 @@ DAUC vector [0]: ck = f64735036e5871319c679f4742a75ea1
 | 
			
		||||
DAUC vector [0]: ik = 27497388b6cb044648f396aa155b95ef
 | 
			
		||||
DAUC vector [0]: res = e229c19e791f2e410000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 059a4f668f6fbe39
 | 
			
		||||
DAUC vector [0]: sres = 9b36efdf
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -117,6 +119,7 @@ DAUC vector [0]: ck = e9922bd036718ed9e40bd1d02c3b81a5
 | 
			
		||||
DAUC vector [0]: ik = f19c20ca863137f8892326d959ec5e01
 | 
			
		||||
DAUC vector [0]: res = 9af5a557902d2db80000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 7526fc13c5976685
 | 
			
		||||
DAUC vector [0]: sres = 0ad888ef
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -137,6 +140,7 @@ DAUC vector [0]: ck = e9922bd036718ed9e40bd1d02c3b81a5
 | 
			
		||||
DAUC vector [0]: ik = f19c20ca863137f8892326d959ec5e01
 | 
			
		||||
DAUC vector [0]: res = 9af5a557902d2db80000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 7526fc13c5976685
 | 
			
		||||
DAUC vector [0]: sres = 0ad888ef
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -147,6 +151,7 @@ DAUC vector [1]: ck = 3686f05df057d1899c66ae4eb18cf941
 | 
			
		||||
DAUC vector [1]: ik = 79f21ed53bcb47787de57d136ff803a5
 | 
			
		||||
DAUC vector [1]: res = 43023475cb29292c0000000000000000
 | 
			
		||||
DAUC vector [1]: res_len = 8
 | 
			
		||||
DAUC vector [1]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [1]: kc = aef73dd515e86c15
 | 
			
		||||
DAUC vector [1]: sres = 882b1d59
 | 
			
		||||
DAUC vector [1]: auth_types = 0x3
 | 
			
		||||
@@ -157,6 +162,7 @@ DAUC vector [2]: ck = d86c3191a36fc0602e48202ef2080964
 | 
			
		||||
DAUC vector [2]: ik = 648dab72016181406243420649e63dc9
 | 
			
		||||
DAUC vector [2]: res = 010cab11cc63a6e40000000000000000
 | 
			
		||||
DAUC vector [2]: res_len = 8
 | 
			
		||||
DAUC vector [2]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [2]: kc = f0eaf8cb19e0758d
 | 
			
		||||
DAUC vector [2]: sres = cd6f0df5
 | 
			
		||||
DAUC vector [2]: auth_types = 0x3
 | 
			
		||||
@@ -179,6 +185,7 @@ DAUC vector [0]: ck = e9922bd036718ed9e40bd1d02c3b81a5
 | 
			
		||||
DAUC vector [0]: ik = f19c20ca863137f8892326d959ec5e01
 | 
			
		||||
DAUC vector [0]: res = 9af5a557902d2db80000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 7526fc13c5976685
 | 
			
		||||
DAUC vector [0]: sres = 0ad888ef
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -189,6 +196,7 @@ DAUC vector [1]: ck = 3686f05df057d1899c66ae4eb18cf941
 | 
			
		||||
DAUC vector [1]: ik = 79f21ed53bcb47787de57d136ff803a5
 | 
			
		||||
DAUC vector [1]: res = 43023475cb29292c0000000000000000
 | 
			
		||||
DAUC vector [1]: res_len = 8
 | 
			
		||||
DAUC vector [1]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [1]: kc = aef73dd515e86c15
 | 
			
		||||
DAUC vector [1]: sres = 882b1d59
 | 
			
		||||
DAUC vector [1]: auth_types = 0x3
 | 
			
		||||
@@ -199,6 +207,7 @@ DAUC vector [2]: ck = d86c3191a36fc0602e48202ef2080964
 | 
			
		||||
DAUC vector [2]: ik = 648dab72016181406243420649e63dc9
 | 
			
		||||
DAUC vector [2]: res = 010cab11cc63a6e40000000000000000
 | 
			
		||||
DAUC vector [2]: res_len = 8
 | 
			
		||||
DAUC vector [2]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [2]: kc = f0eaf8cb19e0758d
 | 
			
		||||
DAUC vector [2]: sres = cd6f0df5
 | 
			
		||||
DAUC vector [2]: auth_types = 0x3
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ DAUC vector [0]: ck = b40ba9a3c58b2a05bbf0d987b21bf8cb
 | 
			
		||||
DAUC vector [0]: ik = f769bcd751044604127672711c6d3441
 | 
			
		||||
DAUC vector [0]: res = a54211d5e3ba50bf0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = eae4be823af9a08b
 | 
			
		||||
DAUC vector [0]: sres = 46f8416a
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -34,6 +35,7 @@ DAUC vector [0]: ck = 5dbdbb2954e8f3cde665b046179a5098
 | 
			
		||||
DAUC vector [0]: ik = 59a92d3b476a0443487055cf88b2307b
 | 
			
		||||
DAUC vector [0]: res = 8011c48c0c214ed20000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = aa01739b8caa976d
 | 
			
		||||
DAUC vector [0]: sres = 8c308a5e
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -56,6 +58,7 @@ DAUC vector [0]: ck = e203edb3971574f5a94b0d61b816345d
 | 
			
		||||
DAUC vector [0]: ik = 0c4524adeac041c4dd830d20854fc46b
 | 
			
		||||
DAUC vector [0]: res = f365cd683cd92e960000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 9a8ec95f408cc507
 | 
			
		||||
DAUC vector [0]: sres = cfbce3fe
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -78,6 +81,7 @@ DAUC vector [0]: ck = 7657766b373d1c2138f307e3de9242f9
 | 
			
		||||
DAUC vector [0]: ik = 1c42e960d89b8fa99f2744e0708ccb53
 | 
			
		||||
DAUC vector [0]: res = 5860fc1bce351e7e0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = cdc1dc0841b81a22
 | 
			
		||||
DAUC vector [0]: sres = 9655e265
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -100,6 +104,7 @@ DAUC vector [0]: ck = 3f8c7587fe8e4b233af676aede30ba3b
 | 
			
		||||
DAUC vector [0]: ik = a7466cc1e6b2a1337d49d3b66e95d7b4
 | 
			
		||||
DAUC vector [0]: res = 16c8233f05a0ac280000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = df75bc5ea899879f
 | 
			
		||||
DAUC vector [0]: sres = 13688f17
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -122,6 +127,7 @@ DAUC vector [0]: ck = 4cd0846020f8fa0731dd47cbdc6be411
 | 
			
		||||
DAUC vector [0]: ik = 88ab80a415f15c73711254a1d388f696
 | 
			
		||||
DAUC vector [0]: res = 8c25a16cd918a1df0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 84b417ae3aeab4f3
 | 
			
		||||
DAUC vector [0]: sres = 553d00b3
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -144,6 +150,7 @@ DAUC vector [0]: ck = 10f05bab75a99a5fbb98a9c287679c3b
 | 
			
		||||
DAUC vector [0]: ik = f9ec0865eb32f22369cade40c59c3a44
 | 
			
		||||
DAUC vector [0]: res = a63241e1ffc3e5ab0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 3b4e244cdc60ce03
 | 
			
		||||
DAUC vector [0]: sres = 59f1a44a
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -166,6 +173,7 @@ DAUC vector [0]: ck = 71236b7129f9b22ab77ea7a54c96da22
 | 
			
		||||
DAUC vector [0]: ik = 90527ebaa5588968db41727325a04d9e
 | 
			
		||||
DAUC vector [0]: res = 4a90b2171ac83a760000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 8d4ec01de597acfe
 | 
			
		||||
DAUC vector [0]: sres = 50588861
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -188,6 +196,7 @@ DAUC vector [0]: ck = 08cef6d004ec61471a3c3cda048137fa
 | 
			
		||||
DAUC vector [0]: ik = ed0318ca5deb9206272f6e8fa64ba411
 | 
			
		||||
DAUC vector [0]: res = 4bc2212d8624910a0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = d8debc4ffbcd60aa
 | 
			
		||||
DAUC vector [0]: sres = cde6b027
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -210,6 +219,7 @@ DAUC vector [0]: ck = 69b1cae7c7429d975e245cacb05a517c
 | 
			
		||||
DAUC vector [0]: ik = 74f24e8c26df58e1b38d7dcd4f1b7fbd
 | 
			
		||||
DAUC vector [0]: res = 6fc30fee6d1235230000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = f0eaa50a1edcebb7
 | 
			
		||||
DAUC vector [0]: sres = 02d13acd
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -232,6 +242,7 @@ DAUC vector [0]: ck = 908c43f0569cb8f74bc971e706c36c5f
 | 
			
		||||
DAUC vector [0]: ik = c251df0d888dd9329bcf46655b226e40
 | 
			
		||||
DAUC vector [0]: res = aefa357beac2a87a0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 82dbab7f83f063da
 | 
			
		||||
DAUC vector [0]: sres = 44389d01
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -254,6 +265,7 @@ DAUC vector [0]: ck = 44c0f23c5493cfd241e48f197e1d1012
 | 
			
		||||
DAUC vector [0]: ik = 0c9fb81613884c2535dd0eabf3b440d8
 | 
			
		||||
DAUC vector [0]: res = 98dbbd099b3b408d0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 3c66cb98cab2d33d
 | 
			
		||||
DAUC vector [0]: sres = 03e0fd84
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -276,6 +288,7 @@ DAUC vector [0]: ck = 5af86b80edb70df5292cc1121cbad50c
 | 
			
		||||
DAUC vector [0]: ik = 7f4d6ae7440e18789a8b75ad3f42f03a
 | 
			
		||||
DAUC vector [0]: res = af4a411e1139f2c20000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 9612b5d88a4130bb
 | 
			
		||||
DAUC vector [0]: sres = be73b3dc
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -298,6 +311,7 @@ DAUC vector [0]: ck = 3f8c3f3ccf7625bf77fc94bcfd22fd26
 | 
			
		||||
DAUC vector [0]: ik = abcbae8fd46115e9961a55d0da5f2078
 | 
			
		||||
DAUC vector [0]: res = 7bffa5c2f41fbc050000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 75a150df3c6aed08
 | 
			
		||||
DAUC vector [0]: sres = 8fe019c7
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -320,6 +334,7 @@ DAUC vector [0]: ck = d42b2d615e49a03ac275a5aef97af892
 | 
			
		||||
DAUC vector [0]: ik = 0b3f8d024fe6bfafaa982b8f82e319c2
 | 
			
		||||
DAUC vector [0]: res = 7e3f44c7591f6f450000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = b7f92e426a36fec5
 | 
			
		||||
DAUC vector [0]: sres = 27202b82
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -342,6 +357,7 @@ DAUC vector [0]: ck = 6edaf99e5bd9f85d5f36d91c1272fb4b
 | 
			
		||||
DAUC vector [0]: ik = d61c853c280dd9c46f297baec386de17
 | 
			
		||||
DAUC vector [0]: res = 70f6bdb9ad21525f0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 88d9de10a22004c5
 | 
			
		||||
DAUC vector [0]: sres = ddd7efe6
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -364,6 +380,7 @@ DAUC vector [0]: ck = 66195dbed0313274c5ca7766615fa25e
 | 
			
		||||
DAUC vector [0]: ik = 66bec707eb2afc476d7408a8f2927b36
 | 
			
		||||
DAUC vector [0]: res = 479dd25c20792d630000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = a819e577a8d6175b
 | 
			
		||||
DAUC vector [0]: sres = 67e4ff3f
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -386,6 +403,7 @@ DAUC vector [0]: ck = 5349fbe098649f948f5d2e973a81c00f
 | 
			
		||||
DAUC vector [0]: ik = 9744871ad32bf9bbd1dd5ce54e3e2e5a
 | 
			
		||||
DAUC vector [0]: res = 28d7b0f2a2ec3de50000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = 9a8d0e883ff0887a
 | 
			
		||||
DAUC vector [0]: sres = 8a3b8d17
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
@@ -408,6 +426,7 @@ DAUC vector [0]: ck = b5f2da03883b69f96bf52e029ed9ac45
 | 
			
		||||
DAUC vector [0]: ik = b4721368bc16ea67875c5598688bb0ef
 | 
			
		||||
DAUC vector [0]: res = a95100e2760952cd0000000000000000
 | 
			
		||||
DAUC vector [0]: res_len = 8
 | 
			
		||||
DAUC vector [0]: deriving 2G from 3G
 | 
			
		||||
DAUC vector [0]: kc = ed29b2f1c27f9f34
 | 
			
		||||
DAUC vector [0]: sres = df58522f
 | 
			
		||||
DAUC vector [0]: auth_types = 0x3
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@
 | 
			
		||||
#include <osmocom/core/application.h>
 | 
			
		||||
#include <osmocom/core/utils.h>
 | 
			
		||||
#include <osmocom/core/logging.h>
 | 
			
		||||
#include <osmocom/core/msgb.h>
 | 
			
		||||
 | 
			
		||||
#include <osmocom/crypt/auth.h>
 | 
			
		||||
 | 
			
		||||
@@ -102,11 +103,14 @@ FUNCTIONS
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
	printf("3GPP TS 55.205 Test Sets\n");
 | 
			
		||||
	osmo_init_logging(&hlr_log_info);
 | 
			
		||||
	void *tall_ctx = talloc_named_const(NULL, 1, "test");
 | 
			
		||||
	msgb_talloc_ctx_init(tall_ctx, 0);
 | 
			
		||||
	osmo_init_logging2(tall_ctx, &hlr_log_info);
 | 
			
		||||
	log_set_print_filename(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_timestamp(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_category(osmo_stderr_target, 1);
 | 
			
		||||
	log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
 | 
			
		||||
 | 
			
		||||
FUNCTION_CALLS
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,15 @@
 | 
			
		||||
AM_CPPFLAGS = \
 | 
			
		||||
AM_CFLAGS = \
 | 
			
		||||
	$(all_includes) \
 | 
			
		||||
	-I$(top_srcdir)/src \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
AM_CFLAGS = \
 | 
			
		||||
	-I$(top_builddir)/src \
 | 
			
		||||
	-Wall \
 | 
			
		||||
	-ggdb3 \
 | 
			
		||||
	$(LIBOSMOCORE_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOGSM_CFLAGS) \
 | 
			
		||||
	$(LIBOSMOABIS_CFLAGS) \
 | 
			
		||||
	$(SQLITE3_CFLAGS) \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
AM_LDFLAGS = \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = \
 | 
			
		||||
	db_test.ok \
 | 
			
		||||
	db_test.err \
 | 
			
		||||
@@ -32,6 +28,7 @@ db_test_LDADD = \
 | 
			
		||||
	$(top_srcdir)/src/logging.c \
 | 
			
		||||
	$(LIBOSMOCORE_LIBS) \
 | 
			
		||||
	$(LIBOSMOGSM_LIBS) \
 | 
			
		||||
	$(LIBOSMOABIS_LIBS) \
 | 
			
		||||
	$(SQLITE3_LIBS) \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -100,6 +100,22 @@ static void _fill_invalid(void *dest, size_t size)
 | 
			
		||||
		fprintf(stderr, "\n"); \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
#define N_VECTORS 3
 | 
			
		||||
 | 
			
		||||
#define ASSERT_DB_GET_AUC(imsi, expect_rc) \
 | 
			
		||||
	do { \
 | 
			
		||||
		struct osmo_auth_vector vec[N_VECTORS]; \
 | 
			
		||||
		ASSERT_RC(db_get_auc(dbc, imsi, 3, vec, N_VECTORS, NULL, NULL), expect_rc); \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
/* Not linking the real auc_compute_vectors(), just returning num_vec.
 | 
			
		||||
 * This gets called by db_get_auc(), but we're only interested in its rc. */
 | 
			
		||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
 | 
			
		||||
			struct osmo_sub_auth_data *aud2g,
 | 
			
		||||
			struct osmo_sub_auth_data *aud3g,
 | 
			
		||||
			const uint8_t *rand_auts, const uint8_t *auts)
 | 
			
		||||
{ return num_vec; }
 | 
			
		||||
 | 
			
		||||
static struct db_context *dbc = NULL;
 | 
			
		||||
static void *ctx = NULL;
 | 
			
		||||
static struct hlr_subscriber g_subscr;
 | 
			
		||||
@@ -457,6 +473,7 @@ static void test_subscr_aud()
 | 
			
		||||
 | 
			
		||||
	comment("Get auth data for non-existent subscriber");
 | 
			
		||||
	ASSERT_SEL_AUD(unknown_imsi, -ENOENT, 0);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOENT);
 | 
			
		||||
 | 
			
		||||
	comment("Create subscriber");
 | 
			
		||||
 | 
			
		||||
@@ -464,7 +481,8 @@ static void test_subscr_aud()
 | 
			
		||||
	ASSERT_SEL(imsi, imsi0, 0);
 | 
			
		||||
 | 
			
		||||
	id = g_subscr.id;
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOKEY);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	comment("Set auth data, 2G only");
 | 
			
		||||
@@ -473,6 +491,7 @@ static void test_subscr_aud()
 | 
			
		||||
		mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, 0, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, N_VECTORS);
 | 
			
		||||
 | 
			
		||||
	/* same again */
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
@@ -500,7 +519,8 @@ static void test_subscr_aud()
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
		mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOKEY);
 | 
			
		||||
 | 
			
		||||
	/* Removing nothing results in -ENOENT */
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
@@ -515,7 +535,8 @@ static void test_subscr_aud()
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
		mk_aud_2g(OSMO_AUTH_ALG_NONE, "f000000000000f00000000000f000000")),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOKEY);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	comment("Set auth data, 3G only");
 | 
			
		||||
@@ -526,6 +547,7 @@ static void test_subscr_aud()
 | 
			
		||||
			  "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, 0, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, N_VECTORS);
 | 
			
		||||
 | 
			
		||||
	/* same again */
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
@@ -562,7 +584,8 @@ static void test_subscr_aud()
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
		mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOKEY);
 | 
			
		||||
 | 
			
		||||
	/* Removing nothing results in -ENOENT */
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
@@ -575,13 +598,15 @@ static void test_subscr_aud()
 | 
			
		||||
			  "BeefedCafeFaceAcedAddedDecadeFee", 5)),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, 0, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, N_VECTORS);
 | 
			
		||||
 | 
			
		||||
	ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
 | 
			
		||||
		mk_aud_3g(OSMO_AUTH_ALG_NONE,
 | 
			
		||||
			  "asdfasdfasd", false,
 | 
			
		||||
			  "asdfasdfasdf", 99999)),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOKEY);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	comment("Set auth data, 2G and 3G");
 | 
			
		||||
@@ -595,6 +620,7 @@ static void test_subscr_aud()
 | 
			
		||||
			  "DeafBeddedBabeAcceededFadedDecaf", 5)),
 | 
			
		||||
		0);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, 0, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, N_VECTORS);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	comment("Set invalid auth data");
 | 
			
		||||
@@ -669,10 +695,12 @@ static void test_subscr_aud()
 | 
			
		||||
	/* For this test to work, we want to get the same subscriber ID back,
 | 
			
		||||
	 * and make sure there are no auth data leftovers for this ID. */
 | 
			
		||||
	OSMO_ASSERT(id == g_subscr.id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOKEY);
 | 
			
		||||
 | 
			
		||||
	ASSERT_RC(db_subscr_delete_by_id(dbc, id), 0);
 | 
			
		||||
	ASSERT_SEL(imsi, imsi0, -ENOENT);
 | 
			
		||||
	ASSERT_DB_GET_AUC(imsi0, -ENOENT);
 | 
			
		||||
 | 
			
		||||
	comment_end();
 | 
			
		||||
}
 | 
			
		||||
@@ -697,15 +725,15 @@ static void test_subscr_sqn()
 | 
			
		||||
	ASSERT_SEL(imsi, imsi0, 0);
 | 
			
		||||
 | 
			
		||||
	id = g_subscr.id;
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
 | 
			
		||||
	comment("Set SQN, but no 3G auth data present");
 | 
			
		||||
 | 
			
		||||
	ASSERT_RC(db_update_sqn(dbc, id, 123), -ENOENT);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
 | 
			
		||||
	ASSERT_RC(db_update_sqn(dbc, id, 543), -ENOENT);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOENT, id);
 | 
			
		||||
	ASSERT_SEL_AUD(imsi0, -ENOKEY, id);
 | 
			
		||||
 | 
			
		||||
	comment("Set auth 3G data");
 | 
			
		||||
 | 
			
		||||
@@ -811,15 +839,18 @@ int main(int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	handle_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
	osmo_init_logging(&hlr_log_info);
 | 
			
		||||
	osmo_init_logging2(ctx, &hlr_log_info);
 | 
			
		||||
	log_set_print_filename(osmo_stderr_target, cmdline_opts.verbose);
 | 
			
		||||
	log_set_print_timestamp(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_use_color(osmo_stderr_target, 0);
 | 
			
		||||
	log_set_print_category(osmo_stderr_target, 1);
 | 
			
		||||
	log_parse_category_mask(osmo_stderr_target, "DMAIN,1:DDB,1:DAUC,1");
 | 
			
		||||
 | 
			
		||||
	/* omit the SQLite version and compilation flags from test output */
 | 
			
		||||
	log_set_log_level(osmo_stderr_target, LOGL_ERROR);
 | 
			
		||||
	dbc = db_open(ctx, "db_test.db");
 | 
			
		||||
	/* Disable SQLite logging so that we're not vulnerable on SQLite error messages changing across
 | 
			
		||||
	 * library versions. */
 | 
			
		||||
	dbc = db_open(ctx, "db_test.db", false);
 | 
			
		||||
	log_set_log_level(osmo_stderr_target, 0);
 | 
			
		||||
	OSMO_ASSERT(dbc);
 | 
			
		||||
 | 
			
		||||
@@ -832,11 +863,6 @@ int main(int argc, char **argv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* stubs */
 | 
			
		||||
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
 | 
			
		||||
			struct osmo_sub_auth_data *aud2g,
 | 
			
		||||
			struct osmo_sub_auth_data *aud3g,
 | 
			
		||||
			const uint8_t *rand_auts, const uint8_t *auts)
 | 
			
		||||
{ OSMO_ASSERT(false); return -1; }
 | 
			
		||||
void *lu_op_alloc_conn(void *conn)
 | 
			
		||||
{ OSMO_ASSERT(false); return NULL; }
 | 
			
		||||
void lu_op_tx_del_subscr_data(void *luop)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@ struct hlr_subscriber {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_subscr_create(dbc, imsi0) --> -EIO
 | 
			
		||||
DDB (2067) abort at 18 in [INSERT INTO subscriber (imsi) VALUES ($imsi)]: UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
DAUC IMSI='123456789000000': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
 | 
			
		||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> 0
 | 
			
		||||
@@ -38,11 +37,9 @@ struct hlr_subscriber {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_subscr_create(dbc, imsi1) --> -EIO
 | 
			
		||||
DDB (2067) abort at 18 in [INSERT INTO subscriber (imsi) VALUES ($imsi)]: UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
 | 
			
		||||
db_subscr_create(dbc, imsi1) --> -EIO
 | 
			
		||||
DDB (2067) abort at 18 in [INSERT INTO subscriber (imsi) VALUES ($imsi)]: UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
DAUC IMSI='123456789000001': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
 | 
			
		||||
db_subscr_get_by_imsi(dbc, imsi1, &g_subscr) --> 0
 | 
			
		||||
@@ -52,11 +49,9 @@ struct hlr_subscriber {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_subscr_create(dbc, imsi2) --> -EIO
 | 
			
		||||
DDB (2067) abort at 18 in [INSERT INTO subscriber (imsi) VALUES ($imsi)]: UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
 | 
			
		||||
db_subscr_create(dbc, imsi2) --> -EIO
 | 
			
		||||
DDB (2067) abort at 18 in [INSERT INTO subscriber (imsi) VALUES ($imsi)]: UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
DAUC IMSI='123456789000002': Cannot create subscriber: SQL error: (2067) UNIQUE constraint failed: subscriber.imsi
 | 
			
		||||
 | 
			
		||||
db_subscr_get_by_imsi(dbc, imsi2, &g_subscr) --> 0
 | 
			
		||||
@@ -720,6 +715,9 @@ db_get_auth_data(dbc, unknown_imsi, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
DAUC IMSI='999999999': No such subscriber
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -2
 | 
			
		||||
DAUC IMSI='123456789000000': No such subscriber
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- Create subscriber
 | 
			
		||||
 | 
			
		||||
@@ -731,11 +729,15 @@ struct hlr_subscriber {
 | 
			
		||||
  .imsi = '123456789000000',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- Set auth data, 2G only
 | 
			
		||||
 | 
			
		||||
@@ -751,6 +753,11 @@ DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
}
 | 
			
		||||
3G: none
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': Calling to generate 3 vectors
 | 
			
		||||
DAUC IMSI='123456789000000': Generated 3 vectors
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "0123456789abcdef0123456789abcdef")) --> 0
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
 | 
			
		||||
@@ -804,11 +811,15 @@ DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> 0
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, NULL)) --> -ENOENT
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0
 | 
			
		||||
@@ -825,11 +836,15 @@ DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_NONE, "f000000000000f00000000000f000000")) --> 0
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- Set auth data, 3G only
 | 
			
		||||
 | 
			
		||||
@@ -849,6 +864,12 @@ DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
  .u.umts.ind_bitlen = 5,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': Calling to generate 3 vectors
 | 
			
		||||
DAUC IMSI='123456789000000': Generated 3 vectors
 | 
			
		||||
DAUC IMSI='123456789000000': Updating SQN=0 in DB
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCafeFaceAcedAddedDecadeFee", true, "C01ffedC1cadaeAc1d1f1edAcac1aB0a", 5)) --> 0
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
 | 
			
		||||
@@ -917,11 +938,15 @@ DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)) --> 0
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, NULL, false, NULL, 0)) --> -ENOENT
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "CededEffacedAceFacedBadFadedBeef", false, "BeefedCafeFaceAcedAddedDecadeFee", 5)) --> 0
 | 
			
		||||
@@ -940,13 +965,23 @@ DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
  .u.umts.ind_bitlen = 5,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': Calling to generate 3 vectors
 | 
			
		||||
DAUC IMSI='123456789000000': Generated 3 vectors
 | 
			
		||||
DAUC IMSI='123456789000000': Updating SQN=0 in DB
 | 
			
		||||
 | 
			
		||||
db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_NONE, "asdfasdfasd", false, "asdfasdfasdf", 99999)) --> 0
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- Set auth data, 2G and 3G
 | 
			
		||||
 | 
			
		||||
@@ -971,6 +1006,11 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
 | 
			
		||||
  .u.umts.ind_bitlen = 5,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> 3
 | 
			
		||||
DAUC IMSI='123456789000000': Calling to generate 3 vectors
 | 
			
		||||
DAUC IMSI='123456789000000': Generated 3 vectors
 | 
			
		||||
DAUC IMSI='123456789000000': Updating SQN=0 in DB
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- Set invalid auth data
 | 
			
		||||
 | 
			
		||||
@@ -1179,16 +1219,23 @@ struct hlr_subscriber {
 | 
			
		||||
  .imsi = '123456789000000',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
db_subscr_delete_by_id(dbc, id) --> 0
 | 
			
		||||
 | 
			
		||||
db_subscr_get_by_imsi(dbc, imsi0, &g_subscr) --> -ENOENT
 | 
			
		||||
DAUC Cannot read subscriber from db: IMSI='123456789000000': No such subscriber
 | 
			
		||||
 | 
			
		||||
db_get_auc(dbc, imsi0, 3, vec, N_VECTORS, NULL, NULL) --> -2
 | 
			
		||||
DAUC IMSI='123456789000000': No such subscriber
 | 
			
		||||
 | 
			
		||||
===== test_subscr_aud: SUCCESS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1219,7 +1266,7 @@ struct hlr_subscriber {
 | 
			
		||||
  .imsi = '123456789000000',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
@@ -1230,7 +1277,7 @@ DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
db_update_sqn(dbc, id, 123) --> -ENOENT
 | 
			
		||||
DAUC Cannot update SQN for subscriber ID=1: no auc_3g entry for such subscriber
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
@@ -1238,7 +1285,7 @@ DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
db_update_sqn(dbc, id, 543) --> -ENOENT
 | 
			
		||||
DAUC Cannot update SQN for subscriber ID=1: no auc_3g entry for such subscriber
 | 
			
		||||
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -2
 | 
			
		||||
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -126
 | 
			
		||||
DAUC IMSI='123456789000000': No 2G Auth Data
 | 
			
		||||
DAUC IMSI='123456789000000': No 3G Auth Data
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,9 @@ OsmoHLR> list
 | 
			
		||||
...
 | 
			
		||||
  show logging vty
 | 
			
		||||
  show alarms
 | 
			
		||||
  show talloc-context (application|all) (full|brief|DEPTH)
 | 
			
		||||
  show talloc-context (application|all) (full|brief|DEPTH) tree ADDRESS
 | 
			
		||||
  show talloc-context (application|all) (full|brief|DEPTH) filter REGEXP
 | 
			
		||||
  subscriber (imsi|msisdn|id) IDENT show
 | 
			
		||||
 | 
			
		||||
OsmoHLR> enable
 | 
			
		||||
@@ -100,10 +103,11 @@ log stderr
 | 
			
		||||
  logging color 1
 | 
			
		||||
  logging print category 1
 | 
			
		||||
  logging print extended-timestamp 1
 | 
			
		||||
  logging print file 1
 | 
			
		||||
  logging level all debug
 | 
			
		||||
  logging level main debug
 | 
			
		||||
  logging level db debug
 | 
			
		||||
  logging level auc debug
 | 
			
		||||
  logging level main notice
 | 
			
		||||
  logging level db notice
 | 
			
		||||
  logging level auc notice
 | 
			
		||||
...
 | 
			
		||||
!
 | 
			
		||||
line vty
 | 
			
		||||
 
 | 
			
		||||
@@ -1,27 +1,614 @@
 | 
			
		||||
GET 1 invalid
 | 
			
		||||
ERROR 1 Command not found
 | 
			
		||||
SET 2 invalid nonsense
 | 
			
		||||
ERROR 2 Command not found
 | 
			
		||||
GET 1 subscriber.by-imsi-901990000000001.info
 | 
			
		||||
GET_REPLY 1 subscriber.by-imsi-901990000000001.info 
 | 
			
		||||
id	1
 | 
			
		||||
imsi	901990000000001
 | 
			
		||||
msisdn	1
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 3 enable-ps 901990000000001
 | 
			
		||||
SET_REPLY 3 enable-ps OK
 | 
			
		||||
SET 4 status-ps 901990000000001
 | 
			
		||||
SET_REPLY 4 status-ps 1
 | 
			
		||||
SET 5 enable-ps 901990000000001
 | 
			
		||||
SET_REPLY 5 enable-ps OK
 | 
			
		||||
SET 6 status-ps 901990000000001
 | 
			
		||||
SET_REPLY 6 status-ps 1
 | 
			
		||||
GET 2 subscriber.by-imsi-901990000000001.info-aud
 | 
			
		||||
GET_REPLY 2 subscriber.by-imsi-901990000000001.info-aud 
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
 | 
			
		||||
SET 7 disable-ps 901990000000001
 | 
			
		||||
SET_REPLY 7 disable-ps OK
 | 
			
		||||
SET 8 status-ps 901990000000001
 | 
			
		||||
SET_REPLY 8 status-ps 0
 | 
			
		||||
SET 9 disable-ps 901990000000001
 | 
			
		||||
SET_REPLY 9 disable-ps OK
 | 
			
		||||
SET 10 status-ps 901990000000001
 | 
			
		||||
SET_REPLY 10 status-ps 0
 | 
			
		||||
GET 3 subscriber.by-imsi-901990000000001.info-all
 | 
			
		||||
GET_REPLY 3 subscriber.by-imsi-901990000000001.info-all 
 | 
			
		||||
id	1
 | 
			
		||||
imsi	901990000000001
 | 
			
		||||
msisdn	1
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
 | 
			
		||||
SET 11 enable-ps 901990000000001
 | 
			
		||||
SET_REPLY 11 enable-ps OK
 | 
			
		||||
SET 12 status-ps 901990000000001
 | 
			
		||||
SET_REPLY 12 status-ps 1
 | 
			
		||||
GET 4 subscriber.by-imsi-901990000000002.info
 | 
			
		||||
GET_REPLY 4 subscriber.by-imsi-901990000000002.info 
 | 
			
		||||
id	2
 | 
			
		||||
imsi	901990000000002
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
GET 5 subscriber.by-imsi-901990000000002.info-aud
 | 
			
		||||
GET_REPLY 5 subscriber.by-imsi-901990000000002.info-aud 
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	4223
 | 
			
		||||
 | 
			
		||||
GET 6 subscriber.by-imsi-901990000000002.info-all
 | 
			
		||||
GET_REPLY 6 subscriber.by-imsi-901990000000002.info-all 
 | 
			
		||||
id	2
 | 
			
		||||
imsi	901990000000002
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	4223
 | 
			
		||||
 | 
			
		||||
GET 7 subscriber.by-imsi-901990000000003.info
 | 
			
		||||
GET_REPLY 7 subscriber.by-imsi-901990000000003.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
GET 8 subscriber.by-imsi-901990000000003.info-aud
 | 
			
		||||
GET_REPLY 8 subscriber.by-imsi-901990000000003.info-aud 
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	2342
 | 
			
		||||
 | 
			
		||||
GET 9 subscriber.by-imsi-901990000000003.info-all
 | 
			
		||||
GET_REPLY 9 subscriber.by-imsi-901990000000003.info-all 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	2342
 | 
			
		||||
 | 
			
		||||
GET 10 subscriber.by-imsi-901990000000003.ps-enabled
 | 
			
		||||
GET_REPLY 10 subscriber.by-imsi-901990000000003.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 11 subscriber.by-imsi-901990000000003.ps-enabled 0
 | 
			
		||||
SET_REPLY 11 subscriber.by-imsi-901990000000003.ps-enabled OK
 | 
			
		||||
GET 12 subscriber.by-imsi-901990000000003.ps-enabled
 | 
			
		||||
GET_REPLY 12 subscriber.by-imsi-901990000000003.ps-enabled 0
 | 
			
		||||
 | 
			
		||||
GET 13 subscriber.by-imsi-901990000000003.info
 | 
			
		||||
GET_REPLY 13 subscriber.by-imsi-901990000000003.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	0
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 14 subscriber.by-imsi-901990000000003.ps-enabled 0
 | 
			
		||||
SET_REPLY 14 subscriber.by-imsi-901990000000003.ps-enabled OK
 | 
			
		||||
GET 15 subscriber.by-imsi-901990000000003.ps-enabled
 | 
			
		||||
GET_REPLY 15 subscriber.by-imsi-901990000000003.ps-enabled 0
 | 
			
		||||
 | 
			
		||||
SET 16 subscriber.by-imsi-901990000000003.ps-enabled 1
 | 
			
		||||
SET_REPLY 16 subscriber.by-imsi-901990000000003.ps-enabled OK
 | 
			
		||||
GET 17 subscriber.by-imsi-901990000000003.ps-enabled
 | 
			
		||||
GET_REPLY 17 subscriber.by-imsi-901990000000003.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 18 subscriber.by-imsi-901990000000003.info
 | 
			
		||||
GET_REPLY 18 subscriber.by-imsi-901990000000003.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 19 subscriber.by-imsi-901990000000003.ps-enabled 1
 | 
			
		||||
SET_REPLY 19 subscriber.by-imsi-901990000000003.ps-enabled OK
 | 
			
		||||
GET 20 subscriber.by-imsi-901990000000003.ps-enabled
 | 
			
		||||
GET_REPLY 20 subscriber.by-imsi-901990000000003.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 21 subscriber.by-imsi-901990000000003.cs-enabled
 | 
			
		||||
GET_REPLY 21 subscriber.by-imsi-901990000000003.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 22 subscriber.by-imsi-901990000000003.cs-enabled 0
 | 
			
		||||
SET_REPLY 22 subscriber.by-imsi-901990000000003.cs-enabled OK
 | 
			
		||||
GET 23 subscriber.by-imsi-901990000000003.cs-enabled
 | 
			
		||||
GET_REPLY 23 subscriber.by-imsi-901990000000003.cs-enabled 0
 | 
			
		||||
 | 
			
		||||
GET 24 subscriber.by-imsi-901990000000003.info
 | 
			
		||||
GET_REPLY 24 subscriber.by-imsi-901990000000003.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	0
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 25 subscriber.by-imsi-901990000000003.cs-enabled 0
 | 
			
		||||
SET_REPLY 25 subscriber.by-imsi-901990000000003.cs-enabled OK
 | 
			
		||||
GET 26 subscriber.by-imsi-901990000000003.cs-enabled
 | 
			
		||||
GET_REPLY 26 subscriber.by-imsi-901990000000003.cs-enabled 0
 | 
			
		||||
 | 
			
		||||
SET 27 subscriber.by-imsi-901990000000003.cs-enabled 1
 | 
			
		||||
SET_REPLY 27 subscriber.by-imsi-901990000000003.cs-enabled OK
 | 
			
		||||
GET 28 subscriber.by-imsi-901990000000003.cs-enabled
 | 
			
		||||
GET_REPLY 28 subscriber.by-imsi-901990000000003.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 29 subscriber.by-imsi-901990000000003.info
 | 
			
		||||
GET_REPLY 29 subscriber.by-imsi-901990000000003.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 30 subscriber.by-imsi-901990000000003.cs-enabled 1
 | 
			
		||||
SET_REPLY 30 subscriber.by-imsi-901990000000003.cs-enabled OK
 | 
			
		||||
GET 31 subscriber.by-imsi-901990000000003.cs-enabled
 | 
			
		||||
GET_REPLY 31 subscriber.by-imsi-901990000000003.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 32 subscriber.by-imsi-901990000000003.ps-enabled 0
 | 
			
		||||
SET_REPLY 32 subscriber.by-imsi-901990000000003.ps-enabled OK
 | 
			
		||||
SET 33 subscriber.by-imsi-901990000000003.cs-enabled 0
 | 
			
		||||
SET_REPLY 33 subscriber.by-imsi-901990000000003.cs-enabled OK
 | 
			
		||||
GET 34 subscriber.by-imsi-901990000000003.info
 | 
			
		||||
GET_REPLY 34 subscriber.by-imsi-901990000000003.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	0
 | 
			
		||||
nam_ps	0
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 35 subscriber.by-imsi-901990000000003.ps-enabled 1
 | 
			
		||||
SET_REPLY 35 subscriber.by-imsi-901990000000003.ps-enabled OK
 | 
			
		||||
SET 36 subscriber.by-imsi-901990000000003.cs-enabled 1
 | 
			
		||||
SET_REPLY 36 subscriber.by-imsi-901990000000003.cs-enabled OK
 | 
			
		||||
GET 37 subscriber.by-imsi-901990000000003.info
 | 
			
		||||
GET_REPLY 37 subscriber.by-imsi-901990000000003.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GET 38 subscriber.by-msisdn-103.info
 | 
			
		||||
GET_REPLY 38 subscriber.by-msisdn-103.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
GET 39 subscriber.by-msisdn-103.info-aud
 | 
			
		||||
GET_REPLY 39 subscriber.by-msisdn-103.info-aud 
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	2342
 | 
			
		||||
 | 
			
		||||
GET 40 subscriber.by-msisdn-103.info-all
 | 
			
		||||
GET_REPLY 40 subscriber.by-msisdn-103.info-all 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	2342
 | 
			
		||||
 | 
			
		||||
GET 41 subscriber.by-msisdn-103.ps-enabled
 | 
			
		||||
GET_REPLY 41 subscriber.by-msisdn-103.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 42 subscriber.by-msisdn-103.ps-enabled 0
 | 
			
		||||
SET_REPLY 42 subscriber.by-msisdn-103.ps-enabled OK
 | 
			
		||||
GET 43 subscriber.by-msisdn-103.ps-enabled
 | 
			
		||||
GET_REPLY 43 subscriber.by-msisdn-103.ps-enabled 0
 | 
			
		||||
 | 
			
		||||
GET 44 subscriber.by-msisdn-103.info
 | 
			
		||||
GET_REPLY 44 subscriber.by-msisdn-103.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	0
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 45 subscriber.by-msisdn-103.ps-enabled 0
 | 
			
		||||
SET_REPLY 45 subscriber.by-msisdn-103.ps-enabled OK
 | 
			
		||||
GET 46 subscriber.by-msisdn-103.ps-enabled
 | 
			
		||||
GET_REPLY 46 subscriber.by-msisdn-103.ps-enabled 0
 | 
			
		||||
 | 
			
		||||
SET 47 subscriber.by-msisdn-103.ps-enabled 1
 | 
			
		||||
SET_REPLY 47 subscriber.by-msisdn-103.ps-enabled OK
 | 
			
		||||
GET 48 subscriber.by-msisdn-103.ps-enabled
 | 
			
		||||
GET_REPLY 48 subscriber.by-msisdn-103.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 49 subscriber.by-msisdn-103.info
 | 
			
		||||
GET_REPLY 49 subscriber.by-msisdn-103.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 50 subscriber.by-msisdn-103.ps-enabled 1
 | 
			
		||||
SET_REPLY 50 subscriber.by-msisdn-103.ps-enabled OK
 | 
			
		||||
GET 51 subscriber.by-msisdn-103.ps-enabled
 | 
			
		||||
GET_REPLY 51 subscriber.by-msisdn-103.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 52 subscriber.by-msisdn-103.cs-enabled
 | 
			
		||||
GET_REPLY 52 subscriber.by-msisdn-103.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 53 subscriber.by-msisdn-103.cs-enabled 0
 | 
			
		||||
SET_REPLY 53 subscriber.by-msisdn-103.cs-enabled OK
 | 
			
		||||
GET 54 subscriber.by-msisdn-103.cs-enabled
 | 
			
		||||
GET_REPLY 54 subscriber.by-msisdn-103.cs-enabled 0
 | 
			
		||||
 | 
			
		||||
GET 55 subscriber.by-msisdn-103.info
 | 
			
		||||
GET_REPLY 55 subscriber.by-msisdn-103.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	0
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 56 subscriber.by-msisdn-103.cs-enabled 0
 | 
			
		||||
SET_REPLY 56 subscriber.by-msisdn-103.cs-enabled OK
 | 
			
		||||
GET 57 subscriber.by-msisdn-103.cs-enabled
 | 
			
		||||
GET_REPLY 57 subscriber.by-msisdn-103.cs-enabled 0
 | 
			
		||||
 | 
			
		||||
SET 58 subscriber.by-msisdn-103.cs-enabled 1
 | 
			
		||||
SET_REPLY 58 subscriber.by-msisdn-103.cs-enabled OK
 | 
			
		||||
GET 59 subscriber.by-msisdn-103.cs-enabled
 | 
			
		||||
GET_REPLY 59 subscriber.by-msisdn-103.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 60 subscriber.by-msisdn-103.info
 | 
			
		||||
GET_REPLY 60 subscriber.by-msisdn-103.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 61 subscriber.by-msisdn-103.cs-enabled 1
 | 
			
		||||
SET_REPLY 61 subscriber.by-msisdn-103.cs-enabled OK
 | 
			
		||||
GET 62 subscriber.by-msisdn-103.cs-enabled
 | 
			
		||||
GET_REPLY 62 subscriber.by-msisdn-103.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 63 subscriber.by-msisdn-103.ps-enabled 0
 | 
			
		||||
SET_REPLY 63 subscriber.by-msisdn-103.ps-enabled OK
 | 
			
		||||
SET 64 subscriber.by-msisdn-103.cs-enabled 0
 | 
			
		||||
SET_REPLY 64 subscriber.by-msisdn-103.cs-enabled OK
 | 
			
		||||
GET 65 subscriber.by-msisdn-103.info
 | 
			
		||||
GET_REPLY 65 subscriber.by-msisdn-103.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	0
 | 
			
		||||
nam_ps	0
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 66 subscriber.by-msisdn-103.ps-enabled 1
 | 
			
		||||
SET_REPLY 66 subscriber.by-msisdn-103.ps-enabled OK
 | 
			
		||||
SET 67 subscriber.by-msisdn-103.cs-enabled 1
 | 
			
		||||
SET_REPLY 67 subscriber.by-msisdn-103.cs-enabled OK
 | 
			
		||||
GET 68 subscriber.by-msisdn-103.info
 | 
			
		||||
GET_REPLY 68 subscriber.by-msisdn-103.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GET 69 subscriber.by-id-3.info
 | 
			
		||||
GET_REPLY 69 subscriber.by-id-3.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
GET 70 subscriber.by-id-3.info-aud
 | 
			
		||||
GET_REPLY 70 subscriber.by-id-3.info-aud 
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	2342
 | 
			
		||||
 | 
			
		||||
GET 71 subscriber.by-id-3.info-all
 | 
			
		||||
GET_REPLY 71 subscriber.by-id-3.info-all 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
aud2g.algo	COMP128v1
 | 
			
		||||
aud2g.ki	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.algo	MILENAGE
 | 
			
		||||
aud3g.k	000102030405060708090a0b0c0d0e0f
 | 
			
		||||
aud3g.opc	101112131415161718191a1b1c1d1e1f
 | 
			
		||||
aud3g.ind_bitlen	5
 | 
			
		||||
aud3g.sqn	2342
 | 
			
		||||
 | 
			
		||||
GET 72 subscriber.by-id-3.ps-enabled
 | 
			
		||||
GET_REPLY 72 subscriber.by-id-3.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 73 subscriber.by-id-3.ps-enabled 0
 | 
			
		||||
SET_REPLY 73 subscriber.by-id-3.ps-enabled OK
 | 
			
		||||
GET 74 subscriber.by-id-3.ps-enabled
 | 
			
		||||
GET_REPLY 74 subscriber.by-id-3.ps-enabled 0
 | 
			
		||||
 | 
			
		||||
GET 75 subscriber.by-id-3.info
 | 
			
		||||
GET_REPLY 75 subscriber.by-id-3.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	0
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 76 subscriber.by-id-3.ps-enabled 0
 | 
			
		||||
SET_REPLY 76 subscriber.by-id-3.ps-enabled OK
 | 
			
		||||
GET 77 subscriber.by-id-3.ps-enabled
 | 
			
		||||
GET_REPLY 77 subscriber.by-id-3.ps-enabled 0
 | 
			
		||||
 | 
			
		||||
SET 78 subscriber.by-id-3.ps-enabled 1
 | 
			
		||||
SET_REPLY 78 subscriber.by-id-3.ps-enabled OK
 | 
			
		||||
GET 79 subscriber.by-id-3.ps-enabled
 | 
			
		||||
GET_REPLY 79 subscriber.by-id-3.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 80 subscriber.by-id-3.info
 | 
			
		||||
GET_REPLY 80 subscriber.by-id-3.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 81 subscriber.by-id-3.ps-enabled 1
 | 
			
		||||
SET_REPLY 81 subscriber.by-id-3.ps-enabled OK
 | 
			
		||||
GET 82 subscriber.by-id-3.ps-enabled
 | 
			
		||||
GET_REPLY 82 subscriber.by-id-3.ps-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 83 subscriber.by-id-3.cs-enabled
 | 
			
		||||
GET_REPLY 83 subscriber.by-id-3.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 84 subscriber.by-id-3.cs-enabled 0
 | 
			
		||||
SET_REPLY 84 subscriber.by-id-3.cs-enabled OK
 | 
			
		||||
GET 85 subscriber.by-id-3.cs-enabled
 | 
			
		||||
GET_REPLY 85 subscriber.by-id-3.cs-enabled 0
 | 
			
		||||
 | 
			
		||||
GET 86 subscriber.by-id-3.info
 | 
			
		||||
GET_REPLY 86 subscriber.by-id-3.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	0
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 87 subscriber.by-id-3.cs-enabled 0
 | 
			
		||||
SET_REPLY 87 subscriber.by-id-3.cs-enabled OK
 | 
			
		||||
GET 88 subscriber.by-id-3.cs-enabled
 | 
			
		||||
GET_REPLY 88 subscriber.by-id-3.cs-enabled 0
 | 
			
		||||
 | 
			
		||||
SET 89 subscriber.by-id-3.cs-enabled 1
 | 
			
		||||
SET_REPLY 89 subscriber.by-id-3.cs-enabled OK
 | 
			
		||||
GET 90 subscriber.by-id-3.cs-enabled
 | 
			
		||||
GET_REPLY 90 subscriber.by-id-3.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
GET 91 subscriber.by-id-3.info
 | 
			
		||||
GET_REPLY 91 subscriber.by-id-3.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 92 subscriber.by-id-3.cs-enabled 1
 | 
			
		||||
SET_REPLY 92 subscriber.by-id-3.cs-enabled OK
 | 
			
		||||
GET 93 subscriber.by-id-3.cs-enabled
 | 
			
		||||
GET_REPLY 93 subscriber.by-id-3.cs-enabled 1
 | 
			
		||||
 | 
			
		||||
SET 94 subscriber.by-id-3.ps-enabled 0
 | 
			
		||||
SET_REPLY 94 subscriber.by-id-3.ps-enabled OK
 | 
			
		||||
SET 95 subscriber.by-id-3.cs-enabled 0
 | 
			
		||||
SET_REPLY 95 subscriber.by-id-3.cs-enabled OK
 | 
			
		||||
GET 96 subscriber.by-id-3.info
 | 
			
		||||
GET_REPLY 96 subscriber.by-id-3.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	0
 | 
			
		||||
nam_ps	0
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
SET 97 subscriber.by-id-3.ps-enabled 1
 | 
			
		||||
SET_REPLY 97 subscriber.by-id-3.ps-enabled OK
 | 
			
		||||
SET 98 subscriber.by-id-3.cs-enabled 1
 | 
			
		||||
SET_REPLY 98 subscriber.by-id-3.cs-enabled OK
 | 
			
		||||
GET 99 subscriber.by-id-3.info
 | 
			
		||||
GET_REPLY 99 subscriber.by-id-3.info 
 | 
			
		||||
id	3
 | 
			
		||||
imsi	901990000000003
 | 
			
		||||
msisdn	103
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
GET 100 subscriber.by-id-00123.info
 | 
			
		||||
GET_REPLY 100 subscriber.by-id-00123.info 
 | 
			
		||||
id	123
 | 
			
		||||
imsi	123123
 | 
			
		||||
msisdn	123
 | 
			
		||||
nam_cs	1
 | 
			
		||||
nam_ps	1
 | 
			
		||||
ms_purged_cs	0
 | 
			
		||||
ms_purged_ps	0
 | 
			
		||||
periodic_lu_timer	0
 | 
			
		||||
periodic_rau_tau_timer	0
 | 
			
		||||
lmsi	00000000
 | 
			
		||||
 | 
			
		||||
GET 101 subscriber.by-id-0x0123.info
 | 
			
		||||
ERROR 101 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,17 @@
 | 
			
		||||
 | 
			
		||||
-- 2G only subscriber
 | 
			
		||||
INSERT INTO subscriber (id, imsi) VALUES (1, '901990000000001');
 | 
			
		||||
INSERT INTO subscriber (id, imsi, msisdn) VALUES (1, '901990000000001', '1');
 | 
			
		||||
INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki) VALUES (1, 1, '000102030405060708090a0b0c0d0e0f');
 | 
			
		||||
 | 
			
		||||
-- 3G only subscriber
 | 
			
		||||
INSERT INTO subscriber (id, imsi) VALUES (2, '901990000000002');
 | 
			
		||||
INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (2, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 0);
 | 
			
		||||
INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (2, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 4223);
 | 
			
		||||
 | 
			
		||||
-- 2G + 3G subscriber
 | 
			
		||||
INSERT INTO subscriber (id, imsi) VALUES (3, '901990000000003');
 | 
			
		||||
INSERT INTO subscriber (id, imsi, msisdn) VALUES (3, '901990000000003', '103');
 | 
			
		||||
INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki) VALUES (3, 1, '000102030405060708090a0b0c0d0e0f');
 | 
			
		||||
INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (3, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 0);
 | 
			
		||||
INSERT INTO auc_3g (subscriber_id, algo_id_3g, k, opc, sqn) VALUES (3, 5, '000102030405060708090a0b0c0d0e0f', '101112131415161718191a1b1c1d1e1f', 2342);
 | 
			
		||||
 | 
			
		||||
-- A subscriber id > 7 and > 15 to check against octal and hex notations
 | 
			
		||||
INSERT INTO subscriber (id, imsi, msisdn) VALUES (123, '123123', '123');
 | 
			
		||||
INSERT INTO auc_2g (subscriber_id, algo_id_2g, ki) VALUES (123, 3, 'BeefedCafeFaceAcedAddedDecadeFee');
 | 
			
		||||
 
 | 
			
		||||
@@ -305,6 +305,7 @@ OsmoHLR# subscriber imsi 123456789023000 show
 | 
			
		||||
             OPC=cededeffacedacefacedbadfadedbeef
 | 
			
		||||
             IND-bitlen=23
 | 
			
		||||
 | 
			
		||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d op C01ffedC1cadaeAc1d1f1edAcac1aB0a
 | 
			
		||||
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d op CoiffedCicadaeAcidifiedAcaciaBoa
 | 
			
		||||
% Invalid value for OP: 'CoiffedCicadaeAcidifiedAcaciaBoa'
 | 
			
		||||
OsmoHLR# subscriber imsi 123456789023000 show
 | 
			
		||||
@@ -313,8 +314,8 @@ OsmoHLR# subscriber imsi 123456789023000 show
 | 
			
		||||
    MSISDN: 423
 | 
			
		||||
    3G auth: MILENAGE
 | 
			
		||||
             K=deaf0ff1ced0d0dabbedd1ced1cef00d
 | 
			
		||||
             OPC=cededeffacedacefacedbadfadedbeef
 | 
			
		||||
             IND-bitlen=23
 | 
			
		||||
             OP=c01ffedc1cadaeac1d1f1edacac1ab0a
 | 
			
		||||
             IND-bitlen=5
 | 
			
		||||
 | 
			
		||||
OsmoHLR# subscriber id 1 update aud2g comp128v2 ki CededEffacedAceFacedBadFadedBeef
 | 
			
		||||
OsmoHLR# subscriber id 1 show
 | 
			
		||||
@@ -325,8 +326,8 @@ OsmoHLR# subscriber id 1 show
 | 
			
		||||
             KI=cededeffacedacefacedbadfadedbeef
 | 
			
		||||
    3G auth: MILENAGE
 | 
			
		||||
             K=deaf0ff1ced0d0dabbedd1ced1cef00d
 | 
			
		||||
             OPC=cededeffacedacefacedbadfadedbeef
 | 
			
		||||
             IND-bitlen=23
 | 
			
		||||
             OP=c01ffedc1cadaeac1d1f1edacac1ab0a
 | 
			
		||||
             IND-bitlen=5
 | 
			
		||||
 | 
			
		||||
OsmoHLR# subscriber imsi 123456789023000 delete
 | 
			
		||||
% Deleted subscriber for IMSI '123456789023000'
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										107
									
								
								tests/test_subscriber_errors.ctrl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								tests/test_subscriber_errors.ctrl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
GET 1 invalid
 | 
			
		||||
ERROR 1 Command not found
 | 
			
		||||
SET 2 invalid nonsense
 | 
			
		||||
ERROR 2 Command not found
 | 
			
		||||
 | 
			
		||||
GET 3 subscriber.by-imsi-nonsense.info
 | 
			
		||||
ERROR 3 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 4 subscriber.by-msisdn-nonsense.info
 | 
			
		||||
ERROR 4 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 5 subscriber.by-id-nonsense.info
 | 
			
		||||
ERROR 5 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
 | 
			
		||||
GET 6 subscriber
 | 
			
		||||
ERROR 6 Command not present.
 | 
			
		||||
GET 7 subscriber.
 | 
			
		||||
ERROR 7 Command not present.
 | 
			
		||||
GET 8 subscriber.by-nonsense
 | 
			
		||||
ERROR 8 Command not present.
 | 
			
		||||
GET 9 subscriber.by-nonsense-
 | 
			
		||||
ERROR 9 Command not present.
 | 
			
		||||
GET 10 subscriber.by-nonsense-123456
 | 
			
		||||
ERROR 10 Command not present.
 | 
			
		||||
GET 11 subscriber.by-nonsense-123456.
 | 
			
		||||
ERROR 11 Command not present.
 | 
			
		||||
GET 12 subscriber.by-imsi-
 | 
			
		||||
ERROR 12 Command not present.
 | 
			
		||||
GET 13 subscriber.by-imsi-.
 | 
			
		||||
ERROR 13 Command not present.
 | 
			
		||||
GET 14 subscriber.by-imsi-901990000000003
 | 
			
		||||
ERROR 14 Command not present.
 | 
			
		||||
GET 15 subscriber.by-imsi-901990000000003.
 | 
			
		||||
ERROR 15 Command not present.
 | 
			
		||||
 | 
			
		||||
GET 16 subscriber.by-nonsense-123456.info
 | 
			
		||||
ERROR 16 Not a known subscriber 'by-xxx-' selector.
 | 
			
		||||
GET 17 subscriber.by-123456.info
 | 
			
		||||
ERROR 17 Not a known subscriber 'by-xxx-' selector.
 | 
			
		||||
 | 
			
		||||
GET 18 subscriber.by-imsi-.info
 | 
			
		||||
ERROR 18 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 19 subscriber.by-imsi--.info
 | 
			
		||||
ERROR 19 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
 | 
			
		||||
GET 20 subscriber.by-imsi-12345678901234567.info
 | 
			
		||||
ERROR 20 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 21 subscriber.by-imsi-12345.info
 | 
			
		||||
ERROR 21 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 22 subscriber.by-imsi-1234567890123456.info
 | 
			
		||||
ERROR 22 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
 | 
			
		||||
GET 23 subscriber.by-id-99999999999999999999999999.info
 | 
			
		||||
ERROR 23 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 24 subscriber.by-id-9223372036854775807.info
 | 
			
		||||
ERROR 24 No such subscriber.
 | 
			
		||||
GET 25 subscriber.by-id-9223372036854775808.info
 | 
			
		||||
ERROR 25 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 26 subscriber.by-id--1.info
 | 
			
		||||
ERROR 26 No such subscriber.
 | 
			
		||||
GET 27 subscriber.by-id--9223372036854775808.info
 | 
			
		||||
ERROR 27 No such subscriber.
 | 
			
		||||
GET 28 subscriber.by-id--9223372036854775809.info
 | 
			
		||||
ERROR 28 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
 | 
			
		||||
GET 29 subscriber.by-id-1+1.info
 | 
			
		||||
ERROR 29 GET variable contains invalid characters
 | 
			
		||||
GET 30 subscriber.by-id--.info
 | 
			
		||||
ERROR 30 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 31 subscriber.by-id-+1.info
 | 
			
		||||
ERROR 31 GET variable contains invalid characters
 | 
			
		||||
GET 32 subscriber.by-id-+-1.info
 | 
			
		||||
ERROR 32 GET variable contains invalid characters
 | 
			
		||||
GET 33 subscriber.by-id--+1.info
 | 
			
		||||
ERROR 33 GET variable contains invalid characters
 | 
			
		||||
GET 34 subscriber.by-id-++1.info
 | 
			
		||||
ERROR 34 GET variable contains invalid characters
 | 
			
		||||
GET 35 subscriber.by-id---1.info
 | 
			
		||||
ERROR 35 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
 | 
			
		||||
GET 36 subscriber.by-id- 1.info
 | 
			
		||||
ERROR 36 GET with trailing characters
 | 
			
		||||
GET 37 subscriber.by-id-+ 1.info
 | 
			
		||||
ERROR 37 GET variable contains invalid characters
 | 
			
		||||
GET 38 subscriber.by-id-- 1.info
 | 
			
		||||
ERROR 38 GET with trailing characters
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SET 39 subscriber.by-imsi-901990000000001.info foo
 | 
			
		||||
ERROR 39 Read Only attribute
 | 
			
		||||
SET 40 subscriber.by-imsi-901990000000001.info-aud foo
 | 
			
		||||
ERROR 40 Read Only attribute
 | 
			
		||||
SET 41 subscriber.by-imsi-901990000000001.info-all foo
 | 
			
		||||
ERROR 41 Read Only attribute
 | 
			
		||||
 | 
			
		||||
SET 42 subscriber.by-imsi-901990000000001.ps-enabled nonsense
 | 
			
		||||
ERROR 42 Value failed verification.
 | 
			
		||||
SET 43 subscriber.by-imsi-901990000000001.cs-enabled nonsense
 | 
			
		||||
ERROR 43 Value failed verification.
 | 
			
		||||
 | 
			
		||||
SET 44 subscriber.by-imsi-901990000000001.ps-enabled
 | 
			
		||||
ERROR 44 SET incomplete
 | 
			
		||||
SET 45 subscriber.by-imsi-901990000000001.cs-enabled
 | 
			
		||||
ERROR 45 SET incomplete
 | 
			
		||||
 | 
			
		||||
GET 46 subscriber.by-imsi-1234567890123456.ps-enabled
 | 
			
		||||
ERROR 46 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
GET 47 subscriber.by-imsi-1234567890123456.cs-enabled
 | 
			
		||||
ERROR 47 Invalid value part of 'by-xxx-value' selector.
 | 
			
		||||
		Reference in New Issue
	
	Block a user