Compare commits

..

41 Commits
1.5.1 ... 1.7.0

Author SHA1 Message Date
Pau Espin Pedrol
d052f076e3 Bump version: 1.6.0.20-37f0-dirty → 1.7.0
Change-Id: I3f169ff8f9b10a4d4b5c50286951d326fa713245
2023-09-12 14:41:34 +02:00
Alexander Couzens
37f0b3a8f3 Add support for multiple APN profiles for subscriber data
Previously the HLR sent in the Insert Subscriber Data call only the
wildcard APN as a single entry.
This violates the spec because the first entry (with the lowest context_id) is
always the default APN, but it is forbidden to have a wildcard APN as default apn.

Introduce a default template/profile which can contain multiple APNs.
This profile is always sent out to the SGSN/MME as part of Insert-Subscriber-Data.
In the future a subscriber might have a profile template name written into the
database which will resolve to a "pdp-profile premium" in the configuration.

To be backward compatible, if the pdp-profile default section is missing,
the HLR will send out only a wildcard APN.

Config example:

hlr
 ps
  pdp-profile default
   profile 1
    apn internet
   profile 2
    apn *

Changes to the apn list will be only handed out to subscribers
when the subscriber do a location update.

Related: SYS#6391
Change-Id: I540132ee5dcfd09f4816e02e702927e1074ca50f
2023-09-12 09:48:02 +00:00
Harald Welte
7a763aa012 Add VTY support for TUAK algorithm
Change-Id: If2611658f7cb990b484d7429ab2f944f56fd2eb6
Depends: libosmocore.git Ib905b8d8bdf248e8299bf50666ee1bca8298433d
2023-08-29 13:42:41 +00:00
Harald Welte
626f5eb740 db: extend database schema to support 256bit K and/or OP[c] values
Other UMTS AKA algorithms than MILENAGE (notably TUAK) support K sizes
of up to 256bit, or mandate a OP/OPc size of 256 bit.

Let's extend our database schema to accommodate such larger sizes.

Change-Id: Ibbde68484c904507a15c35cbfdf88cd47d0c7039
2023-08-29 13:42:41 +00:00
Vadim Yanitskiy
5800f3add5 USSD: fix handling of ussd-DataCodingScheme != 0x0f
The usual Data Coding Scheme value in the mobile-originated USSD
request (processUnstructuredSS-Request) is 0x0f, which means:

  0000 .... = Coding Group: Coding Group 0 (Language using the GSM 7 bit default alphabet)
  .... 1111 = Language: unspecified

However some modems are known to use a different default value, if
not specified explicitly (AT+CUSD has optional DCS parameter):

  0000 .... = Coding Group: Coding Group 0 (Language using the GSM 7 bit default alphabet)
  .... 0000 = Language: German (0)

In function rx_proc_ss_req(), we should not be using req.ussd_text,
because this field has been deprecated and may contain unexpected
data.  For example, in the abovementioned case it would contain the
7 bit encoded ussd-String 'aa510c061b01'O and osmo-hlr would indeed
fail to find a matching route for a non-ASCII string.

Instead of relaying on gsm0480_parse_facility_ie(), let's check the
Data Coding Scheme value and decode the request string ourselves.
Expect the Coding Group 0, but be more tolerant to the indicated
language: print a warning and treat it as '1111'B (unspecified).

Change-Id: Ib7bac660b1a7942adcfbe7b14f162c95061a25db
Related: OS#6075
2023-07-21 12:49:20 +00:00
Vadim Yanitskiy
f8b73f0682 gsup_server: fix msgb memleak in osmo_gsup_server_read_cb()
I noticed that inability to send IPA PONG in response to IPA PING
from osmo-{msc,sgsn} results in an "IPA Multiplex" chunk being leaked.

No matter what's returned from ipa_server_conn_ccm(), we need to free
the msgb containing the incoming IPA message.

Change-Id: I5c5acbffc2913f78db4894ae3633b5eca9c2e8d6
2023-07-05 01:10:43 +07:00
Vadim Yanitskiy
f4223f5b53 ussd: fix GSUP memleaks in rx_proc_ss_{req,error}()
Also take a chance to use a more suitable error cause value.

Change-Id: I22ba5ad470989b7e8ba8fe2be170eac4adcb48c5
2023-07-05 00:24:19 +07:00
Vadim Yanitskiy
1c23f304d1 lu_fsm: fix memleak in lu_fsm_wait_insert_data_result()
Currently osmo-hlr leaks memory (msgb holding 1203 bytes of data and
a struct osmo_gsup_req) on receipt of OSMO_GSUP_MSGT_INSERT_DATA_ERROR.

Change-Id: I4c70a06169158c869360707a7a62436dbf13b9b3
2023-07-05 00:15:17 +07:00
Harald Welte
f4159bd54c src/db.c: Switch from "const char *statements" to "const char * const"
This is primarily to make the linter happy, which spews "static const
char * array should probably be static const char * const" errors in
gerrit when adding similar new code to this existing file.  So let's
first convert the old code and then add new code that makes the linter
happy.  I guess it does have a point, as both the individual string
pointers as well as the array of the pointers are constant.

Change-Id: I39e9fb6bd8052f4878cfc95061775bf940631ae5
2023-06-14 14:53:07 +02:00
Harald Welte
a854b48762 Port to new libosmogsm 'struct osmo_sub_auth_data2'
libosmogsm has recently introdcued a 'struct osmo_sub_auth_data2' as
successor to 'struct osmo_sub_auth_data', together with updated
osmo_auth_gen_vec2/osmo_auth_gen_vec_auts2 API.

The rationale of this new API is to enable
* support for AKA algorithms which use K and/or OP[c] values of 256bit
  (instead of the classic 128bit)
* support for RES length sizes of 4 and 16 bytes (instead of the classic
  8 bytes)

This commit just jumps over to the new API without adding any related
functionality to osmo-hlr.  The latter is left for subsequent commits.

Change-Id: I3207c7bfb73e9ff5471e5c26b66639549e4d48a2
Depends: libosmocore.git Ie775fedba4a3fa12314c0f7c8a369662ef6a40df
2023-06-14 14:53:04 +02:00
Harald Welte
91150802f8 cosmetic: gen_ts_55_205_test_sets/main_template tabs istead of spaces
Let's consistently use our normal tab indent style

Change-Id: I4172b59131ac4166174c1860fcb07b7bee3df728
2023-06-03 19:32:44 +02:00
Harald Welte
8f3fa656e7 cosmetic: gen_ts_55_205_test_sets/func_template.c: Use tab-indent
This templates is used for generating C code, so it should use our
normal tab-based code indenting.

Change-Id: I0be7eb2d7b551d7eaaee15994ef37262694819f6
2023-06-03 19:29:46 +02:00
Harald Welte
829713a69d Introduce support for XOR-2G algorithm
So far we supported a "xor" algorithm in osmo-hlr, without specifying
whether it's the XOR-3G or the (different) XOR-2G algorithm.

Furthermore, it was buggy in the sense that it permitted the XOR[-3G]
for 2G authentication data in the database.

This patch
* renames existing "xor" to "xor-3g"
* disallows "xor-3g" usage with 2G authentication data
* introduces support for XOR-2G as "xor-2g" in the VTY

Change-Id: I039a1f84fda54a908a82fe621e7fd078cb85e4c6
Depends: libosmocore.git I0ee0565382c1e4515d44ff9b1752685c0a66ae39
2023-05-30 21:43:14 +02:00
Oliver Smith
5edf387353 systemd: depend on networking-online.target
Related: SYS#6400
Change-Id: I29e547242b2ed1cfc4750c7d7e5f8636c2e8f3dc
2023-05-26 14:10:45 +02:00
Alexander Couzens
2989873a68 hlr: use talloc for memory allocation in osmo_gsup_create_insert_subscriber_data_msg
Don't use static buffers for APN and MSISDN.
When encoding multiple APNs the static buffer might be too small.
In prepration to support multiple APNs in subscriber data

Change-Id: I00b5c2dfadcf6e0740e93b4c3292d2654d22e80c
2023-05-10 07:58:57 +00:00
Oliver Smith
390f6fcf13 debian: set compat level to 10
Related: OS#5958
Change-Id: I5d26ab03aacf3b8ef8c1c4c669c12090fd0b7899
2023-04-25 16:48:22 +02:00
Vadim Yanitskiy
d10c2ef366 tests/*/Makefile.am: move -I to AM_CPPFLAGS
Change-Id: I654053e11b0cc824c198f68e4ff0a0fcb295efb0
2023-03-14 20:11:45 +00:00
Vadim Yanitskiy
974aed9c04 tests/auc/Makefile.am: put object files to LDADD
Change-Id: Iaefcfe7a8904841a29094fe40eb5850912544b4c
2023-03-14 20:11:45 +00:00
Pau Espin Pedrol
cf535dbcbd mslookup: Call osmo_fd_unregister() before closing and changing bfd->fd
Change-Id: I26bba0dd092ad5fd6b4959b173fae93b542a93f1
2023-03-14 11:42:24 +01:00
Oliver Smith
a55e63b087 tests/db/db_test.err: adjust to XOR-3G rename
Adjust the test to the related libosmocore change.

Related: libosmocore I446e54d0ddf4a18c46ee022b1249af73552e3ce1
Change-Id: I68878d24340659f888e5e348b937161cffbd54e2
2023-02-22 16:58:57 +01:00
Oliver Smith
62e5c1b2c7 Run struct_endianness.py
Ensure there is no diff to prepare to run this in CI.

Related: OS#5884
Change-Id: I4294a18871214b70cef267fcaaaaada42cb61bf9
2023-02-20 10:48:57 +01:00
Pau Espin Pedrol
ed939154f8 Bump version: 1.5.0.19-268a-dirty → 1.6.0
Change-Id: Ide480a902bbfadefa396f3a0cb925f5dceab4f9c
2023-02-07 16:49:15 +01:00
Alexander Couzens
268a33e58b Add vty reject-cause to set the reject cause
Allow to set the LU reject cause independently for both of the
following cases; either when an IMSI is unknown to the HLR or
when the mslookup client does not a receive a timely response
to a GSUP request for the remote home HLR.

Original patchset modified by <keith@rhizomatica.org>

Change-Id: Icea39020c23fbbea9e92847df76af8986fdbf48a
2023-01-20 14:03:01 +00:00
Neels Hofmeyr
8804a2335a fix memleak of proxy_subscr_listentry
Patch-by: whytek
Related: OS#5854
Change-Id: Ic1ec4911fa5ae91cc75aa865c8201edd83af41ed
2023-01-15 22:45:31 +01:00
Keith
c27bc90ae6 Vty: Fixup config shown/written from vty
This commit fixes the following errors:
Missing timeout param for mslookup.
Fails to start reading a written config if an msc node
is configured in the mslookup server.
Places the individual msc node services in the
top-level wildcard node due to incorrect indentation.

* Add missing timeout param.
* Add missing "ipa-name" part to mslookup-server-msc section.
* Add one extra space indentation for msc services.

This commit also adds a DEFINE for the default timeout value.

Change-Id: Ibb60e74a0803f05f37ac13ca529d77b4cb736025
2022-12-27 17:03:08 +00:00
Oliver Smith
f80ab768d0 osmo_mdns_rfc_record/question_encode: remove ctx
Remove the ctx argument to both functions, as it's not used anymore.

Related: OS#5821
Change-Id: I5e3dd18bf08f7aa42f49c262e13250778ea0c6a2
2022-12-23 13:51:28 +01:00
Oliver Smith
5decd49713 mslookup: use apn functions from libosmocore
Use the apn functions from libosmocore to encode and decode qnames to
avoid code duplication and to avoid unnecessary dynamic allocation.

The unit tests for encoding and decoding rfc_question / rfc_record are
still passing and have the same output.

Fixes: OS#5821
Change-Id: I09d3c617fd6eb4075084ee106d3f3c5803861d2f
2022-12-23 13:51:22 +01:00
Oliver Smith
c5f034b13d osmo_mdns_rfc_record_decode: proper free on err
Free the whole talloc tree of ret if we can't allocate memory for
ret->rdata.

Related: OS#5821
Change-Id: Iefc89e3c75a4bf4ffee3871c7b551a2a608f7d5f
2022-12-23 13:38:19 +01:00
Oliver Smith
01155eaee6 osmo_mdns_rfc_record_decode: check ret of talloc
Related: OS#5821
Change-Id: Icd0f54a8eb80ca50976f248e017f6e5c727385f3
2022-12-23 13:38:15 +01:00
arehbein
e4143234c8 osmo-hlr: Transition to use of 'telnet_init_default'
Related: OS#5809
Change-Id: I5cee719a9c4437712915f0f9760d606f6ec2dd43
2022-12-23 11:13:19 +00:00
Max
6263cf350a ctrl: take both address and port from vty config
Change-Id: Iecae15333a4e77b38d9bce8c8e591af3d5fcf347
2022-12-17 20:59:00 +03:00
Harald Welte
63eefabdde Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
... if --enable-werror is used

Change-Id: Id465254bf12eb84acb116c86711a5b52b4d3ad35
2022-11-03 12:56:24 +01:00
Harald Welte
7a4765325d Support building with -Werror=strict-prototypes / -Werror=old-style-definition
Unfortunately "-std=c99" is not sufficient to make gcc ignore code that
uses constructs of earlier C standards, which were abandoned in C99.

See https://lwn.net/ml/fedora-devel/Y1kvF35WozzGBpc8@redhat.com/ for
some related discussion.

Change-Id: I861be39275b40c522c02f553074c5a4489e87127
2022-11-03 12:56:24 +01:00
Max
53f6067e97 hlr_vty.c: fix typo
Change-Id: If79ebd9a8998e64be55e52af43e426f37e3972af
2022-09-24 01:55:46 +00:00
Max
8023d246f2 Debian: install osmo-hlr-dgsm.cfg as example config
Related: OS#4107
Change-Id: Ia64f14ada006acb31c5f725dfa0d52f482d3e8b4
2022-09-18 20:19:42 +07:00
Max
00aea9e0d9 systemd: enable basic hardening
This ensures that systemd will not allow us to modify
/home, /root and /run/user which we shouldn't be doing anyway.
See https://www.freedesktop.org/software/systemd/man/systemd.exec.html
for details.

It should also should silence corresponding lintian warning.

Related: OS#4107
Change-Id: Ida5f13bdb9e5bd956c440a381d94eecc18f0b2ef
2022-09-18 19:23:52 +07:00
Max
023c6524a2 Debian: reformat package description
Shorten the lines of package description to comply with
Debian Policy Manual section 3.4.1

Related: OS#4107
Change-Id: Id6bbfc0b013f0e8da80af76206d3ac7fd6b6b0d4
2022-09-18 19:23:52 +07:00
Max
1d02b51a68 Debian: bump copyright year to match current
Related: OS#4107
Change-Id: I581e62b5410a9dddc6b5fd974081d633cc20416d
2022-09-18 19:23:23 +07:00
Max
78a9f92fda Ignore .deb build byproducts
Change-Id: Id36f55cd55be25f764c2b9515eff84d106bab1dc
2022-09-09 22:08:35 +07:00
Max
ad8866e86e Set working directory in systemd service file
By default systemd will execute service with root directory (or home directory for user instance) which might result in
attempts to create files in unexpected place. Let's set it to 'osmocom' subdir of state directory (/var/lib for system
instance) instead.

Related: OS#4821
Change-Id: I40b5d50470cb55ca94af5e17f21658181a02d4c2
2022-08-29 19:45:03 +07:00
Vadim Yanitskiy
6156950634 db_auc: hexparse_stmt(): check value returned by osmo_hexparse()
Change-Id: I78bb3aff9dd57a38278bb34113ea764e0a54c439
Fixes: CID#272997
2022-06-29 11:30:12 +00:00
63 changed files with 1058 additions and 757 deletions

16
.gitignore vendored
View File

@@ -70,3 +70,19 @@ doc/manuals/common
doc/manuals/build doc/manuals/build
contrib/osmo-hlr.spec contrib/osmo-hlr.spec
/debian/.debhelper/
/debian/libosmo-gsup-client-dev/
/debian/files
/debian/autoreconf.after
/debian/autoreconf.before
/debian/libosmo-gsup-client0/
/debian/libosmo-mslookup0/
/debian/osmo-hlr-dbg/
/debian/tmp/
/doc/manuals/vty/hlr_vty_reference.xml
/debian/libosmo-mslookup-dev/
/debian/osmo-hlr-doc/
/debian/osmo-hlr/
/debian/osmo-mslookup-utils/
/debian/*.log
/debian/*.substvars

View File

@@ -41,11 +41,11 @@ PKG_PROG_PKG_CONFIG([0.20])
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1]) PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.7.0) PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.7.0) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.7.0) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.7.0) PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl >= 1.9.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.3.0) PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 1.5.0)
PKG_CHECK_MODULES(SQLITE3, sqlite3) PKG_CHECK_MODULES(SQLITE3, sqlite3)
@@ -93,6 +93,7 @@ AC_ARG_ENABLE(werror,
if test x"$werror" = x"yes" if test x"$werror" = x"yes"
then then
WERROR_FLAGS="-Werror" WERROR_FLAGS="-Werror"
WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations" WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning" WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
CFLAGS="$CFLAGS $WERROR_FLAGS" CFLAGS="$CFLAGS $WERROR_FLAGS"

View File

@@ -29,11 +29,11 @@ BuildRequires: python3
%if 0%{?suse_version} %if 0%{?suse_version}
BuildRequires: systemd-rpm-macros BuildRequires: systemd-rpm-macros
%endif %endif
BuildRequires: pkgconfig(libosmoabis) >= 1.3.0 BuildRequires: pkgconfig(libosmoabis) >= 1.5.0
BuildRequires: pkgconfig(libosmocore) >= 1.7.0 BuildRequires: pkgconfig(libosmocore) >= 1.9.0
BuildRequires: pkgconfig(libosmoctrl) >= 1.7.0 BuildRequires: pkgconfig(libosmoctrl) >= 1.9.0
BuildRequires: pkgconfig(libosmogsm) >= 1.7.0 BuildRequires: pkgconfig(libosmogsm) >= 1.9.0
BuildRequires: pkgconfig(libosmovty) >= 1.7.0 BuildRequires: pkgconfig(libosmovty) >= 1.9.0
BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(sqlite3)
BuildRequires: pkgconfig(talloc) >= 2.0.1 BuildRequires: pkgconfig(talloc) >= 2.0.1
# only needed for populate_hlr_db.pl # only needed for populate_hlr_db.pl
@@ -75,19 +75,19 @@ and External USSD Entities (EUSEs) using this library to implement clients.
This subpackage contains libraries and header files for developing This subpackage contains libraries and header files for developing
applications that want to make use of libosmo-gsup-client. applications that want to make use of libosmo-gsup-client.
%package -n libosmo-mslookup0 %package -n libosmo-mslookup1
Summary: Osmocom MS lookup library Summary: Osmocom MS lookup library
License: GPL-2.0-or-later License: GPL-2.0-or-later
Group: System/Libraries Group: System/Libraries
%description -n libosmo-mslookup0 %description -n libosmo-mslookup1
This shared library contains routines for looking up mobile subscribers. This shared library contains routines for looking up mobile subscribers.
%package -n libosmo-mslookup-devel %package -n libosmo-mslookup-devel
Summary: Development files for the Osmocom MS lookup library Summary: Development files for the Osmocom MS lookup library
License: GPL-2.0-or-later License: GPL-2.0-or-later
Group: Development/Libraries/C and C++ Group: Development/Libraries/C and C++
Requires: libosmo-mslookup0 = %{version} Requires: libosmo-mslookup1 = %{version}
%description -n libosmo-mslookup-devel %description -n libosmo-mslookup-devel
This shared library contains routines for looking up mobile subscribers. This shared library contains routines for looking up mobile subscribers.
@@ -146,8 +146,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%post -n libosmo-gsup-client0 -p /sbin/ldconfig %post -n libosmo-gsup-client0 -p /sbin/ldconfig
%postun -n libosmo-gsup-client0 -p /sbin/ldconfig %postun -n libosmo-gsup-client0 -p /sbin/ldconfig
%post -n libosmo-mslookup0 -p /sbin/ldconfig %post -n libosmo-mslookup1 -p /sbin/ldconfig
%postun -n libosmo-mslookup0 -p /sbin/ldconfig %postun -n libosmo-mslookup1 -p /sbin/ldconfig
%files %files
%license COPYING %license COPYING
@@ -179,8 +179,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
%{_libdir}/libosmo-gsup-client.so %{_libdir}/libosmo-gsup-client.so
%{_libdir}/pkgconfig/libosmo-gsup-client.pc %{_libdir}/pkgconfig/libosmo-gsup-client.pc
%files -n libosmo-mslookup0 %files -n libosmo-mslookup1
%{_libdir}/libosmo-mslookup.so.0* %{_libdir}/libosmo-mslookup.so.1*
%files -n libosmo-mslookup-devel %files -n libosmo-mslookup-devel
%dir %{_includedir}/osmocom %dir %{_includedir}/osmocom

View File

@@ -1,12 +1,17 @@
[Unit] [Unit]
Description=Osmocom Home Location Register (OsmoHLR) Description=Osmocom Home Location Register (OsmoHLR)
Documentation=https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR Documentation=https://osmocom.org/projects/osmo-hlr/wiki/OsmoHLR
After=network-online.target
Wants=network-online.target
[Service] [Service]
Type=simple Type=simple
Restart=always Restart=always
StateDirectory=osmocom
WorkingDirectory=%S/osmocom
ExecStart=/usr/bin/osmo-hlr -c /etc/osmocom/osmo-hlr.cfg -l /var/lib/osmocom/hlr.db ExecStart=/usr/bin/osmo-hlr -c /etc/osmocom/osmo-hlr.cfg -l /var/lib/osmocom/hlr.db
RestartSec=2 RestartSec=2
ProtectHome=true
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

72
debian/changelog vendored
View File

@@ -1,9 +1,75 @@
osmo-hlr (1.5.1) unstable; urgency=medium osmo-hlr (1.7.0) unstable; urgency=medium
[ Oliver Smith ]
* Run struct_endianness.py * Run struct_endianness.py
* tests: adjust to XOR-3G rename in libosmocore * tests/db/db_test.err: adjust to XOR-3G rename
* debian: set compat level to 10
* systemd: depend on networking-online.target
-- Oliver Smith <osmith@sysmocom.de> Thu, 23 Feb 2023 12:18:25 +0100 [ Pau Espin Pedrol ]
* mslookup: Call osmo_fd_unregister() before closing and changing bfd->fd
[ Vadim Yanitskiy ]
* tests/auc/Makefile.am: put object files to LDADD
* tests/*/Makefile.am: move -I to AM_CPPFLAGS
* lu_fsm: fix memleak in lu_fsm_wait_insert_data_result()
* ussd: fix GSUP memleaks in rx_proc_ss_{req,error}()
* gsup_server: fix msgb memleak in osmo_gsup_server_read_cb()
* USSD: fix handling of ussd-DataCodingScheme != 0x0f
[ Alexander Couzens ]
* hlr: use talloc for memory allocation in osmo_gsup_create_insert_subscriber_data_msg
* Add support for multiple APN profiles for subscriber data
[ Harald Welte ]
* Introduce support for XOR-2G algorithm
* cosmetic: gen_ts_55_205_test_sets/func_template.c: Use tab-indent
* cosmetic: gen_ts_55_205_test_sets/main_template tabs istead of spaces
* Port to new libosmogsm 'struct osmo_sub_auth_data2'
* src/db.c: Switch from "const char *statements" to "const char * const"
* db: extend database schema to support 256bit K and/or OP[c] values
* Add VTY support for TUAK algorithm
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 14:41:33 +0200
osmo-hlr (1.6.0) unstable; urgency=medium
[ Vadim Yanitskiy ]
* db_auc: hexparse_stmt(): check value returned by osmo_hexparse()
[ Max ]
* Set working directory in systemd service file
* Ignore .deb build byproducts
* Debian: bump copyright year to match current
* Debian: reformat package description
* systemd: enable basic hardening
* Debian: install osmo-hlr-dgsm.cfg as example config
* hlr_vty.c: fix typo
* ctrl: take both address and port from vty config
[ Harald Welte ]
* Support building with -Werror=strict-prototypes / -Werror=old-style-definition
* Add -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition
[ arehbein ]
* osmo-hlr: Transition to use of 'telnet_init_default'
[ Oliver Smith ]
* osmo_mdns_rfc_record_decode: check ret of talloc
* osmo_mdns_rfc_record_decode: proper free on err
* mslookup: use apn functions from libosmocore
* osmo_mdns_rfc_record/question_encode: remove ctx
[ Keith ]
* Vty: Fixup config shown/written from vty
[ Neels Hofmeyr ]
* fix memleak of proxy_subscr_listentry
[ Alexander Couzens ]
* Add vty `reject-cause` to set the reject cause
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 16:49:14 +0100
osmo-hlr (1.5.0) unstable; urgency=medium osmo-hlr (1.5.0) unstable; urgency=medium

2
debian/compat vendored
View File

@@ -1 +1 @@
9 10

21
debian/control vendored
View File

@@ -2,17 +2,17 @@ Source: osmo-hlr
Section: net Section: net
Priority: optional Priority: optional
Maintainer: Osmocom team <openbsc@lists.osmocom.org> Maintainer: Osmocom team <openbsc@lists.osmocom.org>
Build-Depends: debhelper (>= 9), Build-Depends: debhelper (>= 10),
pkg-config, pkg-config,
dh-autoreconf, dh-autoreconf,
autotools-dev, autotools-dev,
python3-minimal, python3-minimal,
libosmocore-dev (>= 1.7.0), libosmocore-dev (>= 1.9.0),
libosmo-abis-dev (>= 1.3.0), libosmo-abis-dev (>= 1.5.0),
libosmo-netif-dev (>= 1.2.0), libosmo-netif-dev (>= 1.4.0),
libsqlite3-dev, libsqlite3-dev,
sqlite3, sqlite3,
osmo-gsm-manuals-dev (>= 1.3.0) osmo-gsm-manuals-dev (>= 1.5.0)
Standards-Version: 3.9.6 Standards-Version: 3.9.6
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr
@@ -22,8 +22,9 @@ Package: osmo-hlr
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Osmocom Home Location Register Description: Osmocom Home Location Register
OsmoHLR is a Osmocom implementation of HLR (Home Location Registrar) which works over GSUP OsmoHLR is a Osmocom implementation of HLR (Home Location Registrar) which
protocol. The subscribers are store in sqlite DB. It supports both 2G and 3G authentication. works over GSUP protocol. The subscribers are store in sqlite DB.
It supports both 2G and 3G authentication.
Package: osmo-hlr-dbg Package: osmo-hlr-dbg
Architecture: any Architecture: any
@@ -58,7 +59,7 @@ Description: Development headers of Osmocom GSUP client library
. .
This package contains the development headers. This package contains the development headers.
Package: libosmo-mslookup0 Package: libosmo-mslookup1
Section: libs Section: libs
Architecture: any Architecture: any
Multi-Arch: same Multi-Arch: same
@@ -72,7 +73,7 @@ Package: libosmo-mslookup-dev
Architecture: any Architecture: any
Multi-Arch: same Multi-Arch: same
Depends: ${misc:Depends}, Depends: ${misc:Depends},
libosmo-mslookup0 (= ${binary:Version}), libosmo-mslookup1 (= ${binary:Version}),
libosmocore-dev libosmocore-dev
Pre-Depends: ${misc:Pre-Depends} Pre-Depends: ${misc:Pre-Depends}
Description: Development headers of Osmocom MS lookup library Description: Development headers of Osmocom MS lookup library
@@ -84,7 +85,7 @@ Package: osmo-mslookup-utils
Architecture: any Architecture: any
Section: utils Section: utils
Depends: ${shlibs:Depends}, Depends: ${shlibs:Depends},
libosmo-mslookup0 (= ${binary:Version}), libosmo-mslookup1 (= ${binary:Version}),
${misc:Depends} ${misc:Depends}
Multi-Arch: same Multi-Arch: same
Description: Utilities for Osmocom MS lookup Description: Utilities for Osmocom MS lookup

2
debian/copyright vendored
View File

@@ -3,7 +3,7 @@ Upstream-Name: OsmoHLR
Source: http://cgit.osmocom.org/osmo-hlr/ Source: http://cgit.osmocom.org/osmo-hlr/
Files: * Files: *
Copyright: 2016-2017 Sysmocom s. f. m. c. GmbH <info@sysmocom.de> Copyright: 2016-2022 Sysmocom s. f. m. c. GmbH <info@sysmocom.de>
License: AGPL-3+ License: AGPL-3+
License: AGPL-3+ License: AGPL-3+

View File

@@ -5,5 +5,5 @@
/usr/share/doc/osmo-hlr/sql/hlr.sql /usr/share/doc/osmo-hlr/sql/hlr.sql
/usr/share/doc/osmo-hlr/sql/hlr_data.sql /usr/share/doc/osmo-hlr/sql/hlr_data.sql
/usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg /usr/share/doc/osmo-hlr/examples/osmo-hlr.cfg
/usr/share/doc/osmo-hlr/examples/osmo-hlr-dgsm.cfg
/usr/share/osmocom/osmo-hlr-post-upgrade.sh /usr/share/osmocom/osmo-hlr-post-upgrade.sh
/var/lib/osmocom

View File

@@ -24,3 +24,9 @@ hlr
bind ip 127.0.0.1 bind ip 127.0.0.1
ussd route prefix *#100# internal own-msisdn ussd route prefix *#100# internal own-msisdn
ussd route prefix *#101# internal own-imsi ussd route prefix *#101# internal own-imsi
ps
pdp-profiles default
profile 1
apn internet
profile 2
apn *

View File

@@ -3,6 +3,6 @@
#include <osmocom/crypt/auth.h> #include <osmocom/crypt/auth.h>
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec, int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
struct osmo_sub_auth_data *aud2g, struct osmo_sub_auth_data2 *aud2g,
struct osmo_sub_auth_data *aud3g, struct osmo_sub_auth_data2 *aud3g,
const uint8_t *rand_auts, const uint8_t *auts); const uint8_t *rand_auts, const uint8_t *auts);

View File

@@ -70,8 +70,8 @@ struct db_context *db_open(void *ctx, const char *fname, bool enable_sqlite3_log
/* obtain the authentication data for a given imsi */ /* obtain the authentication data for a given imsi */
int db_get_auth_data(struct db_context *dbc, const char *imsi, int db_get_auth_data(struct db_context *dbc, const char *imsi,
struct osmo_sub_auth_data *aud2g, struct osmo_sub_auth_data2 *aud2g,
struct osmo_sub_auth_data *aud3g, struct osmo_sub_auth_data2 *aud3g,
int64_t *subscr_id); int64_t *subscr_id);
int db_update_sqn(struct db_context *dbc, int64_t id, int db_update_sqn(struct db_context *dbc, int64_t id,
@@ -121,7 +121,7 @@ struct hlr_subscriber {
* See https://sqlite.org/lang_datefunc.html, function datetime(). */ * See https://sqlite.org/lang_datefunc.html, function datetime(). */
#define DB_LAST_LU_SEEN_FMT "%Y-%m-%d %H:%M:%S" #define DB_LAST_LU_SEEN_FMT "%Y-%m-%d %H:%M:%S"
/* Like struct osmo_sub_auth_data, but the keys are in hexdump representation. /* Like struct osmo_sub_auth_data2, but the keys are in hexdump representation.
* This is useful because SQLite requires them in hexdump format, and callers * This is useful because SQLite requires them in hexdump format, and callers
* like the VTY and CTRL interface also have them available as hexdump to begin * like the VTY and CTRL interface also have them available as hexdump to begin
* with. In the binary format, a VTY command would first need to hexparse, * with. In the binary format, a VTY command would first need to hexparse,

View File

@@ -25,6 +25,7 @@
#include <osmocom/gsupclient/cni_peer_id.h> #include <osmocom/gsupclient/cni_peer_id.h>
#include <osmocom/gsupclient/gsup_req.h> #include <osmocom/gsupclient/gsup_req.h>
#define OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS 2000
#define LOG_DGSM(imsi, level, fmt, args...) \ #define LOG_DGSM(imsi, level, fmt, args...) \
LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args) LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)

View File

@@ -69,8 +69,6 @@ void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups);
int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup, int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
uint8_t *apn_buf, size_t apn_buf_size); uint8_t *apn_buf, size_t apn_buf_size);
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn, int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
uint8_t *msisdn_enc, size_t msisdn_enc_size, enum osmo_gsup_cn_domain cn_domain, void *talloc_ctx);
uint8_t *apn_buf, size_t apn_buf_size,
enum osmo_gsup_cn_domain cn_domain);
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer, int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup); struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup);

View File

@@ -23,6 +23,7 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/core/linuxlist.h> #include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/ipa.h> #include <osmocom/gsm/ipa.h>
#include <osmocom/core/tdef.h> #include <osmocom/core/tdef.h>
@@ -48,7 +49,6 @@ struct hlr {
/* Control Interface */ /* Control Interface */
struct ctrl_handle *ctrl; struct ctrl_handle *ctrl;
const char *ctrl_bind_addr;
/* Local bind addr */ /* Local bind addr */
char *gsup_bind_addr; char *gsup_bind_addr;
@@ -56,6 +56,16 @@ struct hlr {
struct llist_head euse_list; struct llist_head euse_list;
struct hlr_euse *euse_default; struct hlr_euse *euse_default;
enum gsm48_gmm_cause reject_cause;
enum gsm48_gmm_cause no_proxy_reject_cause;
/* PS: APN default configuration used by Subscription Data on ISR */
struct {
struct {
bool enabled;
struct osmo_gsup_pdp_info pdp_infos[OSMO_GSUP_MAX_NUM_PDP_INFO];
size_t num_pdp_infos;
} pdp_profile;
} ps;
/* NCSS (call independent) session guard timeout value */ /* NCSS (call independent) session guard timeout value */
int ncss_guard_timeout; int ncss_guard_timeout;

View File

@@ -35,15 +35,19 @@ enum hlr_vty_node {
MSLOOKUP_SERVER_NODE, MSLOOKUP_SERVER_NODE,
MSLOOKUP_SERVER_MSC_NODE, MSLOOKUP_SERVER_MSC_NODE,
MSLOOKUP_CLIENT_NODE, MSLOOKUP_CLIENT_NODE,
PS_NODE,
PS_PDP_PROFILES_NODE,
PS_PDP_PROFILES_PROFILE_NODE,
}; };
#define A38_XOR_MIN_KEY_LEN 12 #define A38_XOR_MIN_KEY_LEN 12
#define A38_XOR_MAX_KEY_LEN 16 #define A38_XOR_MAX_KEY_LEN 16
#define A38_XOR2G_KEY_LEN 16
#define A38_COMP128_KEY_LEN 16 #define A38_COMP128_KEY_LEN 16
#define MILENAGE_KEY_LEN 16 #define MILENAGE_KEY_LEN 16
int hlr_vty_is_config_node(struct vty *vty, int node); int hlr_vty_is_config_node(struct vty *vty, int node);
int hlr_vty_go_parent(struct vty *vty); int hlr_vty_go_parent(struct vty *vty);
void hlr_vty_init(void); void hlr_vty_init(void *hlr_ctx);
void dgsm_vty_init(void); void dgsm_vty_init(void);

View File

@@ -99,15 +99,12 @@ struct osmo_mdns_rfc_record {
uint8_t *rdata; uint8_t *rdata;
}; };
char *osmo_mdns_rfc_qname_encode(void *ctx, const char *domain);
char *osmo_mdns_rfc_qname_decode(void *ctx, const char *qname, size_t qname_len);
void osmo_mdns_rfc_header_encode(struct msgb *msg, const struct osmo_mdns_rfc_header *hdr); void osmo_mdns_rfc_header_encode(struct msgb *msg, const struct osmo_mdns_rfc_header *hdr);
int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_header *hdr); int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_header *hdr);
int osmo_mdns_rfc_question_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_question *qst); int osmo_mdns_rfc_question_encode(struct msgb *msg, const struct osmo_mdns_rfc_question *qst);
struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const uint8_t *data, size_t data_len); struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const uint8_t *data, size_t data_len);
int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_record *rec); int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_record *rec);
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
size_t *record_len); size_t *record_len);

View File

@@ -71,9 +71,9 @@ CREATE TABLE auc_2g (
CREATE TABLE auc_3g ( CREATE TABLE auc_3g (
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value
k VARCHAR(32) NOT NULL, -- hex string: subscriber's secret key (128bit) k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit)
op VARCHAR(32), -- hex string: operator's secret key (128bit) op VARCHAR(64), -- hex string: operator's secret key (128/256bit)
opc VARCHAR(32), -- hex string: derived from OP and K (128bit) opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit)
sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage
-- nr of index bits at lower SQN end -- nr of index bits at lower SQN end
ind_bitlen INTEGER NOT NULL DEFAULT 5 ind_bitlen INTEGER NOT NULL DEFAULT 5
@@ -91,4 +91,4 @@ CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
-- Set HLR database schema version number -- Set HLR database schema version number
-- Note: This constant is currently duplicated in src/db.c and must be kept in sync! -- Note: This constant is currently duplicated in src/db.c and must be kept in sync!
PRAGMA user_version = 6; PRAGMA user_version = 7;

View File

@@ -111,7 +111,7 @@ BOOTSTRAP_SQL = $(top_srcdir)/sql/hlr.sql
db_bootstrap.h: $(BOOTSTRAP_SQL) $(srcdir)/db_sql2c.sed db_bootstrap.h: $(BOOTSTRAP_SQL) $(srcdir)/db_sql2c.sed
echo "/* DO NOT EDIT THIS FILE. It is generated from files in osmo-hlr.git/sql/ */" > "$@" echo "/* DO NOT EDIT THIS FILE. It is generated from files in osmo-hlr.git/sql/ */" > "$@"
echo "#pragma once" >> "$@" echo "#pragma once" >> "$@"
echo "static const char *stmt_bootstrap_sql[] = {" >> "$@" echo "static const char * const stmt_bootstrap_sql[] = {" >> "$@"
cat "$(BOOTSTRAP_SQL)" \ cat "$(BOOTSTRAP_SQL)" \
| sed -f "$(srcdir)/db_sql2c.sed" \ | sed -f "$(srcdir)/db_sql2c.sed" \
>> "$@" >> "$@"

View File

@@ -1,4 +1,4 @@
/* (C) 2015 by Harald Welte <laforge@gnumonks.org> /* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
* *
* All Rights Reserved * All Rights Reserved
* *
@@ -32,8 +32,8 @@
/* compute given number of vectors using either aud2g or aud2g or a combination /* compute given number of vectors using either aud2g or aud2g or a combination
* of both. Handles re-synchronization if rand_auts and auts are set */ * of both. Handles re-synchronization if rand_auts and auts are set */
int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec, int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
struct osmo_sub_auth_data *aud2g, struct osmo_sub_auth_data2 *aud2g,
struct osmo_sub_auth_data *aud3g, struct osmo_sub_auth_data2 *aud3g,
const uint8_t *rand_auts, const uint8_t *auts) const uint8_t *rand_auts, const uint8_t *auts)
{ {
unsigned int i; unsigned int i;
@@ -93,10 +93,10 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
: "2G only", : "2G only",
auts? ", with AUTS resync" : ""); auts? ", with AUTS resync" : "");
if (aud3g) { if (aud3g) {
DBGP("3G: k = %s\n", hexb(aud3g->u.umts.k)); DBGP("3G: k = %s\n", hex(aud3g->u.umts.k, aud3g->u.umts.k_len));
DBGP("3G: %s = %s\n", DBGP("3G: %s = %s\n",
aud3g->u.umts.opc_is_op? "OP" : "opc", aud3g->u.umts.opc_is_op? "OP" : "opc",
hexb(aud3g->u.umts.opc)); hex(aud3g->u.umts.opc, aud3g->u.umts.opc_len));
DBGP("3G: for sqn ind %u, previous sqn was %" PRIu64 "\n", DBGP("3G: for sqn ind %u, previous sqn was %" PRIu64 "\n",
aud3g->u.umts.ind, aud3g->u.umts.sqn); aud3g->u.umts.ind, aud3g->u.umts.sqn);
} }
@@ -115,6 +115,9 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
if (aud3g) { if (aud3g) {
/* 3G or 3G + 2G case */ /* 3G or 3G + 2G case */
/* backwards-compatibiliy: We assume all RES are 8 bytes long */
vec[i].res_len = 8;
/* Do AUTS only for the first vector or we would use /* Do AUTS only for the first vector or we would use
* the same SQN for each following key. */ * the same SQN for each following key. */
if ((i == 0) && auts) { if ((i == 0) && auts) {
@@ -123,10 +126,10 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
DBGP("vector [%u]: resync: rand_auts = %s\n", DBGP("vector [%u]: resync: rand_auts = %s\n",
i, hex(rand_auts, 16)); i, hex(rand_auts, 16));
rc = osmo_auth_gen_vec_auts(vec+i, aud3g, auts, rc = osmo_auth_gen_vec_auts2(vec+i, aud3g, auts,
rand_auts, rand); rand_auts, rand);
} else { } else {
rc = osmo_auth_gen_vec(vec+i, aud3g, rand); rc = osmo_auth_gen_vec2(vec+i, aud3g, rand);
} }
if (rc < 0) { if (rc < 0) {
LOGP(DAUC, LOGL_ERROR, "Error in 3G vector " LOGP(DAUC, LOGL_ERROR, "Error in 3G vector "
@@ -154,7 +157,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
DBGP("vector [%u]: calculating 2G separately\n", i); DBGP("vector [%u]: calculating 2G separately\n", i);
rc = osmo_auth_gen_vec(&vtmp, aud2g, rand); rc = osmo_auth_gen_vec2(&vtmp, aud2g, rand);
if (rc < 0) { if (rc < 0) {
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector" LOGP(DAUC, LOGL_ERROR, "Error in 2G vector"
"generation: [%u]: rc = %d\n", i, rc); "generation: [%u]: rc = %d\n", i, rc);
@@ -165,7 +168,7 @@ int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
vec[i].auth_types |= OSMO_AUTH_TYPE_GSM; vec[i].auth_types |= OSMO_AUTH_TYPE_GSM;
} else { } else {
/* 2G only case */ /* 2G only case */
rc = osmo_auth_gen_vec(vec+i, aud2g, rand); rc = osmo_auth_gen_vec2(vec+i, aud2g, rand);
if (rc < 0) { if (rc < 0) {
LOGP(DAUC, LOGL_ERROR, "Error in 2G vector " LOGP(DAUC, LOGL_ERROR, "Error in 2G vector "
"generation: [%u]: rc = %d\n", i, rc); "generation: [%u]: rc = %d\n", i, rc);

View File

@@ -1,6 +1,6 @@
/* OsmoHLR Control Interface implementation */ /* OsmoHLR Control Interface implementation */
/* (C) 2017 sysmocom s.f.m.c. GmbH <info@sysmocom.de> /* (C) 2017-2023 sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved * All Rights Reserved
* *
* Author: Max Suraev <msuraev@sysmocom.de> * Author: Max Suraev <msuraev@sysmocom.de>
@@ -39,7 +39,7 @@
#define SEL_BY_ID SEL_BY "id-" #define SEL_BY_ID SEL_BY "id-"
extern bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo, extern bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
int *minlen, int *maxlen); int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc);
#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf)) #define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
@@ -166,7 +166,7 @@ static void print_subscr_info(struct ctrl_cmd *cmd,
); );
} }
static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud) static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data2 *aud)
{ {
if (aud->algo == OSMO_AUTH_ALG_NONE) if (aud->algo == OSMO_AUTH_ALG_NONE)
return; return;
@@ -178,7 +178,7 @@ static void print_subscr_info_aud2g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
hexdump_buf(aud->u.gsm.ki)); hexdump_buf(aud->u.gsm.ki));
} }
static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data *aud) static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_data2 *aud)
{ {
if (aud->algo == OSMO_AUTH_ALG_NONE) if (aud->algo == OSMO_AUTH_ALG_NONE)
return; return;
@@ -187,7 +187,7 @@ static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
"\naud3g.k\t%s" "\naud3g.k\t%s"
, ,
osmo_auth_alg_name(aud->algo), osmo_auth_alg_name(aud->algo),
hexdump_buf(aud->u.umts.k)); osmo_hexdump_nospc(aud->u.umts.k, aud->u.umts.k_len));
/* hexdump uses a static string buffer, hence only one hexdump per /* hexdump uses a static string buffer, hence only one hexdump per
* printf(). */ * printf(). */
ctrl_cmd_reply_printf(cmd, ctrl_cmd_reply_printf(cmd,
@@ -196,7 +196,7 @@ static void print_subscr_info_aud3g(struct ctrl_cmd *cmd, struct osmo_sub_auth_d
"\naud3g.sqn\t%" PRIu64 "\naud3g.sqn\t%" PRIu64
, ,
aud->u.umts.opc_is_op? "op" : "opc", aud->u.umts.opc_is_op? "op" : "opc",
hexdump_buf(aud->u.umts.opc), osmo_hexdump_nospc(aud->u.umts.opc, aud->u.umts.opc_len),
aud->u.umts.ind_bitlen, aud->u.umts.ind_bitlen,
aud->u.umts.sqn); aud->u.umts.sqn);
} }
@@ -291,8 +291,8 @@ CTRL_CMD_DEFINE_RO(subscr_info_aud, "info-aud");
static int get_subscr_info_aud(struct ctrl_cmd *cmd, void *data) static int get_subscr_info_aud(struct ctrl_cmd *cmd, void *data)
{ {
const char *imsi; const char *imsi;
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
struct hlr *hlr = data; struct hlr *hlr = data;
const char *by_selector = cmd->node; const char *by_selector = cmd->node;
int rc; int rc;
@@ -327,8 +327,8 @@ CTRL_CMD_DEFINE_RO(subscr_info_all, "info-all");
static int get_subscr_info_all(struct ctrl_cmd *cmd, void *data) static int get_subscr_info_all(struct ctrl_cmd *cmd, void *data)
{ {
struct hlr_subscriber subscr; struct hlr_subscriber subscr;
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
struct hlr *hlr = data; struct hlr *hlr = data;
const char *by_selector = cmd->node; const char *by_selector = cmd->node;
int rc; int rc;
@@ -492,8 +492,8 @@ static int get_subscr_aud2g(struct ctrl_cmd *cmd, void *data)
struct hlr_subscriber subscr; struct hlr_subscriber subscr;
struct hlr *hlr = data; struct hlr *hlr = data;
const char *by_selector = cmd->node; const char *by_selector = cmd->node;
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g_unused; struct osmo_sub_auth_data2 aud3g_unused;
int rc; int rc;
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd)) if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
@@ -550,7 +550,7 @@ static int set_subscr_aud2g(struct ctrl_cmd *cmd, void *data)
} }
if (strcmp(tok, "none") == 0) { if (strcmp(tok, "none") == 0) {
aud2g.algo = OSMO_AUTH_ALG_NONE; aud2g.algo = OSMO_AUTH_ALG_NONE;
} else if (!auth_algo_parse(tok, &aud2g.algo, &minlen, &maxlen)) { } else if (!auth_algo_parse(tok, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) {
cmd->reply = "Unknown auth algorithm."; cmd->reply = "Unknown auth algorithm.";
return CTRL_CMD_ERROR; return CTRL_CMD_ERROR;
} }
@@ -592,8 +592,8 @@ static int get_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
struct hlr_subscriber subscr; struct hlr_subscriber subscr;
struct hlr *hlr = data; struct hlr *hlr = data;
const char *by_selector = cmd->node; const char *by_selector = cmd->node;
struct osmo_sub_auth_data aud2g_unused; struct osmo_sub_auth_data2 aud2g_unused;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
int rc; int rc;
if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd)) if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
@@ -618,9 +618,9 @@ static int get_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
} }
cmd->reply = talloc_asprintf(cmd, "%s,%s,%s,%s,%u", osmo_auth_alg_name(aud3g.algo), cmd->reply = talloc_asprintf(cmd, "%s,%s,%s,%s,%u", osmo_auth_alg_name(aud3g.algo),
osmo_hexdump_nospc_c(cmd, aud3g.u.umts.k, sizeof(aud3g.u.umts.k)), osmo_hexdump_nospc_c(cmd, aud3g.u.umts.k, aud3g.u.umts.k_len),
aud3g.u.umts.opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc_is_op ? "OP" : "OPC",
osmo_hexdump_nospc_c(cmd, aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc)), osmo_hexdump_nospc_c(cmd, aud3g.u.umts.opc, aud3g.u.umts.opc_len),
aud3g.u.umts.ind_bitlen); aud3g.u.umts.ind_bitlen);
return CTRL_CMD_REPLY; return CTRL_CMD_REPLY;
} }
@@ -630,8 +630,8 @@ static int set_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
struct hlr *hlr = data; struct hlr *hlr = data;
const char *by_selector = cmd->node; const char *by_selector = cmd->node;
char *tmp = NULL, *tok, *saveptr; char *tmp = NULL, *tok, *saveptr;
int minlen = 0; int minlen = 0, minlen_opc = 0;
int maxlen = 0; int maxlen = 0, maxlen_opc = 0;
struct sub_auth_data_str aud3g = { struct sub_auth_data_str aud3g = {
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.u.umts = { .u.umts = {
@@ -657,7 +657,7 @@ static int set_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
} }
if (strcmp(tok, "none") == 0) { if (strcmp(tok, "none") == 0) {
aud3g.algo = OSMO_AUTH_ALG_NONE; aud3g.algo = OSMO_AUTH_ALG_NONE;
} else if (!auth_algo_parse(tok, &aud3g.algo, &minlen, &maxlen)) { } else if (!auth_algo_parse(tok, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) {
cmd->reply = "Unknown auth algorithm."; cmd->reply = "Unknown auth algorithm.";
return CTRL_CMD_ERROR; return CTRL_CMD_ERROR;
} }
@@ -699,7 +699,7 @@ static int set_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
} }
aud3g.u.umts.opc = tok; aud3g.u.umts.opc = tok;
if (!osmo_is_hexstr(aud3g.u.umts.opc, MILENAGE_KEY_LEN * 2, MILENAGE_KEY_LEN * 2, true)) { if (!osmo_is_hexstr(aud3g.u.umts.opc, minlen_opc * 2, maxlen_opc * 2, true)) {
cmd->reply = talloc_asprintf(cmd, "Invalid OP/OPC."); cmd->reply = talloc_asprintf(cmd, "Invalid OP/OPC.");
return CTRL_CMD_ERROR; return CTRL_CMD_ERROR;
} }
@@ -749,7 +749,7 @@ static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
return 1; return 1;
} }
static int hlr_ctrl_cmds_install() static int hlr_ctrl_cmds_install(void)
{ {
int rc = 0; int rc = 0;
@@ -771,11 +771,8 @@ static int hlr_ctrl_cmds_install()
struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr) struct ctrl_handle *hlr_controlif_setup(struct hlr *hlr)
{ {
int rc; int rc;
struct ctrl_handle *hdl = ctrl_interface_setup_dynip2(hlr, struct ctrl_handle *hdl = ctrl_interface_setup2(hlr, OSMO_CTRL_PORT_HLR, hlr_ctrl_node_lookup,
hlr->ctrl_bind_addr, _LAST_CTRL_NODE_HLR);
OSMO_CTRL_PORT_HLR,
hlr_ctrl_node_lookup,
_LAST_CTRL_NODE_HLR);
if (!hdl) if (!hdl)
return NULL; return NULL;

View File

@@ -1,4 +1,4 @@
/* (C) 2015 by Harald Welte <laforge@gnumonks.org> /* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
* *
* All Rights Reserved * All Rights Reserved
* *
@@ -28,7 +28,7 @@
#include "db_bootstrap.h" #include "db_bootstrap.h"
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */ /* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
#define CURRENT_SCHEMA_VERSION 6 #define CURRENT_SCHEMA_VERSION 7
#define SEL_COLUMNS \ #define SEL_COLUMNS \
"id," \ "id," \
@@ -235,7 +235,7 @@ void db_close(struct db_context *dbc)
talloc_free(dbc); talloc_free(dbc);
} }
static int db_run_statements(struct db_context *dbc, const char **statements, size_t statements_count) static int db_run_statements(struct db_context *dbc, const char * const *statements, size_t statements_count)
{ {
int rc = 0; int rc = 0;
int i; int i;
@@ -308,7 +308,7 @@ static int
db_upgrade_v1(struct db_context *dbc) db_upgrade_v1(struct db_context *dbc)
{ {
int rc; int rc;
const char *statements[] = { const char * const statements[] = {
"ALTER TABLE subscriber ADD COLUMN last_lu_seen TIMESTAMP default NULL", "ALTER TABLE subscriber ADD COLUMN last_lu_seen TIMESTAMP default NULL",
"PRAGMA user_version = 1", "PRAGMA user_version = 1",
}; };
@@ -324,7 +324,7 @@ db_upgrade_v1(struct db_context *dbc)
static int db_upgrade_v2(struct db_context *dbc) static int db_upgrade_v2(struct db_context *dbc)
{ {
int rc; int rc;
const char *statements[] = { const char * const statements[] = {
"ALTER TABLE subscriber ADD COLUMN imei VARCHAR(14)", "ALTER TABLE subscriber ADD COLUMN imei VARCHAR(14)",
"PRAGMA user_version = 2", "PRAGMA user_version = 2",
}; };
@@ -437,7 +437,7 @@ static int db_upgrade_v3(struct db_context *dbc)
"ms_purged_ps," \ "ms_purged_ps," \
"last_lu_seen" "last_lu_seen"
const char *statements[] = { const char * const statements[] = {
"BEGIN TRANSACTION", "BEGIN TRANSACTION",
"CREATE TEMPORARY TABLE subscriber_backup" SUBSCR_V3_CREATE, "CREATE TEMPORARY TABLE subscriber_backup" SUBSCR_V3_CREATE,
"INSERT INTO subscriber_backup SELECT " SUBSCR_V2_COLUMN_NAMES " FROM subscriber", "INSERT INTO subscriber_backup SELECT " SUBSCR_V2_COLUMN_NAMES " FROM subscriber",
@@ -460,7 +460,7 @@ static int db_upgrade_v3(struct db_context *dbc)
static int db_upgrade_v4(struct db_context *dbc) static int db_upgrade_v4(struct db_context *dbc)
{ {
int rc; int rc;
const char *statements[] = { const char * const statements[] = {
"ALTER TABLE subscriber ADD COLUMN last_lu_seen_ps TIMESTAMP default NULL", "ALTER TABLE subscriber ADD COLUMN last_lu_seen_ps TIMESTAMP default NULL",
"PRAGMA user_version = 4", "PRAGMA user_version = 4",
}; };
@@ -476,7 +476,7 @@ static int db_upgrade_v4(struct db_context *dbc)
static int db_upgrade_v5(struct db_context *dbc) static int db_upgrade_v5(struct db_context *dbc)
{ {
int rc; int rc;
const char *statements[] = { const char * const statements[] = {
"ALTER TABLE subscriber ADD COLUMN vlr_via_proxy VARCHAR", "ALTER TABLE subscriber ADD COLUMN vlr_via_proxy VARCHAR",
"ALTER TABLE subscriber ADD COLUMN sgsn_via_proxy VARCHAR", "ALTER TABLE subscriber ADD COLUMN sgsn_via_proxy VARCHAR",
"PRAGMA user_version = 5", "PRAGMA user_version = 5",
@@ -493,7 +493,7 @@ static int db_upgrade_v5(struct db_context *dbc)
static int db_upgrade_v6(struct db_context *dbc) static int db_upgrade_v6(struct db_context *dbc)
{ {
int rc; int rc;
const char *statements[] = { const char * const statements[] = {
"CREATE TABLE ind (\n" "CREATE TABLE ind (\n"
" -- 3G auth IND pool to be used for this VLR\n" " -- 3G auth IND pool to be used for this VLR\n"
" ind INTEGER PRIMARY KEY,\n" " ind INTEGER PRIMARY KEY,\n"
@@ -513,6 +513,46 @@ static int db_upgrade_v6(struct db_context *dbc)
return rc; return rc;
} }
static int db_upgrade_v7(struct db_context *dbc)
{
int rc;
/* SQLite doesn't allow us to change the column type in-place, so we
* first rename the old table, create a new table and then copy
* the data over before deleting the old table */
#define CREATE_AUC_3G_V7 \
"CREATE TABLE auc_3g (\n" \
" subscriber_id INTEGER PRIMARY KEY, -- subscriber.id\n" \
" algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value\n" \
" k VARCHAR(64) NOT NULL, -- hex string: subscriber's secret key (128/256bit)\n" \
" op VARCHAR(64), -- hex string: operator's secret key (128/256bit)\n" \
" opc VARCHAR(64), -- hex string: derived from OP and K (128/256bit)\n" \
" sqn INTEGER NOT NULL DEFAULT 0, -- sequence number of key usage\n" \
" -- nr of index bits at lower SQN end\n" \
" ind_bitlen INTEGER NOT NULL DEFAULT 5\n" \
");"
const char * const statements[] = {
"BEGIN TRANSACTION",
/* rename old table */
"ALTER TABLE auc_3g RENAME TO old_auc_3g",
/* create new table */
CREATE_AUC_3G_V7,
/* copy over old data */
"INSERT INTO auc_3g SELECT subscriber_id, algo_id_3g, k, op, opc,sqn, ind_bitlen FROM old_auc_3g",
/* delete old table */
"DROP TABLE old_auc_3g",
/* update user_version */
"PRAGMA user_version = 7",
"COMMIT",
};
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
if (rc != SQLITE_DONE) {
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 7\n");
return rc;
}
return rc;
}
typedef int (*db_upgrade_func_t)(struct db_context *dbc); typedef int (*db_upgrade_func_t)(struct db_context *dbc);
static db_upgrade_func_t db_upgrade_path[] = { static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v1, db_upgrade_v1,
@@ -521,6 +561,7 @@ static db_upgrade_func_t db_upgrade_path[] = {
db_upgrade_v4, db_upgrade_v4,
db_upgrade_v5, db_upgrade_v5,
db_upgrade_v6, db_upgrade_v6,
db_upgrade_v7,
}; };
static int db_get_user_version(struct db_context *dbc) static int db_get_user_version(struct db_context *dbc)

View File

@@ -1,4 +1,4 @@
/* (C) 2015 by Harald Welte <laforge@gnumonks.org> /* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
* *
* All Rights Reserved * All Rights Reserved
* *
@@ -74,9 +74,9 @@ out:
} }
/* hexparse a specific column of a sqlite prepared statement into dst (with length check) /* hexparse a specific column of a sqlite prepared statement into dst (with length check)
* returns 0 for success, -EIO on error */ * returns byte length in case of success, -EIO on error */
static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int col, const char *col_name, static int hexparse_stmt(uint8_t *dst, size_t dst_len_min, size_t dst_len_max, sqlite3_stmt *stmt,
const char *imsi) int col, const char *col_name, const char *imsi)
{ {
const uint8_t *text; const uint8_t *text;
size_t col_len; size_t col_len;
@@ -84,9 +84,15 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int c
/* Bytes are stored as hex strings in database, hence divide length by two */ /* Bytes are stored as hex strings in database, hence divide length by two */
col_len = sqlite3_column_bytes(stmt, col) / 2; col_len = sqlite3_column_bytes(stmt, col) / 2;
if (col_len != dst_len) { if (col_len < dst_len_min) {
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected length %lu but has length %lu\n", col_name, LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected min length %lu but has length %lu\n", col_name,
dst_len, col_len); dst_len_min, col_len);
return -EIO;
}
if (col_len > dst_len_max) {
LOGAUC(imsi, LOGL_ERROR, "Error reading %s, expected max length %lu but has length %lu\n", col_name,
dst_len_max, col_len);
return -EIO; return -EIO;
} }
@@ -95,8 +101,11 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int c
LOGAUC(imsi, LOGL_ERROR, "Error reading %s\n", col_name); LOGAUC(imsi, LOGL_ERROR, "Error reading %s\n", col_name);
return -EIO; return -EIO;
} }
osmo_hexparse((void *)text, dst, dst_len);
return 0; if (osmo_hexparse((void *)text, dst, dst_len_max) != col_len)
return -EINVAL;
return col_len;
} }
/* obtain the authentication data for a given imsi /* obtain the authentication data for a given imsi
@@ -104,8 +113,8 @@ static int hexparse_stmt(uint8_t *dst, size_t dst_len, sqlite3_stmt *stmt, int c
* -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data, * -ENOENT if the IMSI is not known, -ENOKEY if the IMSI is known but has no auth data,
* -EIO on db failure */ * -EIO on db failure */
int db_get_auth_data(struct db_context *dbc, const char *imsi, int db_get_auth_data(struct db_context *dbc, const char *imsi,
struct osmo_sub_auth_data *aud2g, struct osmo_sub_auth_data2 *aud2g,
struct osmo_sub_auth_data *aud3g, struct osmo_sub_auth_data2 *aud3g,
int64_t *subscr_id) int64_t *subscr_id)
{ {
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_AUC_BY_IMSI]; sqlite3_stmt *stmt = dbc->stmt[DB_STMT_AUC_BY_IMSI];
@@ -139,7 +148,8 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
/* obtain result values using sqlite3_column_*() */ /* obtain result values using sqlite3_column_*() */
if (sqlite3_column_type(stmt, 1) == SQLITE_INTEGER) { if (sqlite3_column_type(stmt, 1) == SQLITE_INTEGER) {
/* we do have some 2G authentication data */ /* we do have some 2G authentication data */
if (hexparse_stmt(aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki), stmt, 2, "Ki", imsi)) if (hexparse_stmt(aud2g->u.gsm.ki, sizeof(aud2g->u.gsm.ki), sizeof(aud2g->u.gsm.ki),
stmt, 2, "Ki", imsi) < 0)
goto end_2g; goto end_2g;
aud2g->algo = sqlite3_column_int(stmt, 1); aud2g->algo = sqlite3_column_int(stmt, 1);
aud2g->type = OSMO_AUTH_TYPE_GSM; aud2g->type = OSMO_AUTH_TYPE_GSM;
@@ -148,24 +158,30 @@ int db_get_auth_data(struct db_context *dbc, const char *imsi,
end_2g: end_2g:
if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) { if (sqlite3_column_type(stmt, 3) == SQLITE_INTEGER) {
/* we do have some 3G authentication data */ /* we do have some 3G authentication data */
if (hexparse_stmt(aud3g->u.umts.k, sizeof(aud3g->u.umts.k), stmt, 4, "K", imsi)) { rc = hexparse_stmt(aud3g->u.umts.k, 16, sizeof(aud3g->u.umts.k), stmt, 4, "K", imsi);
if (rc < 0) {
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
aud3g->u.umts.k_len = rc;
aud3g->algo = sqlite3_column_int(stmt, 3); aud3g->algo = sqlite3_column_int(stmt, 3);
/* UMTS Subscribers can have either OP or OPC */ /* UMTS Subscribers can have either OP or OPC */
if (sqlite3_column_text(stmt, 5)) { if (sqlite3_column_text(stmt, 5)) {
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 5, "OP", imsi)) { rc = hexparse_stmt(aud3g->u.umts.opc, 16, sizeof(aud3g->u.umts.opc), stmt, 5, "OP", imsi);
if (rc < 0) {
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
aud3g->u.umts.opc_len = rc;
aud3g->u.umts.opc_is_op = 1; aud3g->u.umts.opc_is_op = 1;
} else { } else {
if (hexparse_stmt(aud3g->u.umts.opc, sizeof(aud3g->u.umts.opc), stmt, 6, "OPC", imsi)) { rc = hexparse_stmt(aud3g->u.umts.opc, 16, sizeof(aud3g->u.umts.opc), stmt, 6, "OPC", imsi);
if (rc < 0) {
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
aud3g->u.umts.opc_len = rc;
aud3g->u.umts.opc_is_op = 0; aud3g->u.umts.opc_is_op = 0;
} }
aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7); aud3g->u.umts.sqn = sqlite3_column_int64(stmt, 7);
@@ -191,7 +207,7 @@ int db_get_auc(struct db_context *dbc, const char *imsi,
unsigned int num_vec, const uint8_t *rand_auts, unsigned int num_vec, const uint8_t *rand_auts,
const uint8_t *auts, bool separation_bit) const uint8_t *auts, bool separation_bit)
{ {
struct osmo_sub_auth_data aud2g, aud3g; struct osmo_sub_auth_data2 aud2g, aud3g;
int64_t subscr_id; int64_t subscr_id;
int ret = 0; int ret = 0;
int rc; int rc;

View File

@@ -1,4 +1,4 @@
/* (C) 2015 by Harald Welte <laforge@gnumonks.org> /* (C) 2015-2023 by Harald Welte <laforge@gnumonks.org>
* *
* All Rights Reserved * All Rights Reserved
* *
@@ -238,8 +238,9 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
case OSMO_AUTH_ALG_COMP128v1: case OSMO_AUTH_ALG_COMP128v1:
case OSMO_AUTH_ALG_COMP128v2: case OSMO_AUTH_ALG_COMP128v2:
case OSMO_AUTH_ALG_COMP128v3: case OSMO_AUTH_ALG_COMP128v3:
case OSMO_AUTH_ALG_XOR: case OSMO_AUTH_ALG_XOR_2G:
break; break;
case OSMO_AUTH_ALG_XOR_3G:
case OSMO_AUTH_ALG_MILENAGE: case OSMO_AUTH_ALG_MILENAGE:
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
" auth algo not suited for 2G: %s\n", " auth algo not suited for 2G: %s\n",
@@ -267,11 +268,12 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
switch (aud->algo) { switch (aud->algo) {
case OSMO_AUTH_ALG_NONE: case OSMO_AUTH_ALG_NONE:
case OSMO_AUTH_ALG_MILENAGE: case OSMO_AUTH_ALG_MILENAGE:
case OSMO_AUTH_ALG_XOR: case OSMO_AUTH_ALG_XOR_3G:
break; break;
case OSMO_AUTH_ALG_COMP128v1: case OSMO_AUTH_ALG_COMP128v1:
case OSMO_AUTH_ALG_COMP128v2: case OSMO_AUTH_ALG_COMP128v2:
case OSMO_AUTH_ALG_COMP128v3: case OSMO_AUTH_ALG_COMP128v3:
case OSMO_AUTH_ALG_XOR_2G:
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
" auth algo not suited for 3G: %s\n", " auth algo not suited for 3G: %s\n",
osmo_auth_alg_name(aud->algo)); osmo_auth_alg_name(aud->algo));
@@ -284,12 +286,12 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
if (aud->algo == OSMO_AUTH_ALG_NONE) if (aud->algo == OSMO_AUTH_ALG_NONE)
break; break;
if (!osmo_is_hexstr(aud->u.umts.k, 32, 32, true)) { if (!osmo_is_hexstr(aud->u.umts.k, 32, 64, true)) {
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
" Invalid K: '%s'\n", aud->u.umts.k); " Invalid K: '%s'\n", aud->u.umts.k);
return -EINVAL; return -EINVAL;
} }
if (!osmo_is_hexstr(aud->u.umts.opc, 32, 32, true)) { if (!osmo_is_hexstr(aud->u.umts.opc, 32, 64, true)) {
LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:" LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
" Invalid OP/OPC: '%s'\n", aud->u.umts.opc); " Invalid OP/OPC: '%s'\n", aud->u.umts.opc);
return -EINVAL; return -EINVAL;

View File

@@ -170,7 +170,7 @@ void dgsm_init(void *ctx)
g_hlr->mslookup.server.local_attach_max_age = 60 * 60; g_hlr->mslookup.server.local_attach_max_age = 60 * 60;
g_hlr->mslookup.client.result_timeout_milliseconds = 2000; g_hlr->mslookup.client.result_timeout_milliseconds = OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS;
g_hlr->gsup_unit_name.unit_name = "HLR"; g_hlr->gsup_unit_name.unit_name = "HLR";
g_hlr->gsup_unit_name.serno = "unnamed-HLR"; g_hlr->gsup_unit_name.serno = "unnamed-HLR";
@@ -191,7 +191,7 @@ void dgsm_start(void *ctx)
dgsm_mdns_client_config_apply(); dgsm_mdns_client_config_apply();
} }
void dgsm_stop() void dgsm_stop(void)
{ {
g_hlr->mslookup.allow_startup = false; g_hlr->mslookup.allow_startup = false;
mslookup_server_mdns_config_apply(); mslookup_server_mdns_config_apply();

View File

@@ -447,8 +447,8 @@ int config_write_mslookup(struct vty *vty)
llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) { llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name)) if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
continue; continue;
vty_out(vty, " msc %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE); vty_out(vty, " msc ipa-name %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
config_write_msc_services(vty, " ", msc); config_write_msc_services(vty, " ", msc);
} }
/* If the server is disabled, still output the above to not lose the service config. */ /* If the server is disabled, still output the above to not lose the service config. */
@@ -475,6 +475,10 @@ int config_write_mslookup(struct vty *vty)
vty_out(vty, " mdns domain-suffix %s%s", vty_out(vty, " mdns domain-suffix %s%s",
g_hlr->mslookup.client.mdns.domain_suffix, g_hlr->mslookup.client.mdns.domain_suffix,
VTY_NEWLINE); VTY_NEWLINE);
if (g_hlr->mslookup.client.result_timeout_milliseconds != OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS)
vty_out(vty, " timeout %u%s",
g_hlr->mslookup.client.result_timeout_milliseconds,
VTY_NEWLINE);
} }
return CMD_SUCCESS; return CMD_SUCCESS;

View File

@@ -32,6 +32,7 @@
#include <osmocom/hlr/gsup_server.h> #include <osmocom/hlr/gsup_server.h>
#include <osmocom/hlr/gsup_router.h> #include <osmocom/hlr/gsup_router.h>
#include <osmocom/hlr/hlr.h>
#define LOG_GSUP_CONN(conn, level, fmt, args...) \ #define LOG_GSUP_CONN(conn, level, fmt, args...) \
LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \ LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \
@@ -179,11 +180,9 @@ static int osmo_gsup_server_read_cb(struct ipa_server_conn *conn,
if (hh->proto == IPAC_PROTO_IPACCESS) { if (hh->proto == IPAC_PROTO_IPACCESS) {
rc = ipa_server_conn_ccm(conn, msg); rc = ipa_server_conn_ccm(conn, msg);
if (rc < 0) {
/* conn is already invalid here! */
return -1;
}
msgb_free(msg); msgb_free(msg);
if (rc < 0) /* conn is already invalid here! */
return -1;
return 0; return 0;
} }
@@ -446,19 +445,16 @@ int osmo_gsup_configure_wildcard_apn(struct osmo_gsup_message *gsup,
* \param[out] gsup The gsup message to populate. * \param[out] gsup The gsup message to populate.
* \param[in] imsi The subscriber's IMSI. * \param[in] imsi The subscriber's IMSI.
* \param[in] msisdn The subscriber's MSISDN. * \param[in] msisdn The subscriber's MSISDN.
* \param[out] msisdn_enc A buffer large enough to store the MSISDN in encoded form.
* \param[in] msisdn_enc_size Size of the buffer (must be >= OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN).
* \param[out] apn_buf A buffer large enough to store an APN (required if cn_domain is OSMO_GSUP_CN_DOMAIN_PS).
* \param[in] apn_buf_size Size of APN buffer (must be >= APN_MAXLEN).
* \param[in] cn_domain The CN Domain of the subscriber connection. * \param[in] cn_domain The CN Domain of the subscriber connection.
* \param[in] talloc_ctx To allocation memory for dynamic fields (msisdn, apn) in the gsup field
* \returns 0 on success, and negative on error. * \returns 0 on success, and negative on error.
*/ */
int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn, int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup, const char *imsi, const char *msisdn,
uint8_t *msisdn_enc, size_t msisdn_enc_size, enum osmo_gsup_cn_domain cn_domain,
uint8_t *apn_buf, size_t apn_buf_size, void *talloc_ctx)
enum osmo_gsup_cn_domain cn_domain)
{ {
int len; int len;
uint8_t *msisdn_buf = talloc_size(talloc_ctx, OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN);
OSMO_ASSERT(gsup); OSMO_ASSERT(gsup);
*gsup = (struct osmo_gsup_message){ *gsup = (struct osmo_gsup_message){
@@ -467,27 +463,29 @@ int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup,
osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi)); osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));
if (msisdn_enc_size < OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN) len = gsm48_encode_bcd_number(msisdn_buf, OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN, 0, msisdn);
return -ENOSPC;
OSMO_ASSERT(msisdn_enc);
len = gsm48_encode_bcd_number(msisdn_enc, msisdn_enc_size, 0, msisdn);
if (len < 1) { if (len < 1) {
LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn); LOGP(DLGSUP, LOGL_ERROR, "%s: Error: cannot encode MSISDN '%s'\n", imsi, msisdn);
return -ENOSPC; return -ENOSPC;
} }
gsup->msisdn_enc = msisdn_enc; gsup->msisdn_enc = msisdn_buf;
gsup->msisdn_enc_len = len; gsup->msisdn_enc_len = len;
#pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc" #pragma message "FIXME: deal with encoding the following data: gsup.hlr_enc"
gsup->cn_domain = cn_domain; gsup->cn_domain = cn_domain;
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) { if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS) {
OSMO_ASSERT(apn_buf_size >= APN_MAXLEN); if (g_hlr->ps.pdp_profile.enabled) {
OSMO_ASSERT(apn_buf); OSMO_ASSERT(g_hlr->ps.pdp_profile.num_pdp_infos <= ARRAY_SIZE(g_hlr->ps.pdp_profile.pdp_infos));
/* FIXME: PDP infos - use more fine-grained access control OSMO_ASSERT(g_hlr->ps.pdp_profile.num_pdp_infos <= ARRAY_SIZE(gsup->pdp_infos));
instead of wildcard APN */ memcpy(gsup->pdp_infos,
osmo_gsup_configure_wildcard_apn(gsup, apn_buf, apn_buf_size); g_hlr->ps.pdp_profile.pdp_infos,
sizeof(struct osmo_gsup_pdp_info) * g_hlr->ps.pdp_profile.num_pdp_infos);
gsup->num_pdp_infos = g_hlr->ps.pdp_profile.num_pdp_infos;
} else {
uint8_t *apn_buf = talloc_size(talloc_ctx, APN_MAXLEN);
osmo_gsup_configure_wildcard_apn(gsup, apn_buf, APN_MAXLEN);
}
} }
return 0; return 0;

View File

@@ -85,8 +85,6 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
llist_for_each_entry(co, &g_hlr->gs->clients, list) { llist_for_each_entry(co, &g_hlr->gs->clients, list) {
struct osmo_gsup_message gsup = { }; struct osmo_gsup_message gsup = { };
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
uint8_t apn[APN_MAXLEN];
struct msgb *msg_out; struct msgb *msg_out;
uint8_t *peer; uint8_t *peer;
int peer_len; int peer_len;
@@ -131,8 +129,7 @@ osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr)
subscr->imsi, cn_domain == OSMO_GSUP_CN_DOMAIN_PS ? "PS" : "CS", subscr->imsi, cn_domain == OSMO_GSUP_CN_DOMAIN_PS ? "PS" : "CS",
osmo_quote_str(peer_compare, -1)); osmo_quote_str(peer_compare, -1));
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, msisdn_enc, if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, subscr->msisdn, cn_domain, OTC_SELECT) != 0) {
sizeof(msisdn_enc), apn, sizeof(apn), cn_domain) != 0) {
LOGP(DLGSUP, LOGL_ERROR, LOGP(DLGSUP, LOGL_ERROR,
"IMSI='%s': Cannot notify GSUP client; could not create gsup message " "IMSI='%s': Cannot notify GSUP client; could not create gsup message "
"for %s:%u\n", subscr->imsi, "for %s:%u\n", subscr->imsi,
@@ -324,7 +321,7 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
" Returning slightly inaccurate cause 'IMSI Unknown' via GSUP"); " Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");
return rc; return rc;
case -ENOENT: case -ENOENT:
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown"); osmo_gsup_req_respond_err(req, g_hlr->reject_cause, "IMSI unknown");
return rc; return rc;
default: default:
osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db"); osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db");
@@ -568,12 +565,12 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
return 0; return 0;
} }
static void print_usage() static void print_usage(void)
{ {
printf("Usage: osmo-hlr\n"); printf("Usage: osmo-hlr\n");
} }
static void print_help() static void print_help(void)
{ {
printf(" -h --help This text.\n"); printf(" -h --help This text.\n");
printf(" -c --config-file filename The config file to use.\n"); printf(" -c --config-file filename The config file to use.\n");
@@ -727,7 +724,7 @@ static void signal_hdlr(int signal)
} }
static const char vlr_copyright[] = static const char vlr_copyright[] =
"Copyright (C) 2016, 2017 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n" "Copyright (C) 2016-2023 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n" "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n" "This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n"; "There is NO WARRANTY, to the extent permitted by law.\r\n";
@@ -759,6 +756,8 @@ int main(int argc, char **argv)
g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH); g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
g_hlr->mslookup.server.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT); g_hlr->mslookup.server.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
g_hlr->mslookup.client.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT); g_hlr->mslookup.client.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
g_hlr->reject_cause = GMM_CAUSE_IMSI_UNKNOWN;
g_hlr->no_proxy_reject_cause = GMM_CAUSE_IMSI_UNKNOWN;
/* Init default (call independent) SS session guard timeout value */ /* Init default (call independent) SS session guard timeout value */
g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT; g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
@@ -775,7 +774,7 @@ int main(int argc, char **argv)
osmo_stats_init(hlr_ctx); osmo_stats_init(hlr_ctx);
vty_init(&vty_info); vty_init(&vty_info);
ctrl_vty_init(hlr_ctx); ctrl_vty_init(hlr_ctx);
hlr_vty_init(); hlr_vty_init(hlr_ctx);
dgsm_vty_init(); dgsm_vty_init();
osmo_cpu_sched_vty_init(hlr_ctx); osmo_cpu_sched_vty_init(hlr_ctx);
handle_options(argc, argv); handle_options(argc, argv);
@@ -816,8 +815,7 @@ int main(int argc, char **argv)
} }
/* start telnet after reading config for vty_get_bind_addr() */ /* start telnet after reading config for vty_get_bind_addr() */
rc = telnet_init_dynif(hlr_ctx, NULL, vty_get_bind_addr(), rc = telnet_init_default(hlr_ctx, NULL, OSMO_VTY_PORT_HLR);
OSMO_VTY_PORT_HLR);
if (rc < 0) if (rc < 0)
return rc; return rc;
@@ -830,7 +828,6 @@ int main(int argc, char **argv)
} }
proxy_init(g_hlr->gs); proxy_init(g_hlr->gs);
g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
g_hlr->ctrl = hlr_controlif_setup(g_hlr); g_hlr->ctrl = hlr_controlif_setup(g_hlr);
dgsm_start(hlr_ctx); dgsm_start(hlr_ctx);

View File

@@ -51,7 +51,7 @@ static struct {
.db_upgrade = false, .db_upgrade = false,
}; };
static void print_help() static void print_help(void)
{ {
printf("\n"); printf("\n");
printf("Usage: osmo-hlr-db-tool [-l <hlr.db>] [create|import-nitb-db <nitb.db>]\n"); printf("Usage: osmo-hlr-db-tool [-l <hlr.db>] [create|import-nitb-db <nitb.db>]\n");

View File

@@ -122,9 +122,40 @@ void ussd_route_del(struct hlr_ussd_route *rt)
talloc_free(rt); talloc_free(rt);
} }
static struct hlr_ussd_route *ussd_route_lookup_7bit(struct hlr *hlr, const char *ussd_code) static struct hlr_ussd_route *ussd_route_lookup_for_req(struct hlr *hlr, const struct ss_request *req)
{ {
const uint8_t cgroup = req->ussd_data_dcs >> 4;
const uint8_t lang = req->ussd_data_dcs & 0x0f;
char ussd_code[GSM0480_USSD_7BIT_STRING_LEN];
struct hlr_ussd_route *rt; struct hlr_ussd_route *rt;
ussd_code[0] = '\0';
/* We support only the Coding Group 0 (GSM 7-bit default alphabeet). In fact,
* the USSD request is usually limited to [*#0-9], so we don't really need to
* support other coding groups and languages. */
switch (cgroup) {
case 0:
/* The Language is usually set to '1111'B (unspecified), but some UEs
* are known to indicate '0000'B (German). */
if (lang != 0x0f) {
LOGP(DSS, LOGL_NOTICE, "USSD DataCodingScheme (0x%02x): "
"the Language is usually set to 15 (unspecified), "
"but the request indicates %u - ignoring this\n",
req->ussd_data_dcs, lang);
/* do not abort, attempt to decode as if it was '1111'B */
}
gsm_7bit_decode_n_ussd(&ussd_code[0], sizeof(ussd_code),
req->ussd_data, (req->ussd_data_len * 8) / 7);
break;
default:
LOGP(DSS, LOGL_ERROR, "USSD DataCodingScheme (0x%02x): "
"Coding Group %u is not supported, expecting Coding Group 0\n",
req->ussd_data_dcs, cgroup);
return NULL;
}
llist_for_each_entry(rt, &hlr->ussd_routes, list) { llist_for_each_entry(rt, &hlr->ussd_routes, list) {
if (!strncmp(ussd_code, rt->prefix, strlen(rt->prefix))) { if (!strncmp(ussd_code, rt->prefix, strlen(rt->prefix))) {
LOGP(DSS, LOGL_DEBUG, "Found %s '%s' (prefix '%s') for USSD " LOGP(DSS, LOGL_DEBUG, "Found %s '%s' (prefix '%s') for USSD "
@@ -603,7 +634,7 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
} else { } else {
/* VLR->EUSE: MO USSD. VLR is known ('conn'), EUSE is to be resolved */ /* VLR->EUSE: MO USSD. VLR is known ('conn'), EUSE is to be resolved */
struct hlr_ussd_route *rt; struct hlr_ussd_route *rt;
rt = ussd_route_lookup_7bit(hlr, (const char *) req.ussd_text); rt = ussd_route_lookup_for_req(hlr, &req);
if (rt) { if (rt) {
if (rt->is_external) { if (rt->is_external) {
ss->is_external = true; ss->is_external = true;
@@ -631,7 +662,8 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
if (!ss) { if (!ss) {
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: CONTINUE for unknown SS session\n", LOGP(DSS, LOGL_ERROR, "%s/0x%08x: CONTINUE for unknown SS session\n",
gsup->imsi, gsup->session_id); gsup->imsi, gsup->session_id);
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_INV_MAND_INFO, "CONTINUE for unknown SS session"); osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_MSGT_INCOMP_P_STATE,
"CONTINUE for unknown SS session");
return; return;
} }
@@ -652,6 +684,8 @@ void rx_proc_ss_req(struct osmo_gsup_req *gsup_req)
if (!ss) { if (!ss) {
LOGP(DSS, LOGL_ERROR, "%s/0x%08x: END for unknown SS session\n", LOGP(DSS, LOGL_ERROR, "%s/0x%08x: END for unknown SS session\n",
gsup->imsi, gsup->session_id); gsup->imsi, gsup->session_id);
osmo_gsup_req_respond_err(gsup_req, GMM_CAUSE_MSGT_INCOMP_P_STATE,
"END for unknown SS session");
return; return;
} }
@@ -682,4 +716,5 @@ void rx_proc_ss_error(struct osmo_gsup_req *req)
{ {
LOGP(DSS, LOGL_NOTICE, "%s/0x%08x: Process SS ERROR (%s)\n", req->gsup.imsi, req->gsup.session_id, LOGP(DSS, LOGL_NOTICE, "%s/0x%08x: Process SS ERROR (%s)\n", req->gsup.imsi, req->gsup.session_id,
osmo_gsup_session_state_name(req->gsup.session_state)); osmo_gsup_session_state_name(req->gsup.session_state));
osmo_gsup_req_free(req);
} }

View File

@@ -25,7 +25,13 @@
* *
*/ */
#include <errno.h>
#include <string.h>
#include <osmocom/core/talloc.h> #include <osmocom/core/talloc.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/vty/vty.h> #include <osmocom/vty/vty.h>
#include <osmocom/vty/stats.h> #include <osmocom/vty/stats.h>
#include <osmocom/vty/command.h> #include <osmocom/vty/command.h>
@@ -40,6 +46,36 @@
#include <osmocom/hlr/hlr_ussd.h> #include <osmocom/hlr/hlr_ussd.h>
#include <osmocom/hlr/gsup_server.h> #include <osmocom/hlr/gsup_server.h>
static const struct value_string gsm48_gmm_cause_vty_names[] = {
{ GMM_CAUSE_IMSI_UNKNOWN, "imsi-unknown" },
{ GMM_CAUSE_ILLEGAL_MS, "illegal-ms" },
{ GMM_CAUSE_PLMN_NOTALLOWED, "plmn-not-allowed" },
{ GMM_CAUSE_LA_NOTALLOWED, "la-not-allowed" },
{ GMM_CAUSE_ROAMING_NOTALLOWED, "roaming-not-allowed" },
{ GMM_CAUSE_NO_SUIT_CELL_IN_LA, "no-suitable-cell-in-la" },
{ GMM_CAUSE_NET_FAIL, "net-fail" },
{ GMM_CAUSE_CONGESTION, "congestion" },
{ GMM_CAUSE_GSM_AUTH_UNACCEPT, "auth-unacceptable" },
{ GMM_CAUSE_PROTO_ERR_UNSPEC, "proto-error-unspec" },
{ 0, NULL },
};
/* TS 24.008 4.4.4.7 */
static const struct value_string gsm48_gmm_cause_vty_descs[] = {
{ GMM_CAUSE_IMSI_UNKNOWN, " #02: (IMSI unknown in HLR)" },
{ GMM_CAUSE_ILLEGAL_MS, " #03 (Illegal MS)" },
{ GMM_CAUSE_PLMN_NOTALLOWED, " #11: (PLMN not allowed)" },
{ GMM_CAUSE_LA_NOTALLOWED, " #12: (Location Area not allowed)" },
{ GMM_CAUSE_ROAMING_NOTALLOWED, " #13: (Roaming not allowed in this location area)" },
{ GMM_CAUSE_NO_SUIT_CELL_IN_LA, " #15: (No Suitable Cells In Location Area [continue search in PLMN])." },
{ GMM_CAUSE_NET_FAIL, " #17: (Network Failure)" },
{ GMM_CAUSE_CONGESTION, " #22: (Congestion)" },
{ GMM_CAUSE_GSM_AUTH_UNACCEPT, " #23: (GSM authentication unacceptable [UMTS])" },
{ GMM_CAUSE_PROTO_ERR_UNSPEC, "#111: (Protocol error, unspecified)" },
{ 0, NULL },
};
struct cmd_node hlr_node = { struct cmd_node hlr_node = {
HLR_NODE, HLR_NODE,
"%s(config-hlr)# ", "%s(config-hlr)# ",
@@ -70,9 +106,194 @@ DEFUN(cfg_gsup,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
struct cmd_node ps_node = {
PS_NODE,
"%s(config-hlr-ps)# ",
1,
};
DEFUN(cfg_ps,
cfg_ps_cmd,
"ps",
"Configure the PS options")
{
vty->node = PS_NODE;
return CMD_SUCCESS;
}
struct cmd_node ps_pdp_profiles_node = {
PS_PDP_PROFILES_NODE,
"%s(config-hlr-ps-pdp-profiles)# ",
1,
};
DEFUN(cfg_ps_pdp_profiles,
cfg_ps_pdp_profiles_cmd,
"pdp-profiles default",
"Define a PDP profile set.\n"
"Define the global default profile.\n")
{
g_hlr->ps.pdp_profile.enabled = true;
vty->node = PS_PDP_PROFILES_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_no_ps_pdp_profiles,
cfg_no_ps_pdp_profiles_cmd,
"no pdp-profiles default",
NO_STR
"Delete PDP profile.\n"
"Unique identifier for this PDP profile set.\n")
{
g_hlr->ps.pdp_profile.enabled = false;
return CMD_SUCCESS;
}
struct cmd_node ps_pdp_profiles_profile_node = {
PS_PDP_PROFILES_PROFILE_NODE,
"%s(config-hlr-ps-pdp-profile)# ",
1,
};
/* context_id == 0 means the slot is free */
struct osmo_gsup_pdp_info *get_pdp_profile(uint8_t context_id)
{
for (int i = 0; i < OSMO_GSUP_MAX_NUM_PDP_INFO; i++) {
struct osmo_gsup_pdp_info *info = &g_hlr->ps.pdp_profile.pdp_infos[i];
if (info->context_id == context_id)
return info;
}
return NULL;
}
struct osmo_gsup_pdp_info *create_pdp_profile(uint8_t context_id)
{
struct osmo_gsup_pdp_info *info = get_pdp_profile(0);
if (!info)
return NULL;
memset(info, 0, sizeof(*info));
info->context_id = context_id;
info->have_info = 1;
g_hlr->ps.pdp_profile.num_pdp_infos++;
return info;
}
void destroy_pdp_profile(struct osmo_gsup_pdp_info *info)
{
info->context_id = 0;
if (info->apn_enc)
talloc_free((void *) info->apn_enc);
g_hlr->ps.pdp_profile.num_pdp_infos--;
memset(info, 0, sizeof(*info));
}
DEFUN(cfg_ps_pdp_profiles_profile,
cfg_ps_pdp_profiles_profile_cmd,
"profile <1-10>",
"Configure a PDP profile\n"
"Unique PDP context identifier. The lowest profile will be used as default context.\n")
{
struct osmo_gsup_pdp_info *info;
uint8_t context_id = atoi(argv[0]);
info = get_pdp_profile(context_id);
if (!info) {
info = create_pdp_profile(context_id);
if (!info) {
vty_out(vty, "Failed to create profile %d!%s", context_id, VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
}
vty->node = PS_PDP_PROFILES_PROFILE_NODE;
vty->index = info;
return CMD_SUCCESS;
}
DEFUN(cfg_no_ps_pdp_profiles_profile,
cfg_no_ps_pdp_profiles_profile_cmd,
"no profile <1-10>",
NO_STR
"Delete a PDP profile\n"
"Unique PDP context identifier. The lowest profile will be used as default context.\n")
{
struct osmo_gsup_pdp_info *info;
uint8_t context_id = atoi(argv[0]);
info = get_pdp_profile(context_id);
if (info)
destroy_pdp_profile(info);
return CMD_SUCCESS;
}
DEFUN(cfg_ps_pdp_profile_apn, cfg_ps_pdp_profile_apn_cmd,
"apn ID",
"Configure the APN.\n"
"APN name or * for wildcard apn.\n")
{
struct osmo_gsup_pdp_info *info = vty->index;
const char *apn_name = argv[0];
/* apn encoded takes one more byte than strlen() */
size_t apn_enc_len = strlen(apn_name) + 1;
uint8_t *apn_enc;
int ret;
if (apn_enc_len > APN_MAXLEN) {
vty_out(vty, "APN name is too long '%s'. Max is %d!%s", apn_name, APN_MAXLEN, VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
info->apn_enc = apn_enc = (uint8_t *) talloc_zero_size(g_hlr, apn_enc_len);
ret = info->apn_enc_len = osmo_apn_from_str(apn_enc, apn_enc_len, apn_name);
if (ret < 0) {
talloc_free(apn_enc);
info->apn_enc = NULL;
info->apn_enc_len = 0;
vty_out(vty, "Invalid APN name %s!", apn_name);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(cfg_no_ps_pdp_profile_apn, cfg_no_ps_pdp_profile_apn_cmd,
"no apn",
NO_STR
"Delete the APN.\n")
{
struct osmo_gsup_pdp_info *info = vty->index;
if (info->apn_enc) {
talloc_free((void *) info->apn_enc);
info->apn_enc = NULL;
info->apn_enc_len = 0;
}
return CMD_SUCCESS;
}
static int config_write_hlr(struct vty *vty) static int config_write_hlr(struct vty *vty)
{ {
vty_out(vty, "hlr%s", VTY_NEWLINE); vty_out(vty, "hlr%s", VTY_NEWLINE);
if (g_hlr->reject_cause != GMM_CAUSE_IMSI_UNKNOWN)
vty_out(vty, " reject-cause not-found %s%s",
get_value_string_or_null(gsm48_gmm_cause_vty_names,
(uint32_t) g_hlr->reject_cause), VTY_NEWLINE);
if (g_hlr->no_proxy_reject_cause != GMM_CAUSE_IMSI_UNKNOWN)
vty_out(vty, " reject-cause no-proxy %s%s",
get_value_string_or_null(gsm48_gmm_cause_vty_names,
(uint32_t) g_hlr->no_proxy_reject_cause), VTY_NEWLINE);
if (g_hlr->store_imei) if (g_hlr->store_imei)
vty_out(vty, " store-imei%s", VTY_NEWLINE); vty_out(vty, " store-imei%s", VTY_NEWLINE);
if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH)) if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH))
@@ -107,6 +328,37 @@ static int config_write_hlr_gsup(struct vty *vty)
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static int config_write_hlr_ps(struct vty *vty)
{
vty_out(vty, " ps%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
static int config_write_hlr_ps_pdp_profiles(struct vty *vty)
{
char apn[APN_MAXLEN + 1] = {};
if (!g_hlr->ps.pdp_profile.enabled)
return CMD_SUCCESS;
vty_out(vty, " pdp-profiles default%s", VTY_NEWLINE);
for (int i = 0; i < g_hlr->ps.pdp_profile.num_pdp_infos; i++) {
struct osmo_gsup_pdp_info *pdp_info = &g_hlr->ps.pdp_profile.pdp_infos[i];
if (!pdp_info->context_id)
continue;
vty_out(vty, " profile %d%s", pdp_info->context_id, VTY_NEWLINE);
if (!pdp_info->have_info)
continue;
if (pdp_info->apn_enc && pdp_info->apn_enc_len) {
osmo_apn_to_str(apn, pdp_info->apn_enc, pdp_info->apn_enc_len);
vty_out(vty, " apn %s%s", apn, VTY_NEWLINE);
}
}
return CMD_SUCCESS;
}
static void show_one_conn(struct vty *vty, const struct osmo_gsup_conn *conn) static void show_one_conn(struct vty *vty, const struct osmo_gsup_conn *conn)
{ {
const struct ipa_server_conn *isc = conn->conn; const struct ipa_server_conn *isc = conn->conn;
@@ -158,7 +410,7 @@ DEFUN(cfg_hlr_gsup_ipa_name,
{ {
if (vty->type != VTY_FILE) { if (vty->type != VTY_FILE) {
vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; " vty_out(vty, "gsup/ipa-name: The GSUP IPA name cannot be changed at run-time; "
"It can only be set in the configuraton file.%s", VTY_NEWLINE); "It can only be set in the configuration file.%s", VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }
@@ -358,6 +610,21 @@ DEFUN(cfg_ncss_guard_timeout, cfg_ncss_guard_timeout_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_reject_cause, cfg_reject_cause_cmd,
"reject-cause TYPE CAUSE", "") /* Dynamically Generated */
{
int cause_code = get_string_value(gsm48_gmm_cause_vty_names, argv[1]);
OSMO_ASSERT(cause_code >= 0);
if (strcmp(argv[0], "not-found") == 0)
g_hlr->reject_cause = (enum gsm48_gmm_cause) cause_code;
if (strcmp(argv[0], "no-proxy") == 0)
g_hlr->no_proxy_reject_cause = (enum gsm48_gmm_cause) cause_code;
return CMD_SUCCESS;
}
DEFUN(cfg_store_imei, cfg_store_imei_cmd, DEFUN(cfg_store_imei, cfg_store_imei_cmd,
"store-imei", "store-imei",
"Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send" "Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
@@ -450,8 +717,22 @@ int hlr_vty_is_config_node(struct vty *vty, int node)
} }
} }
void hlr_vty_init(void) void hlr_vty_init(void *hlr_ctx)
{ {
cfg_reject_cause_cmd.string =
vty_cmd_string_from_valstr(hlr_ctx,
gsm48_gmm_cause_vty_names,
"reject-cause (not-found|no-proxy) (", "|", ")",
VTY_DO_LOWER);
cfg_reject_cause_cmd.doc =
vty_cmd_string_from_valstr(hlr_ctx,
gsm48_gmm_cause_vty_descs,
"GSUP/GMM cause to be sent\n"
"in the case the IMSI could not be found in the database\n"
"in the case no remote HLR reponded to mslookup GSUP request\n",
"\n", "", 0);
logging_vty_add_cmds(); logging_vty_add_cmds();
osmo_talloc_vty_add_cmds(); osmo_talloc_vty_add_cmds();
osmo_stats_vty_add_cmds(); osmo_stats_vty_add_cmds();
@@ -467,6 +748,20 @@ void hlr_vty_init(void)
install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd); install_element(GSUP_NODE, &cfg_hlr_gsup_bind_ip_cmd);
install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd); install_element(GSUP_NODE, &cfg_hlr_gsup_ipa_name_cmd);
/* PS */
install_node(&ps_node, config_write_hlr_ps);
install_element(HLR_NODE, &cfg_ps_cmd);
install_node(&ps_pdp_profiles_node, config_write_hlr_ps_pdp_profiles);
install_element(PS_NODE, &cfg_ps_pdp_profiles_cmd);
install_element(PS_NODE, &cfg_no_ps_pdp_profiles_cmd);
install_node(&ps_pdp_profiles_profile_node, NULL);
install_element(PS_PDP_PROFILES_NODE, &cfg_ps_pdp_profiles_profile_cmd);
install_element(PS_PDP_PROFILES_NODE, &cfg_no_ps_pdp_profiles_profile_cmd);
install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_ps_pdp_profile_apn_cmd);
install_element(PS_PDP_PROFILES_PROFILE_NODE, &cfg_no_ps_pdp_profile_apn_cmd);
install_element(HLR_NODE, &cfg_database_cmd); install_element(HLR_NODE, &cfg_database_cmd);
install_element(HLR_NODE, &cfg_euse_cmd); install_element(HLR_NODE, &cfg_euse_cmd);
@@ -478,6 +773,7 @@ void hlr_vty_init(void)
install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd); install_element(HLR_NODE, &cfg_ussd_defaultroute_cmd);
install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd); install_element(HLR_NODE, &cfg_ussd_no_defaultroute_cmd);
install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd); install_element(HLR_NODE, &cfg_ncss_guard_timeout_cmd);
install_element(HLR_NODE, &cfg_reject_cause_cmd);
install_element(HLR_NODE, &cfg_store_imei_cmd); install_element(HLR_NODE, &cfg_store_imei_cmd);
install_element(HLR_NODE, &cfg_no_store_imei_cmd); install_element(HLR_NODE, &cfg_no_store_imei_cmd);
install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd); install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);

View File

@@ -1,5 +1,5 @@
/* OsmoHLR subscriber management VTY implementation */ /* OsmoHLR subscriber management VTY implementation */
/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de> /* (C) 2017-2023 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved * All Rights Reserved
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@@ -77,8 +77,8 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr) static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
{ {
int rc; int rc;
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE); vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
@@ -137,12 +137,12 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
if (aud2g.type != OSMO_AUTH_TYPE_NONE && aud2g.type != OSMO_AUTH_TYPE_GSM) { if (aud2g.type != OSMO_AUTH_TYPE_NONE && aud2g.type != OSMO_AUTH_TYPE_GSM) {
vty_out(vty, "%% Error: 2G auth data is not of type 'GSM'%s", VTY_NEWLINE); vty_out(vty, "%% Error: 2G auth data is not of type 'GSM'%s", VTY_NEWLINE);
aud2g = (struct osmo_sub_auth_data){}; aud2g = (struct osmo_sub_auth_data2){};
} }
if (aud3g.type != OSMO_AUTH_TYPE_NONE && aud3g.type != OSMO_AUTH_TYPE_UMTS) { if (aud3g.type != OSMO_AUTH_TYPE_NONE && aud3g.type != OSMO_AUTH_TYPE_UMTS) {
vty_out(vty, "%% Error: 3G auth data is not of type 'UMTS'%s", VTY_NEWLINE); vty_out(vty, "%% Error: 3G auth data is not of type 'UMTS'%s", VTY_NEWLINE);
aud3g = (struct osmo_sub_auth_data){}; aud3g = (struct osmo_sub_auth_data2){};
} }
if (aud2g.algo != OSMO_AUTH_ALG_NONE && aud2g.type != OSMO_AUTH_TYPE_NONE) { if (aud2g.algo != OSMO_AUTH_ALG_NONE && aud2g.type != OSMO_AUTH_TYPE_NONE) {
@@ -154,9 +154,10 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
if (aud3g.algo != OSMO_AUTH_ALG_NONE && aud3g.type != OSMO_AUTH_TYPE_NONE) { if (aud3g.algo != OSMO_AUTH_ALG_NONE && aud3g.type != OSMO_AUTH_TYPE_NONE) {
vty_out(vty, " 3G auth: %s%s", osmo_auth_alg_name(aud3g.algo), VTY_NEWLINE); vty_out(vty, " 3G auth: %s%s", osmo_auth_alg_name(aud3g.algo), VTY_NEWLINE);
vty_out(vty, " K=%s%s", hexdump_buf(aud3g.u.umts.k), VTY_NEWLINE); vty_out(vty, " K=%s%s",
osmo_hexdump_nospc(aud3g.u.umts.k, aud3g.u.umts.k_len), VTY_NEWLINE);
vty_out(vty, " %s=%s%s", aud3g.u.umts.opc_is_op? "OP" : "OPC", vty_out(vty, " %s=%s%s", aud3g.u.umts.opc_is_op? "OP" : "OPC",
hexdump_buf(aud3g.u.umts.opc), VTY_NEWLINE); osmo_hexdump_nospc(aud3g.u.umts.opc, aud3g.u.umts.opc_len), VTY_NEWLINE);
vty_out(vty, " IND-bitlen=%u", aud3g.u.umts.ind_bitlen); vty_out(vty, " IND-bitlen=%u", aud3g.u.umts.ind_bitlen);
if (aud3g.u.umts.sqn) if (aud3g.u.umts.sqn)
vty_out(vty, " last-SQN=%"PRIu64, aud3g.u.umts.sqn); vty_out(vty, " last-SQN=%"PRIu64, aud3g.u.umts.sqn);
@@ -460,20 +461,27 @@ static bool is_hexkey_valid(struct vty *vty, const char *label,
return false; return false;
} }
#define AUTH_ALG_TYPES_2G "(comp128v1|comp128v2|comp128v3|xor)" #define AUTH_ALG_TYPES_2G "(comp128v1|comp128v2|comp128v3|xor-2g)"
#define AUTH_ALG_TYPES_2G_HELP \ #define AUTH_ALG_TYPES_2G_HELP \
"Use COMP128v1 algorithm\n" \ "Use COMP128v1 algorithm\n" \
"Use COMP128v2 algorithm\n" \ "Use COMP128v2 algorithm\n" \
"Use COMP128v3 algorithm\n" \ "Use COMP128v3 algorithm\n" \
"Use XOR algorithm\n" "Use XOR-2G algorithm\n"
#define AUTH_ALG_TYPES_3G "milenage" #define AUTH_ALG_TYPES_3G "(milenage|tuak)"
#define AUTH_ALG_TYPES_3G_HELP \ #define AUTH_ALG_TYPES_3G_HELP \
"Use Milenage algorithm\n" "Use Milenage algorithm\n" \
"Use TUAK algorithm\n"
bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo, bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
int *minlen, int *maxlen) int *minlen, int *maxlen, int *minlen_opc, int *maxlen_opc)
{ {
/* Default: no OP[c]. True for all 2G algorithms, and 3G-XOR. Overridden below for real 3G AKA algorithms. */
if (minlen_opc)
*minlen_opc = 0;
if (maxlen_opc)
*maxlen_opc = 0;
if (!strcasecmp(alg_str, "none")) { if (!strcasecmp(alg_str, "none")) {
*algo = OSMO_AUTH_ALG_NONE; *algo = OSMO_AUTH_ALG_NONE;
*minlen = *maxlen = 0; *minlen = *maxlen = 0;
@@ -486,13 +494,28 @@ bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
} else if (!strcasecmp(alg_str, "comp128v3")) { } else if (!strcasecmp(alg_str, "comp128v3")) {
*algo = OSMO_AUTH_ALG_COMP128v3; *algo = OSMO_AUTH_ALG_COMP128v3;
*minlen = *maxlen = A38_COMP128_KEY_LEN; *minlen = *maxlen = A38_COMP128_KEY_LEN;
} else if (!strcasecmp(alg_str, "xor")) { } else if (!strcasecmp(alg_str, "xor-3g")) {
*algo = OSMO_AUTH_ALG_XOR; *algo = OSMO_AUTH_ALG_XOR_3G;
*minlen = A38_XOR_MIN_KEY_LEN; *minlen = A38_XOR_MIN_KEY_LEN;
*maxlen = A38_XOR_MAX_KEY_LEN; *maxlen = A38_XOR_MAX_KEY_LEN;
} else if (!strcasecmp(alg_str, "xor-2g")) {
*algo = OSMO_AUTH_ALG_XOR_2G;
*minlen = *maxlen = A38_XOR2G_KEY_LEN;
} else if (!strcasecmp(alg_str, "milenage")) { } else if (!strcasecmp(alg_str, "milenage")) {
*algo = OSMO_AUTH_ALG_MILENAGE; *algo = OSMO_AUTH_ALG_MILENAGE;
*minlen = *maxlen = MILENAGE_KEY_LEN; *minlen = *maxlen = MILENAGE_KEY_LEN;
if (minlen_opc)
*minlen_opc = MILENAGE_KEY_LEN;
if (maxlen_opc)
*maxlen_opc = MILENAGE_KEY_LEN;
} else if (!strcasecmp(alg_str, "tuak")) {
*algo = OSMO_AUTH_ALG_TUAK;
*minlen = 16;
*maxlen = 32;
if (minlen_opc)
*minlen_opc = 32;
if (maxlen_opc)
*maxlen_opc = 32;
} else } else
return false; return false;
return true; return true;
@@ -548,7 +571,7 @@ DEFUN(subscriber_aud2g,
.u.gsm.ki = ki, .u.gsm.ki = ki,
}; };
if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen)) { if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen, NULL, NULL)) {
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE); vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }
@@ -607,21 +630,21 @@ DEFUN(subscriber_aud3g,
SUBSCR_UPDATE_HELP SUBSCR_UPDATE_HELP
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n" "Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
AUTH_ALG_TYPES_3G_HELP AUTH_ALG_TYPES_3G_HELP
"Set Encryption Key K\n" "K as 32 hexadecimal characters\n" "Set Encryption Key K\n" "K as 32/64 hexadecimal characters\n"
"Set OP key\n" "Set OPC key\n" "OP or OPC as 32 hexadecimal characters\n" "Set OP key\n" "Set OPC key\n" "OP or OPC as 32/64 hexadecimal characters\n"
"Set IND bit length\n" "IND bit length value (default: 5)\n") "Set IND bit length\n" "IND bit length value (default: 5)\n")
{ {
struct hlr_subscriber subscr; struct hlr_subscriber subscr;
int minlen = 0; int minlen = 0, minlen_opc = 0;
int maxlen = 0; int maxlen = 0, maxlen_opc = 0;
int rc; int rc;
const char *id_type = argv[0]; const char *id_type = argv[0];
const char *id = argv[1]; const char *id = argv[1];
const char *alg_type = AUTH_ALG_TYPES_3G; const char *alg_type = argv[2];
const char *k = argv[2]; const char *k = argv[3];
bool opc_is_op = (strcasecmp("op", argv[3]) == 0); bool opc_is_op = (strcasecmp("op", argv[4]) == 0);
const char *op_opc = argv[4]; const char *op_opc = argv[5];
int ind_bitlen = argc > 6? atoi(argv[6]) : 5; int ind_bitlen = argc > 7 ? atoi(argv[7]) : 5;
struct sub_auth_data_str aud3g = { struct sub_auth_data_str aud3g = {
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.u.umts = { .u.umts = {
@@ -632,7 +655,7 @@ DEFUN(subscriber_aud3g,
}, },
}; };
if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen)) { if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen, &minlen_opc, &maxlen_opc)) {
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE); vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }
@@ -640,8 +663,7 @@ DEFUN(subscriber_aud3g,
if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen)) if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen))
return CMD_WARNING; return CMD_WARNING;
if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc, if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc, minlen_opc, maxlen_opc))
MILENAGE_KEY_LEN, MILENAGE_KEY_LEN))
return CMD_WARNING; return CMD_WARNING;
if (get_subscr_by_argv(vty, id_type, id, &subscr)) if (get_subscr_by_argv(vty, id_type, id, &subscr))
@@ -659,11 +681,11 @@ DEFUN(subscriber_aud3g,
DEFUN(subscriber_aud3g_xor, DEFUN(subscriber_aud3g_xor,
subscriber_aud3g_xor_cmd, subscriber_aud3g_xor_cmd,
SUBSCR_UPDATE "aud3g xor k K" SUBSCR_UPDATE "aud3g xor-3g k K"
" [ind-bitlen] [<0-28>]", " [ind-bitlen] [<0-28>]",
SUBSCR_UPDATE_HELP SUBSCR_UPDATE_HELP
"Set UMTS authentication data (3G, and 2G with UMTS AKA)\n" "Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
"Use XOR algorithm\n" "Use XOR-3G algorithm\n"
"Set Encryption Key K\n" "K as 32 hexadecimal characters\n" "Set Encryption Key K\n" "K as 32 hexadecimal characters\n"
"Set IND bit length\n" "IND bit length value (default: 5)\n") "Set IND bit length\n" "IND bit length value (default: 5)\n")
{ {
@@ -685,8 +707,8 @@ DEFUN(subscriber_aud3g_xor,
}, },
}; };
if (!auth_algo_parse("xor", &aud3g.algo, &minlen, &maxlen)) { if (!auth_algo_parse("xor-3g", &aud3g.algo, &minlen, &maxlen, NULL, NULL)) {
vty_out(vty, "%% Unknown auth algorithm: '%s'%s", "xor", VTY_NEWLINE); vty_out(vty, "%% Unknown auth algorithm: '%s'%s", "xor-3g", VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }

View File

@@ -136,7 +136,7 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
} }
if (db_subscr_get_by_imsi(g_hlr->dbc, update_location_req->gsup.imsi, &lu->subscr) < 0) { if (db_subscr_get_by_imsi(g_hlr->dbc, update_location_req->gsup.imsi, &lu->subscr) < 0) {
lu_failure(lu, GMM_CAUSE_IMSI_UNKNOWN, "Subscriber does not exist"); lu_failure(lu, g_hlr->reject_cause, "Subscriber does not exist");
return; return;
} }
@@ -241,13 +241,11 @@ static void lu_fsm_wait_insert_data_result_onenter(struct osmo_fsm_inst *fi, uin
struct lu *lu = fi->priv; struct lu *lu = fi->priv;
struct hlr_subscriber *subscr = &lu->subscr; struct hlr_subscriber *subscr = &lu->subscr;
struct osmo_gsup_message gsup; struct osmo_gsup_message gsup;
uint8_t msisdn_enc[OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN];
uint8_t apn[APN_MAXLEN];
if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi, if (osmo_gsup_create_insert_subscriber_data_msg(&gsup, subscr->imsi,
subscr->msisdn, msisdn_enc, sizeof(msisdn_enc), subscr->msisdn,
apn, sizeof(apn), lu->is_ps ? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS,
lu->is_ps? OSMO_GSUP_CN_DOMAIN_PS : OSMO_GSUP_CN_DOMAIN_CS)) { OTC_SELECT)) {
lu_failure(lu, GMM_CAUSE_NET_FAIL, "cannot encode Insert Subscriber Data message"); lu_failure(lu, GMM_CAUSE_NET_FAIL, "cannot encode Insert Subscriber Data message");
return; return;
} }
@@ -277,6 +275,7 @@ void lu_fsm_wait_insert_data_result(struct osmo_fsm_inst *fi, uint32_t event, vo
case OSMO_GSUP_MSGT_INSERT_DATA_ERROR: case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Rx %s", osmo_gsup_message_type_name(req->gsup.message_type)); lu_failure(lu, GMM_CAUSE_NET_FAIL, "Rx %s", osmo_gsup_message_type_name(req->gsup.message_type));
osmo_gsup_req_free(req);
break; break;
default: default:
@@ -314,7 +313,7 @@ static struct osmo_fsm lu_fsm = {
.cleanup = lu_fsm_cleanup, .cleanup = lu_fsm_cleanup,
}; };
static __attribute__((constructor)) void lu_fsm_init() static __attribute__((constructor)) void lu_fsm_init(void)
{ {
OSMO_ASSERT(osmo_fsm_register(&lu_fsm) == 0); OSMO_ASSERT(osmo_fsm_register(&lu_fsm) == 0);
} }

View File

@@ -1,7 +1,7 @@
# This is _NOT_ the library release version, it's an API version. # This is _NOT_ the library release version, it's an API version.
# Please read chapter "Library interface versions" of the libtool documentation # Please read chapter "Library interface versions" of the libtool documentation
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html # before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
LIBVERSION=0:0:0 LIBVERSION=1:1:0
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include
AM_CFLAGS = -fPIC -Wall $(PCSC_CFLAGS) $(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS) AM_CFLAGS = -fPIC -Wall $(PCSC_CFLAGS) $(TALLOC_CFLAGS) $(LIBOSMOCORE_CFLAGS)

View File

@@ -40,7 +40,7 @@ int osmo_mdns_msg_request_encode(void *ctx, struct msgb *msg, const struct osmo_
qst.domain = req->domain; qst.domain = req->domain;
qst.qtype = req->type; qst.qtype = req->type;
qst.qclass = OSMO_MDNS_RFC_CLASS_IN; qst.qclass = OSMO_MDNS_RFC_CLASS_IN;
if (osmo_mdns_rfc_question_encode(ctx, msg, &qst) != 0) if (osmo_mdns_rfc_question_encode(msg, &qst) != 0)
return -EINVAL; return -EINVAL;
return 0; return 0;
@@ -106,7 +106,7 @@ int osmo_mdns_msg_answer_encode(void *ctx, struct msgb *msg, const struct osmo_m
rec.rdlength = ans_record->length; rec.rdlength = ans_record->length;
rec.rdata = ans_record->data; rec.rdata = ans_record->data;
if (osmo_mdns_rfc_record_encode(ctx, msg, &rec) != 0) if (osmo_mdns_rfc_record_encode(msg, &rec) != 0)
return -EINVAL; return -EINVAL;
} }

View File

@@ -27,91 +27,9 @@
#include <osmocom/core/msgb.h> #include <osmocom/core/msgb.h>
#include <osmocom/core/bitvec.h> #include <osmocom/core/bitvec.h>
#include <osmocom/core/logging.h> #include <osmocom/core/logging.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/mslookup/mdns_rfc.h> #include <osmocom/mslookup/mdns_rfc.h>
/*
* Encode/decode IEs
*/
/*! Encode a domain string as qname (RFC 1035 4.1.2).
* \param[in] domain multiple labels separated by dots, e.g. "sip.voice.1234.msisdn".
* \returns allocated buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...), NULL on error.
*/
char *osmo_mdns_rfc_qname_encode(void *ctx, const char *domain)
{
char *domain_dup;
char *domain_iter;
char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 2] = ""; /* len(qname) is len(domain) +1 */
struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
char *label;
if (strlen(domain) > OSMO_MDNS_RFC_MAX_NAME_LEN)
return NULL;
domain_iter = domain_dup = talloc_strdup(ctx, domain);
while ((label = strsep(&domain_iter, "."))) {
size_t len = strlen(label);
/* Empty domain, dot at start, two dots in a row, or ending with a dot */
if (!len)
goto error;
OSMO_STRBUF_PRINTF(sb, "%c%s", (char)len, label);
}
talloc_free(domain_dup);
return talloc_strdup(ctx, buf);
error:
talloc_free(domain_dup);
return NULL;
}
/*! Decode a domain string from a qname (RFC 1035 4.1.2).
* \param[in] qname buffer with length-value pairs for each label (e.g. 0x03 "sip" 0x05 "voice" ...)
* \param[in] qname_max_len amount of bytes that can be read at most from the memory location that qname points to.
* \returns allocated buffer with domain string, multiple labels separated by dots (e.g. "sip.voice.1234.msisdn"),
* NULL on error.
*/
char *osmo_mdns_rfc_qname_decode(void *ctx, const char *qname, size_t qname_max_len)
{
const char *next_label, *qname_end = qname + qname_max_len;
char buf[OSMO_MDNS_RFC_MAX_NAME_LEN + 1];
int i = 0;
if (qname_max_len < 1)
return NULL;
while (*qname) {
size_t len;
if (i >= qname_max_len)
return NULL;
len = *qname;
next_label = qname + len + 1;
if (next_label >= qname_end || i + len > OSMO_MDNS_RFC_MAX_NAME_LEN)
return NULL;
if (i) {
/* Two dots in a row is not allowed */
if (buf[i - 1] == '.')
return NULL;
buf[i] = '.';
i++;
}
memcpy(buf + i, qname + 1, len);
i += len;
qname = next_label;
}
buf[i] = '\0';
return talloc_strdup(ctx, buf);
}
/* /*
* Encode/decode message sections * Encode/decode message sections
*/ */
@@ -151,20 +69,17 @@ int osmo_mdns_rfc_header_decode(const uint8_t *data, size_t data_len, struct osm
/*! Encode question section (RFC 1035 4.1.2). /*! Encode question section (RFC 1035 4.1.2).
* \param[in] msgb mesage buffer to which the encoded data will be appended. * \param[in] msgb mesage buffer to which the encoded data will be appended.
*/ */
int osmo_mdns_rfc_question_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_question *qst) int osmo_mdns_rfc_question_encode(struct msgb *msg, const struct osmo_mdns_rfc_question *qst)
{ {
char *qname; uint8_t *buf;
size_t qname_len; size_t buf_len;
uint8_t *qname_buf;
/* qname */ /* qname */
qname = osmo_mdns_rfc_qname_encode(ctx, qst->domain); buf_len = strlen(qst->domain) + 1;
if (!qname) buf = msgb_put(msg, buf_len);
if (osmo_apn_from_str(buf, buf_len, qst->domain) < 0)
return -EINVAL; return -EINVAL;
qname_len = strlen(qname) + 1; msgb_put_u8(msg, 0x00);
qname_buf = msgb_put(msg, qname_len);
memcpy(qname_buf, qname, qname_len);
talloc_free(qname);
/* qtype and qclass */ /* qtype and qclass */
msgb_put_u16(msg, qst->qtype); msgb_put_u16(msg, qst->qtype);
@@ -182,21 +97,25 @@ struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const ui
if (data_len < 6) if (data_len < 6)
return NULL; return NULL;
/* qname */
ret = talloc_zero(ctx, struct osmo_mdns_rfc_question); ret = talloc_zero(ctx, struct osmo_mdns_rfc_question);
if (!ret) if (!ret)
return NULL; return NULL;
ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, qname_len);
if (!ret->domain) { /* qname */
talloc_free(ret); ret->domain = talloc_size(ret, qname_len - 1);
return NULL; if (!ret->domain)
} goto error;
if (!osmo_apn_to_str(ret->domain, data, qname_len - 1))
goto error;
/* qtype and qclass */ /* qtype and qclass */
ret->qtype = osmo_load16be(data + qname_len); ret->qtype = osmo_load16be(data + qname_len);
ret->qclass = osmo_load16be(data + qname_len + 2); ret->qclass = osmo_load16be(data + qname_len + 2);
return ret; return ret;
error:
talloc_free(ret);
return NULL;
} }
/* /*
@@ -206,20 +125,17 @@ struct osmo_mdns_rfc_question *osmo_mdns_rfc_question_decode(void *ctx, const ui
/*! Encode one resource record (RFC 1035 4.1.3). /*! Encode one resource record (RFC 1035 4.1.3).
* \param[in] msgb mesage buffer to which the encoded data will be appended. * \param[in] msgb mesage buffer to which the encoded data will be appended.
*/ */
int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_mdns_rfc_record *rec) int osmo_mdns_rfc_record_encode(struct msgb *msg, const struct osmo_mdns_rfc_record *rec)
{ {
char *name;
size_t name_len;
uint8_t *buf; uint8_t *buf;
size_t buf_len;
/* name */ /* name */
name = osmo_mdns_rfc_qname_encode(ctx, rec->domain); buf_len = strlen(rec->domain) + 1;
if (!name) buf = msgb_put(msg, buf_len);
if (osmo_apn_from_str(buf, buf_len, rec->domain) < 0)
return -EINVAL; return -EINVAL;
name_len = strlen(name) + 1; msgb_put_u8(msg, 0x00);
buf = msgb_put(msg, name_len);
memcpy(buf, name, name_len);
talloc_free(name);
/* type, class, ttl, rdlength */ /* type, class, ttl, rdlength */
msgb_put_u16(msg, rec->type); msgb_put_u16(msg, rec->type);
@@ -237,15 +153,26 @@ int osmo_mdns_rfc_record_encode(void *ctx, struct msgb *msg, const struct osmo_m
struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len, struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_t *data, size_t data_len,
size_t *record_len) size_t *record_len)
{ {
struct osmo_mdns_rfc_record *ret = talloc_zero(ctx, struct osmo_mdns_rfc_record); struct osmo_mdns_rfc_record *ret;
size_t name_len; size_t name_len;
/* name */ /* name length: represented as a series of labels, and terminated by a
ret->domain = osmo_mdns_rfc_qname_decode(ret, (const char *)data, data_len - 10); * label with zero length (RFC 1035 3.3). A label with zero length is a
* NUL byte. */
name_len = strnlen((const char *)data, data_len - 10) + 1;
if (data[name_len])
return NULL;
/* allocate ret + ret->domain */
ret = talloc_zero(ctx, struct osmo_mdns_rfc_record);
if (!ret)
return NULL;
ret->domain = talloc_size(ctx, name_len - 1);
if (!ret->domain) if (!ret->domain)
goto error; goto error;
name_len = strlen(ret->domain) + 2;
if (name_len + 10 > data_len) /* name */
if (!osmo_apn_to_str(ret->domain, data, name_len - 1))
goto error; goto error;
/* type, class, ttl, rdlength */ /* type, class, ttl, rdlength */
@@ -259,7 +186,7 @@ struct osmo_mdns_rfc_record *osmo_mdns_rfc_record_decode(void *ctx, const uint8_
/* rdata */ /* rdata */
ret->rdata = talloc_memdup(ret, data + name_len + 10, ret->rdlength); ret->rdata = talloc_memdup(ret, data + name_len + 10, ret->rdlength);
if (!ret->rdata) if (!ret->rdata)
return NULL; goto error;
*record_len = name_len + 10 + ret->rdlength; *record_len = name_len + 10 + ret->rdlength;
return ret; return ret;

View File

@@ -53,7 +53,7 @@ static void print_version(void)
"\n"); "\n");
} }
static void print_help() static void print_help(void)
{ {
print_version(); print_version();
printf( printf(
@@ -419,9 +419,9 @@ static void socket_client_close(struct socket_client *c)
{ {
struct osmo_fd *ofd = &c->ofd; struct osmo_fd *ofd = &c->ofd;
osmo_fd_unregister(ofd);
close(ofd->fd); close(ofd->fd);
ofd->fd = -1; ofd->fd = -1;
osmo_fd_unregister(ofd);
llist_del(&c->entry); llist_del(&c->entry);
talloc_free(c); talloc_free(c);
@@ -555,15 +555,15 @@ int socket_init(const char *sock_path)
return 0; return 0;
} }
void socket_close() void socket_close(void)
{ {
struct socket_client *c, *n; struct socket_client *c, *n;
llist_for_each_entry_safe(c, n, &globals.socket_clients, entry) llist_for_each_entry_safe(c, n, &globals.socket_clients, entry)
socket_client_close(c); socket_client_close(c);
if (osmo_fd_is_registered(&globals.socket_ofd)) { if (osmo_fd_is_registered(&globals.socket_ofd)) {
osmo_fd_unregister(&globals.socket_ofd);
close(globals.socket_ofd.fd); close(globals.socket_ofd.fd);
globals.socket_ofd.fd = -1; globals.socket_ofd.fd = -1;
osmo_fd_unregister(&globals.socket_ofd);
} }
} }

View File

@@ -49,7 +49,7 @@ static void set_result(struct osmo_mslookup_result *result,
result->age = age; result->age = age;
} }
const struct mslookup_service_host *mslookup_server_get_local_gsup_addr() const struct mslookup_service_host *mslookup_server_get_local_gsup_addr(void)
{ {
static struct mslookup_service_host gsup_bind = {}; static struct mslookup_service_host gsup_bind = {};
struct mslookup_service_host *host; struct mslookup_service_host *host;

View File

@@ -121,7 +121,7 @@ void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server)
talloc_free(server); talloc_free(server);
} }
void mslookup_server_mdns_config_apply() void mslookup_server_mdns_config_apply(void)
{ {
/* Check whether to start/stop/restart mDNS server */ /* Check whether to start/stop/restart mDNS server */
bool should_run; bool should_run;

View File

@@ -29,6 +29,7 @@
#include <osmocom/gsupclient/gsup_client.h> #include <osmocom/gsupclient/gsup_client.h>
#include <osmocom/gsupclient/gsup_req.h> #include <osmocom/gsupclient/gsup_req.h>
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/logging.h> #include <osmocom/hlr/logging.h>
#include <osmocom/hlr/proxy.h> #include <osmocom/hlr/proxy.h>
#include <osmocom/hlr/remote_hlr.h> #include <osmocom/hlr/remote_hlr.h>
@@ -80,7 +81,19 @@ static void proxy_deferred_gsup_req_add(struct proxy *proxy, struct osmo_gsup_re
static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *req, struct remote_hlr *remote_hlr) static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *req, struct remote_hlr *remote_hlr)
{ {
if (!remote_hlr || !remote_hlr_is_up(remote_hlr)) { if (!remote_hlr || !remote_hlr_is_up(remote_hlr)) {
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "Proxy: Failed to connect to home HLR"); /* Do not respond with an error to a CHECK_IMEI_REQUEST as osmo-msc will send a LU Reject Cause #6
* Just respond ACK and deal with the IMSI check that comes next. */
if (req->gsup.message_type == OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST) {
/* Accept all IMEIs */
struct osmo_gsup_message gsup_reply = (struct osmo_gsup_message){
.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT,
.imei_result = OSMO_GSUP_IMEI_RESULT_ACK,
};
osmo_gsup_req_respond(req, &gsup_reply, false, true);
return;
}
osmo_gsup_req_respond_err(req, g_hlr->no_proxy_reject_cause,
"Proxy: Failed to connect to home HLR");
return; return;
} }
@@ -190,6 +203,7 @@ int proxy_subscr_create_or_update(struct proxy *proxy, const struct proxy_subscr
int _proxy_subscr_del(struct proxy_subscr_listentry *e) int _proxy_subscr_del(struct proxy_subscr_listentry *e)
{ {
llist_del(&e->entry); llist_del(&e->entry);
talloc_free(e);
return 0; return 0;
} }

View File

@@ -2,12 +2,12 @@ SUBDIRS = gen_ts_55_205_test_sets
AM_CPPFLAGS = \ AM_CPPFLAGS = \
$(all_includes) \ $(all_includes) \
-I$(top_srcdir)/include \
$(NULL) $(NULL)
AM_CFLAGS = \ AM_CFLAGS = \
-Wall \ -Wall \
-ggdb3 \ -ggdb3 \
-I$(top_srcdir)/include \
$(LIBOSMOCORE_CFLAGS) \ $(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \ $(LIBOSMOGSM_CFLAGS) \
$(NULL) $(NULL)
@@ -30,8 +30,8 @@ auc_test_SOURCES = \
$(NULL) $(NULL)
auc_test_LDADD = \ auc_test_LDADD = \
$(top_srcdir)/src/auc.c \ $(top_builddir)/src/auc.o \
$(top_srcdir)/src/logging.c \ $(top_builddir)/src/logging.o \
$(LIBOSMOCORE_LIBS) \ $(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \ $(LIBOSMOGSM_LIBS) \
$(NULL) $(NULL)
@@ -41,8 +41,8 @@ auc_ts_55_205_test_sets_SOURCES = \
$(NULL) $(NULL)
auc_ts_55_205_test_sets_LDADD = \ auc_ts_55_205_test_sets_LDADD = \
$(top_srcdir)/src/auc.c \ $(top_builddir)/src/auc.o \
$(top_srcdir)/src/logging.c \ $(top_builddir)/src/logging.o \
$(LIBOSMOCORE_LIBS) \ $(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \ $(LIBOSMOGSM_LIBS) \
$(NULL) $(NULL)

View File

@@ -116,14 +116,14 @@ int rand_get(uint8_t *rand, unsigned int len)
/* Subscriber with 2G-only (COMP128v1) authentication data */ /* Subscriber with 2G-only (COMP128v1) authentication data */
static void test_gen_vectors_2g_only(void) static void test_gen_vectors_2g_only(void)
{ {
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec; struct osmo_auth_vector vec;
int rc; int rc;
comment_start(); comment_start();
aud2g = (struct osmo_sub_auth_data){ aud2g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_GSM, .type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_COMP128v1, .algo = OSMO_AUTH_ALG_COMP128v1,
}; };
@@ -131,7 +131,7 @@ static void test_gen_vectors_2g_only(void)
osmo_hexparse("EB215756028D60E3275E613320AEC880", osmo_hexparse("EB215756028D60E3275E613320AEC880",
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki)); aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
aud3g = (struct osmo_sub_auth_data){ 0 }; aud3g = (struct osmo_sub_auth_data2){ 0 };
next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true); next_rand("39fa2f4e3d523d8619a73b4f65c3e14d", true);
@@ -179,14 +179,14 @@ static void test_gen_vectors_2g_only(void)
* reflects the default configuration of sysmoUSIM-SJS1 */ * reflects the default configuration of sysmoUSIM-SJS1 */
static void test_gen_vectors_2g_plus_3g(void) static void test_gen_vectors_2g_plus_3g(void)
{ {
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec; struct osmo_auth_vector vec;
int rc; int rc;
comment_start(); comment_start();
aud2g = (struct osmo_sub_auth_data){ aud2g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_GSM, .type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_COMP128v1, .algo = OSMO_AUTH_ALG_COMP128v1,
}; };
@@ -194,9 +194,11 @@ static void test_gen_vectors_2g_plus_3g(void)
osmo_hexparse("EB215756028D60E3275E613320AEC880", osmo_hexparse("EB215756028D60E3275E613320AEC880",
aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki)); aud2g.u.gsm.ki, sizeof(aud2g.u.gsm.ki));
aud3g = (struct osmo_sub_auth_data){ aud3g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_MILENAGE, .algo = OSMO_AUTH_ALG_MILENAGE,
.u.umts.k_len = 16,
.u.umts.opc_len = 16,
.u.umts.sqn = 31, .u.umts.sqn = 31,
}; };
@@ -292,8 +294,8 @@ void _test_gen_vectors_3g_only__expect_vecs(struct osmo_auth_vector vecs[3])
* tuples are suitable for both 2G and 3G authentication */ * tuples are suitable for both 2G and 3G authentication */
static void test_gen_vectors_3g_only(void) static void test_gen_vectors_3g_only(void)
{ {
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec; struct osmo_auth_vector vec;
struct osmo_auth_vector vecs[3]; struct osmo_auth_vector vecs[3];
uint8_t auts[14]; uint8_t auts[14];
@@ -302,11 +304,13 @@ static void test_gen_vectors_3g_only(void)
comment_start(); comment_start();
aud2g = (struct osmo_sub_auth_data){ 0 }; aud2g = (struct osmo_sub_auth_data2){ 0 };
aud3g = (struct osmo_sub_auth_data){ aud3g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_MILENAGE, .algo = OSMO_AUTH_ALG_MILENAGE,
.u.umts.k_len = 16,
.u.umts.opc_len = 16,
.u.umts.sqn = 31, .u.umts.sqn = 31,
}; };
@@ -466,18 +470,20 @@ static void test_gen_vectors_3g_only(void)
* 2G and 3G authentication */ * 2G and 3G authentication */
static void test_gen_vectors_3g_xor(void) static void test_gen_vectors_3g_xor(void)
{ {
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec; struct osmo_auth_vector vec;
int rc; int rc;
comment_start(); comment_start();
aud2g = (struct osmo_sub_auth_data){ 0 }; aud2g = (struct osmo_sub_auth_data2){ 0 };
aud3g = (struct osmo_sub_auth_data){ aud3g = (struct osmo_sub_auth_data2){
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_XOR, .algo = OSMO_AUTH_ALG_XOR_3G,
.u.umts.k_len = 16,
.u.umts.opc_len = 16,
.u.umts.sqn = 0, .u.umts.sqn = 0,
}; };
@@ -509,7 +515,7 @@ static void test_gen_vectors_3g_xor(void)
} }
/* Test a variety of invalid authentication data combinations */ /* Test a variety of invalid authentication data combinations */
void test_gen_vectors_bad_args() void test_gen_vectors_bad_args(void)
{ {
struct osmo_auth_vector vec; struct osmo_auth_vector vec;
uint8_t auts[14]; uint8_t auts[14];
@@ -517,39 +523,43 @@ void test_gen_vectors_bad_args()
int rc; int rc;
int i; int i;
struct osmo_sub_auth_data aud2g = { struct osmo_sub_auth_data2 aud2g = {
.type = OSMO_AUTH_TYPE_GSM, .type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_COMP128v1, .algo = OSMO_AUTH_ALG_COMP128v1,
}; };
struct osmo_sub_auth_data aud3g = { struct osmo_sub_auth_data2 aud3g = {
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_MILENAGE, .algo = OSMO_AUTH_ALG_MILENAGE,
.u.umts.k_len = 16,
.u.umts.opc_len = 16,
}; };
struct osmo_sub_auth_data aud2g_noalg = { struct osmo_sub_auth_data2 aud2g_noalg = {
.type = OSMO_AUTH_TYPE_GSM, .type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_NONE, .algo = OSMO_AUTH_ALG_NONE,
}; };
struct osmo_sub_auth_data aud3g_noalg = { struct osmo_sub_auth_data2 aud3g_noalg = {
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_NONE, .algo = OSMO_AUTH_ALG_NONE,
.u.umts.k_len = 16,
.u.umts.opc_len = 16,
}; };
struct osmo_sub_auth_data aud_notype = { struct osmo_sub_auth_data2 aud_notype = {
.type = OSMO_AUTH_TYPE_NONE, .type = OSMO_AUTH_TYPE_NONE,
.algo = OSMO_AUTH_ALG_MILENAGE, .algo = OSMO_AUTH_ALG_MILENAGE,
}; };
struct osmo_sub_auth_data no_aud = { struct osmo_sub_auth_data2 no_aud = {
.type = OSMO_AUTH_TYPE_NONE, .type = OSMO_AUTH_TYPE_NONE,
.algo = OSMO_AUTH_ALG_NONE, .algo = OSMO_AUTH_ALG_NONE,
}; };
struct { struct {
struct osmo_sub_auth_data *aud2g; struct osmo_sub_auth_data2 *aud2g;
struct osmo_sub_auth_data *aud3g; struct osmo_sub_auth_data2 *aud3g;
uint8_t *rand_auts; uint8_t *rand_auts;
uint8_t *auts; uint8_t *auts;
const char *label; const char *label;

View File

@@ -24,43 +24,46 @@
static void {func_name}(void) static void {func_name}(void)
{{ {{
struct osmo_sub_auth_data aud2g; struct osmo_sub_auth_data2 aud2g;
struct osmo_sub_auth_data aud3g; struct osmo_sub_auth_data2 aud3g;
struct osmo_auth_vector vec; struct osmo_auth_vector vec;
int rc; int rc;
comment_start(); comment_start();
aud2g = (struct osmo_sub_auth_data){{ 0 }}; aud2g = (struct osmo_sub_auth_data2){{ 0 }};
aud3g = (struct osmo_sub_auth_data){{ aud3g = (struct osmo_sub_auth_data2){{
.type = OSMO_AUTH_TYPE_UMTS, .type = OSMO_AUTH_TYPE_UMTS,
.algo = OSMO_AUTH_ALG_MILENAGE, .algo = OSMO_AUTH_ALG_MILENAGE,
.u.umts.k_len = 16,
.u.umts.opc_len = 16,
.u.umts.sqn = 31, .u.umts.sqn = 31,
}}; }};
osmo_hexparse("{Ki}", osmo_hexparse("{Ki}",
aud3g.u.umts.k, sizeof(aud3g.u.umts.k)); aud3g.u.umts.k, sizeof(aud3g.u.umts.k));
osmo_hexparse("{OPc}", osmo_hexparse("{OPc}",
aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc)); aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc));
osmo_hexparse("{RAND}", osmo_hexparse("{RAND}",
fake_rand, sizeof(fake_rand)); fake_rand, sizeof(fake_rand));
vec = (struct osmo_auth_vector){{ {{0}} }}; vec = (struct osmo_auth_vector){{ {{0}} }};
vec.res_len = 8;
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64); VERBOSE_ASSERT(aud3g.u.umts.sqn, == 31, "%"PRIu64);
rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL); rc = auc_compute_vectors(&vec, 1, &aud2g, &aud3g, NULL, NULL);
VERBOSE_ASSERT(rc, == 1, "%d"); VERBOSE_ASSERT(rc, == 1, "%d");
VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64); VERBOSE_ASSERT(aud3g.u.umts.sqn, == 32, "%"PRIu64);
VEC_IS(&vec, VEC_IS(&vec,
" rand: {RAND}\n" " rand: {RAND}\n"
" ck: {MIL3G-CK}\n" " ck: {MIL3G-CK}\n"
" ik: {MIL3G-IK}\n" " ik: {MIL3G-IK}\n"
" res: {MIL3G-RES}0000000000000000\n" " res: {MIL3G-RES}0000000000000000\n"
" kc: {Kc}\n" " kc: {Kc}\n"
" sres: {SRES#1}\n" " sres: {SRES#1}\n"
); );
comment_end(); comment_end();
}} }}

View File

@@ -55,7 +55,7 @@ char *vec_str(const struct osmo_auth_vector *vec)
if (pos >= end) \ if (pos >= end) \
return buf; \ return buf; \
pos += snprintf(pos, sizeof(buf) - (pos - buf), \ pos += snprintf(pos, sizeof(buf) - (pos - buf), \
" " #what ": %s\n", \ " " #what ": %s\n", \
osmo_hexdump_nospc((void*)&vec->what, sizeof(vec->what))) osmo_hexdump_nospc((void*)&vec->what, sizeof(vec->what)))
append(rand); append(rand);
@@ -71,7 +71,7 @@ char *vec_str(const struct osmo_auth_vector *vec)
#define VEC_IS(vec, expect) do { \ #define VEC_IS(vec, expect) do { \
char *_is = vec_str(vec); \ char *_is = vec_str(vec); \
if (strcmp(_is, expect)) { \ if (strcmp(_is, expect)) { \
fprintf(stderr, "MISMATCH! expected ==\n%s\n", \ fprintf(stderr, "MISMATCH! expected ==\n%s\n", \
expect); \ expect); \
char *a = _is; \ char *a = _is; \
@@ -100,7 +100,7 @@ int rand_get(uint8_t *rand, unsigned int len)
FUNCTIONS FUNCTIONS
int main() int main(int argc, char **argv)
{ {
printf("3GPP TS 55.205 Test Sets\n"); printf("3GPP TS 55.205 Test Sets\n");
void *tall_ctx = talloc_named_const(NULL, 1, "test"); void *tall_ctx = talloc_named_const(NULL, 1, "test");

View File

@@ -1,7 +1,10 @@
AM_CFLAGS = \ AM_CPPFLAGS = \
$(all_includes) \ $(all_includes) \
-I$(top_srcdir)/include \ -I$(top_srcdir)/include \
-I$(top_builddir)/include \ -I$(top_builddir)/include \
$(NULL)
AM_CFLAGS = \
-Wall \ -Wall \
-ggdb3 \ -ggdb3 \
$(LIBOSMOCORE_CFLAGS) \ $(LIBOSMOCORE_CFLAGS) \

View File

@@ -122,16 +122,16 @@ static void _fill_invalid(void *dest, size_t size)
/* Not linking the real auc_compute_vectors(), just returning num_vec. /* 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. */ * 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, int auc_compute_vectors(struct osmo_auth_vector *vec, unsigned int num_vec,
struct osmo_sub_auth_data *aud2g, struct osmo_sub_auth_data2 *aud2g,
struct osmo_sub_auth_data *aud3g, struct osmo_sub_auth_data2 *aud3g,
const uint8_t *rand_auts, const uint8_t *auts) const uint8_t *rand_auts, const uint8_t *auts)
{ return num_vec; } { return num_vec; }
static struct db_context *dbc = NULL; static struct db_context *dbc = NULL;
static void *ctx = NULL; static void *ctx = NULL;
static struct hlr_subscriber g_subscr; static struct hlr_subscriber g_subscr;
static struct osmo_sub_auth_data g_aud2g; static struct osmo_sub_auth_data2 g_aud2g;
static struct osmo_sub_auth_data g_aud3g; static struct osmo_sub_auth_data2 g_aud3g;
static int g_rc; static int g_rc;
static int64_t g_id; static int64_t g_id;
@@ -180,18 +180,21 @@ void dump_subscr(struct hlr_subscriber *subscr)
#undef Pb #undef Pb
} }
void dump_aud(const char *label, struct osmo_sub_auth_data *aud) void dump_aud(const char *label, struct osmo_sub_auth_data2 *aud)
{ {
if (aud->type == OSMO_AUTH_TYPE_NONE) { if (aud->type == OSMO_AUTH_TYPE_NONE) {
fprintf(stderr, "%s: none\n", label); fprintf(stderr, "%s: none\n", label);
return; return;
} }
fprintf(stderr, "%s: struct osmo_sub_auth_data {\n", label); fprintf(stderr, "%s: struct osmo_sub_auth_data2 {\n", label);
#define Pf(name, fmt) \ #define Pf(name, fmt) \
Pfo(name, fmt, aud) Pfo(name, fmt, aud)
#define Phex(name) \ #define Phex(name) \
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name))) Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, sizeof(aud->name)))
#define Phexl(name, len) \
Pfv(name, "'%s'", osmo_hexdump_nospc(aud->name, aud->len))
Pfv(type, "%s", osmo_sub_auth_type_name(aud->type)); Pfv(type, "%s", osmo_sub_auth_type_name(aud->type));
Pfv(algo, "%s", osmo_auth_alg_name(aud->algo)); Pfv(algo, "%s", osmo_auth_alg_name(aud->algo));
@@ -200,9 +203,9 @@ void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
Phex(u.gsm.ki); Phex(u.gsm.ki);
break; break;
case OSMO_AUTH_TYPE_UMTS: case OSMO_AUTH_TYPE_UMTS:
Phex(u.umts.opc); Phexl(u.umts.opc, u.umts.opc_len);
Pf(u.umts.opc_is_op, "%u"); Pf(u.umts.opc_is_op, "%u");
Phex(u.umts.k); Phexl(u.umts.k, u.umts.k_len);
Phex(u.umts.amf); Phex(u.umts.amf);
if (aud->u.umts.sqn) { if (aud->u.umts.sqn) {
Pf(u.umts.sqn, "%"PRIu64); Pf(u.umts.sqn, "%"PRIu64);
@@ -219,6 +222,7 @@ void dump_aud(const char *label, struct osmo_sub_auth_data *aud)
#undef Pf #undef Pf
#undef Phex #undef Phex
#undef Phexl
} }
void db_raw_sql(struct db_context *dbc, const char *sql) void db_raw_sql(struct db_context *dbc, const char *sql)
@@ -246,7 +250,7 @@ static int db_subscr_lu_str(struct db_context *dbc, int64_t subscr_id,
return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL); return db_subscr_lu(dbc, subscr_id, &vlr_nr, is_ps, NULL);
} }
static void test_subscr_create_update_sel_delete() static void test_subscr_create_update_sel_delete(void)
{ {
int64_t id0, id1, id2, id_short; int64_t id0, id1, id2, id_short;
comment_start(); comment_start();
@@ -541,7 +545,7 @@ static const struct sub_auth_data_str *mk_aud_3g(enum osmo_auth_algo algo,
return &aud; return &aud;
} }
static void test_subscr_aud() static void test_subscr_aud(void)
{ {
int64_t id; int64_t id;
@@ -586,7 +590,7 @@ static void test_subscr_aud()
ASSERT_SEL_AUD(imsi0, 0, id); ASSERT_SEL_AUD(imsi0, 0, id);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id, ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")), mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
0); 0);
ASSERT_SEL_AUD(imsi0, 0, id); ASSERT_SEL_AUD(imsi0, 0, id);
@@ -604,7 +608,7 @@ static void test_subscr_aud()
-ENOENT); -ENOENT);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id, ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")), mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")),
0); 0);
ASSERT_SEL_AUD(imsi0, 0, id); ASSERT_SEL_AUD(imsi0, 0, id);
@@ -707,12 +711,12 @@ static void test_subscr_aud()
ASSERT_SEL_AUD(imsi0, 0, id); ASSERT_SEL_AUD(imsi0, 0, id);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id, ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")), mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")),
-EINVAL); -EINVAL);
ASSERT_SEL_AUD(imsi0, 0, id); ASSERT_SEL_AUD(imsi0, 0, id);
ASSERT_RC(db_subscr_update_aud_by_id(dbc, id, ASSERT_RC(db_subscr_update_aud_by_id(dbc, id,
mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")), mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")),
-EINVAL); -EINVAL);
ASSERT_SEL_AUD(imsi0, 0, id); ASSERT_SEL_AUD(imsi0, 0, id);
@@ -783,7 +787,7 @@ static void test_subscr_aud()
/* Make each key too short in this test. Note that we can't set them longer than the allowed size without changing the /* Make each key too short in this test. Note that we can't set them longer than the allowed size without changing the
* table structure. */ * table structure. */
static void test_subscr_aud_invalid_len() static void test_subscr_aud_invalid_len(void)
{ {
int64_t id; int64_t id;
@@ -845,7 +849,7 @@ static void test_subscr_aud_invalid_len()
comment_end(); comment_end();
} }
static void test_subscr_sqn() static void test_subscr_sqn(void)
{ {
int64_t id; int64_t id;
@@ -918,7 +922,7 @@ static void test_subscr_sqn()
comment_end(); comment_end();
} }
static void test_ind() static void test_ind(void)
{ {
comment_start(); comment_start();

View File

@@ -824,7 +824,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data DAUC IMSI='123456789000000': No 3G Auth Data
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v1, .algo = COMP128v1,
.u.gsm.ki = '0123456789abcdef0123456789abcdef', .u.gsm.ki = '0123456789abcdef0123456789abcdef',
@@ -841,7 +841,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v1, "01234567
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data DAUC IMSI='123456789000000': No 3G Auth Data
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v1, .algo = COMP128v1,
.u.gsm.ki = '0123456789abcdef0123456789abcdef', .u.gsm.ki = '0123456789abcdef0123456789abcdef',
@@ -853,7 +853,7 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v2, "BeadedBe
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data DAUC IMSI='123456789000000': No 3G Auth Data
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v2, .algo = COMP128v2,
.u.gsm.ki = 'beadedbeeaced1ebbeddefacedfacade', .u.gsm.ki = 'beadedbeeaced1ebbeddefacedfacade',
@@ -865,21 +865,21 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_COMP128v3, "DeafBedd
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data DAUC IMSI='123456789000000': No 3G Auth Data
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'deafbeddedbabeacceededfadeddecaf', .u.gsm.ki = 'deafbeddedbabeacceededfadeddecaf',
} }
3G: none 3G: none
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0 db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data DAUC IMSI='123456789000000': No 3G Auth Data
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = XOR, .algo = XOR-2G,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: none 3G: none
@@ -900,14 +900,14 @@ 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_NONE, NULL)) --> -ENOENT
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "CededEffacedAceFacedBadFadedBeef")) --> 0 db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "CededEffacedAceFacedBadFadedBeef")) --> 0
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 3G Auth Data DAUC IMSI='123456789000000': No 3G Auth Data
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = XOR, .algo = XOR-2G,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: none 3G: none
@@ -932,7 +932,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -954,7 +954,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -970,7 +970,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'deaf0ff1ced0d0dabbedd1ced1cef00d', .u.umts.opc = 'deaf0ff1ced0d0dabbedd1ced1cef00d',
@@ -985,7 +985,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1001,7 +1001,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef', .u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
@@ -1033,7 +1033,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'cededeffacedacefacedbadfadedbeef', .u.umts.opc = 'cededeffacedacefacedbadfadedbeef',
@@ -1069,12 +1069,12 @@ db_subscr_update_aud_by_id(dbc, id, mk_aud_3g(OSMO_AUTH_ALG_MILENAGE, "BeefedCaf
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1097,12 +1097,12 @@ DAUC Cannot update auth tokens: Unknown auth algo: 99999
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1112,17 +1112,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
.u.umts.ind_bitlen = 5, .u.umts.ind_bitlen = 5,
} }
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f000000000000f00000000000f000000f00000000")) --> -EINVAL db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f000000000000f00000000000f000000f00000000")) --> -EINVAL
DAUC Cannot update auth tokens: Invalid KI: 'f000000000000f00000000000f000000f00000000' DAUC Cannot update auth tokens: Invalid KI: 'f000000000000f00000000000f000000f00000000'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1132,17 +1132,17 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
.u.umts.ind_bitlen = 5, .u.umts.ind_bitlen = 5,
} }
db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR, "f00")) --> -EINVAL db_subscr_update_aud_by_id(dbc, id, mk_aud_2g(OSMO_AUTH_ALG_XOR_2G, "f00")) --> -EINVAL
DAUC Cannot update auth tokens: Invalid KI: 'f00' DAUC Cannot update auth tokens: Invalid KI: 'f00'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1157,12 +1157,12 @@ DAUC Cannot update auth tokens: auth algo not suited for 2G: MILENAGE
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1177,12 +1177,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: '0f000000000000f00000000000f0000
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1197,12 +1197,12 @@ DAUC Cannot update auth tokens: Invalid K: '000000000000f00000000000f000000'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1217,12 +1217,12 @@ DAUC Cannot update auth tokens: Invalid ind_bitlen: 29
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1237,12 +1237,12 @@ DAUC Cannot update auth tokens: Invalid OP/OPC: 'X000000000000f00000000000f00000
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1257,12 +1257,12 @@ DAUC Cannot update auth tokens: Invalid K: 'f000000000000 f00000000000 f000000'
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
2G: struct osmo_sub_auth_data { 2G: struct osmo_sub_auth_data2 {
.type = GSM, .type = GSM,
.algo = COMP128v3, .algo = COMP128v3,
.u.gsm.ki = 'cededeffacedacefacedbadfadedbeef', .u.gsm.ki = 'cededeffacedacefacedbadfadedbeef',
} }
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1338,7 +1338,7 @@ sqlite3_prepare_v2(dbc->db, sql, -1, &stmt, NULL) --> SQLITE_OK
sqlite3_step(stmt) --> SQLITE_DONE sqlite3_step(stmt) --> SQLITE_DONE
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -ENOKEY
DAUC IMSI='123456789000000': Error reading Ki, expected length 16 but has length 15 DAUC IMSI='123456789000000': Error reading Ki, expected min length 16 but has length 15
DAUC IMSI='123456789000000': No 3G Auth Data DAUC IMSI='123456789000000': No 3G Auth Data
@@ -1359,7 +1359,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': Error reading K, expected length 16 but has length 15 DAUC IMSI='123456789000000': Error reading K, expected min length 16 but has length 15
@@ -1374,7 +1374,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': Error reading OP, expected length 16 but has length 15 DAUC IMSI='123456789000000': Error reading OP, expected min length 16 but has length 15
@@ -1389,7 +1389,7 @@ sqlite3_step(stmt) --> SQLITE_DONE
db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5 db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> -5
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
DAUC IMSI='123456789000000': Error reading OPC, expected length 16 but has length 15 DAUC IMSI='123456789000000': Error reading OPC, expected min length 16 but has length 15
@@ -1458,7 +1458,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1477,7 +1477,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1495,7 +1495,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1513,7 +1513,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1534,7 +1534,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1550,7 +1550,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1568,7 +1568,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',
@@ -1586,7 +1586,7 @@ db_get_auth_data(dbc, imsi0, &g_aud2g, &g_aud3g, &g_id) --> 0
DAUC IMSI='123456789000000': No 2G Auth Data DAUC IMSI='123456789000000': No 2G Auth Data
2G: none 2G: none
3G: struct osmo_sub_auth_data { 3G: struct osmo_sub_auth_data2 {
.type = UMTS, .type = UMTS,
.algo = MILENAGE, .algo = MILENAGE,
.u.umts.opc = 'beefedcafefaceacedaddeddecadefee', .u.umts.opc = 'beefedcafefaceacedaddeddecadefee',

View File

@@ -43,5 +43,5 @@ OsmoHLR# subscriber imsi 5555555 create
MSISDN: none MSISDN: none
OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555 OsmoHLR# subscriber imsi 5555555 update msisdn 55555555555555
% Updated subscriber IMSI='5555555' to MSISDN='55555555555555' % Updated subscriber IMSI='5555555' to MSISDN='55555555555555'
OsmoHLR# subscriber imsi 5555555 update aud2g xor ki 55555555555555555555555555555555 OsmoHLR# subscriber imsi 5555555 update aud2g xor-2g ki 55555555555555555555555555555555
OsmoHLR# subscriber imsi 5555555 update aud3g milenage k 55555555555555555555555555555555 opc 55555555555555555555555555555555 OsmoHLR# subscriber imsi 5555555 update aud3g milenage k 55555555555555555555555555555555 opc 55555555555555555555555555555555

View File

@@ -12,7 +12,7 @@ Table auc_2g contents:
algo_id_2g|ki|subscriber_id algo_id_2g|ki|subscriber_id
1|BeefedCafeFaceAcedAddedDecadeFee|1 1|BeefedCafeFaceAcedAddedDecadeFee|1
2|33333333333333333333333333333333|4 2|33333333333333333333333333333333|4
4|55555555555555555555555555555555|6 6|55555555555555555555555555555555|6
Table: auc_3g Table: auc_3g
name|type|notnull|dflt_value|pk name|type|notnull|dflt_value|pk
@@ -86,6 +86,7 @@ DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 3
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4 DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5 DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6 DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 7
DMAIN Cmdline option --db-check: Database was opened successfully, quitting. DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
Resulting db: Resulting db:
@@ -100,15 +101,15 @@ Table auc_2g contents:
algo_id_2g|ki|subscriber_id algo_id_2g|ki|subscriber_id
1|BeefedCafeFaceAcedAddedDecadeFee|1 1|BeefedCafeFaceAcedAddedDecadeFee|1
2|33333333333333333333333333333333|4 2|33333333333333333333333333333333|4
4|55555555555555555555555555555555|6 6|55555555555555555555555555555555|6
Table: auc_3g Table: auc_3g
name|type|notnull|dflt_value|pk name|type|notnull|dflt_value|pk
algo_id_3g|INTEGER|1||0 algo_id_3g|INTEGER|1||0
ind_bitlen|INTEGER|1|5|0 ind_bitlen|INTEGER|1|5|0
k|VARCHAR(32)|1||0 k|VARCHAR(64)|1||0
op|VARCHAR(32)|0||0 op|VARCHAR(64)|0||0
opc|VARCHAR(32)|0||0 opc|VARCHAR(64)|0||0
sqn|INTEGER|1|0|0 sqn|INTEGER|1|0|0
subscriber_id|INTEGER|0||1 subscriber_id|INTEGER|0||1
@@ -179,5 +180,5 @@ osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
rc = 0 rc = 0
DMAIN hlr starting DMAIN hlr starting
DDB using database: <PATH>test.db DDB using database: <PATH>test.db
DDB Database <PATH>test.db' has HLR DB schema version 6 DDB Database <PATH>test.db' has HLR DB schema version 7
DMAIN Cmdline option --db-check: Database was opened successfully, quitting. DMAIN Cmdline option --db-check: Database was opened successfully, quitting.

View File

@@ -61,7 +61,7 @@ CREATE TABLE auc_2g (
); );
INSERT INTO auc_2g VALUES(1,1,'BeefedCafeFaceAcedAddedDecadeFee'); INSERT INTO auc_2g VALUES(1,1,'BeefedCafeFaceAcedAddedDecadeFee');
INSERT INTO auc_2g VALUES(4,2,'33333333333333333333333333333333'); INSERT INTO auc_2g VALUES(4,2,'33333333333333333333333333333333');
INSERT INTO auc_2g VALUES(6,4,'55555555555555555555555555555555'); INSERT INTO auc_2g VALUES(6,6,'55555555555555555555555555555555');
CREATE TABLE auc_3g ( CREATE TABLE auc_3g (
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value algo_id_3g INTEGER NOT NULL, -- enum osmo_auth_algo value

View File

@@ -1,9 +1,9 @@
AM_CPPFLAGS = \ AM_CPPFLAGS = \
$(all_includes) \ $(all_includes) \
-I$(top_srcdir)/include \
$(NULL) $(NULL)
AM_CFLAGS = \ AM_CFLAGS = \
-I$(top_srcdir)/include \
$(LIBOSMOCORE_CFLAGS) \ $(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \ $(LIBOSMOGSM_CFLAGS) \
$(NULL) $(NULL)

View File

@@ -1,11 +1,11 @@
AM_CPPFLAGS = \ AM_CPPFLAGS = \
$(all_includes) \ $(all_includes) \
-I$(top_srcdir)/include \
$(NULL) $(NULL)
AM_CFLAGS = \ AM_CFLAGS = \
-Wall \ -Wall \
-ggdb3 \ -ggdb3 \
-I$(top_srcdir)/include \
$(LIBOSMOCORE_CFLAGS) \ $(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \ $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \ $(LIBOSMOABIS_CFLAGS) \

View File

@@ -32,148 +32,6 @@ struct qname_enc_dec_test {
size_t qname_max_len; /* default: strlen(qname) + 1 */ size_t qname_max_len; /* default: strlen(qname) + 1 */
}; };
static const struct qname_enc_dec_test qname_enc_dec_test_data[] = {
{
/* OK: typical mslookup domain */
.domain = "hlr.1234567.imsi",
.qname = "\x03" "hlr" "\x07" "1234567" "\x04" "imsi",
},
{
/* Wrong format: double dot */
.domain = "hlr..imsi",
.qname = NULL,
},
{
/* Wrong format: double dot */
.domain = "hlr",
.qname = "\x03hlr\0\x03imsi",
},
{
/* Wrong format: dot at end */
.domain = "hlr.",
.qname = NULL,
},
{
/* Wrong format: dot at start */
.domain = ".hlr",
.qname = NULL,
},
{
/* Wrong format: empty */
.domain = "",
.qname = NULL,
},
{
/* OK: maximum length */
.domain =
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"12345"
,
.qname =
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\x05" "12345"
},
{
/* Error: too long domain */
.domain =
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"123456789." "123456789." "123456789." "123456789." "123456789."
"12345toolong"
,
.qname = NULL,
},
{
/* Error: too long qname */
.domain = NULL,
.qname =
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
"\t123456789\t123456789\t123456789\t123456789\t123456789"
},
{
/* Error: wrong token length in qname */
.domain = NULL,
.qname = "\x03" "hlr" "\x07" "1234567" "\x05" "imsi",
},
{
/* Error: wrong token length in qname */
.domain = NULL,
.qname = "\x02" "hlr" "\x07" "1234567" "\x04" "imsi",
},
{
/* Wrong format: token length at end of qname */
.domain = NULL,
.qname = "\x03hlr\x03",
},
{
/* Error: overflow in label length */
.domain = NULL,
.qname = "\x03" "hlr" "\x07" "1234567" "\x04" "imsi",
.qname_max_len = 17,
},
};
void test_enc_dec_rfc_qname(void *ctx)
{
char quote_buf[300];
int i;
fprintf(stderr, "-- %s --\n", __func__);
for (i = 0; i < ARRAY_SIZE(qname_enc_dec_test_data); i++) {
const struct qname_enc_dec_test *t = &qname_enc_dec_test_data[i];
char *res;
if (t->domain) {
fprintf(stderr, "domain: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->domain, -1));
fprintf(stderr, "exp: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->qname, -1));
res = osmo_mdns_rfc_qname_encode(ctx, t->domain);
fprintf(stderr, "res: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), res, -1));
if (t->qname == res || (t->qname && res && strcmp(t->qname, res) == 0))
fprintf(stderr, "=> OK\n");
else
fprintf(stderr, "=> ERROR\n");
if (res)
talloc_free(res);
fprintf(stderr, "\n");
}
if (t->qname) {
size_t qname_max_len = t->qname_max_len;
if (qname_max_len)
fprintf(stderr, "qname_max_len: %lu\n", qname_max_len);
else
qname_max_len = strlen(t->qname) + 1;
fprintf(stderr, "qname: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->qname, -1));
fprintf(stderr, "exp: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), t->domain, -1));
res = osmo_mdns_rfc_qname_decode(ctx, t->qname, qname_max_len);
fprintf(stderr, "res: %s\n", osmo_quote_str_buf2(quote_buf, sizeof(quote_buf), res, -1));
if (t->domain == res || (t->domain && res && strcmp(t->domain, res) == 0))
fprintf(stderr, "=> OK\n");
else
fprintf(stderr, "=> ERROR\n");
if (res)
talloc_free(res);
fprintf(stderr, "\n");
}
}
}
#define PRINT_HDR(hdr, name) \ #define PRINT_HDR(hdr, name) \
fprintf(stderr, "header %s:\n" \ fprintf(stderr, "header %s:\n" \
".id = %i\n" \ ".id = %i\n" \
@@ -216,7 +74,7 @@ static const struct osmo_mdns_rfc_header header_enc_dec_test_data[] = {
}, },
}; };
void test_enc_dec_rfc_header() void test_enc_dec_rfc_header(void)
{ {
int i; int i;
@@ -241,7 +99,7 @@ void test_enc_dec_rfc_header()
} }
} }
void test_enc_dec_rfc_header_einval() void test_enc_dec_rfc_header_einval(void)
{ {
struct osmo_mdns_rfc_header out = {0}; struct osmo_mdns_rfc_header out = {0};
struct msgb *msg = msgb_alloc(4096, "dns_test"); struct msgb *msg = msgb_alloc(4096, "dns_test");
@@ -289,7 +147,7 @@ void test_enc_dec_rfc_question(void *ctx)
struct msgb *msg = msgb_alloc(4096, "dns_test"); struct msgb *msg = msgb_alloc(4096, "dns_test");
PRINT_QST(&in, "in"); PRINT_QST(&in, "in");
assert(osmo_mdns_rfc_question_encode(ctx, msg, &in) == 0); assert(osmo_mdns_rfc_question_encode(msg, &in) == 0);
fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg))); fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg)));
out = osmo_mdns_rfc_question_decode(ctx, msgb_data(msg), msgb_length(msg)); out = osmo_mdns_rfc_question_decode(ctx, msgb_data(msg), msgb_length(msg));
assert(out); assert(out);
@@ -353,7 +211,7 @@ void test_enc_dec_rfc_record(void *ctx)
size_t record_len; size_t record_len;
PRINT_REC(&in, "in"); PRINT_REC(&in, "in");
assert(osmo_mdns_rfc_record_encode(ctx, msg, &in) == 0); assert(osmo_mdns_rfc_record_encode(msg, &in) == 0);
fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg))); fprintf(stderr, "encoded: %s\n", osmo_hexdump(msgb_data(msg), msgb_length(msg)));
out = osmo_mdns_rfc_record_decode(ctx, msgb_data(msg), msgb_length(msg), &record_len); out = osmo_mdns_rfc_record_decode(ctx, msgb_data(msg), msgb_length(msg), &record_len);
fprintf(stderr, "record_len: %lu\n", record_len); fprintf(stderr, "record_len: %lu\n", record_len);
@@ -578,7 +436,7 @@ static void test_result_from_answer(void *ctx)
} }
} }
int main() int main(int argc, char **argv)
{ {
void *ctx = talloc_named_const(NULL, 0, "main"); void *ctx = talloc_named_const(NULL, 0, "main");
osmo_init_logging2(ctx, NULL); osmo_init_logging2(ctx, NULL);
@@ -589,7 +447,6 @@ int main()
log_set_print_category_hex(osmo_stderr_target, 0); log_set_print_category_hex(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0); log_set_use_color(osmo_stderr_target, 0);
test_enc_dec_rfc_qname(ctx);
test_enc_dec_rfc_header(); test_enc_dec_rfc_header();
test_enc_dec_rfc_header_einval(); test_enc_dec_rfc_header_einval();
test_enc_dec_rfc_question(ctx); test_enc_dec_rfc_question(ctx);

View File

@@ -1,85 +1,3 @@
-- test_enc_dec_rfc_qname --
domain: "hlr.1234567.imsi"
exp: "\3hlr\a1234567\4imsi"
res: "\3hlr\a1234567\4imsi"
=> OK
qname: "\3hlr\a1234567\4imsi"
exp: "hlr.1234567.imsi"
res: "hlr.1234567.imsi"
=> OK
domain: "hlr..imsi"
exp: NULL
res: NULL
=> OK
domain: "hlr"
exp: "\3hlr"
res: "\3hlr"
=> OK
qname: "\3hlr"
exp: "hlr"
res: "hlr"
=> OK
domain: "hlr."
exp: NULL
res: NULL
=> OK
domain: ".hlr"
exp: NULL
res: NULL
=> OK
domain: ""
exp: NULL
res: NULL
=> OK
domain: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345"
exp: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\512345"
res: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\512345"
=> OK
qname: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\512345"
exp: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345"
res: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345"
=> OK
domain: "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.12345toolong"
exp: NULL
res: NULL
=> OK
qname: "\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\t123456789\
exp: NULL
res: NULL
=> OK
qname: "\3hlr\a1234567\5imsi"
exp: NULL
res: NULL
=> OK
qname: "\2hlr\a1234567\4imsi"
exp: NULL
res: NULL
=> OK
qname: "\3hlr\3"
exp: NULL
res: NULL
=> OK
qname_max_len: 17
qname: "\3hlr\a1234567\4imsi"
exp: NULL
res: NULL
=> OK
-- test_enc_dec_rfc_header -- -- test_enc_dec_rfc_header --
header in: header in:
.id = 1337 .id = 1337

View File

@@ -80,14 +80,14 @@ static int server_recv(struct osmo_fd *osmo_fd, unsigned int what)
return n; return n;
} }
static void server_init() static void server_init(void)
{ {
fprintf(stderr, "%s\n", __func__); fprintf(stderr, "%s\n", __func__);
server_mc = osmo_mdns_sock_init(ctx, TEST_IP, TEST_PORT, server_recv, NULL, 0); server_mc = osmo_mdns_sock_init(ctx, TEST_IP, TEST_PORT, server_recv, NULL, 0);
OSMO_ASSERT(server_mc); OSMO_ASSERT(server_mc);
} }
static void server_stop() static void server_stop(void)
{ {
fprintf(stderr, "%s\n", __func__); fprintf(stderr, "%s\n", __func__);
OSMO_ASSERT(server_mc); OSMO_ASSERT(server_mc);
@@ -98,7 +98,7 @@ static void server_stop()
struct osmo_mslookup_client* client; struct osmo_mslookup_client* client;
struct osmo_mslookup_client_method* client_method; struct osmo_mslookup_client_method* client_method;
static void client_init() static void client_init(void)
{ {
fprintf(stderr, "%s\n", __func__); fprintf(stderr, "%s\n", __func__);
client = osmo_mslookup_client_new(ctx); client = osmo_mslookup_client_new(ctx);
@@ -117,7 +117,7 @@ static void client_recv(struct osmo_mslookup_client *client, uint32_t request_ha
osmo_mslookup_client_request_cancel(client, request_handle); osmo_mslookup_client_request_cancel(client, request_handle);
} }
static void client_query() static void client_query(void)
{ {
struct osmo_mslookup_id id = {.type = OSMO_MSLOOKUP_ID_IMSI, struct osmo_mslookup_id id = {.type = OSMO_MSLOOKUP_ID_IMSI,
.imsi = "123456789012345"}; .imsi = "123456789012345"};
@@ -134,7 +134,7 @@ static void client_query()
osmo_mslookup_client_request(client, &query, &handling); osmo_mslookup_client_request(client, &query, &handling);
} }
static void client_stop() static void client_stop(void)
{ {
fprintf(stderr, "%s\n", __func__); fprintf(stderr, "%s\n", __func__);
osmo_mslookup_client_free(client); osmo_mslookup_client_free(client);
@@ -154,7 +154,7 @@ const struct timeval fake_time_start_time = { 0, 0 };
osmo_timers_update(); \ osmo_timers_update(); \
} while (0) } while (0)
static void fake_time_start() static void fake_time_start(void)
{ {
struct timespec *clock_override; struct timespec *clock_override;
@@ -167,7 +167,7 @@ static void fake_time_start()
osmo_clock_override_enable(CLOCK_MONOTONIC, true); osmo_clock_override_enable(CLOCK_MONOTONIC, true);
fake_time_passes(0, 0); fake_time_passes(0, 0);
} }
static void test_server_client() static void test_server_client(void)
{ {
fprintf(stderr, "-- %s --\n", __func__); fprintf(stderr, "-- %s --\n", __func__);
server_init(); server_init();
@@ -190,7 +190,7 @@ static void test_server_client()
client_stop(); client_stop();
} }
bool is_multicast_enabled() bool is_multicast_enabled(void)
{ {
bool ret = true; bool ret = true;
struct addrinfo *ai; struct addrinfo *ai;
@@ -222,7 +222,7 @@ bool is_multicast_enabled()
/* /*
* Run all tests * Run all tests
*/ */
int main() int main(int argc, char **argv)
{ {
if (!is_multicast_enabled()) { if (!is_multicast_enabled()) {
fprintf(stderr, "ERROR: multicast is disabled! (OS#4361)"); fprintf(stderr, "ERROR: multicast is disabled! (OS#4361)");

View File

@@ -147,7 +147,7 @@ const struct timeval fake_time_start_time = { 0, 0 };
osmo_timers_update(); \ osmo_timers_update(); \
} while (0) } while (0)
static void fake_time_start() static void fake_time_start(void)
{ {
struct timespec *clock_override; struct timespec *clock_override;
@@ -169,7 +169,7 @@ static void result_cb_once(struct osmo_mslookup_client *client,
LOGP(DMSLOOKUP, LOGL_DEBUG, "result_cb(): %s\n", osmo_mslookup_result_name_c(ctx, query, result)); LOGP(DMSLOOKUP, LOGL_DEBUG, "result_cb(): %s\n", osmo_mslookup_result_name_c(ctx, query, result));
} }
int main() int main(int argc, char **argv)
{ {
ctx = talloc_named_const(NULL, 0, "main"); ctx = talloc_named_const(NULL, 0, "main");
osmo_init_logging2(ctx, NULL); osmo_init_logging2(ctx, NULL);

View File

@@ -50,7 +50,7 @@ const char *domains[] = {
"qwerty.1.qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmm", "qwerty.1.qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnmm",
}; };
void test_osmo_mslookup_query_init_from_domain_str() void test_osmo_mslookup_query_init_from_domain_str(void)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(domains); i++) { for (i = 0; i < ARRAY_SIZE(domains); i++) {
@@ -68,7 +68,7 @@ void test_osmo_mslookup_query_init_from_domain_str()
} }
} }
int main() int main(int argc, char **argv)
{ {
ctx = talloc_named_const(NULL, 0, "main"); ctx = talloc_named_const(NULL, 0, "main");
osmo_init_logging2(ctx, NULL); osmo_init_logging2(ctx, NULL);

View File

@@ -47,11 +47,13 @@ OsmoHLR(config-hlr)# ?
no Negate a command or set its defaults no Negate a command or set its defaults
ussd USSD Configuration ussd USSD Configuration
ncss-guard-timeout Set guard timer for NCSS (call independent SS) session activity ncss-guard-timeout Set guard timer for NCSS (call independent SS) session activity
reject-cause GSUP/GMM cause to be sent
store-imei Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1'). store-imei Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').
subscriber-create-on-demand Make a new record when a subscriber is first seen. subscriber-create-on-demand Make a new record when a subscriber is first seen.
OsmoHLR(config-hlr)# list OsmoHLR(config-hlr)# list
... ...
gsup gsup
ps
database PATH database PATH
euse NAME euse NAME
no euse NAME no euse NAME
@@ -61,6 +63,7 @@ OsmoHLR(config-hlr)# list
ussd default-route external EUSE ussd default-route external EUSE
no ussd default-route no ussd default-route
ncss-guard-timeout <0-255> ncss-guard-timeout <0-255>
reject-cause (not-found|no-proxy) (imsi-unknown|illegal-ms|plmn-not-allowed|la-not-allowed|roaming-not-allowed|no-suitable-cell-in-la|net-fail|congestion|auth-unacceptable|proto-error-unspec)
store-imei store-imei
no store-imei no store-imei
subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps) subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)
@@ -110,6 +113,12 @@ hlr
ipa-name unnamed-HLR ipa-name unnamed-HLR
ussd route prefix *#100# internal own-msisdn ussd route prefix *#100# internal own-msisdn
ussd route prefix *#101# internal own-imsi ussd route prefix *#101# internal own-imsi
ps
pdp-profiles default
profile 1
apn internet
profile 2
apn *
end end
OsmoHLR# configure terminal OsmoHLR# configure terminal
@@ -349,15 +358,15 @@ mslookup
service foo.bar at 123.45.67.89 1011 service foo.bar at 123.45.67.89 1011
service baz.bar at 121.31.41.5 1617 service baz.bar at 121.31.41.5 1617
service baz.bar at a:b:c::d 1819 service baz.bar at a:b:c::d 1819
msc MSC-1 msc ipa-name MSC-1
msc msc-901-70-23 msc ipa-name msc-901-70-23
service foo.bar at 76.54.32.10 1234 service foo.bar at 76.54.32.10 1234
service baz.bar at 12.11.10.98 7654 service baz.bar at 12.11.10.98 7654
service baz.bar at dd:cc:bb::a 3210 service baz.bar at dd:cc:bb::a 3210
msc msc-901-70-42 msc ipa-name msc-901-70-42
service foo.bar at 1.1.1.1 1111 service foo.bar at 1.1.1.1 1111
service baz.bar at 2.2.2.2 2222 service baz.bar at 2.2.2.2 2222
service baz.bar at 2222:2222:2222::2 2222 service baz.bar at 2222:2222:2222::2 2222
client client
gateway-proxy 1.2.3.4 4222 gateway-proxy 1.2.3.4 4222
mdns bind 239.192.23.42 4266 mdns bind 239.192.23.42 4266
@@ -404,12 +413,12 @@ mslookup
mdns bind 239.192.23.42 4266 mdns bind 239.192.23.42 4266
service foo.bar at 123.45.67.89 1011 service foo.bar at 123.45.67.89 1011
service baz.bar at 121.31.41.5 1617 service baz.bar at 121.31.41.5 1617
msc MSC-1 msc ipa-name MSC-1
msc msc-901-70-23 msc ipa-name msc-901-70-23
service foo.bar at 76.54.32.10 1234 service foo.bar at 76.54.32.10 1234
service baz.bar at 12.11.10.98 7654 service baz.bar at 12.11.10.98 7654
msc msc-901-70-42 msc ipa-name msc-901-70-42
service foo.bar at 1.1.1.1 1111 service foo.bar at 1.1.1.1 1111
client client
mdns bind 239.192.23.42 4266 mdns bind 239.192.23.42 4266
... ...
@@ -437,12 +446,53 @@ mslookup
service foo.bar at 123.45.67.89 1011 service foo.bar at 123.45.67.89 1011
service baz.bar at 121.31.41.5 1617 service baz.bar at 121.31.41.5 1617
service gsup.hlr at 23.42.17.11 4223 service gsup.hlr at 23.42.17.11 4223
msc MSC-1 msc ipa-name MSC-1
msc msc-901-70-23 msc ipa-name msc-901-70-23
service foo.bar at 76.54.32.10 1234 service foo.bar at 76.54.32.10 1234
service baz.bar at 12.11.10.98 7654 service baz.bar at 12.11.10.98 7654
msc msc-901-70-42 msc ipa-name msc-901-70-42
service foo.bar at 1.1.1.1 1111 service foo.bar at 1.1.1.1 1111
client client
mdns bind 239.192.23.42 4266 mdns bind 239.192.23.42 4266
... ...
OsmoHLR(config-mslookup-server)# end
OsmoHLR# configure terminal
OsmoHLR(config)# hlr
OsmoHLR(config-hlr)# ps?
ps Configure the PS options
OsmoHLR(config-hlr)# ps
OsmoHLR(config-hlr-ps)# list
...
pdp-profiles default
no pdp-profiles default
...
OsmoHLR(config-hlr-ps)# no pdp-profiles default
OsmoHLR(config-hlr-ps)# pdp-profiles default
OsmoHLR(config-hlr-ps-pdp-profiles)# ?
...
profile Configure a PDP profile
...
OsmoHLR(config-hlr-ps-pdp-profiles)# profile 1
OsmoHLR(config-hlr-ps-pdp-profile)# ?
...
apn Configure the APN.
...
OsmoHLR(config-hlr-ps-pdp-profile)# apn internet
OsmoHLR(config-hlr-ps-pdp-profile)# exit
OsmoHLR(config-hlr-ps-pdp-profiles)# profile 2
OsmoHLR(config-hlr-ps-pdp-profile)# apn *
OsmoHLR(config-hlr-ps-pdp-profile)# show running-config
...
ps
pdp-profiles default
profile 1
apn internet
profile 2
apn *
...

View File

@@ -674,9 +674,12 @@ lmsi 00000000
GET 112 subscriber.by-imsi-901991234567891.aud2g GET 112 subscriber.by-imsi-901991234567891.aud2g
GET_REPLY 112 subscriber.by-imsi-901991234567891.aud2g none GET_REPLY 112 subscriber.by-imsi-901991234567891.aud2g none
SET 113 subscriber.by-imsi-901991234567891.aud2g xor,c01ffedc1cadaeac1d1f1edacac1ab0a SET 113 subscriber.by-imsi-901991234567891.aud2g xor-2g,c01ffedc1cadaeac1d1f1edacac1ab0a
SET_REPLY 113 subscriber.by-imsi-901991234567891.aud2g OK SET_REPLY 113 subscriber.by-imsi-901991234567891.aud2g OK
GET 114 subscriber.by-imsi-901991234567891.aud2g
GET_REPLY 114 subscriber.by-imsi-901991234567891.aud2g XOR-2G,c01ffedc1cadaeac1d1f1edacac1ab0a
SET 115 subscriber.by-imsi-901991234567891.aud2g none SET 115 subscriber.by-imsi-901991234567891.aud2g none
SET_REPLY 115 subscriber.by-imsi-901991234567891.aud2g OK SET_REPLY 115 subscriber.by-imsi-901991234567891.aud2g OK

View File

@@ -8,10 +8,10 @@ OsmoHLR# list
subscriber (imsi|msisdn|id|imei) IDENT delete subscriber (imsi|msisdn|id|imei) IDENT delete
subscriber (imsi|msisdn|id|imei) IDENT update msisdn (none|MSISDN) subscriber (imsi|msisdn|id|imei) IDENT update msisdn (none|MSISDN)
subscriber (imsi|msisdn|id|imei) IDENT update aud2g none subscriber (imsi|msisdn|id|imei) IDENT update aud2g none
subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor) ki KI subscriber (imsi|msisdn|id|imei) IDENT update aud2g (comp128v1|comp128v2|comp128v3|xor-2g) ki KI
subscriber (imsi|msisdn|id|imei) IDENT update aud3g none subscriber (imsi|msisdn|id|imei) IDENT update aud3g none
subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>] subscriber (imsi|msisdn|id|imei) IDENT update aud3g (milenage|tuak) k K (op|opc) OP_C [ind-bitlen] [<0-28>]
subscriber (imsi|msisdn|id|imei) IDENT update aud3g xor k K [ind-bitlen] [<0-28>] subscriber (imsi|msisdn|id|imei) IDENT update aud3g xor-3g k K [ind-bitlen] [<0-28>]
subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI) subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI)
subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps) subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps)
show mslookup services show mslookup services
@@ -144,7 +144,7 @@ OsmoHLR# subscriber imsi 123456789023000 update aud2g ?
comp128v1 Use COMP128v1 algorithm comp128v1 Use COMP128v1 algorithm
comp128v2 Use COMP128v2 algorithm comp128v2 Use COMP128v2 algorithm
comp128v3 Use COMP128v3 algorithm comp128v3 Use COMP128v3 algorithm
xor Use XOR algorithm xor-2g Use XOR-2G algorithm
OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ? OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ?
ki Set Ki Encryption Key ki Set Ki Encryption Key
@@ -155,12 +155,12 @@ OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki ?
OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki val ? OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki val ?
<cr> <cr>
OsmoHLR# subscriber imsi 123456789023000 update aud2g xor ki Deaf0ff1ceD0d0DabbedD1ced1ceF00d OsmoHLR# subscriber imsi 123456789023000 update aud2g xor-2g ki Deaf0ff1ceD0d0DabbedD1ced1ceF00d
OsmoHLR# subscriber imsi 123456789023000 show OsmoHLR# subscriber imsi 123456789023000 show
ID: 101 ID: 101
IMSI: 123456789023000 IMSI: 123456789023000
MSISDN: 423 MSISDN: 423
... 2G auth: XOR-2G
KI=deaf0ff1ced0d0dabbedd1ced1cef00d KI=deaf0ff1ced0d0dabbedd1ced1cef00d
OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee OsmoHLR# subscriber imsi 123456789023000 update aud2g comp128v1 ki BeefedCafeFaceAcedAddedDecadeFee
@@ -241,7 +241,7 @@ OsmoHLR# subscriber id 101 show
2G auth: COMP128v3 2G auth: COMP128v3
KI=c01ffedc1cadaeac1d1f1edacac1ab0a KI=c01ffedc1cadaeac1d1f1edacac1ab0a
OsmoHLR# subscriber id 101 update aud2g xor ki CoiffedCicadaeAcidifiedAcaciaBoa OsmoHLR# subscriber id 101 update aud2g xor-2g ki CoiffedCicadaeAcidifiedAcaciaBoa
% Invalid value for KI: 'CoiffedCicadaeAcidifiedAcaciaBoa' % Invalid value for KI: 'CoiffedCicadaeAcidifiedAcaciaBoa'
OsmoHLR# subscriber id 101 show OsmoHLR# subscriber id 101 show
ID: 101 ID: 101
@@ -250,7 +250,7 @@ OsmoHLR# subscriber id 101 show
2G auth: COMP128v3 2G auth: COMP128v3
KI=c01ffedc1cadaeac1d1f1edacac1ab0a KI=c01ffedc1cadaeac1d1f1edacac1ab0a
OsmoHLR# subscriber id 101 update aud2g xor ki C01ffedC1cadaeAc1d1f1edAcac1aB0aX OsmoHLR# subscriber id 101 update aud2g xor-2g ki C01ffedC1cadaeAc1d1f1edAcac1aB0aX
% Invalid value for KI: 'C01ffedC1cadaeAc1d1f1edAcac1aB0aX' % Invalid value for KI: 'C01ffedC1cadaeAc1d1f1edAcac1aB0aX'
OsmoHLR# subscriber id 101 show OsmoHLR# subscriber id 101 show
ID: 101 ID: 101
@@ -269,20 +269,21 @@ OsmoHLR# subscriber id 101 show
OsmoHLR# subscriber imsi 123456789023000 update aud3g ? OsmoHLR# subscriber imsi 123456789023000 update aud3g ?
none Delete 3G authentication data none Delete 3G authentication data
milenage Use Milenage algorithm milenage Use Milenage algorithm
xor Use XOR algorithm tuak Use TUAK algorithm
xor-3g Use XOR-3G algorithm
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage ? OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage ?
k Set Encryption Key K k Set Encryption Key K
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k ? OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k ?
K K as 32 hexadecimal characters K K as 32/64 hexadecimal characters
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d ? OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d ?
op Set OP key op Set OP key
opc Set OPC key opc Set OPC key
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc ? OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc ?
OP_C OP or OPC as 32 hexadecimal characters OP_C OP or OPC as 32/64 hexadecimal characters
OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc CededEffacedAceFacedBadFadedBeef ? OsmoHLR# subscriber imsi 123456789023000 update aud3g milenage k Deaf0ff1ceD0d0DabbedD1ced1ceF00d opc CededEffacedAceFacedBadFadedBeef ?
[ind-bitlen] Set IND bit length [ind-bitlen] Set IND bit length

View File

@@ -130,7 +130,7 @@ ERROR 54 Value failed verification.
SET 55 subscriber.by-imsi-901990000000003.aud2g foobar,2134 SET 55 subscriber.by-imsi-901990000000003.aud2g foobar,2134
ERROR 55 Unknown auth algorithm. ERROR 55 Unknown auth algorithm.
SET 56 subscriber.by-imsi-901990000000003.aud2g xor,2134 SET 56 subscriber.by-imsi-901990000000003.aud2g xor-2g,2134
ERROR 56 Invalid KI. ERROR 56 Invalid KI.
SET 57 subscriber.by-imsi-901990000000003.aud3g foobar SET 57 subscriber.by-imsi-901990000000003.aud3g foobar
@@ -139,17 +139,17 @@ ERROR 57 Value failed verification.
SET 58 subscriber.by-imsi-901990000000003.aud3g foobar,2134 SET 58 subscriber.by-imsi-901990000000003.aud3g foobar,2134
ERROR 58 Unknown auth algorithm. ERROR 58 Unknown auth algorithm.
SET 60 subscriber.by-imsi-901990000000003.aud3g milenage,2134 SET 59 subscriber.by-imsi-901990000000003.aud3g milenage,2134
ERROR 60 Invalid KI. ERROR 59 Invalid KI.
SET 61 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,AAA SET 60 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,AAA
ERROR 60 Invalid format.
SET 61 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC
ERROR 61 Invalid format. ERROR 61 Invalid format.
SET 62 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC SET 62 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,zzz
ERROR 62 Invalid format. ERROR 62 Invalid OP/OPC.
SET 63 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,zzz SET 63 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,
ERROR 63 Invalid OP/OPC. ERROR 63 Invalid format.
SET 64 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,
ERROR 64 Invalid format.

View File

@@ -27,12 +27,7 @@ AT_KEYWORDS([db])
cat $abs_srcdir/db/db_test.ok > expout cat $abs_srcdir/db/db_test.ok > expout
cat $abs_srcdir/db/db_test.err > experr cat $abs_srcdir/db/db_test.err > experr
sqlite3 db_test.db < $abs_top_srcdir/sql/hlr.sql sqlite3 db_test.db < $abs_top_srcdir/sql/hlr.sql
AT_CHECK([$abs_top_builddir/tests/db/db_test], [], [expout], [experr])
# Compatibility with libosmocore I446e54d0ddf4a18c46ee022b1249af73552e3ce1
$abs_top_builddir/tests/db/db_test >out 2>err
sed -i "s/XOR-3G,/XOR,/g" err
AT_CHECK([cat out; cat err >&2], [], [expout], [experr])
AT_CLEANUP AT_CLEANUP
# AT_SKIP_IF: disable for old sqlite versions, because the way we dump tables in the test doesn't work with it. # AT_SKIP_IF: disable for old sqlite versions, because the way we dump tables in the test doesn't work with it.